From 7e02344672d3c40e4fe2fc0d5010ebf1286b4e6e Mon Sep 17 00:00:00 2001 From: cluade-reviewer-andresmgsl Date: Wed, 5 Aug 2026 14:02:08 +0000 Subject: [PATCH] docs(runner-probes): the arming gate asserts what each carrier IS, not that a literal is gone (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @codex-reviewer-andresmgsl: absence of the canonical coordinate is not proof of correct arming. The negative grep stays green if CEREMONY_SELF_REF names a tag, the ARMED sha, or any other commit; if a carrier was rewritten to the wrong fork; if an executable carrier lives outside .github; or if a carrier simply disappeared rather than being rewritten. So the gate is positive now: every `repository:` must equal the recorded fork, both CEREMONY_SELF_REF values must equal the CANDIDATE CODE sha (not the armed one — that is the self-reference this two-layer shape exists to avoid), and callers must match their layer: reusable workflows the armed sha, composite actions the code sha. With a COUNT beside the comparison. `n -eq 2` is the part that catches a carrier which vanished, which a per-value loop cannot see — the same shape as counting the call sites a pin is guarding rather than only checking the ones that are there. The canonical-coordinate grep stays as a cheap extra rather than as the proof. Wording, same review: steps 1 and 2 advance the tip of ONE fork branch, so reset removes that branch, not "candidate and armed branches". test/run.sh 28/28; shellcheck 0.10.0 and changelog-armed clean. Refs #202 --- changelog.d/202.md | 9 ++++++-- docs/RUNNER-PROBES.md | 49 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/changelog.d/202.md b/changelog.d/202.md index 66e445d..ced3047 100644 --- a/changelog.d/202.md +++ b/changelog.d/202.md @@ -28,8 +28,13 @@ reusable workflows to the armed SHA, which is the only revision whose inner checkout points at the fork (#202). -- A `git grep` over the armed tree gates the rewrite non-zero, so a partial one - refuses instead of silently testing canonical main (#202). +- The arming gate asserts what each carrier IS, not only that the old literal + is gone: every `repository:` equals the fork, both `CEREMONY_SELF_REF` values + equal the candidate code SHA, and callers match the layer they belong to + (#202). + +- It counts the `CEREMONY_SELF_REF` carriers as well as comparing them, which + is what catches one that vanished rather than being rewritten (#202). - Probe results are written to an issue in the probe repo and carried to the ceremony issue by a human, so the probe holds no path that can write to the diff --git a/docs/RUNNER-PROBES.md b/docs/RUNNER-PROBES.md index 9315c23..ed25ba4 100644 --- a/docs/RUNNER-PROBES.md +++ b/docs/RUNNER-PROBES.md @@ -107,7 +107,9 @@ So: ### The procedure 1. **Push the candidate tree** to a fork under the identity that will run the - probe — `/ceremony@probe-` — and record its SHA. That is + probe — one branch, `/ceremony@probe-` — and record its + SHA. Steps 1 and 2 advance the tip of that **same** branch; there are two + commits, not two branches. That is the **candidate code SHA**. Never create a branch on `heavy-duty/ceremony` named like a tag: it shadows that tag for every consumer until somebody remembers to delete it. @@ -122,18 +124,44 @@ So: - reusable-workflow callers → `/ceremony/.github/workflows/@`, since that is the only revision whose inner checkout is rewritten. -4. **Gate the rewrite mechanically, against the armed tree** — not against - whichever checkout happens to be current, and not by eyeballing prose: +4. **Gate the arming POSITIVELY, against the armed tree.** Absence of the old + literal is not proof of correct arming: a negative grep stays green if + `CEREMONY_SELF_REF` names a tag, the *armed* SHA or some other commit; if a + carrier was rewritten to the wrong fork; if an executable carrier lives + outside `.github`; or if a carrier simply disappeared + (@codex-reviewer-andresmgsl, #202 review). So assert what each carrier + **is**, not merely what it is not: ```sh - git -C grep -nE \ - '(uses:|repository:)[[:space:]]*heavy-duty/ceremony' -- .github \ - && { echo "arming incomplete" >&2; exit 1; } + fork=/ceremony ; code_sha= ; armed_sha= + fail() { echo "arming incomplete: $*" >&2; exit 1; } + + # every self-checkout points at the fork + for v in $(git grep -hoP '(?<=repository:\s)\S+' -- .github); do + [ "$v" = "$fork" ] || fail "repository: $v" + done + # both CEREMONY_SELF_REF carriers name the CANDIDATE CODE sha + n=0 + for v in $(git grep -hoP '(?<=CEREMONY_SELF_REF:\s)"?\K[^"]+' -- .github); do + [ "$v" = "$code_sha" ] || fail "CEREMONY_SELF_REF: $v"; n=$((n+1)) + done + [ "$n" -eq 2 ] || fail "expected 2 CEREMONY_SELF_REF carriers, found $n" + # and in the PROBE repo: workflows pin the armed sha, actions the code sha + git grep -hoP '(?<=uses:\s)\S+' -- .github | while read -r u; do + case "$u" in + */.github/workflows/*) [ "${u##*@}" = "$armed_sha" ] || fail "workflow caller $u" ;; + */actions/*) [ "${u##*@}" = "$code_sha" ] || fail "action caller $u" ;; + esac + done + # the negative check stays, as a cheap extra rather than as the proof + ! git grep -qE '(uses:|repository:)[[:space:]]*heavy-duty/ceremony' -- .github \ + || fail "canonical coordinate still present" ``` - Exit non-zero on any hit. A partial rewrite does not fail loudly on its - own — it silently tests canonical `main`, and the probe's answer is then - about the wrong tree. + **A count, not just a comparison** — `n -eq 2` is what catches a carrier + that vanished rather than being rewritten, which a per-value loop alone + cannot see. + 5. **Invoke the probe by the event it is about**, and record which: a `workflow_dispatch`, or the real board event under test. A probe that fires a different event than the one under test proves something else. @@ -143,7 +171,8 @@ So: without the two SHAs distinguished, a later reader cannot tell which tree answered. 7. **Reset removes the candidate-specific EXECUTABLE state**: the caller stubs, - the probe workflow, the candidate and armed branches — so the next probe + the probe workflow, and the fork's probe branch — whose tip carries both the + candidate commit and the armed commit on top of it — so the next probe cannot inherit a pin it did not choose. **Result issues are never deleted.** They may be closed or relabelled; deleting them would recreate the expiring-log problem this venue exists to avoid.