Repository navigation
Arm 4 (present) is RED on every live PR and required by nothing — no PR-review receipt has landed since #3491 #3818
Description
Found by aprender-c7, 2026-09-22, while reading batch-1's CI (#3772 @ 935f2cc88). Not a batch-1 defect — measured across the fleet.
The measurement
present (job present in .github/workflows/pr-review-quorum.yml, Arm 4, scripts/check_pr_review_arm4.sh) fails on every open PR sampled: #3772, #3814, #3808, #3802. The failure is identical and is about absence, not content:
A1 .github/pr-review.pub present (RWTeGb4p8Ma1IqgL...)
A2 no receipt directory at .../evidence/pr-review/3772
S6.3: a missing receipt is RED, not skipped. S8 fixes
receipt_presence at 100% with no ratchet.
check_pr_review_arm4.sh: FAIL - see the arm above.
Base rate from the tree (origin/main), because one red PR is an anecdote:
| fact | value |
|---|---|
| PRs that have ever carried a receipt directory | 24 |
of those, above the grandfather line PR_REVIEW_CUTOFF=2840 |
22 |
| newest PR with a receipt | #3491, landed 2026-09-20 (237fbc32f) |
| PRs merged above #3491 since | 45 |
| open PRs today | 58 |
| receipts above #3491 | 0 |
And it is required by nothing, under either mechanism — both were read, not one:
| mechanism | required contexts |
|---|---|
branch protection on main |
ci / gate, workspace-test (strict: true) |
| ruleset 13878864 "Green Main" | gate |
| ruleset 19814559 "workspace-test" | workspace-test |
present is in none of them, and gate no longer needs: it (that was the deliberate PP-066 C0-5 / PRQ-013 move, so a PR could not define the check that judged its own receipt).
Why this is a defect and not just an empty queue
This is the mirror image of the class being closed all week. Not a green badge over nothing — a red one nobody reads. Both are gate theater: a check that fires on 100% of pull requests carries exactly as much information as one that fires on 0%, and a reviewer who sees present red on every PR learns to scroll past the row where a real receipt failure would appear.
The workflow's own header states the intent against which the tree can be measured: it "arms FORWARD", grandfathering below the cutoff because "the measured receipt rate on the day this landed was 1 across 24 open PRs — arming it retroactively is not a ratchet, it is an outage", and receipt_presence is "fixed at 100% with no ratchet". The forward arming stopped landing after #3491. The same argument that justified cutoff 2840 now applies to the window above it.
Neither producing side fails, by design, which is why this went unnoticed:
ci.ymlpr-review-signexits 0 when there is nothing to sign: "no receipt directory $root — nothing to sign. The review is still owed; the S13.11 shadow lane records its absence."pr-review-shadowinvokes the arm with--explainand records the verdict; it is shadow-only and in noneeds:list (PR-REVIEW-SKILL-002 v2 §13.11, still not armed).
So the only surface that says "the review is owed" is a check nothing requires, on every PR at once.
Probable cause, stated as a hypothesis and not as a finding: the fleet's review evidence moved. docs/audits/ carries 69 quorum-*.json artifacts on main, most recent 2026-09-21 (a9502d992); evidence/pr-review/ carries 24 PR directories, most recent #3491 on 2026-09-20. Two mechanisms answer "was this diff reviewed", and only one of them is still being fed. Confirming or refuting that is step 1 of any fix — do not assume it.
done_when
Exactly one of these, with its falsifier. Not "Arm 4 is green".
Option A — restore production (RECOMMENDED). Every PR above the cutoff carries evidence/pr-review/<pr>/<head sha>/receipt.intoto.jsonl, produced by whatever process is now the review of record, and the existing signer signs it.
- Falsifier: a PR opened with no receipt turns
presentRED (it already does — that row must stay RED, so the mutation is the inverse: delete the receipt from a PR that has one and show the row go RED, and point the receipt at a stale head sha and show it go RED), and after the fix a freshly opened PR has a receipt directory within one CI run without a human writing it. - Why recommended: it is the only option under which the arm carries information again. Every other path makes the row quieter without making it true.
Option B — advance the cutoff to where production actually resumes (FALLBACK, only if A is refused). PR_REVIEW_CUTOFF moves from 2840 to the first PR number from which receipts genuinely land; below it, absence is reported and not RED; above it, unchanged.
- Falsifier:
check_pr_review_arm4.shalready ships the two-polarity cutoff case table (scripts/check_pr_review_arm4.sh:341-347— the same receiptless tree passes below the cutoff and fails above it). That table must be re-run at the NEW number, both polarities, per the standing rule that extending a guard's scope requires re-mutating in the new scope. A present-but-tampered receipt stays RED at any PR number (flip a byte inreceipt.intoto.jsonl→ RED). - Why only a fallback: advancing the cutoff without restoring production converts a red-nobody-reads into a green-that-means-nothing. That is trading one theater for the other, and it must be recorded as an accepted loss of coverage rather than as a fix.
Explicitly out of scope
Do not make present a required check. A gate red on 100% of live PRs must not become blocking; arming it in this state blocks all 58 open PRs at once, which is the outage the cutoff comment already describes from experience. Whichever option lands, present stays advisory until its red rate reflects real absences.
Not a 0.69.1 blocker, deliberately
Filed against 0.70.0. It blocks nothing under either mechanism today, and fixing a reporting-only gate during a release train is how release trains slip — the same call f0 made on #3805. 0.69.1 ships with present red on its PRs and this issue as the record of why.
Refs #2982 (PP-066 C0-5 / PRQ-013, the move that made this check base-owned)
Activity
noahgift commentedon Sep 24, 2026
Milestone 0.70.0 → 0.70.1 (gate triage). 0.70.0 now holds only the operator's release gate: "FULL ontology spec and all aprender binary working" + "0.70 to crates.io" (ONT-001, every [[bin]] build+smoke, the publish cascade), plus P0s and operator-ruled rows. This issue isn't needed for any of those. Evidence: evidence/m070-gate-triage-1835.md. If that's wrong, move it back to 0.70.0 and say which gate it serves.
noahgift commentedon Sep 25, 2026
Parked by APR-EPIC-001: over S1 budget (rank 89/163). Reopen = pull. Applied by aprender-d1: claude+agy both said close, apr shadow row recorded (handoff/close-quorum-2026-09-25.json).