Release/deploy facts measured during the 2026-08-06 stuck cut — for the next clean release #36
Labels
No labels
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
status/deferred
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/purser#36
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Recording what was measured during the 2026-08-06 stuck-cut morning, so the next release doesn't
rediscover it. The operator picked B for that incident; this is for whoever does the clean cut later.
purser publishes immediately — it does not stop at a draft
The toolkit default is
draft(ADR-0003 Gate-3). purser overrides it. So a successful cut herepublishes the release, which fires deploy.yml. There is no human gate between cut and deploy on the
current config.
If a gate is wanted, that's a one-line change to
release.ymlor apublish_mode:key inrelease-toolkit.yml— not a workflow rewrite.The v0.1.0 precedent does not mean publishing is safe
v0.1.0 was published and nothing deployed. The reason is that
deploy.ymlwas not in the taggedtree — it landed on main at 22:28 and the tag predates it by ten minutes.
Both current candidates contain it. Anyone reasoning "publishing was fine last time" would fire the
deploy on a precedent that only held because the workflow didn't exist yet. Measured by
Quartermaster; control by Surveyor.
Tag and publish are separable
All five workflows have zero tag triggers:
So
git push origin <tag>emits no release event and cannot deploy. Creating and publishing therelease is the step that deploys. If a future recovery needs the repo consistent without shipping,
that split is available — but state it as "stopping deliberately short of what a cut would do", not
as "reproducing what a cut would do", because with
publish_mode: immediatethose differ.That wording matters: a later reader who checks the default, finds
immediate, and concludes thehold rested on a mistake would publish and fire the deploy. The false rationale is what removes the
safeguard.
Tag target has a downstream consequence
Measured by Quartermaster with
rt v0.35.0 decide --dry-run, control arm first:Tagging the prep commit leaves later commits reading as new work. The next person to merge anything
gets an unexpected release.
Do not hand-write a manifest
purser has none and runs on
release-decide.sh's bootstrap-from-tags path. A hand-written manifestmissing
"schema": 1converts a working bootstrap into a hard FATAL (release-decide.sh:136-143).Separately: purser is a path-gamma consumer, gamma delivers the manifest by PR, and no manifest PR
has ever existed here. Filed as release-toolkit#661 — an observation, since the v0.1.0 run log
hasn't been read.
Not verified
Nobody has watched a cut complete on this repo end to end. Every finding above is a source read or a
--dry-run, which exercises decide's git-side logic and skips the API-dependent layers.What actually gates a cut here — added after #35 settled
The unwind is done (#35). Three facts from settling it belong with the rest, because they will
otherwise be re-derived at the real v0.2.0.
The prepare commit is still armed, and the CHANGELOG has nothing to do with it
9f73225 chore(release): prepare v0.2.0remains inv0.1.0..HEAD. History is append-only, soneither renaming the section nor reverting #25 removes it — Layer 1's range-scan still matches it
(
buried-prepare, #259). Whenever the real v0.2.0 goes out, that buried commit is still the thingauthorising the version.
Layer 2 is what gates the cut, not the CHANGELOG state
release-decide.shgates the whole cut onLAYER2_RESULT != "fail". Layer 2 compares the mergedPR's
head.labeltoROLLING_BRANCH_NAME, which defaults torelease-prep/rollingand is neverexported by the reusable.
So an ordinary merge to main cannot cut. Only merging the rolling PR does. Layer 1 finding the
prepare commit is necessary and not sufficient, which is the part all three of us initially reasoned
past.
Practical consequence: the buried prepare commit is inert until someone merges a
release-prep/rollingPR — and at that momentpublish_mode: immediate(above) means it publishesand deploys in one step.
Why B2 rather than B1, measured
B1 (rename the heading, leave fragments deleted) duplicates.
changelog_dedup_cc_by_fragment_refs()takes only
fragments_dirandcommits_file, so the[Unreleased]prose is never in scope; with nofragments the ref set is empty and every commit bullet passes through. Control run by @bosun on the
two candidate trees:
Fragments carry the dedup keys. That is the reason to restore them, and it is unrelated to deferral.
Caveat carried forward
No cut has been watched end to end on this repo. Layer 2's fall-through is established from the
source plus
head.labelreads, not from a live post-merge run.Caveat update — NARROWED, not lifted
@bosun drove the real Layer-2 code path without a live merge, using the seam the toolkit's own
FAIL-path tests use (
LAYER2_BYPASS_DRY_RUN=1+FORGEJO_TEST_PR_LOOKUP_FILE), two arms against thepost-merge tree:
The control arm is what makes it evidence rather than a harness that answers
updateto everything,and it reproduces the live 10:12 outcome —
#25's label wasrelease-prep/rolling.Exactly what is and is not established
@surveyor separately enumerated that all three lookup outcomes (match, empty, empty
head.label)land on
fail, which is why the mocked leg is reasonable rather than load-bearing. It is still anassumption and should be named as one.
Why this correction is here rather than dropped
The person who ran the measurement is the one who narrowed it, unprompted and against his own result.
A caveat that gets removed because a partial measurement landed is worse than one that was never
written — the next reader inherits "this was checked" with no way to see which layer.
End-to-end observation — the update path is now watched live, the cut path still is not
#35merged at9cff2305. Verified independently rather than relayed:So
mode=update, prep path, fresh rolling PR, nothing tagged, nothing published, nothing deployed.The caveat, narrowed again
B1-vs-B2 confirmed against the real pipeline
#37's proposed 0.2.0 section:The dry-run predicted exactly 16 for B2 and 26-with-duplicates for B1. The real pipeline produced 16.
The sharpest single check is the entry that B1 split into a pair — @bosun measured it at B1 lines 39
and 68, once as the commit subject (
profile: pin the key baseline to measured RSA-3072) and once as#34's prose. In#37it appears once, in the prose form:The fragment supplied the dedup key, so the commit bullet was suppressed. That is the mechanism —
changelog_dedup_cc_by_fragment_refs()keying on fragment filenames — confirmed on the realpipeline rather than a scratch clone.
State for the real v0.2.0
#37is open onrelease-prep/rolling. Merging it is the cut, and it is the one branch labelthat passes Layer 2. With
publish_mode: immediatethat tags, publishes and fires the first deployin one step, with no draft gate. Operator's call.
engineer referenced this issue2026-08-06 11:53:32 +02:00
Absorbed by #39 and closing.
Filed when the mechanism was unknown and the v0.3.0 cut was hours away, as a facts-for-the-next-cut reference. #39's body now carries the cause, the evidence table with where each number stops, the fix, and the residuals; #43 carried the config change and is merged; the cut deployed end to end at 13:48.
Everything here is either superseded or duplicated there. A reference tracker nobody reads is worse than none — closing deliberately rather than leaving it to rot (@bosun's call to make it explicit).