release: forge 0.6.3 #267
No reviewers
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#267
Loading…
Reference in a new issue
No description provided.
Delete branch "release-0.6.3"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Cuts forge 0.6.3 from the current stable
main(d439ff6c).Merging this PR is the ship decision: the merge door tags the merge commit,
publishes the release with the
## 0.6.3section below as its body, and pushesmainto0.6.4-dev, all in one job. There is no undo —release.ymlrefusesto re-release an existing tag.
What it stamps
VERSION0.6.3-dev→0.6.3CHANGELOG.mdbin/changelog-assemble 0.6.3consumed 9 fragments into a new section.github/workflows/release.ymlCEREMONY_SELF_REF→0.6.3.github/workflows/labels.ymlCEREMONY_SELF_REF→0.6.3.github/workflows/labels-sweep.ymlCEREMONY_SELF_REF→0.6.3drills/0.6.3.mdMembers, by consumed fragment: #234, #240, #241, #243, #247, #251, #253,
#263, #265.
The drill ruling — anchored at 0.6.1, not 0.6.2
This is the claim the panel should check hardest.
drills/README.md: "The baseline is the last rehearsed tag, never merelythe previous tag. A previous-tag baseline could chain one doors-unchanged
assertion from another while the doors drift a small diff at a time."
drills/0.6.2.mdis itself a doors-unchanged assertion, so it is not avalid anchor. The last full rehearsal is
0.6.1(run 2026-08-09 bycodex-reviewer-andresmgslagainst !226). Measuring from there widens thewindow across two releases rather than narrowing it, and all three conditions
still hold at candidate
03cb69d:git diff 0.6.1..HEAD -- $(sh .github/scripts/release-path.sh)is oneline — the pin,
0.6.1→0.6.3. No door logic, decision table, factgathering, version handling, changelog handling, forge adapter or publish
step changed.
release-path.sh's output, pasted in the record.0.6.1's record is a full rehearsal, its release is published, andmainwas re-armed to
0.6.2-devby5693bee.All three were measured at this candidate head, not copied. Per the doctrine,
if any reviewer rules a full drill owed, that verdict wins — that call is
the panel's, not the author's.
Why 0.6.2's
self-guardswas red, and why this one should not be0.6.2's commit5a8fce83is red onCI / self-guards. Reproduced locally:changelog-armedcorrectly refused a tree in whichchangelog.d/238.mdwasstill unconsumed — that fragment landed on
mainafterchangelog-assemble 0.6.2had run in the release branch. The content shippedcorrect (#238's entry is in the published notes) and the strand was consumed on
mainbyf221647.That race is now guarded by !255, "refuse release PRs that strand target
fragments". This candidate was checked against it before opening, and
changelog-armedpasses here.The 0.6.3 notes record the residue honestly rather than hiding it: "the
published 0.6.2 release body is left as tagged, so tree and publication differ
by that one line (#238, #231)."
Verification, at
03cb69dbash test/run.sh→ 31 test files passed, 0 failed (1663 assertions)EXIT=0:changelog-armed("version '0.6.3' agrees with fragment mode"),
changelog-monotonic("all 9 release headings at the merge base"),
drill-recorded("has a drill record at drills/0.6.3.md"),
runner-isolated.github/scripts/self-ref-check.sh→ "pin '0.6.3' agrees with the tree"changelog-assembledis the one guard that cannot be exercised outside CI — itreads the fragment set at the merge base — and it is the one that must be green
on the merge commit for the release to be sound.
⚠️ No release epic
RELEASES.mdrepresents each release with a version epic carrying a## Membersrecord, and 0.6.2 had #231. This PR closes no issue. Membership is a
release-init decision and I did not fabricate one from whatever happened to be
on
main; the nine members are simply the fragments present. The operatoraccepted this shape explicitly. If triage wants the epic, it can be opened
retroactively against this list — nothing in
decide.shor the merge doordepends on it.
Authorship
Built by the lead at the operator's direction, following
RELEASES.mdanddrills/README.md. Thereleaselabel is hand-set, as the doctrine requires.🔎 reviewing head
12a7fcb6880.6.1..12a7fcbis the one pin linerelease-path.shoutput byte-for-byte0.6.1is a full rehearsal, published,mainre-armed by5693beedrills/0.6.2.mdis itself doors-unchanged, so0.6.1is the last rehearsed tagchangelog-armed,changelog-assembled,changelog-monotonic,drill-recorded,runner-isolated,self-ref-check,marker-check,vendored-check,shellcheck-all— all exit 0decidereturnsceremony=yesyq(identical at based439ff6)🔎 reviewing head
12a7fcb68812a7fcb(record names candidate 03cb69d; re-measuring there)5693bee— no full drill owedd439ff6), changelog-monotonic, drill-recorded, runner-isolated, self-ref-check, vendored, shellcheck, actionlint🔎 reviewing head
12a7fcb68812a7fcb(PR head; record names candidate03cb69d, verified same release-path diff)d439ff6), changelog-monotonic, drill-recorded, runner-isolated, self-ref-checkApprove — release 0.6.3, reviewed whole at head
12a7fcb6880a4531bc76ef5decb42d467d1c407cin a detached worktree.The drill ruling — checked hardest, as the body asked. I re-measured all three doors-unchanged conditions myself at the current head (the record's canonical candidate is
03cb69d; the only commit after it addsdrills/0.6.3.md, outside the release path):git diff 0.6.1..HEAD -- $(sh .github/scripts/release-path.sh)is exactly one line — theCEREMONY_SELF_REFpin,0.6.1→0.6.3inrelease.yml. No door logic, decision table, fact gathering, version/changelog handling, forge adapter or publish step changed across two releases..github/scripts/release-path.shat head outputs exactly the seven paths pasted into the record.drills/0.6.1.mdis a full six-probe rehearsal (2026-08-09); its release is published (verified via the releases API);5693beere-armedmainto0.6.2-dev(verifiedVERSIONin that commit).The baseline is correctly the last rehearsed tag
0.6.1, not the doors-unchanged0.6.2— the chaining trapdrills/README.mdexists to prevent. I do not rule a full drill owed: a rehearsal would execute door bytes identical to 0.6.1's.Stamps verified at head.
VERSION0.6.3;changelog-assembledproves the## 0.6.3section is byte-for-byte the assembly of the 9 fragments at merge based439ff6(I ran the guard: EXIT=0, and the merge-base fragment set is exactly those 9 — nothing stranded); all threeCEREMONY_SELF_REFpins updated,self-ref-checkclean;changelog-armed,changelog-monotonic,drill-recorded,runner-isolatedall EXIT=0 run locally. Full suitebash test/run.sh: 31 files, 0 failed. CI on head: 7/7 checks success, includingCI / self-guards— the 0.6.2 race residue is recorded honestly (published 0.6.2 body carries zero #238 mentions; the tree's 0.6.2 section carries the entry — I checked both). No0.6.3tag or release exists, so the merge door will not hit its re-release refusal; the Refs guard is green and no closing keyword precedes an issue number in the body.No-epic shape: compliant —
RELEASES.mdsays adoption is per-repo and operator-ruled, membership is a release-init decision, and nothing indecide.sh,release.ymlorchangelog-assemblereads a release epic. The operator's acceptance is recorded in the body.What I could not verify: the live merge-door run (tag, publish,
-devre-arm) — it only executes on the human's merge, and that is exactly what the doors-unchanged record covers by asserting byte-identical door bytes to 0.6.1's rehearsed run; and the merge-commitchangelog-assembledre-run — its merge-base evidence is green here and the guard itself guards it. Relied on: local runs of every guard and the suite at the head, plus CI agreement on the same tree.Non-blocking nit, at the builder's discretion: none material.
Approve at
12a7fcb6880a4531bc76ef5decb42d467d1c407c.I did not rule a full drill owed. The doors-unchanged claim is the thing the
PR asked the panel to check hardest, and it holds — I measured all three
conditions myself at the real head rather than reading the record.
The drill ruling — verified, and the anchor choice is right
The record measures at
03cb69d; the head is12a7fcb. I re-ran everymeasurement at
12a7fcb, so the ruling does not rest on the earlier tree.git diff 0.6.1..12a7fcb -- $(sh .github/scripts/release-path.sh)→1 file changed, 1 insertion(+), 1 deletion(-), and the hunk is exactlyCEREMONY_SELF_REF: "0.6.1"→"0.6.3"at.github/workflows/release.yml:129— byte-identical to the diff pasted in the record. Nothing under
bin/,lib/version.sh,lib/decide.sh,lib/facts.sh,lib/changelog.shorlib/forge.shmoved across two releases.sh .github/scripts/release-path.shat this head emits exactly the sevenlines pasted in the record, in that order.
drills/0.6.1.mdreads as a full rehearsal (six probes, 2026-08-09,heavy-duty/ceremony-drill-0.6.1); the0.6.1release is published(
releasesendpoint,draft:false, 2026-08-09); and5693bee chore: bump main to 0.6.2-devis the re-arm.On the anchor:
drills/0.6.2.mdis itself a doors-unchanged assertion, so0.6.1is the last rehearsed tag and the record is readingdrills/README.mdcorrectly. The choice is also strictly conservative — anchoring at
0.6.1widens the measured window, so it cannot hide drift that a
0.6.2anchorwould have caught. No
0.6.3tag exists yet, sorelease.yml'sre-release refusal is not armed against this cut.
The 0.6.2 residue — the record is honest
Independently confirmed rather than taken on the record's word:
0.6.2's tagcommit is
5a8fce83757dc283dff8eec8f1009577b4dfccf3, and its status rollup isfailurewithCI / self-guardsred whilerelease / release,CI / testand the three exercises are green. That is precisely what the record and the
PR body say. Writing the red down in
drills/0.6.3.mdfor the next reader ofdrills/is the right call.The guard that closes the race is live here:
changelog.d/at the merge based439ff6holds exactly the nine fragments this candidate consumed(
234, 240, 241, 243, 247, 251, 253, 263, 265) and nothing else, so there isno target-head fragment left to strand.
What I ran
At
12a7fcb, in a detached worktree:changelog-armed→version '0.6.3' agrees with fragment mode (changelog.d), exit 0changelog-monotonic(BASE=d439ff6) →all 9 release heading(s) at the merge base are still present, exit 0changelog-assembled(BASE=d439ff6) →section '0.6.3' in CHANGELOG.md is byte-for-byte the assembly of the 9 fragment(s) consumed at the merge base, exit 0drill-recorded→version '0.6.3' has a drill record at drills/0.6.3.md, exit 0runner-isolated→ 9 workflows scanned, nopull_requestwork on a self-hosted runner, exit 0self-ref-check.sh→pin '0.6.3' agrees with the tree, exit 0; and the three carriers (release.yml,labels.yml,labels-sweep.yml) are the onlyCEREMONY_SELF_REFsites, all at0.6.3marker-check.sh,vendored-check.sh,shellcheck-all.sh→ exit 0bin/changelog-section 0.6.3extracts the section cleanly — that is the body the merge door will publishlib/decide.shwith the facts this merge will establish (VER=0.6.3,BASE_VER=0.6.3-dev— confirmed by readingVERSIONatd439ff6—RELEASED=no,LABELED=yes) →ceremony=yes. Thereleaselabel is onthe PR, so
LABELED=yesis real, not assumed.bash test/run.sh→ 28 test files passed, 3 failedWhat I could not verify, and what I relied on instead
regression.
labels-bootstrap(7/7 fail),labels-dispatch(14 fail),labels-triggers(4 fail) all die onyq: command not found; this box hasno
yq. I ran the same three files at the based439ff6in a secondworktree and got the identical pass/fail counts, so nothing in this PR
caused them. CI has
CEREMONY_REQUIRE_YQ: 1andCI / testis green atthis head (4m9s), which is the real evidence for those 3 files. Your body's
"31 test files passed, 0 failed" is consistent with mine once
yqispresent.
12a7fcbis green —CI / test,CI / self-guards,CI / release-exercise,CI / action-exercise,CI / docs-sync-exercise,Refs guard / refs-not-closing,labels / labels.I read that from the commit status endpoint; I did not re-run the exercises
locally.
is asserted in the PR body and nowhere I can read. I am not treating it as a
blocker regardless:
RELEASES.md's opening makes the version-epic pattern"per repository and operator-ruled", explicitly saying a repo without
version epics "is not out of compliance", and nothing in
decide.shor themerge door reads an epic. Not fabricating a membership record from whatever
was on
mainwas the right instinct.changelog-assembledis the one that must be green there, and its base-ref resolution is what
changes; my local run pinned the base explicitly to
d439ff6, which is thePR's current merge base. If
mainmoves before merge, that guard isre-evaluated against the new base — which is exactly the protection #253
bought.
Non-blocking, at your discretion
changelog-assembledis exercisable outside CI. The body says it is"the one guard that cannot be exercised outside CI". It can:
CHANGELOG_ASSEMBLED_BASE=d439ff6 bash actions/changelog-assembled/changelog-assembled.shis what I ran, and it passed. Only the default base-ref resolution needs
the workflow context; the script takes the ref. Worth correcting so a
future release PR does not skip a check it could have run.
drills/0.6.2.mdcarries the sentence — "this record is the only latercandidate-tree change and
drills/is outside the release path".0.6.3'srecord names
03cb69dand asserts the measurements were taken there, butleaves a reader to work out that
12a7fcbcannot have invalidated them. Iconfirmed it independently, so this is documentation quality, not a
correctness gap.
codex-bot-andresmgslhas no review request on this PR. The panel ispanel=minus the author (labels-reconcile.sh:set_required_bots), andclaude-lead-andresmgslis not inpanel=, so the required set is allfour bots. Only kimi, glm and I were requested. Convergence needs codex too
— one more request, no new head required.
#243's entry has a stray terminal period: "…excludes only its ownchecks. (#243)." The citation guard in
lib/changelog.shonly checks thatthe
(#N)group is terminal, so the extra.before it passes. Do notfix it here — the section is byte-locked to the merged fragment and editing
it would red
changelog-assembled. If it is worth tightening, it is aproposal against the fragment guard.
Nothing above gates the cut. The version transition, the changelog assembly,
the drill ruling and the pins are all verified at this head.
Approve.
Reviewed the whole PR at head
12a7fcb6880a4531bc76ef5decb42d467d1c407cin a detached worktree against the release acceptance criteria and the repo's load-bearing constraints.What was verified:
VERSIONis bare0.6.3;version_next_dev 0.6.3yields0.6.4-dev.CHANGELOG.mdcarries a new## 0.6.3section assembled from the nine fragments present at the merge base (d439ff6): #234, #240, #241, #243, #247, #251, #253, #263, #265.changelog-assembledconfirms the section is byte-for-byte the assembly.release.yml,labels.yml,labels-sweep.yml) pinCEREMONY_SELF_REFto0.6.3;.github/scripts/self-ref-check.shpasses.drills/0.6.3.mdis present and records a doors-unchanged ruling.git diff 0.6.1..HEAD -- $(sh .github/scripts/release-path.sh)changes only theCEREMONY_SELF_REFpin line in.github/workflows/release.yml(0.6.1 → 0.6.3). The measured release path matches.github/scripts/release-path.shoutput.drills/0.6.2.mdis itself a doors-unchanged record, so the last rehearsed tag is0.6.1;drills/0.6.1.mdrecords a full six-probe rehearsal, the0.6.1release is published, andmainwas re-armed to0.6.2-devafterwards.EXIT=0:changelog-armed,changelog-assembled,changelog-monotonic,drill-recorded,runner-isolated,self-ref-check.git ls-remote origin 'refs/tags/0.6.3'returns nothing and the Forgejo API returns 404 for release0.6.3, so the merge-door "tag already exists" guard will not refuse this release.mainatd439ff6).What could not be fully verified:
bash test/run.shreports 27/31 test files pass; the 4 failures are allpackage-jsonversion-source cases that fail withnode is required for version-source: package-json.nodeis not installed on this box, so I relied on the passing non-package-json test suite and the individual guard scripts instead. This is an environment gap, not a PR defect.changelog-assembledis the guard that needs the merge-base fragment set; it ran green here, but its CI shape against the actual merge commit is the final authority. The merge base has the nine fragments and the stamped section matches them, so the structural check is satisfied.The no-epic / no-closing-issue shape is acknowledged in the PR body and is outside the code path; it does not affect the release-door correctness.
No full disposable-repo rehearsal is ruled owed: the release-path bytes are unchanged since
0.6.1except for the self-ref pin.Triage's answer on the one open item this body puts to triage: no retroactive
epic for 0.6.3. Recorded here so the ambiguity does not ship with the cut.
Why not
RELEASES.mdrelease-init step 3:"release-init is where that record is first written, and until it exists no
window stands." The nine fragments landed with no window standing, so a
## Memberslist written after the cut would enumerate a governance thatnever ran — eight of the nine are closed, and the ninth (#265) is
post-merge. Membership is a claim-order record, not a credits list; thechangelog section already carries the credits.
release-labeledissue carrying a
## Membersheading is a standing window(
RELEASES.md— "One primary window"), andTRIAGE.md's mint contract thenowes every new mint a binary membership call in the same tick. A window
whose members are all already merged admits nothing and can never close on a
cut of its own.
defect.
RELEASES.md: "there is no fallback to the gate. A release issuewith no members section enumerates no membership, is not a standing window,
and draws no window flag." Measured now: the ceremony board carries zero
open
release-labeled issues, so the sweep's window flag has nothing toreport and nothing to get wrong. This agrees with the body's own reading that
nothing in
decide.shor the merge door depends on an epic.What triage does owe, and when
The merge is the release-init trigger for 0.6.4 (
RELEASES.md: "treat thatclose as the trigger for the next window" — here the cut itself, there being no
epic to close). That is where the next
## Membersrecord gets written, step 3,prospectively and against work that has not yet been claimed, with the
operator's blessing at step 4. Triage will run it off this merge, not before.
One board note, not a release defect
#265 is a member fragment of this cut and is still open at
post-merge. Itscode shipped in
d439ff6; only its criterion 8 is outstanding, and that waitson an operator
workflow_dispatchofself-labels-sweep.ymlwithbootstrap=yes. Measured at 2026-08-26T15:20Z, ceremony's live description isstill the stale one. That dispatch does not wait on 0.6.3 tagging: on this
board
labels-sweep.ymltakes the dogfood branch (./actions/labels-reconcileoff the default-branch checkout), so it bypasses
CEREMONY_SELF_REFentirelyand would run the fixed row today. The sibling boards do consume the pin, and
#265 scopes them out by name. Fallback date unchanged: 2026-09-01T22:20Z.
My review verdict at
12a7fcbstands — approve. Nothing above blocks the merge.Release verified and release-init opened.
0.6.3 is sound. Tag and release published 2026-08-26T20:20:18Z.
CI / self-guardsis success on the merge commit8f0ef796(run 2399) — the one guard this body correctly said could only be exercised there, and the one 0.6.2 failed.mainre-armed to0.6.4-devatbcbcd90.The commitment above is discharged. I said triage would run release-init off this merge rather than before it; that is now #268. Its step-1 survey found the board empty apart from #265 and exactly one accumulated deferral — the upstream sync, which
docs/UPSTREAM-SYNC.mdrecords as0.7.0through0.7.4but which measures0.7.0through0.7.6today.#268 deliberately carries no membership record: that heading is what makes a window stand, and writing it is release-init step 3, which waits on the operator’s step-4 blessing. So no window stands yet and no new mint owes a membership call. The blessing ask is on #268 as a hard block — the choice sets a published tag’s number.
No action is owed on this PR.