ceremony/drills/0.4.1.md
cluade-reviewer-andresmgsl d089ab57b3
All checks were successful
CI / test (pull_request) Successful in 1m29s
CI / release-exercise (pull_request) Successful in 11s
CI / self-guards (pull_request) Successful in 6s
CI / action-exercise (pull_request) Successful in 5s
CI / docs-sync-exercise (pull_request) Successful in 5s
labels / labels (pull_request) Successful in 1m35s
drill(0.4.1): probes 2 and 4 ran — all six probes now have live results (#191)
Codex (!194 #1588) is right on the text: #191's criterion is a drill that
runs all six probes with 1 and 5 passing, not two probes passing and four
recorded. Probe 2 (mislabeled ordinary PR) and probe 4 (a re-run of the
completed ceremony) were run on the same consumer, un-archived for them and
archived again after.

Probe 4 diverges in mechanism because Forgejo 8.0.3 has no run-rerun API:
the ceremony was re-run by reproducing its input rather than replaying the
run. The record says so, and says which assert refused.
2026-08-04 15:30:55 +00:00

5.5 KiB
Raw Blame History

0.4.1 — drill record

Two runs. The first, 2026-08-04 against release PR !190 head 9a229ee, failed: both doors were inoperable and the release could not publish at all. The second, after #191 landed as fda5657, passed. Both are recorded, because the first is why the second exists.

Run 2 — against merged main fda5657 (the one that counts)

Where: disposable private repo heavy-duty/ceremony-drill-0.4.1-final, armed at 0.4.1-dev, carrying the docs/CONSUMERS.md release caller, a fragment-mode fixture, and — unlike run 1 — an artifact hook dropping two deliberately awkward filenames, drill asset.tgz and a&b.tgz. Archived at the end; the operator's delete is pending, and cleanup gates nothing.

Candidate ref: cluade-reviewer-andresmgsl/ceremony@drill-main, parent fda5657, whose only extra commit rewrites both CEREMONY_SELF_REF carriers to that SHA — release.yml's self-checkout is hardcoded to heavy-duty/ceremony, so only a SHA that resolves there can stand in for a tag that does not exist yet. No 0.4.1 branch was created on heavy-duty/ceremony.

# probe run result
1 merge-door ceremony 637 exactly one release 0.4.1; body is the version's own changelog section; tag and release on merge commit 4a83fa1b; main re-armed to 0.4.2-dev; both assets uploaded
2 mislabeled ordinary PR 652 green no-op in 7s on merge commit e71df4e3 — release count stayed 2, no tag created
3 bare version, no release label 638 refused at b091aff2 — release count stayed 1
4 re-run of the completed ceremony 654 refused in 8s on merge commit 82e7d11b — release count stayed 2, and tag 0.4.1 stayed on 4a83fa1b, the original merge commit
5 tag door, matching tag 639 0.5.0 published with its own section and both assets; main VERSION untouched
6 mismatched tag 640 9.9.9 refused — release count stayed 2; the tag exists, the release does not

Probes 2 and 4 were run last, at 15:2315:28Z, on the same consumer: it was un-archived for them and archived again at the end. Nothing else about the run changed — same candidate ref, same caller pin.

Probe 4 diverges in mechanism, not in what it proves. The 0.3.0 and 0.4.0 siblings re-ran the completed ceremony's workflow run (GitHub's "attempt 2"). Forgejo 8.0.3 exposes no run-rerun API — there are no actions/runs/{id} routes in its swagger at all — so the ceremony was re-run by reproducing its input instead: main re-armed to 0.4.1-dev (setup run 653), then a second release-labeled PR stamping bare 0.4.1 merged on top. That is the same state the door refuses on, reached by a push rather than a re-trigger, and it is stricter than the sibling shape in one way — it re-enters through factsdecide rather than replaying a decided run.

Which refusal fired is measurable even without run logs. Replaying the door's own inputs against the live consumer at 82e7d11b:

facts: ver='0.4.1' base_ver='0.4.1-dev' released='' labeled='yes'
decide: ceremony=yes

So decide said go — a labeled bare transition is row 6 — and the stop came from the merge door's own pre-publish assert, release.yml:216-219, whose comment names this exact probe ("what makes a re-run of a completed ceremony refuse instead of clobber"): the tag existed, so it refused before forge_tag_create ever ran. The second net behind it is #191's own verb, and it reads this consumer correctly:

forge_release_exists 0.4.1 -> yes    0.5.0 -> yes    9.9.9 -> no

9.9.9 is the probe-6 receipt in the same breath: the tag exists, the release does not.

Evidence for every probe here is the run conclusion plus the repository state before and after — this instance serves no run logs (the API 404s on every log route), so no probe's result is quoted from a log line.

End state, as observed when this was written: releases 0.4.1 and 0.5.0 and nothing else; tags 0.4.1 on 4a83fa1b, 0.5.0 and 9.9.9 on b091aff2; the consumer's main left at bare 0.4.1 where probe 4 stopped it, private and archived.

The asset names survived intact: a&b.tgz and drill asset.tgz both appear under those exact names on both releases. Before #191's fix the space made curl reject the URL outright and the & split the query — the failure landing after the tag exists, mid-publish, which is the worst place this door has.

Run 1 — against 9a229ee, before the fix (FAILED)

Recorded in full because the failure is the reason #191 exists.

# probe result
1 merge-door ceremony decide refused: labeled=no for a PR that was labeled and was merged
5 tag door gh: command not found at publish the release
6 mismatched tag refused, creating nothing

Root cause, both doors: lib/facts.sh and release.yml spoke gh, which the runner image does not ship. facts.sh read any failure as a definite no, so a missing binary silently demoted a release ceremony to "a bare push". Release count across the whole of run 1: 0.

What changed between them

#191, merged as fda5657: both doors onto lib/forge.sh; a read that did not complete refuses instead of fabricating a no; forgejo_api_base refuses an empty REPO so repos//… cannot be addressed; release asset names percent-encoded.

Every refusal path, in both runs, created nothing. That property never broke — what broke was the doors' ability to say yes.