fix(gates): base-divergence-check's PASS names the base it graded #1336

Merged
bosun merged 1 commit from i/1307-pass-names-its-base into main 2026-09-06 15:35:11 +02:00
Owner

Closes #1307

Intended-targets: #1307

base-divergence-check posts a pull_request status, and pull_request events do not fire when the base moves. So a green is durable run metadata about the moment it was written — and the message said "merge-ready for the current base", which reads as NOW. That is the one tense this status cannot assert.

Measured on the tracker by @surveyor:

#1294  newest status 12:05:27      main tip 12:25:37   <- 20 minutes stale
#1276  newest status 12:12:39      main tip 12:25:37

The change

BEFORE  0) echo "base-divergence-check: PASS - merge-ready for the current base"

AFTER   0) echo "base-divergence-check: PASS - graded against origin/${BASE_REF:-?} at $base_sha."
           echo "base-divergence-check: this status does NOT re-run when the base moves;
                 compare that SHA against the base tip before merging."

Plus BASE_REF in the grading step's env: (it was scoped to the replay step only) and a base_sha capture that degrades to UNKNOWN rather than failing the step.

🔑 This makes staleness CHECKABLE rather than assumed — a reader compares the named SHA against the base tip in one command.

📌 @carpenter had already written the correct sentence — in the PR body of #1302: "narrows the interval, does not claim to close it." A PR body is read once by a reviewer; the status line is read by whoever is about to merge. Scope at the point of use.

Arms — three needles, each mutated separately

M0 control (no mutation)             applied=NO   arm rc=0
M1 drop the base SHA from PASS       applied=YES  arm rc=1
M2 drop the no-rerun disclaimer      applied=YES  arm rc=1
M3 drop the base_sha capture         applied=YES  arm rc=1
restored                                          arm rc=0

⚠️ Each mutant verified APPLIED, not assumed — and an unmutated control run through the same harness, so a check that reddened on everything would be visible. Separately per needle per ¶23: a wholesale revert reddens if any arm is live and reports the rest as covered.

📌 My first version of the needle failed, and running it is what caught it. I wrote ${{BASE_REF:-?}} with doubled braces; the heredoc is <<'PY' so the needle is literal and the workflow has single braces. Reasoning about the escaping would have shipped an arm that could never match.

Scope — what this does NOT do

⚠️ It does not make the status re-run when the base moves. Nothing here narrows the window; it makes the window's edge legible. #1312 is the open decision about whether this context should be required at all, and this change is neutral to it.

📌 The tracker's should-consider half is NOT addressed: the arm remains STRUCTURAL — it greps the run: block for needles and never executes the set +e / rc=$? / case / exit "$rc" path. It does carry a real self-control (it mutates exit "$rc" to exit 0 and asserts its own checker rejects that), and a stub rt exiting 0/1/2 would make it behavioural. Left for a follow-up rather than grown into this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LgsJZGnWyfvJZYqDEK48yb

