Skip to content

Execution audit

Before creating a release tag, run just audit-code on the source being released. The same gate runs in CI on CPython 3.14. It uses the existing coverage/testing dependencies; BlackBull's supported Python floor is unchanged. Keep the generated report under build/execution-audit/ until review is complete.

The gate runs unit, architecture, properties, integration and conformance suites together, with integration enabled. Docker-dependent tests retain their normal skip conditions. Quantitative tests marked no_audit(reason=...) must first pass without instrumentation. Their exact JUnit identities are checked against the tests skipped during collection; a missing control fails the gate.

The source inventory lists definitions; coverage records executed lines. sys.monitoring records function entry, including one-line bodies, and global/name reads. A module subtype records attribute reads, including aliases, from imports and getattr. Values are not proxied. Class references and method entry remain separate from class-definition execution: importing a class does not exercise its methods.

The report lists unobserved candidates, not proven dead code. Static reference-zero scans misclassify re-exports, aliases and registry callbacks. For a documented API, add a test of its behavior. Remove a definition only after confirming it is obsolete. Other retained candidates require an exact symbol and a specific reason in tools/execution_audit_allowlist.json; there are no wildcards or automatic baseline updates. Removed/renamed allowances fail too.

Each collection uses fresh output, source hashes and a run token. A failed test, initialization error, missing observation or absent suite prevents success. Normal subprocess, fork, spawn, forkserver, low-level exit and re-exec paths save observations separately; pre-exec records survive a reused PID.

Limits: observation covers the executed configuration, not every possible platform or input. Reads through globals()/vars() dictionaries, rebound code namespaces and custom import loaders can evade the binding observer. Reads are tracked by fixed symbol name, not assignment version. SIGKILL or a native crash can lose a child's final observations. Instrumentation changes timing and allocation, so this gate cannot measure performance or prove semantic equivalence.

For diagnosis, collect with python -m tools.execution_audit collect --output DIR and inspect with python -m tools.execution_audit check --output DIR --require-suites. A failed collection can still produce a diagnostic candidate list; it cannot pass the gate. Reports and individual observations are generated evidence, not files to commit. Record the method, classification and summary in the issue.