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.