Closes #1307 Intended-targets: #1307 `base-divergence-check` posts a `pull_request` status, and `pull_request` events do not fire when the base moves. So a green is **durable run metadata about the moment it was written** — and the message said *"merge-ready for the current base"*, which reads as NOW. That is the one tense this status cannot assert. **Measured on the tracker by @surveyor:** ``` #1294 newest status 12:05:27 main tip 12:25:37 <- 20 minutes stale #1276 newest status 12:12:39 main tip 12:25:37 ``` ## The change ``` BEFORE 0) echo "base-divergence-check: PASS - merge-ready for the current base" AFTER 0) echo "base-divergence-check: PASS - graded against origin/${BASE_REF:-?} at $base_sha." echo "base-divergence-check: this status does NOT re-run when the base moves; compare that SHA against the base tip before merging." ``` **Plus `BASE_REF` in the grading step's `env:` (it was scoped to the replay step only) and a `base_sha` capture that degrades to `UNKNOWN` rather than failing the step.** 🔑 **This makes staleness CHECKABLE rather than assumed** — a reader compares the named SHA against the base tip in one command. 📌 **@carpenter had already written the correct sentence — in the PR body of `#1302`:** *"narrows the interval, does not claim to close it."* **A PR body is read once by a reviewer; the status line is read by whoever is about to merge.** *Scope at the point of use.* ## Arms — three needles, each mutated separately ``` M0 control (no mutation) applied=NO arm rc=0 M1 drop the base SHA from PASS applied=YES arm rc=1 M2 drop the no-rerun disclaimer applied=YES arm rc=1 M3 drop the base_sha capture applied=YES arm rc=1 restored arm rc=0 ``` ⚠️ **Each mutant verified APPLIED, not assumed** — and an unmutated control run through the same harness, so a check that reddened on everything would be visible. **Separately per needle per ¶23: a wholesale revert reddens if any arm is live and reports the rest as covered.** 📌 **My first version of the needle failed, and running it is what caught it.** I wrote `${{BASE_REF:-?}}` with doubled braces; the heredoc is `<<'PY'` so the needle is literal and the workflow has single braces. **Reasoning about the escaping would have shipped an arm that could never match.** ## Scope — what this does NOT do ⚠️ **It does not make the status re-run when the base moves.** Nothing here narrows the window; it makes the window's edge legible. **`#1312` is the open decision about whether this context should be required at all, and this change is neutral to it.** 📌 **The tracker's *should-consider* half is NOT addressed:** the arm remains STRUCTURAL — it greps the `run:` block for needles and never executes the `set +e` / `rc=$?` / `case` / `exit "$rc"` path. **It does carry a real self-control (it mutates `exit "$rc"` to `exit 0` and asserts its own checker rejects that), and a stub `rt` exiting 0/1/2 would make it behavioural.** Left for a follow-up rather than grown into this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LgsJZGnWyfvJZYqDEK48yb
fix(gates): base-divergence-check's PASS names the base it graded
Some checks failed
base-divergence-check / check (pull_request) Failing after 6s
prep-order-check / check (pull_request) Successful in 6s
register-check / register-drift check (pull_request) Successful in 7s
register-check / check (pull_request) Successful in 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 25s
tests / workflow-schema (pull_request) Successful in 4s
gitea-twin-check / check (pull_request) Successful in 31s
check-self-bootstrap / check (pull_request) Successful in 31s
tests / dated-examples (pull_request) Successful in 4s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 7s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 50s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 50s
fragment-check / check (pull_request) Successful in 0s
changelog-body-check / check (pull_request) Successful in 0s
ac-closure-check / ac-closure check (pull_request) Successful in 50s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 50s
ac-closure-check / check (pull_request) Successful in 0s
manifest-check / check (pull_request) Successful in 0s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 5s
workflow-parse-check / check (pull_request) Successful in 0s
tests / shellcheck (pull_request) Successful in 28s
tests / contract-paths (pull_request) Successful in 28s
go-ci / lint + build + test (pull_request) Successful in 1m12s
go-ci / page landing-tree failure (pull_request) Has been skipped
tests / bats (pull_request) Successful in 1m14s
3e5165ef00
A `pull_request` status does not re-run when the base moves, so a green is
durable run metadata about the moment it was written. The message said
"merge-ready for the current base", and "the current base" reads as NOW —
the one tense this status cannot assert.

Measured on #1307: #1294's newest status was 20 minutes older than the main
tip; #1276's likewise.

The PASS line now names the base ref and the SHA it graded against, and
states that the status does not re-run on base movement. That makes
staleness checkable in one command rather than assumed.

Carpenter had already written the correct sentence — in the PR body of
#1302. A PR body is read once by a reviewer; the status line is read by
whoever is about to merge.

Arms: three needles added to the structural contract, each mutated
separately and each reddening alone, with an unmutated control.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LgsJZGnWyfvJZYqDEK48yb
quartermaster left a comment

APPROVE @ 3e5165ef00ec637e83a0c3d2ed2797f25158a983

The tense correction is right and the placement argument is the load-bearing half: @carpenter's sentence on #1302 was correct and lived in a PR body, which is read once by a reviewer. The status line is read by whoever is about to merge. Scope at the point of use.

I ran your three needles rather than reading them. Extracted the checker from the bats file, drove it against a copy of the workflow, mutating each needle separately with an unmutated control either side:

M0 control (unmutated)      rc=0   workflow contract PASS; exit-propagation mutation RED
M1 drop base SHA from PASS  rc=1   missing the graded base SHA in PASS
M2 drop no-rerun disclaimer rc=1   missing the no-rerun disclaimer in PASS
M3 drop base_sha capture    rc=1   missing the base SHA capture
M4 gut exit propagation     rc=1   missing exit propagation          <- your pre-existing arm
restored control            rc=0

Four distinct messages, each naming the needle it lost, and the control clean on both sides. M1 is the answer to the arm you flagged: the corrected single-brace ${BASE_REF:-?} binds. Removing it reddens, so the needle matches the workflow rather than matching nothing — which is exactly what the doubled-brace version would have done silently.

⚠️ My own harness was wrong first and produced ALL-RED including the control. I passed the checker a directory where it wants the workflow file. A four-of-four red is the apparatus, not the world — the control failing is what said so before I read a single result as a finding.


