Contracts
collection-store.md
Contract: collection store and reuse evidence
collect_universe(repo_root: Path | None = None) -> list[TestRecord]
The signature and return value are unchanged. For identical inputs the returned list is equal, element for element, to what a fresh collection returns.
| Situation | Store read | Store written | Report outcome / reason |
|---|---|---|---|
repo_root passed | no | no | bypassed / root-override |
| checkout has uncommitted changes | no | no | bypassed / dirty-checkout |
| platform or store unusable | no | no | bypassed / unsupported-platform |
| git cannot describe the checkout | no | no | bypassed / git-unavailable |
| lock or store error | no | no | bypassed / unsupported-platform, with detail |
| operator env file exists but cannot be read | no | no | bypassed / env-file-unreadable, with detail |
| valid record, matching key and origin | yes | no | reused |
| no record for key | yes | yes, after a successful collection | collected / no-record |
| record unreadable, wrong schema, empty, below the 1,000-record sanity floor, count mismatch | yes | yes, replaced after a successful collection | collected / invalid-record |
| record key matches, commit or tree differs | yes | yes, replaced | collected / origin-mismatch |
| collection fails | — | no | none; the existing RuntimeError is raised unchanged |
Concurrency: for one key, at most one collection runs at a time on a machine; other callers block on the lock and then reuse.
python -m scripts.ci.collect_universe_prestep <command>
| Command | Behaviour | Exit |
|---|---|---|
key | prints the collection key for the current checkout and environment (used as the CI cache key) | 0; 2 when the checkout is dirty |
collect | calls collect_universe() once; prints the report line | 0 only when its line is reused, or collected with the record stored, or bypassed / unsupported-platform with no detail; non-zero otherwise (dirty checkout, git unavailable, lock or store failure, record not stored, collection failure, no report line) |
check | reads the report file, writes a table to the job summary, and compares with the pre-test step's outcome | 1 when the pre-test step's own line is anything other than reused, a stored collected, or bypassed / unsupported-platform with no detail; 1 when the pre-test step stored or reused a record and any later line is collected, or bypassed for a reason other than root-override; 1 on a malformed line; 0 otherwise. Fallback mode (exit 0 with a note) applies only when there is no report file, an empty report, or no prestep line |
compare | performs one fresh collection with the store bypassed and diffs it against the stored record | 1 on any difference or when no stored record exists; 0 when equal |
Workflow shape (pinned by test)
In each consuming job, in this order: compute key → restore store (guarded on a non-empty key) → collect → save store → pytest (unchanged command) → check with if: always(). The save does not depend on pytest's outcome. The pytest command line of each job is byte-identical to today's.
scheduled-recapture.md
Contract: generalised scheduled recapture
python -m scripts.ci.recapture_shard_timings
| Option | Meaning |
|---|---|
--module NAME (repeatable) | restrict to these registry modules; default is every registry module |
--budget-seconds N | stop starting captures once N seconds have elapsed |
--write | write refreshed data through the canonical producer; without it, report only |
Behaviour, in order:
1. Count-only pass: collect each candidate module's test count without running tests. 2. A module is drifted when its collected count differs from the committed count, or its provenance record is missing or not valid. 3. For each drifted module, longest-untouched first, while budget remains: run the canonical producer for that module in its own subprocess. 4. A capture is valid when its exit status is 0 or 1 and it recorded at least one duration (the shared predicate). An invalid capture leaves that module's committed data byte-identical. 5. Shard counts are not touched by the script; the existing skew check reports a count that no longer fits. 6. Print a machine-readable result (drifted, captured, failed, deferred) and a job-summary table.
Exit status: 0 when nothing failed (including "nothing drifted"); 1 when any capture failed.
Workflow
- Triggers and the primary-branch gate are unchanged.
- A rejected push exits non-zero with a message naming the missing repository permission and the secret that supplies the token.
- Publication: no drift → no proposal. Drift and no open proposal → push the fixed proposal branch and open a pull request. Drift and an open proposal → add a follow-up commit on that branch (never a forced push).
- The strict agreement check stays in the same workflow as an independent job (no ordering between it and the recapture job, as before).
Provenance completeness (tests/architectural/test_shard_capture_provenance.py)
- Every module in
.github/ci-module-registry.ymlhas a valid provenance record; a failure names the module. - Self-mutation: removing one module's provenance, and replacing it with an invalid record, each make the check fail on the same data.
- Shard counts are covered by the existing skew check in
tests/architectural/test_module_shard_registry.py; this mission adds no second check.