Files
gstack/docs/test-audit-2026-10.md
Garry Tanandcapy-ai[bot] a889ef9393 v1.91.105.0 fix(tests): the free suite stops needing its retry pass; test:health tells the truth (#3154) (#3212)
* test: turn git auto-maintenance off in free fixtures, with a runner backstop

git 2.29+ starts a detached `git maintenance run --auto` after every commit;
it creates and deletes .git/objects/maintenance.lock after the commit returns.
Diagnosed on 47d639a (git 2.55.0):

- gstack-docs-candidate (ledger 37742176952/16): 4/150 replicated snapshots
  saw the .git listing change, every one `-objects/maintenance.lock`; 0/150
  with the keys. repo() now sets maintenance.auto=false and gc.auto=0.
- plan-design-sdk-fixture (ledger 37807608021/6): under commit load 18/150
  runs failed the collector check; in every one Bun's rmSync(recursive, force)
  returned without throwing and left the scratch repo behind. 0/100 with the
  keys in the fixture's replacement git env, which never sees the runner's.
- qa-functional-observer (ledger 37800857251/4): under load 6/200 observer
  setups threw ENOENT lstat .git/objects/maintenance.lock; 0/400 with the keys
  in the inherited env. The observer and its fixture (22 paid cases) are not
  edited; the runner backstop covers them.

runFreeShard appends the two keys after any inherited GIT_CONFIG_* pairs of
each shard child (a malformed inherited count is left for git to reject).
A GIT_TRACE commit shows 3 maintenance lines with defaults and 0 in the
runner child env; the new test pins that and the env merge cases.
Failure messages now name the changed .git entries and surviving fixture
directories; no assertion changed.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test: synchronize the zombie publication-lock test on a framed PID line

Ledger 38153371796/3 and 38161906980/3: line 69 `existsSync(ready)` failed.
The test polled 300 x 10 ms for the Python parent's readiness file, then
another 300 x 10 ms of /proc for state Z; under shard load the fixed count
expired. existsSync also raced the write (an empty file read as pid 0).

The parent now waits for its child with os.waitid(P_PID, WEXITED|WNOWAIT),
which leaves it unreaped in state Z, and prints the PID with flush=True. The
test reads exactly one newline-framed line from the parent's stdout under the
test's own (unchanged) 10 s timeout, rejects a malformed or non-positive PID,
and makes one /proc read that must show Z. Early exit, a malformed line or a
timeout reports the parent's exit status and stderr tail; the owned parent is
always killed in cleanup.

Intentional assertion replacement: the readiness-file existence check and the
polling loop are replaced by the framed-line requirement (a positive PID) and
one /proc read; `expect(state).toBe('Z')` and every lock-recovery assertion
are unchanged.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test: stop the next-version smoke test from calling live GitHub

Ledger 37804770972/9: "CLI runs against real repo and emits parseable JSON"
failed with `JSON Parse error: Unexpected EOF` after 30032 ms. The smoke test
ran the real CLI against live `gh`; bin/gstack-next-version's per-PR
`gh api` calls run one after another (spawnSync inside its async workers), so
27 open PRs passed the 30 s spawn timeout and stdout was empty. Measured with
a delayed fake gh: 8 PRs x 0.5 s = 4108 ms; 27 PRs x 1.2 s = 32637 ms. The
CLI defect is filed as a P1 follow-up, not fixed here.

The test keeps the real repository and the real CLI and puts a named fake gh
first on PATH. It logs every argv, answers exactly the calls the CLI makes
(auth status only when origin is not github.com, pr view exit 1, canned pr
list, repo view and contents with one same-owner PR claiming 1.6.4.0) and
exits 2 with a FAKE_GH_UNHANDLED marker for anything else; glab exits 1. The
test now checks the exit code with stderr before JSON.parse, the exact call
set, no marker, no glab call, host github, offline false, no fallback, no
warnings, the canned claim, and version 1.6.5.0. Every existing assertion is
kept; the spawn timeout is unchanged.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(test-health): report the Windows wall over PR runs and name the seed's real prerequisite

free-wall read windows-free-tests.yml with `branch: 'main'`, but that
workflow runs only on pull requests and workflow_dispatch, so the "main" runs
it averaged were dispatch duration recordings. It now uses listWorkflowRuns'
existing `event: 'pull_request'` filter and prints the population inline:
`windows-free-tests (successful PR runs) 7.1 min (23 runs)`, or `no
successful PR runs in window`. The free-tests half is byte-identical.

The CEO-10 fix text stops offering a "CI recording" (none exists for the Linux
seed) and names UBICLOUD_API_KEY; test:ubicloud --record-durations copies the
seed back into the checkout, and contributors without the key leave the
refresh to a maintainer. docs/TESTING_INTERNALS.md drops "or a CI recording"
in the same change.

Intentional pin change: test/test-health-report.test.ts free-wall value
`windows-free-tests 0.0 min (1 runs)` -> `windows-free-tests (successful PR
runs) 0.0 min (1 runs)`; the fixture now carries a PR run and an excluded
dispatch run, plus a new case for the empty and mixed populations.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(timeline-read): reject missing and unparseable --since/--branch values

`--since` and `--branch` read an unbound $2 under `set -u` and crashed with
exit 1 when given no value, and an unparseable --since ("yesterday", "2
weeks") silently returned unfiltered history because the Bun regex was
unanchored and fell through. Unknown arguments were silently ignored.

--since is now parsed once in bash (no `date -d`, no bash-4 features) into a
cutoff in epoch ms, and the Bun regex is deleted. Accepted forms: "<N>
minute|hour|day|week|month[s] ago" (case-insensitive, as before), "<N>h|d|w"
(the form gstack-global-discover documents) and ISO dates YYYY-MM-DD or
YYYY-MM-DDTHH:MM:SSZ (UTC). In #1723's shape, before any read:

  --since must be a relative time like "7 days ago" (got no value); accepted: ...
  --since must be a relative time like "7 days ago" (got 'yesterday'); accepted: ...
  --branch must be a branch name (got flag '--limit')

with "got an empty value" for ''. Unknown arguments exit 2 with the usage
line; --help/-h prints it and exits 0. Tests extend the --limit table in
test/timeline.test.ts and run every case on empty and populated history,
plus each accepted --since form filtering old events; the quoted-branch and
no-filter tests are unchanged.

Behavior change: unrecognized arguments (previously ignored) now exit 2.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs: record the due audit follow-ups with verdicts, and file wave-2 follow-ups

docs/test-audit-2026-10.md gains a dated 2026-10-15 section from a no-spend
`bun run test:health --since-days 7`, with the 2026-10-12 figures from #3154
kept as history and a verdict per target: full-fallback 45.9% (open; the
audit's next step is touchfile mappings for bin/, lib/, hosts/, make-pdf/),
spend per merged PR $73.52 (verdict unavailable: the pre-change baseline,
recomputed with collectHealth at now=2026-10-04 behind an upper-bound client,
holds no trial-outcomes artifacts because the recorder shipped with the
audit), cancelled slice-minutes 1,545/week, push-to-verdict p50 11.4 min
(missed against 3-5 min), flaky-pass 6.1% (missed; this wave repairs it).
Census reliability is not due until 2026-10-26; the interim figure is
recorded and the repair stays with #3153/#3200.

TODOS.md: one appended dated section (P1 gstack-next-version serial fetch with
the 4160 ms measurement, P1 standing seed recorder, P1 full-fallback/spend,
P1 dated flake follow-ups, P2 createQAFunctionalFixture maintenance keys, P2
diagnostic-mode HOME/state-root artifacts). The timeline-read bullet was
deleted with its fix.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* chore(release): tentative stamp v1.91.105.0 with its CHANGELOG entry

Stamp-at-merge policy (.gstack/ship-policy.json): the branch carries a
tentative PATCH stamp and its CHANGELOG section directly under
`# Changelog`; the queue restamps at merge time. Base 47d639a is 1.91.101.0,
but the live slot scan shows 1.91.102.0 (#3190), 1.91.103.0 (#3200) and
1.91.104.0 (#3209) claimed, so this branch takes 1.91.105.0. Written with
`gstack-restamp --version 1.91.105.0 --base main --expect-base 47d639a
--allow-repo-commands` (VERSION, package.json's npm translation, the agents
digest via the policy's release tool, and the CHANGELOG header).

* test(seed): refresh the free-suite duration seed from a Ubicloud recording (#3154)

Recorded with `bun run test:ubicloud --record-durations` (standard-16,
eu-central-h1) on this branch, which equals origin/main 47d639a plus this
wave; the recorder exited 0 and wrote 1219 durations (1055 before, 164 new,
none removed; serial 2439 s -> 3202 s). `test:health` CEO-10 now reports
0 unseeded files.

Two earlier recordings did not count: one failed on an unrelated fixed-sleep
race in test/plan-seed-submission.test.ts (filed P2, not edited here), the
other failed free-seed-ratchet because it ran against the first attempt's
pulled seed. No file was excluded.

free-seed-ratchet: three files are over the 60 s ceiling in this recording
and are allowlisted with a split todo (setup-install-registry 82 s,
host-renders-prune 64 s, setup-codex-scope 60.4 s); the split follow-up and
the plan-seed-submission race are filed in the appended TODOS section.

The ratchet test now names scripts/free-test-seed-allowlist.json literally
(a pin on SEED_ALLOWLIST_FILE): pregate's lanes check maps data files to
tests through string literals, and the allowlist had no lane
(PREGATE_NO_LANE). Additive assertion; nothing weakened.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test: give the git-maintenance backstop test a Windows-safe empty global config

windows-free-shard (2) on #3212 (run 38832498861) failed two cases in
test/test-free-shards-git-maintenance.test.ts, both serially reproduced by
the retry pass: Git for Windows rejects GIT_CONFIG_GLOBAL=os.devNull
(`fatal: unable to access '\\.\nul': Invalid argument`), so the malformed-count
case saw that error instead of git's GIT_CONFIG_COUNT rejection, and the traced
commit's `git init` exited nonzero. Point GIT_CONFIG_GLOBAL at a file that does
not exist in the scratch HOME, as test/ceo-plan-mode-fixture.test.ts does;
git reads a missing global config as empty on every platform. No assertion
changed.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-16 13:29:38 -07:00

17 KiB
Raw Permalink Blame History

Test, eval and CI audit — October 2026

This document records the evidence behind the October 2026 test, eval and CI wave: the EVAL_POLICY v2 decision memo (D1) with its pre-registered backtest, and the commands that reproduce every number. Metrics that need post-merge traffic are measured with bun run test:health --since-days 7 (merge + 7 days) and bun run test:health --since-days 28 (after the fourth scheduled census).

EVAL_POLICY v2 decision memo (D1)

Why the census is red

The weekly census is red by arithmetic, not by a handful of broken tests. Over 22 censuses with trial outcomes the periodic lane recorded 76 failed trials in 3,550 (about 3.5 failed trials per run) and the gate census 27 in 2,241 (about 1.2 per run). With independent failures, P(green) is e^-3.5 ≈ 3% for the periodic lane and e^-1.2 ≈ 30% for the gate census; observed green rates were 0/22 and 8/22. Holding a ~190-case single-trial lane green 80% of the time needs every case at or below about 0.12% failure per run, which a live agent judged by one trial does not reach. Fixing the top five chronic cases leaves the lane red.

Three levers stay inside the no-retry, no-threshold, no-rejudge rule: make detectors deterministic over structured artifacts (W3), classify INFRA honestly (W2d, owned by the reliability follow-ups), and make quarantine reachable for detector, harness and model-latency failures. v2 targets the third lever.

test:health reports the census as three separate numbers, so a policy change cannot read as a reliability gain: the raw trial failure rate per kind and failure class, P(lane red) from pooled per-case rates under the recorded panels, and the same evidence re-aggregated with every case judged on one trial. Both red probabilities treat every observed failure as nondeterminism, so they are upper bounds for known-good inputs.

False-blocking targets. Periodic lane: at most 1.0 expected failed trial per census (P(red) ≤ 63%) at the 28-day check; gate census: at most 0.5 (P(red) ≤ 39%). Neither target may be reached by a threshold, retry or rejudge change. A miss opens a P1 TODOS entry with the per-kind, per-failure-class breakdown from test:health.

What v2 changes

  • Series identity (W4a, CEO-27, ENG-3). A case's pass-rate series is keyed by the bytes it owns plus HARNESS_VERSION: its paid test file, its fixtures, and the prompt files of the skills it names (templates, sections, manifests and the generated SKILL.md the model reads). The series key adds the model id, the pinned Claude Code CLI version and the policy version. Shared helpers no longer start new series. Every trial also records the full consumed-input fingerprint (all touchfiles, globals included) as series_fingerprint, plus harness_version, as provenance. (caseSeriesIdentitiesV2 in scripts/eval-trial-series.ts.)
  • Harness guard. scripts/harness-version.json pins the blob of every shared execution-harness file: GLOBAL_TOUCHFILES plus the session runners, the PTY harness, the e2e gate and the LLM judge (36 files). A free test (test/harness-version.test.ts) fails when one changes without a decision. bun run scripts/bump-harness-version.ts --bump "<reason>" raises HARNESS_VERSION and starts a new series for every case; --non-behavioral "<reason>" records the new blobs as compatible with no reset. Entries are one line per file so concurrent PRs that touch different files merge cleanly; on a conflict, take the higher version, then rerun.
  • Weekly history (W4b). Weeks for quarantine expiry and drift are evals-periodic.yml runs on main: scheduled runs and main dispatches. Trials from branch census runs in the same window pool into a series main has also run (option (b) below, approved 2026-10-05); a branch identity main has not run is dropped and never becomes the current series.
  • Kinds (W4c). No kind changes; see the evidence below.
  • Pre-v2 evidence does not qualify. Readers segment strictly by policy_version: only v2 trials count toward the quarantine entry rule; v1 trials stay visible as display-only. Quarantine is not seeded at merge; a case enters only after it reaches entry.minTrials qualifying v2 trials, and test:health shows qualifying-vs-required counts with "insufficient evidence" distinct from healthy (DX-12).

W4c: the named "stochastic" cases are deterministic in the record

Recorded census and PR trials (all 95 recorded revisions, October 2026):

Case Kind Passed / trials Failures
plan-ceo-finding-floor rule 26/27 1 timeout (608 s)
plan-devex-finding-floor rule 27/27 —
plan-eng-finding-floor rule 9/9 —
plan-design-finding-floor rule 9/9 —
plan-ceo-review-plan-mode rule 34/34 —
plan-devex-review-plan-mode rule 27/27 —
plan-eng-review-plan-mode rule 9/9 —

The comments calling plan-*-finding-floor "stochastic ask-first" are stale: the record shows these cases behave like rules. AGENTS.md forbids changing a kind without pass-rate evidence, and a 3-trial panel would triple their cost for no measurable gain, so they stay rule. plan-design-review-plan-mode (17/22) is handled by its detector repair, not by a kind change.

Backtest (ENG-3, DX-12)

bun run scripts/eval-trial-series.ts --backtest --weeks 30 --records <dir> replays identities with today's registry over historical trees (cases whose test file did not exist at a revision are absent there).

Weekly main revisions (29 Mondays, 06:00 UTC, 2026-03-16 to 2026-09-28). A case qualifies at a week when one identity holds long enough to collect 10 trials within the last 10 weekly runs (rule and judge cases record one trial per run, behavior cases a panel of three):

Identity Qualifying at the latest week Mean qualifying share, last 8 weeks Median identity changes per case
v1 (own touchfiles minus globals) 0/195 0.3% 15
v2 (case-owned bytes) 0/195 0.7% 14
v2, reset on every pinned-harness change 0/195 0.1% 14
v2 without the generated SKILL.md (prototype) 0/217 2.0% 7

Recorded trials re-keyed by the v2 identity of the revision that produced them (blocking cases with at least 10 trials on one series):

Trial source Recorded (v1) identity v2 identity
22 census runs (5,665 trials) 52/210 67/210
Census + PR lane, 95 revisions (14,898 trials) 107/210 134/210

Harness churn. The pinned harness changed in 24 of 28 consecutive-week transitions, and 33 of the last 60 main commits (2026-08-04 to 2026-10-04) touched a pinned file. About half of PRs therefore record a bump-harness-version decision, and only --bump decisions reset series.

What the backtest shows

  1. v2 makes series honest and longer when trials are dense: on the recorded census runs, 67 blocking cases reach 10 trials on one series versus 52 under v1, and 134 versus 107 with PR-lane trials included.
  2. Under the approved weekly history (main scheduled runs plus main dispatches, about one run per week), no blocking case reaches 10 qualifying trials at any recent week. A rule case needs ten consecutive weekly runs on unchanged owned bytes, and a case's own prompt files change about every two weeks (the generated SKILL.md carries the shared preamble). Excluding the generated SKILL.md halves identity churn but still qualifies at most 2% of cases, and it would let preamble and resolver prompt changes pool unless every such edit went through the harness guard.
  3. So v2 alone does not make quarantine reachable. Reaching it needs one of: (a) keep the history as approved and accept that quarantine stays rare, so census redness is fixed at source (W3) and tracked by test:health; (b) pool trials from every v2 census run whose series key matches, including branch dispatches, while weeks for expiry still count from main only — the recorded backtest's 67/210, at the cost of pooling branch code whose unbumped harness edits match; or (c) extra census dispatches on an unchanged main revision (about $175 recorded each). Garry approved (b) on 2026-10-05, and this PR implements it: pooled branch trials count only toward a series a main run also has.

Alternatives considered

  • Gating vs trended. The native CEO voice proposed keeping live-agent cases trended (reported, never blocking) and gating only on deterministic detectors. v2 keeps the census blocking because quarantine and the pass-rate gate already provide a trended path per case; the false-blocking targets above are the check on that choice. If the 28-day check misses them, trended reporting for the remaining stochastic cases is the next proposal.
  • Adaptive sequential panels (one trial, escalate to three on a failure, about 1.04× cost across ~190 cases) would be the strongest lever for a green census. They are not adopted: an escalation triggered by a failure is a retry, which Garry's rule forbids.
  • Buy vs build. Hosted eval platforms (Braintrust, LangSmith, Weights & Biases Weave) store per-case pass-rate history and cost natively, but gstack's verdicts are produced inside GitHub Actions from Claude Code sessions with pre-registered panels and receipts, and the history is a few thousand JSONL lines per week that gh already serves. A platform would add an external dependency and a second source of truth for verdicts without removing the in-repo policy. Building on the existing artifacts stays the choice; revisit if history outgrows artifact retention (90 days).

Rollout and rollback (ENG-14, DX-12)

The reader-compatibility commit lands first: readers score only trials under their own EVAL_POLICY.version, show older-policy trials as display-only, and ignore newer-policy trials with a printed count. The v2 writer (identity stamping and version: 2) lands last. The supported rollback is reverting the v2 writer commits; a whole-PR revert is not claimed safe.

On a mixed v1/v2 fixture (10 passing v1 trials, 12 v2 trials with 3 failures), the pre-PR reader at 2db0b3a pools the v2 records as the current v1 series and fails its gate:

pass-rates: policy v1, 22 post-policy trial(s), 0 pre-policy (display only)
  FAILING       rule      gate      9/12 [46.8%–91.1%]  ...  plan-ceo-review-plan-mode  (baseline reset)
ACTION REQUIRED (2): [drift] ... [rule-as-behavior] ...
exit=1

The compatibility reader ignores the v2 records and keeps the v1 series:

pass-rates: policy v1, 10 post-policy trial(s), 0 pre-policy (display only)
  ignored 12 trial(s) recorded under a policy newer than v1: this checkout predates them. Fix: ...
  PASSING       rule      gate      10/10 [72.2%–100%]  ...  plan-ceo-review-plan-mode
exit=0

Wave evidence

PR paid lane selection replay (CEO-23, ENG-18)

The replay sends each recorded PR push's changed files through today's selector and dependency graph:

gh run list -R garrytan/gstack --workflow evals.yml --json databaseId,headSha,event,createdAt,conclusion -L 200 > runs.json
bun run scripts/replay-pr-selection.ts --runs runs.json

Over 168 PR pushes with plan manifests (2026-09-25 to 2026-10-04):

Measure Recorded Replayed
Full-fallback pushes 165 of 168 (98.2%) 164 of 168 (97.6%)
Misses (a failed case that depends on the diff and is no longer selected) — 0
Failed cases that no longer exist (counted apart) — 6

113 of the 168 diffs exceed the compare API's 300-file cap and are replayed on their first 300 files. The rate barely moves because the replay uses each push's cumulative branch diff, and the wave branches of that week touch shared inputs that correctly select every case: scripts/ in 156 pushes, .github/ in 125 (mostly the eval workflows), bin/ in 120, make-pdf/ in 90, test/helpers/ in 86, design/ in 67, lib/ in 58, hosts/ in 56 and tsconfig*.json in 37. The selector removes the single-class fallbacks (duration seeds, free-only workflows, scripts/ubicloud/**, free tests and free fixtures; run 36497566037 now selects the pr profile) and cannot narrow a branch that changes bin/ or lib/; narrowing those needs touchfile mappings for bin/, lib/, hosts/ and make-pdf/. The post-merge test:health check measures the fallback rate on ordinary PRs.

Paid slices and concurrency (ENG-17)

Live census with EVALS_ALL=1 (periodic: --list --slice-budget S --jobs 2; gate census: --emit-plan <file> --slice-budget S --jobs 2 --skip-judges):

Lane Before (540 s) After (420 s)
Periodic slices / peak shard processes 26 / 52 33 / 66 (max-parallel 26 → 36)
Weekly gate census slices / peak 12 / 24 16 / 32 (max-parallel 16 → 20)
CI job ceiling One value for every slice: 173 min periodic, 254 min gate census Per slice: ordinary 50 min (30-minute shard wall + 20), periodic outliers 52 and 73 min, the overlay slice 173 min (5 serialized overlay wrappers); gate census 34–82 min

The PR lane (evals.yml) uses the same 420-second budget and per-slice ceilings.

Free suite

  • The Windows lane runs on six windows-latest jobs packed by Windows-measured durations: about 4.6 minutes wall in the free-suite branch's validation runs, down from 8.1 minutes on one runner.
  • Unseeded files pack at the 99th percentile (was the 75th), and the seed growth ratchet (test/free-seed-ratchet.test.ts) keeps files over 60 seconds on a shrink-only allowlist.
  • The bash+zsh portability tests (#2669) run in CI now that the free-suite job installs zsh.
  • Native Windows and Dia qualification campaigns moved out of the PR workflow into the dispatch-only native-qualification.yml.

Prose pins (D2)

D2 is approved: the prompt-byte contract in test-value-bar.md covers machine-read tokens only, and sentence pins in 55 free test files became structural checks through test/helpers/prompt-structure.ts. A sentence pin here is a 40-or-more-character English string literal, or a prose regex of five or more words, asserted against SKILL.md, template or section text in a free test.

Measure main (2db0b3a) This wave
Sentence pins 2,332 in 217 files 1,190 in 209 files
Shouting pins (NEVER/MUST/ALWAYS/CRITICAL emphasis) 8 4

The 4 remaining shouting pins are enum or marker tokens (PLAN MODE EXCEPTION — ALWAYS RUN, [CRITICAL], ALWAYS-ON CLI output), not emphasis. Most remaining sentence pins sit in QA caller, detector-helper and workflow files that other work in flight owns.

Post-merge follow-up (2026-10-15)

The "post-merge audit metrics" TODO, from a no-spend run of bun run test:health --since-days 7 (window 2026-10-08T22:14Z to 2026-10-15T22:14Z). The 2026-10-12 figures are the weekly health run in issue #3154 (run 38234556073), kept as dated history.

Metric 2026-10-12 2026-10-15 Target Verdict
PR full-fallback rate 45.0% (58/129 runs) 45.9% (39/85 runs) none numeric; the replay above names the cause open: branches touching bin/, lib/, hosts/ or make-pdf/ still select every case
Recorded PR-lane spend per merged PR $75.09 (46 merged) $73.52 (33 merged) down at least 50% from the pre-change baseline unavailable: baseline not recorded (below)
Cancelled slice-minutes per week 1,939 (44 runs) 1,545 (33 runs) none numeric reported
PR push-to-verdict p50 12.0 min, p95 1,160.7 min (122 runs) p50 11.4 min, p95 107.9 min (80 runs) 3–5 minutes for typical PR checks (CONTRIBUTING.md) missed
Free-suite flaky-pass rate 13.0% (6/46 main runs) 6.1% (2/33 main runs; terminal-agent-publication-lock 2/33, over the 5% per-file check) under 5% of main runs missed; fix wave 2 repairs the five ledger files

Spend baseline. The pre-change window was recomputed with the exported collectHealth at now = 2026-10-04T00:00Z, seven days, through a client that drops runs created and PRs merged after that instant (listWorkflowRuns has no upper bound of its own). The window holds 12 merged PRs but no trial-outcomes-pr-* artifacts and no paid-plan manifest with prCoverage: the recorder that feeds this metric shipped with the audit, so the PR lanes before it wrote nothing it can read (their other artifacts are retained until 2026-11-02 and later). Baseline not recorded; verdict unavailable. The P1 in TODOS.md is opened on the absolute figures.

Census reliability (not yet due). Due after the fourth scheduled census after the audit merge (2026-10-26). Interim: periodic 2.00 expected failed trials per run (6/538 over 3 runs; target at most 1.0), gate census 0.33 (1/308 over 3 runs; target at most 0.5). The TODO keeps its due date; the census repair stays with #3153 and #3200.