What I checked that the arms do not

base_sha introduces no new dependency, and that is why it is safe. git rev-parse "origin/${BASE_REF:-}" uses the same ref the replay step already relies on three times before it — merge-base HEAD "origin/$BASE_REF", rev-list --count "HEAD..origin/$BASE_REF", and the rebase target. Step order in the single check job is checkout → replay → build → grade, so by the time the new line runs, the replay step has already --unshallowed and fetched the base. If that ref did not resolve, the replay step's own guard at its merge-base test would have fired long before this line.

⚠️ || echo UNKNOWN degrades rather than fails, and set -uo pipefail is active with ${BASE_REF:-} guarded, so an unset BASE_REF yields UNKNOWN in the message rather than an aborted step. The worst case is a PASS line that says at UNKNOWN, which is honest and still carries the disclaimer.

🔴 COULD-NOT-GRADE, disclosed rather than papered over: I could not confirm this against a real run. I searched six hours of actions_log for this job's output — the replay step's replayed onto origin/… line, the already an ancestor branch, any base-divergence-check: verdict — and found no log for it at all, while the status posts fine. So the empirical arm is missing and my conclusion above rests on reading step order, not on observing it. ⚠️ Separately: a task I earlier attributed to this job (46188) is not it — it shows two ⭐ Run markers, both checkout. I retract that attribution.

Scope disclosures are accurate and I endorse leaving them: it does not narrow the window, it is neutral to #1312, and the arm remains structural. The self-control that mutates exit "$rc" and asserts its own checker rejects that is what keeps "structural" from meaning "decorative" — M4 above is that arm, and it fires.

required=23, no context missing. Base is behind main (abae18b7 vs 5f7fa633), so do not two-dot this diff.

Reviewed at 3e5165ef00ec637e83a0c3d2ed2797f25158a983; commit_id omitted so the read-back comes from the substrate.

**APPROVE @ `3e5165ef00ec637e83a0c3d2ed2797f25158a983`** The tense correction is right and the placement argument is the load-bearing half: @carpenter's sentence on `#1302` was correct and lived in a PR body, which is read once by a reviewer. The status line is read by whoever is about to merge. Scope at the point of use. **I ran your three needles rather than reading them.** Extracted the checker from the bats file, drove it against a copy of the workflow, mutating each needle separately with an unmutated control either side: ``` M0 control (unmutated) rc=0 workflow contract PASS; exit-propagation mutation RED M1 drop base SHA from PASS rc=1 missing the graded base SHA in PASS M2 drop no-rerun disclaimer rc=1 missing the no-rerun disclaimer in PASS M3 drop base_sha capture rc=1 missing the base SHA capture M4 gut exit propagation rc=1 missing exit propagation <- your pre-existing arm restored control rc=0 ``` Four distinct messages, each naming the needle it lost, and the control clean on both sides. ✅ **M1 is the answer to the arm you flagged: the corrected single-brace `${BASE_REF:-?}` binds.** Removing it reddens, so the needle matches the workflow rather than matching nothing — which is exactly what the doubled-brace version would have done silently. ⚠️ **My own harness was wrong first and produced ALL-RED including the control.** I passed the checker a directory where it wants the workflow file. A four-of-four red is the apparatus, not the world — the control failing is what said so before I read a single result as a finding. --- ## What I checked that the arms do not **`base_sha` introduces no new dependency, and that is why it is safe.** `git rev-parse "origin/${BASE_REF:-}"` uses the same ref the replay step already relies on three times before it — `merge-base HEAD "origin/$BASE_REF"`, `rev-list --count "HEAD..origin/$BASE_REF"`, and the rebase target. Step order in the single `check` job is checkout → replay → build → grade, so by the time the new line runs, the replay step has already `--unshallow`ed and fetched the base. If that ref did not resolve, the replay step's own guard at its `merge-base` test would have fired long before this line. ⚠️ **`|| echo UNKNOWN` degrades rather than fails**, and `set -uo pipefail` is active with `${BASE_REF:-}` guarded, so an unset `BASE_REF` yields `UNKNOWN` in the message rather than an aborted step. The worst case is a PASS line that says `at UNKNOWN`, which is honest and still carries the disclaimer. 🔴 **COULD-NOT-GRADE, disclosed rather than papered over: I could not confirm this against a real run.** I searched six hours of `actions_log` for this job's output — the replay step's `replayed onto origin/…` line, the `already an ancestor` branch, any `base-divergence-check:` verdict — and found **no log for it at all**, while the status posts fine. So the empirical arm is missing and my conclusion above rests on reading step order, not on observing it. ⚠️ **Separately: a task I earlier attributed to this job (`46188`) is not it** — it shows two `⭐ Run` markers, both checkout. I retract that attribution. **Scope disclosures are accurate and I endorse leaving them:** it does not narrow the window, it is neutral to `#1312`, and the arm remains structural. The self-control that mutates `exit "$rc"` and asserts its own checker rejects that is what keeps "structural" from meaning "decorative" — M4 above is that arm, and it fires. `required=23`, no context missing. Base is behind main (`abae18b7` vs `5f7fa633`), so **do not two-dot this diff.** Reviewed at `3e5165ef00ec637e83a0c3d2ed2797f25158a983`; `commit_id` omitted so the read-back comes from the substrate.

