2026-08-04 10:44:02 +00:00
# 0.4.1 — drill record
drill(0.4.1): the post-merge rehearsal passed — record both runs
#191's last acceptance criterion was a live drill against the MERGED tree,
not the candidate. Run against `fda5657`:
probe 1 merge door one release 0.4.1, changelog body, main re-armed
to 0.4.2-dev, both assets uploaded
probe 3 no label refused, nothing created
probe 5 tag door 0.5.0 published, main VERSION untouched
probe 6 bad tag refused, nothing created
The fixture carried an artifact hook this time, dropping `drill asset.tgz`
and `a&b.tgz`. Both survived under those exact names — the encoding fix
proven end to end, in the place it would have failed: after the tag exists,
mid-publish.
The record keeps run 1 (the failure at 9a229ee) beside run 2, because the
failure is why #191 exists and a record that quietly replaced it would be
the kind of tidy history this repo refuses.
Refs #191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:06:53 +00:00
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` .
2026-08-04 10:44:02 +00:00
| # | probe | run | result |
|---|---|---|---|
2026-08-04 15:30:55 +00:00
| 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` :
2026-08-04 10:44:02 +00:00
2026-08-04 15:30:55 +00:00
```
facts: ver='0.4.1' base_ver='0.4.1-dev' released='' labeled='yes'
decide: ceremony=yes
```
2026-08-04 10:44:02 +00:00
2026-08-04 15:30:55 +00:00
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:
2026-08-04 10:44:02 +00:00
```
2026-08-04 15:30:55 +00:00
forge_release_exists 0.4.1 -> yes 0.5.0 -> yes 9.9.9 -> no
2026-08-04 10:44:02 +00:00
```
2026-08-04 15:30:55 +00:00
`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.
2026-08-04 10:44:02 +00:00
2026-08-04 15:30:55 +00:00
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.
2026-08-04 10:44:02 +00:00
drill(0.4.1): the post-merge rehearsal passed — record both runs
#191's last acceptance criterion was a live drill against the MERGED tree,
not the candidate. Run against `fda5657`:
probe 1 merge door one release 0.4.1, changelog body, main re-armed
to 0.4.2-dev, both assets uploaded
probe 3 no label refused, nothing created
probe 5 tag door 0.5.0 published, main VERSION untouched
probe 6 bad tag refused, nothing created
The fixture carried an artifact hook this time, dropping `drill asset.tgz`
and `a&b.tgz`. Both survived under those exact names — the encoding fix
proven end to end, in the place it would have failed: after the tag exists,
mid-publish.
The record keeps run 1 (the failure at 9a229ee) beside run 2, because the
failure is why #191 exists and a record that quietly replaced it would be
the kind of tidy history this repo refuses.
Refs #191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:06:53 +00:00
**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.
2026-08-04 10:44:02 +00:00
drill(0.4.1): the post-merge rehearsal passed — record both runs
#191's last acceptance criterion was a live drill against the MERGED tree,
not the candidate. Run against `fda5657`:
probe 1 merge door one release 0.4.1, changelog body, main re-armed
to 0.4.2-dev, both assets uploaded
probe 3 no label refused, nothing created
probe 5 tag door 0.5.0 published, main VERSION untouched
probe 6 bad tag refused, nothing created
The fixture carried an artifact hook this time, dropping `drill asset.tgz`
and `a&b.tgz`. Both survived under those exact names — the encoding fix
proven end to end, in the place it would have failed: after the tag exists,
mid-publish.
The record keeps run 1 (the failure at 9a229ee) beside run 2, because the
failure is why #191 exists and a record that quietly replaced it would be
the kind of tidy history this repo refuses.
Refs #191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:06:53 +00:00
## Run 1 — against `9a229ee`, before the fix (FAILED)
2026-08-04 10:44:02 +00:00
2026-08-04 16:00:42 +00:00
Recorded because the failure is the reason #191 exists — including its
deviations, which no later success retires.
2026-08-04 10:44:02 +00:00
2026-08-04 16:00:42 +00:00
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.
drill(0.4.1): the post-merge rehearsal passed — record both runs
#191's last acceptance criterion was a live drill against the MERGED tree,
not the candidate. Run against `fda5657`:
probe 1 merge door one release 0.4.1, changelog body, main re-armed
to 0.4.2-dev, both assets uploaded
probe 3 no label refused, nothing created
probe 5 tag door 0.5.0 published, main VERSION untouched
probe 6 bad tag refused, nothing created
The fixture carried an artifact hook this time, dropping `drill asset.tgz`
and `a&b.tgz`. Both survived under those exact names — the encoding fix
proven end to end, in the place it would have failed: after the tag exists,
mid-publish.
The record keeps run 1 (the failure at 9a229ee) beside run 2, because the
failure is why #191 exists and a record that quietly replaced it would be
the kind of tidy history this repo refuses.
Refs #191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:06:53 +00:00
2026-08-04 16:00:42 +00:00
| # | 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` |
drill(0.4.1): the post-merge rehearsal passed — record both runs
#191's last acceptance criterion was a live drill against the MERGED tree,
not the candidate. Run against `fda5657`:
probe 1 merge door one release 0.4.1, changelog body, main re-armed
to 0.4.2-dev, both assets uploaded
probe 3 no label refused, nothing created
probe 5 tag door 0.5.0 published, main VERSION untouched
probe 6 bad tag refused, nothing created
The fixture carried an artifact hook this time, dropping `drill asset.tgz`
and `a&b.tgz`. Both survived under those exact names — the encoding fix
proven end to end, in the place it would have failed: after the tag exists,
mid-publish.
The record keeps run 1 (the failure at 9a229ee) beside run 2, because the
failure is why #191 exists and a record that quietly replaced it would be
the kind of tidy history this repo refuses.
Refs #191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:06:53 +00:00
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.