docs(runner-probes): the arming gate asserts what each carrier IS, not that a literal is gone (#202)

@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
This commit is contained in:
cluade-reviewer-andresmgsl 2026-08-05 14:02:08 +00:00
parent e27acd8ab9
commit 7e02344672
2 changed files with 46 additions and 12 deletions

View file

@ -28,8 +28,13 @@
reusable workflows to the armed SHA, which is the only revision whose inner reusable workflows to the armed SHA, which is the only revision whose inner
checkout points at the fork (#202). checkout points at the fork (#202).
- A `git grep` over the armed tree gates the rewrite non-zero, so a partial one - The arming gate asserts what each carrier IS, not only that the old literal
refuses instead of silently testing canonical main (#202). 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 - 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 ceremony issue by a human, so the probe holds no path that can write to the

View file

@ -107,7 +107,9 @@ So:
### The procedure ### The procedure
1. **Push the candidate tree** to a fork under the identity that will run the 1. **Push the candidate tree** to a fork under the identity that will run the
probe — `<identity>/ceremony@probe-<issue>` — and record its SHA. That is probe — one branch, `<identity>/ceremony@probe-<issue>` — 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 the **candidate code SHA**. Never create a branch on
`heavy-duty/ceremony` named like a tag: it shadows that tag for every `heavy-duty/ceremony` named like a tag: it shadows that tag for every
consumer until somebody remembers to delete it. consumer until somebody remembers to delete it.
@ -122,18 +124,44 @@ So:
- reusable-workflow callers → - reusable-workflow callers →
`<identity>/ceremony/.github/workflows/<file>@<armed-workflow-sha>`, since `<identity>/ceremony/.github/workflows/<file>@<armed-workflow-sha>`, since
that is the only revision whose inner checkout is rewritten. that is the only revision whose inner checkout is rewritten.
4. **Gate the rewrite mechanically, against the armed tree** — not against 4. **Gate the arming POSITIVELY, against the armed tree.** Absence of the old
whichever checkout happens to be current, and not by eyeballing prose: 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 ```sh
git -C <armed-checkout> grep -nE \ fork=<identity>/ceremony ; code_sha=<candidate-code-sha> ; armed_sha=<armed-workflow-sha>
'(uses:|repository:)[[:space:]]*heavy-duty/ceremony' -- .github \ fail() { echo "arming incomplete: $*" >&2; exit 1; }
&& { 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 **A count, not just a comparison**`n -eq 2` is what catches a carrier
own — it silently tests canonical `main`, and the probe's answer is then that vanished rather than being rewritten, which a per-value loop alone
about the wrong tree. cannot see.
5. **Invoke the probe by the event it is about**, and record which: a 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 `workflow_dispatch`, or the real board event under test. A probe that fires
a different event than the one under test proves something else. 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 without the two SHAs distinguished, a later reader cannot tell which tree
answered. answered.
7. **Reset removes the candidate-specific EXECUTABLE state**: the caller stubs, 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.** cannot inherit a pin it did not choose. **Result issues are never deleted.**
They may be closed or relabelled; deleting them would recreate the They may be closed or relabelled; deleting them would recreate the
expiring-log problem this venue exists to avoid. expiring-log problem this venue exists to avoid.