The section is re-assembled: main's merge base now carries two fragments (188.md and 191.md), so 0.4.1 publishes with the door port it actually ships, and neither fragment survives its own release. drills/0.4.1.md takes main's two-run record, with run 1's disclosures restored — the scratch repo it used, its candidate ref, and the ~8 minutes it spent public to read job logs. A later success does not retire a disclosed deviation.
6.8 KiB
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:23–15: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
facts → decide 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 because the failure is the reason #191 exists — including its deviations, which no later success retires.
Where: disposable private repo heavy-duty/ceremony-drill-0.4.1 — a
different consumer from run 2's, archived at the end with the operator's
delete pending. Candidate ref
cluade-reviewer-andresmgsl/ceremony@drill-0.4.1 (f148255), parent
9a229ee, its only extra commit rewriting both CEREMONY_SELF_REF carriers
to that SHA.
Deviation, disclosed and not retired by run 2: run 1's scratch repo was
flipped public for roughly 8 minutes to read job logs — Forgejo's web log
route 404s for a token-authenticated private repo and the /api/v1 log
routes 404 outright — then restored to private and archived. That is a real
departure from drills/README.md's "scratch private repo", and it stays
in the record. Run 2 did not repeat it: it read no logs at all, which is why
every run-2 row is a repository-state measurement.
| # | probe | run | result |
|---|---|---|---|
| 1 | merge-door ceremony | 12 (and 7, at 0.4.1) |
❌ FAILED — decide refused; no tag, no release, main left bare |
| 2 | -dev push no-op |
9, and the fixture push | ✅ green no-op, nothing created |
| 3 | bare version, no release label |
— | ⚠️ not run independently; probe 1 refused through exactly this path, because the label fact read no |
| 4 | re-run of a completed ceremony | — | ⚠️ not reachable — no ceremony ever completed to re-run |
| 5 | tag door | 14 | ❌ FAILED — gh: command not found at publish the release; no release |
| 6 | mismatched tag | 16 | ✅ tag '9.9.9' does not match the tree's version '0.4.2' — 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.