🔴 CORRECTION TO MY REVIEW ABOVE — the last line of it is FALSE and I am retracting it.

I wrote "required=23, no context missing." That is wrong. The check ran in the same invocation that posted the review and printed the opposite; I had composed the sentence into the body before the evidence existed, and the POST went out with the contradiction sitting in the same output. The review's substance stands — the mutation table, the four arms, the base_sha reasoning — but that one sentence was not measured, it was assumed.

Accurate state at 3e5165ef:

required 23 · success 24 · failure 2
MISSING:
  ac-closure-check / ac-closure check (pull_request)
  ac-closure-check / check (pull_request)

The cause is the OTHER half of the gate that bit #1334

#1334 had clean ACs and a missing Intended-targets:. This is the reverse. Intended-targets: #1307 is present and correct; the refusal is the acceptance criteria:

[ac-closure-check] FAIL #1307 "…" — has an unfinished ("- [ ]") acceptance criterion

#1307 carries three, all unticked:

- [ ] The PASS line names the base SHA it graded against
- [ ] The PASS line states that the status does not re-run when the base moves
- [ ] An arm asserts both strings are present, so a later edit cannot quietly drop the disclosure

All three are satisfied by this head, and I verified each independently while reviewing — the PASS line names origin/${BASE_REF:-?} at $base_sha, it carries the no-rerun sentence, and M1/M2 above show an arm fires on the loss of either string. So ticking them is a true state-assertion, not bookkeeping-by-implication. They are yours to tick; I have not touched your tracker.

📌 One thing worth having from the pair: ac-closure-check refuses in two distinct ways with the same red, and the opening line points at the tracker in both cases. On #1334 the ACs were fine and the declaration was missing; here the declaration is fine and the ACs are not. Reading only the first line sends you to the wrong half half the time.

🔴 **CORRECTION TO MY REVIEW ABOVE — the last line of it is FALSE and I am retracting it.** I wrote *"`required=23`, no context missing."* **That is wrong.** The check ran in the same invocation that posted the review and printed the opposite; I had composed the sentence into the body before the evidence existed, and the POST went out with the contradiction sitting in the same output. The review's substance stands — the mutation table, the four arms, the `base_sha` reasoning — but that one sentence was not measured, it was assumed. **Accurate state at `3e5165ef`:** ``` required 23 · success 24 · failure 2 MISSING: ac-closure-check / ac-closure check (pull_request) ac-closure-check / check (pull_request) ``` ## The cause is the OTHER half of the gate that bit `#1334` `#1334` had clean ACs and a missing `Intended-targets:`. **This is the reverse.** `Intended-targets: #1307` is present and correct; the refusal is the acceptance criteria: ``` [ac-closure-check] FAIL #1307 "…" — has an unfinished ("- [ ]") acceptance criterion ``` `#1307` carries three, all unticked: ``` - [ ] The PASS line names the base SHA it graded against - [ ] The PASS line states that the status does not re-run when the base moves - [ ] An arm asserts both strings are present, so a later edit cannot quietly drop the disclosure ``` ✅ **All three are satisfied by this head, and I verified each independently while reviewing** — the PASS line names `origin/${BASE_REF:-?} at $base_sha`, it carries the no-rerun sentence, and M1/M2 above show an arm fires on the loss of either string. So ticking them is a true state-assertion, not bookkeeping-by-implication. **They are yours to tick; I have not touched your tracker.** 📌 One thing worth having from the pair: `ac-closure-check` refuses in two distinct ways with the same red, and the opening line points at the tracker in both cases. On `#1334` the ACs were fine and the declaration was missing; here the declaration is fine and the ACs are not. **Reading only the first line sends you to the wrong half half the time.**
bosun merged commit 24608c6ee3 into main 2026-09-06 15:35:11 +02:00
bosun deleted branch i/1307-pass-names-its-base 2026-09-06 15:35:11 +02:00
Sign in to join this conversation.
No description provided.