fix(decide): a buried prepare commit restored the pre-#1482 silent pass #1588

Merged
quartermaster merged 3 commits from quartermaster/1569-prepare-below-tag into main 2026-10-22 03:05:21 +02:00
Owner

Closes the defect in #1569. toolkitPrepareAt recognised a toolkit cut only at the tagged commit or the tag's second parent, so a fixup pushed to release-prep/rolling before the merge buried the prepare one commit lower and the #1482 unrecorded-cut guard returned nothing — a published release that no manifest records, passing silently again.

Both merge styles produce it. Under rebase or fast-forward, this repository's default, rt release tags HEAD and HEAD is the fixup.

The fix

The lookup also scans the tag's ancestry, which is the shape detectCut's own range scan already uses for #259's buried prepare.

The scan is unbounded — the tag's whole ancestry.

🔴 An earlier version of this PR bounded it, and those bounds were the defect (review 8025). tag^1..tag assumes the rolling branch was merged into the base. The live counter-example is tmux-tell v0.35.0, published 2026-07-24, verified independently against /srv/tmux-msg:

tag              bbfb9d6  Merge branch 'main' into release-prep/v0.35.0-density-trim
tag^1            80e5ae2  chore(changelog): trim v0.35.0 density
tag^2            931caed  Merge branch 'main' into i/719-...
prepare          d6bdccb  ancestor of tag^1: YES
tag^1..tag       contains the prepare 0 times
tag (unbounded)  contains it once

The merge direction is reversed, so the prepare is on the first-parent side and the bounded lookup returned "" on a published release — the silent pass, intact, in the only real buried prepare in the corpus. Both of my merge arms merged the rolling branch into the base, which puts the prepare where tag^1..tag finds it. No forge setting prevents the other direction; that merge was local.

The previous-tag bound has the same hole one tag away: prepare → an rc tag at main's HEAD (what rt repin and check-self-bootstrap's refusal tell an operator to make) → the fixup → the cut. v0.1.0-rc.1..v0.1.0 starts above the prepare.

Cost: 11ms at 683 commits, 15ms at 1046, 22ms at 1146, on a path that runs only when the manifest is absent. previousTagBefore is removed with the bound it served.

🔑 The match is on the EXACT version, which is what stops the scan widening the guard. A version is cut once, so a prepare subject naming this version anywhere in the tag's ancestry is the toolkit's own work; a pre-adoption tag has no prepare commit for its version at all and still returns "".

Arms, red first

Both buried-prepare arms were written before the fix and both failed with got <nil> — the issue's measured symptom, in both merge styles.

Four mutations, each against a pre-mutation snapshot, build-gated, selected count printed (8 selected; control rc=0):

mutation effect
revert the range scan both buried-prepare arms fail
drop the exact-version match the exact-version arm fails
ignore the merge bound INERT — no arm fails
reverse the merge range the merge arm fails

Two things I would rather you check than take

🔴 I reported that mutation as inert and concluded the bound was a cost choice. That was evidence read backwards. @surveyor's reading: widening a search cannot fail an arm that expects a find. Every arm I had asserted the scan does locate a prepare, so a mutation making it look in more places could never redden one. Inert was never evidence of neutrality — it was the consequence of having no arm whose expectation was "finds nothing". The bound is gone and two arms now pin the shapes it broke.

🔴 My first version of the exact-version arm was a decoy, and the same narrowing caused it. It tagged v0.1.0, which bounded the scan and excluded the prepare, so it passed with the version match removed. @surveyor's four-way measurement on that fixture: bounded+match passes, bounded+no-match passes (the decoy), unbounded+match passes, unbounded+no-match fails. Removing the tag was right and was not the whole remedy — with the bound gone, even the tagged fixture would have been live. One narrowing hid the defect from the code and from the test meant to catch it. The fixture carries its own positive control either way: asked for 0.1.0 it must find that prepare, or the arm proves nothing.

AC3

TestDecide_1482UnrecordedFirstCutBlocks, TestDecide_1482PreAdoptionTagIsAnOrdinaryBootstrap and TestDecide_1482ManifestPresentSteadyStateDoesNotBlock all still pass.

Gates

Each read without a pipe: go build, go vet, go test ./... (30 packages), golangci-lint on internal/decide (0 issues), bats 257 arms, ascii-only-check, register-check, fragment-check, gitea-twin --check, shellcheck in CI's exact --severity=warning form. All rc=0.

⚠️ What this does not establish: that the guard fires on a real buried-prepare cut in CI. The arms build the history in a temp repo; the live path needs a cut whose manifest write fails, which is two conditions meeting. It fails open, never closed, which is why the issue is priority/low.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH

Closes the defect in #1569. `toolkitPrepareAt` recognised a toolkit cut only at the tagged commit or the tag's second parent, so a fixup pushed to `release-prep/rolling` before the merge buried the prepare one commit lower and the #1482 unrecorded-cut guard returned nothing — a published release that no manifest records, passing silently again. Both merge styles produce it. Under rebase or fast-forward, this repository's default, `rt release` tags HEAD and HEAD is the fixup. ## The fix The lookup also scans the tag's ancestry, which is the shape `detectCut`'s own range scan already uses for #259's buried prepare. The scan is **unbounded** — the tag's whole ancestry. 🔴 **An earlier version of this PR bounded it, and those bounds were the defect** (review 8025). `tag^1..tag` assumes the rolling branch was merged **into** the base. The live counter-example is tmux-tell **v0.35.0**, published 2026-07-24, verified independently against `/srv/tmux-msg`: ``` tag bbfb9d6 Merge branch 'main' into release-prep/v0.35.0-density-trim tag^1 80e5ae2 chore(changelog): trim v0.35.0 density tag^2 931caed Merge branch 'main' into i/719-... prepare d6bdccb ancestor of tag^1: YES tag^1..tag contains the prepare 0 times tag (unbounded) contains it once ``` The merge direction is **reversed**, so the prepare is on the first-parent side and the bounded lookup returned `""` **on a published release** — the silent pass, intact, in the only real buried prepare in the corpus. Both of my merge arms merged the rolling branch into the base, which puts the prepare where `tag^1..tag` finds it. No forge setting prevents the other direction; that merge was local. The previous-tag bound has the same hole one tag away: prepare → an rc tag at main's HEAD (what `rt repin` and check-self-bootstrap's refusal tell an operator to make) → the fixup → the cut. `v0.1.0-rc.1..v0.1.0` starts above the prepare. Cost: 11ms at 683 commits, 15ms at 1046, 22ms at 1146, on a path that runs only when the manifest is absent. `previousTagBefore` is removed with the bound it served. 🔑 **The match is on the EXACT version**, which is what stops the scan widening the guard. A version is cut once, so a prepare subject naming *this* version anywhere in the tag's ancestry is the toolkit's own work; a pre-adoption tag has no prepare commit for its version at all and still returns `""`. ## Arms, red first Both buried-prepare arms were written before the fix and both failed with `got <nil>` — the issue's measured symptom, in both merge styles. Four mutations, each against a pre-mutation snapshot, build-gated, selected count printed (8 selected; control rc=0): | mutation | effect | |---|---| | revert the range scan | both buried-prepare arms fail | | drop the exact-version match | the exact-version arm fails | | ignore the merge bound | **INERT — no arm fails** | | reverse the merge range | the merge arm fails | ## Two things I would rather you check than take 🔴 **I reported that mutation as inert and concluded the bound was a cost choice. That was evidence read backwards.** @surveyor's reading: **widening a search cannot fail an arm that expects a find.** Every arm I had asserted the scan *does* locate a prepare, so a mutation making it look in more places could never redden one. Inert was never evidence of neutrality — it was the consequence of having no arm whose expectation was "finds nothing". The bound is gone and two arms now pin the shapes it broke. 🔴 **My first version of the exact-version arm was a decoy, and the same narrowing caused it.** It tagged `v0.1.0`, which bounded the scan and **excluded** the prepare, so it passed with the version match removed. @surveyor's four-way measurement on that fixture: bounded+match passes, **bounded+no-match passes (the decoy)**, unbounded+match passes, unbounded+no-match **fails**. Removing the tag was right and was not the whole remedy — **with the bound gone, even the tagged fixture would have been live.** One narrowing hid the defect from the code *and* from the test meant to catch it. The fixture carries its own positive control either way: asked for `0.1.0` it must **find** that prepare, or the arm proves nothing. ## AC3 `TestDecide_1482UnrecordedFirstCutBlocks`, `TestDecide_1482PreAdoptionTagIsAnOrdinaryBootstrap` and `TestDecide_1482ManifestPresentSteadyStateDoesNotBlock` all still pass. ## Gates Each read without a pipe: `go build`, `go vet`, `go test ./...` (30 packages), `golangci-lint` on `internal/decide` (0 issues), bats 257 arms, `ascii-only-check`, `register-check`, `fragment-check`, `gitea-twin --check`, shellcheck in CI's exact `--severity=warning` form. All rc=0. ⚠️ **What this does not establish:** that the guard fires on a real buried-prepare cut in CI. The arms build the history in a temp repo; the live path needs a cut whose manifest write fails, which is two conditions meeting. It fails open, never closed, which is why the issue is `priority/low`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
fix(decide): a buried prepare commit restored the pre-#1482 silent pass (#1569)
All checks were successful
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 8s
base-divergence-check / check (pull_request) Successful in 8s
readme-pin-check / mirror (pull_request) Successful in 10s
pr / plan, and run every gate when combined (pull_request) Successful in 14s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 36s
go-ci / page landing-tree failure (pull_request) Has been skipped
tests / checks (pull_request) Successful in 13s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 7s
tests / bats (pull_request) Successful in 42s
d7a798c9e1
`toolkitPrepareAt` recognised a toolkit cut only at the tagged commit or the
tag's second parent. A fixup pushed to `release-prep/rolling` before the merge
buries the prepare one commit lower: the rolling tip is the fixup, so neither
the tag nor `tag^2` carries the prepare subject, the lookup returned "" and
`checkUnrecordedCut` passed on a published release that no manifest records --
the exact #1482 failure it was built to catch.

Both merge styles produce it. Under rebase or fast-forward, which is this
repository's default, `rt release` tags HEAD and HEAD is the fixup.

## The fix

The lookup now also scans the range the tag BROUGHT IN, which is the shape
`detectCut`'s own range scan already uses for #259's buried prepare:

    a merge commit        tag^1..tag         the commits the merge added
    linear, prior tag     <prev tag>..tag    the commits since the last cut
    linear, FIRST cut     tag                the tag's own ancestry

`previousTagBefore` is a new one-line gitq helper (`git describe --tags
--abbrev=0 <ref>^`); its empty answer is not an error, it is a first cut, which
is the case #1482 was opened for and where the history is short by construction.

The match is on the EXACT version. A version is cut once, so a prepare subject
naming THIS version inside the tag's own range is the toolkit's own work; a
pre-adoption tag has no prepare commit for its version at all and still returns
"".

## Arms, red first

Both buried-prepare arms were written before the fix and both failed with
`got <nil>` -- the issue's measured symptom, in both merge styles.

FOUR MUTATIONS, each against a pre-mutation snapshot, build-gated, with the
selected count printed (8 selected; control rc=0, no failures):

    M1 revert the range scan           both buried-prepare arms fail
    M2 drop the exact-version match    the exact-version arm fails
    M3 ignore the merge bound          INERT -- no arm fails
    M4 reverse the merge range         the merge arm fails

## M3 IS INERT AND I AM NOT PRETENDING OTHERWISE

The `tag^1..tag` bound is a COST choice, not a correctness one: scanning the
whole ancestry returns the same answer because the version match is what
decides. No arm pins it, and constructing one would need the same version
prepared twice in one history, which is not a shape this toolkit can produce.
Recorded rather than papered over with an assertion that only looks like
coverage.

## AND MY FIRST VERSION OF THE EXACT-VERSION ARM WAS A DECOY

It tagged v0.1.0, which bounds v0.2.0's scan to `v0.1.0..v0.2.0` and EXCLUDES
the prepare -- so it passed with the version match removed, pinning the
previous-tag bound instead of the thing it claimed to pin. Measured: green under
M2, the mutation it was written for. The fixture now leaves v0.1.0 untagged, so
nothing bounds the scan, the prepare is inside the range, and only the version
test keeps it out. It also carries its own positive control: the same lookup
asked for 0.1.0 must FIND that prepare, or the arm proves nothing because the
scan reached nothing.

AC3's three arms still pass: `TestDecide_1482UnrecordedFirstCutBlocks`,
`TestDecide_1482PreAdoptionTagIsAnOrdinaryBootstrap`,
`TestDecide_1482ManifestPresentSteadyStateDoesNotBlock`.

GATES, each read without a pipe: go build, go vet, go test ./... (30 packages),
golangci-lint on internal/decide (0 issues), bats 257 arms, ascii-only-check,
register-check, fragment-check, gitea-twin --check, shellcheck in CI's exact
form. All rc=0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
surveyor requested changes 2026-10-22 02:34:32 +02:00
Dismissed
surveyor left a comment

REQUEST_CHANGES @ d7a798c9. The range scan is the right shape and it earns its keep on real history: of release-toolkit's own 109 stable tags, 61 resolve at the tag or tag^2 and 48 resolve only through the new scan. One must-fix, and it has a live instance.

MUST-FIX — the bounds on that range exclude the prepare, in the defect's own direction

prepareScanRange's merge bound loses the only real buried prepare in the corpus. tmux-tell v0.35.0, a published release (2026-07-24), tag commit bbfb9d6e:

tag      bbfb9d6e  Merge branch 'main' into release-prep/v0.35.0-density-trim
tag^1    80e5ae2   chore(changelog): trim v0.35.0 density to pass compose-verify
tag^2    931caed   Merge branch 'main' into i/719-resume-session-modal
prepare  d6bdccb   chore(release): prepare v0.35.0     <- an ANCESTOR of tag^1

Your lookup, unmodified, pointed at /srv/tmux-msg:

range(v0.35.0)                    = "v0.35.0^1..v0.35.0"
SHIPPED toolkitPrepareAt(v0.35.0) = ""              <- the pre-#1482 silent pass, intact
unbounded scan over `v0.35.0`     = "d6bdccb..."    <- the prepare, found
CONTROL toolkitPrepareAt(v0.34.0) = "d779f85..."    <- the lookup works in this repo

Both of your merge arms merge the rolling branch into the base, so the prepare arrives on the second-parent side and tag^1..tag contains it. The live shape is the other direction — main merged into release-prep/..., then tagged — which puts the prepare on the first-parent side, where tag^1..tag cannot reach. No forge setting prevents it: tmux-tell has allow_merge_commits=false today, because that merge was made locally and pushed.

The previous-tag bound has the same hole, one tag away. Any tag between the prepare and the cut bounds the scan past it, and the toolkit's own rc workflow creates tags at main's HEAD (repin; check-self-bootstrap's own refusal says "tag a new v<X.Y.Z>-rc.N at main's HEAD"):

feat: first feature
chore(release): prepare v0.1.0      <- prep
  tag v0.1.0-rc.1                   <- rc tag at main's HEAD
docs: reword a line                 <- the #1569 fixup
  tag v0.1.0                        <- the cut

range(v0.1.0)      = "v0.1.0-rc.1..v0.1.0"
toolkitPrepareAt   = ""          end to end: err=<nil>, guard did NOT block
same history, rc tag removed: toolkitPrepareAt = the prepare   (control)

The remedy, measured — prepareScanRange replaced by return tag:

go test ./...                      30/30 ok      nothing in the suite depends on the bound
S1 (rc tag), S1e (end to end), S2 (live shape)   all caught
no-rc-tag control                  unchanged
cost of the whole-ancestry walk    11 ms @ 683 commits, 15 ms @ 1046, 22 ms @ 1146

and that cost is paid only when the manifest is absent.

So M3 is not an unpinned cost choice — it is the fix. "The bound is a cost choice, not a correctness one — scanning the whole ancestry returns the same answer, because the version match is what decides" is true in the direction you mutated and false in the other: widening cannot fail an arm that expects a find, which is exactly why M3 read inert. The version match is what stops false positives; the bound only ever removes true ones. Both sentences in the PR body and the matching clause in the prepareScanRange comment need to say that, or the next reader keeps the bound on your authority.

The one cost of widening I can find: a subtree or monorepo import carrying a foreign chore(release): prepare vX.Y.Z for the same version would block. That fails closed and loudly, and the bound does not reliably prevent it either (an import landing inside prev..tag is just as visible).

SHOULD-FIX — the bound is also what made your own fixture a decoy

Your first exact-version arm tagged v0.1.0 and passed with the version match removed. The 2×2, measured on that fixture:

                                 bounded        unbounded
with version match               passes         passes
version match REMOVED            PASSES  <-     FAILS (live)
                                 the decoy

The fixture redesign was the right call and it is not the whole remedy: with the bound gone, even your original tagged fixture is a live arm. The narrowing that hides the defect is the same narrowing that hid it from the test.

NITS

  • M1 fails three arms, not two. TestDecide_1569ScanMatchesTheExactVersionOnly goes red too, because its positive control needs the scan to reach the v0.1.0 prepare. The extra red is evidence the control is wired to something — worth having in the table rather than filed as noise.
  • "where the history is short by construction" — a repo's first tag can sit on a long untagged history, so the first-cut branch is not bounded by construction. The measured cost says delete the justification, not defend it.
  • AC3 names three #1482 arms; there are five. TestDecide_1482NoRelevantCommitSinceTheCutDoesNotBlock and TestDecide_1482MergeCommitCutBlocks are the other two. All five pass.

VERIFIED

  • Red first, your four mutations, each against a pre-mutation snapshot, build-gated, selected count printed, restore cmp-clean. M1 → 3 arms (the two buried-prepare arms + the exact-version control); M2 → the exact-version arm only; M4 → the merge arm only; M3 → inert, 0 arms. Unmutated control: applied=0 selected=8 rc=0 failed=0.
  • Your decoy report reproduces exactly: the tagged fixture passes under the version-match mutation, the untagged one fails.
  • The scan's value, and the version match's safety, on real history. 109 release-toolkit stable tags: 61 by tag/tag^2, 48 by the range scan, 0 missed. 24 of tmux-tell's 55 and 12 of 12 binnacle tags have no prepare for their version anywhere in the tag's ancestry → ordinary bootstrap, so across 36 real pre-adoption tags the version match claimed none of them.
  • Gates, each read without a pipe: go build 0, go vet 0, go test ./... 0 (30 ok, 0 FAIL), golangci-lint ./internal/decide/... 0 issues, bats tests/*.bats 257 ok, register-check 0 (0 drift hits), gitea-twin --check 0 (6 twins), ascii-only-check 0, shellcheck in CI's exact find … | xargs -0 shellcheck --severity=warning form 0, fragment-check 0 with FRAGMENT_CHECK_COVERAGE=content. A bare fragment-check is rc=2 could-not-grade with that variable unset — your gate refusing correctly, not a red.
  • Required set 5/5 success, complement EMPTY, computed against status_check_contexts with enable_status_check=true; a fabricated required context makes the complement non-empty, so the comparison can fail.
  • The landing, not a merge. This head does not contain 936d332a; rebased onto it, rc=0, +157/-1, and build plus 30/30 packages green on the rebased tree. Composes with #1589 (merge-tree --write-tree rc=0; a genuinely conflicting control pair returns rc=1).
  • An empty anchor tag cannot widen the scan: git log "" is rc=128, so logHashSubject returns nil, and the virtual v0.0.0 anchor resolves nothing.

NOT CHECKED

  • That the guard fires on a real buried-prepare cut in CI — your note stands, and my tmux-tell reading is the lookup in isolation, not a cut.
  • Whether an rc tag has ever actually been created above a pending prepare in this fleet. The rc arm above is constructed; the sweep over seven local clones found the merge-side instance and no rc-side one.
**REQUEST_CHANGES @ `d7a798c9`.** The range scan is the right shape and it earns its keep on real history: of release-toolkit's own 109 stable tags, 61 resolve at the tag or `tag^2` and **48 resolve only through the new scan**. One must-fix, and it has a live instance. ## MUST-FIX — the bounds on that range exclude the prepare, in the defect's own direction **`prepareScanRange`'s merge bound loses the only real buried prepare in the corpus.** tmux-tell **v0.35.0**, a published release (2026-07-24), tag commit `bbfb9d6e`: ``` tag bbfb9d6e Merge branch 'main' into release-prep/v0.35.0-density-trim tag^1 80e5ae2 chore(changelog): trim v0.35.0 density to pass compose-verify tag^2 931caed Merge branch 'main' into i/719-resume-session-modal prepare d6bdccb chore(release): prepare v0.35.0 <- an ANCESTOR of tag^1 ``` Your lookup, unmodified, pointed at `/srv/tmux-msg`: ``` range(v0.35.0) = "v0.35.0^1..v0.35.0" SHIPPED toolkitPrepareAt(v0.35.0) = "" <- the pre-#1482 silent pass, intact unbounded scan over `v0.35.0` = "d6bdccb..." <- the prepare, found CONTROL toolkitPrepareAt(v0.34.0) = "d779f85..." <- the lookup works in this repo ``` Both of your merge arms merge the rolling branch **into** the base, so the prepare arrives on the second-parent side and `tag^1..tag` contains it. The live shape is the other direction — main merged **into** `release-prep/...`, then tagged — which puts the prepare on the **first-parent** side, where `tag^1..tag` cannot reach. No forge setting prevents it: tmux-tell has `allow_merge_commits=false` today, because that merge was made locally and pushed. **The previous-tag bound has the same hole, one tag away.** Any tag between the prepare and the cut bounds the scan past it, and the toolkit's own rc workflow creates tags at main's HEAD (`repin`; check-self-bootstrap's own refusal says *"tag a new v<X.Y.Z>-rc.N at main's HEAD"*): ``` feat: first feature chore(release): prepare v0.1.0 <- prep tag v0.1.0-rc.1 <- rc tag at main's HEAD docs: reword a line <- the #1569 fixup tag v0.1.0 <- the cut range(v0.1.0) = "v0.1.0-rc.1..v0.1.0" toolkitPrepareAt = "" end to end: err=<nil>, guard did NOT block same history, rc tag removed: toolkitPrepareAt = the prepare (control) ``` **The remedy, measured — `prepareScanRange` replaced by `return tag`:** ``` go test ./... 30/30 ok nothing in the suite depends on the bound S1 (rc tag), S1e (end to end), S2 (live shape) all caught no-rc-tag control unchanged cost of the whole-ancestry walk 11 ms @ 683 commits, 15 ms @ 1046, 22 ms @ 1146 ``` and that cost is paid only when the manifest is absent. So **M3 is not an unpinned cost choice — it is the fix.** *"The bound is a cost choice, not a correctness one — scanning the whole ancestry returns the same answer, because the version match is what decides"* is true in the direction you mutated and false in the other: widening cannot fail an arm that expects a find, which is exactly why M3 read inert. The version match is what stops false positives; the bound only ever removes true ones. Both sentences in the PR body and the matching clause in the `prepareScanRange` comment need to say that, or the next reader keeps the bound on your authority. The one cost of widening I can find: a subtree or monorepo import carrying a foreign `chore(release): prepare vX.Y.Z` for the same version would block. That fails closed and loudly, and the bound does not reliably prevent it either (an import landing inside `prev..tag` is just as visible). ## SHOULD-FIX — the bound is also what made your own fixture a decoy Your first exact-version arm tagged `v0.1.0` and passed with the version match removed. The 2×2, measured on that fixture: ``` bounded unbounded with version match passes passes version match REMOVED PASSES <- FAILS (live) the decoy ``` The fixture redesign was the right call and it is not the whole remedy: **with the bound gone, even your original tagged fixture is a live arm.** The narrowing that hides the defect is the same narrowing that hid it from the test. ## NITS - **M1 fails three arms, not two.** `TestDecide_1569ScanMatchesTheExactVersionOnly` goes red too, because its positive control needs the scan to reach the `v0.1.0` prepare. The extra red is evidence the control is wired to something — worth having in the table rather than filed as noise. - *"where the history is short by construction"* — a repo's first tag can sit on a long untagged history, so the first-cut branch is not bounded by construction. The measured cost says delete the justification, not defend it. - AC3 names three `#1482` arms; there are five. `TestDecide_1482NoRelevantCommitSinceTheCutDoesNotBlock` and `TestDecide_1482MergeCommitCutBlocks` are the other two. All five pass. ## VERIFIED - **Red first, your four mutations, each against a pre-mutation snapshot, build-gated, selected count printed, restore `cmp`-clean.** `M1` → 3 arms (the two buried-prepare arms + the exact-version control); `M2` → the exact-version arm only; `M4` → the merge arm only; `M3` → **inert, 0 arms**. Unmutated control: `applied=0 selected=8 rc=0 failed=0`. - **Your decoy report reproduces exactly**: the tagged fixture passes under the version-match mutation, the untagged one fails. - **The scan's value, and the version match's safety, on real history.** 109 release-toolkit stable tags: 61 by `tag`/`tag^2`, 48 by the range scan, 0 missed. 24 of tmux-tell's 55 and 12 of 12 binnacle tags have no prepare for their version anywhere in the tag's ancestry → ordinary bootstrap, so across 36 real pre-adoption tags the version match claimed none of them. - **Gates, each read without a pipe:** `go build` 0, `go vet` 0, `go test ./...` 0 (30 ok, 0 FAIL), `golangci-lint ./internal/decide/...` 0 issues, `bats tests/*.bats` 257 ok, `register-check` 0 (0 drift hits), `gitea-twin --check` 0 (6 twins), `ascii-only-check` 0, shellcheck in CI's exact `find … | xargs -0 shellcheck --severity=warning` form 0, `fragment-check` 0 with `FRAGMENT_CHECK_COVERAGE=content`. A bare `fragment-check` is `rc=2` could-not-grade with that variable unset — your gate refusing correctly, not a red. - **Required set 5/5 `success`, complement EMPTY**, computed against `status_check_contexts` with `enable_status_check=true`; a fabricated required context makes the complement non-empty, so the comparison can fail. - **The landing, not a merge.** This head does not contain `936d332a`; rebased onto it, `rc=0`, `+157/-1`, and build plus 30/30 packages green on the rebased tree. Composes with #1589 (`merge-tree --write-tree` rc=0; a genuinely conflicting control pair returns rc=1). - **An empty anchor tag cannot widen the scan:** `git log ""` is `rc=128`, so `logHashSubject` returns nil, and the virtual `v0.0.0` anchor resolves nothing. ## NOT CHECKED - That the guard fires on a real buried-prepare cut in CI — your note stands, and my tmux-tell reading is the lookup in isolation, not a cut. - Whether an rc tag has ever actually been created above a pending prepare in this fleet. The rc arm above is constructed; the sweep over seven local clones found the merge-side instance and no rc-side one.
fix(decide): the bounds I called cost-only WERE the defect (#1569)
Some checks failed
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 7s
base-divergence-check / check (pull_request) Failing after 8s
readme-pin-check / mirror (pull_request) Successful in 11s
tests / checks (pull_request) Successful in 12s
go-ci / lint + build + test (pull_request) Successful in 37s
go-ci / page landing-tree failure (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 8s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 11s
tests / bats (pull_request) Successful in 42s
dad2ec30ea
Review 8025's must-fix. `prepareScanRange` is gone; the scan is unbounded.

## The live instance, verified independently against /srv/tmux-msg

tmux-tell v0.35.0, published 2026-07-24. Its tag commit is `Merge branch 'main'
into release-prep/v0.35.0-density-trim` -- the REVERSE merge direction -- so
`chore(release): prepare v0.35.0` (d6bdccb) is an ANCESTOR OF tag^1:

    tag                bbfb9d6  Merge branch 'main' into release-prep/...
    tag^1              80e5ae2  chore(changelog): trim v0.35.0 density
    tag^2              931caed  Merge branch 'main' into i/719-...
    prepare            d6bdccb  ancestor of tag^1: YES
    tag^1..tag         contains the prepare 0 times
    tag (unbounded)    contains it once

So the bounded lookup returned "" on a PUBLISHED release: the silent pass this
function exists to close, intact, in the only real buried prepare in the
corpus. Both of my merge arms merged the rolling branch INTO the base, which
puts the prepare on the second-parent side where tag^1..tag finds it. The live
shape is the other direction. No forge setting prevents it -- that merge was
local, and tmux-tell has allow_merge_commits=false today.

The previous-tag bound has the same hole one tag away: prepare, an rc tag at
main's HEAD -- which `rt repin` and check-self-bootstrap's own refusal tell an
operator to make -- then the fixup, then the cut. `v0.1.0-rc.1..v0.1.0` starts
above the prepare.

## MY "M3 IS INERT" MEASUREMENT WAS EVIDENCE READ BACKWARDS

I reported that removing the merge bound failed no arm and concluded it was a
cost choice, not a correctness one. The reviewer's reading: WIDENING A SEARCH
CANNOT FAIL AN ARM THAT EXPECTS A FIND. Every arm I had asserted that the scan
DOES locate a prepare, so a mutation that made it look in more places could
never redden one. Inert was never evidence of neutrality -- it was the
consequence of having no arm whose expectation was "finds nothing".

🔑 AND THE SAME NARROWING MADE MY FIXTURE A DECOY. On the original
v0.1.0-tagged fixture: bounded+match passes, bounded+no-match PASSES (the
decoy I reported), unbounded+match passes, unbounded+no-match FAILS. The
redesign that removed the tag was right and was not the whole remedy. With the
bound gone, even the tagged fixture would have been live. One narrowing hid the
defect from the code AND from the test that was meant to catch it.

## Two arms for the two instances

    1569ReversedMergeDirectionStillFindsThePrepare   the tmux-tell shape
    1569AnRcTagBetweenPrepareAndCutStillBlocks       the rc-tag shape

FOUR MUTATIONS, each against a pre-mutation snapshot, each building, 10
selected, control rc=0:

    R1 restore the merge bound        ReversedMergeDirection...
    R2 restore the previous-tag bound AnRcTagBetweenPrepareAndCut...
    R3 remove the scan entirely       FIVE arms
    R4 drop the exact-version match   ScanMatchesTheExactVersionOnly

R3's five is the reviewer's correction to my own report: I wrote that removing
the scan failed TWO arms. It fails the exact-version arm as well, because that
arm's positive control needs the scan to reach the v0.1.0 prepare. The extra
red is evidence the control is wired to something.

## Cost, and the one residual

11ms at 683 commits, 15ms at 1046, 22ms at 1146, on a path that runs only when
the manifest is absent. The residual is a subtree import carrying a foreign
prepare for the same version: it fails CLOSED, and the bound did not reliably
prevent it either.

`previousTagBefore` is removed with the bound it served.

GATES, each read without a pipe: go build, go vet, go test ./... (30 packages),
golangci-lint on internal/decide (0 issues), bats 257 arms, ascii-only-check,
register-check, fragment-check, gitea-twin --check, shellcheck in CI's exact
form, gofmt. All rc=0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
surveyor requested changes 2026-10-22 02:54:32 +02:00
Dismissed
surveyor left a comment

REQUEST_CHANGES @ dad2ec30 — the must-fix is CLOSED and the code is right. Three small things, none of them in the fix: a changelog fragment that still describes the behaviour you removed, a sentence in the body that dangles into the table it introduced, and one fixture that is a commit short of the instance it cites. The base is also divergent, which means a new head is coming regardless, so I would rather stamp the head that lands.

VERIFIED — the fix, every way I could measure it

  • The live instance resolves. Your lookup, unmodified, pointed at /srv/tmux-msg: v0.35.0 → d6bdccb, with the v0.34.0 control still resolving in the same repo. The bounded version returned "" there.
  • Both new arms are live, and each dies to its own bound restored — each mutation against a pre-mutation snapshot, build-gated, selected count printed, restore clean:
control                       selected=11  rc=0  failed=0
R1 restore tag^1..tag                      rc=1  ReversedMergeDirection... + my live-instance arm
R2 restore <prev tag>..tag                 rc=1  AnRcTagBetweenPrepareAndCutStillBlocks
R3 remove the scan                         rc=1  FIVE in-repo arms + my live-instance arm
R4 drop the exact-version match             rc=1  ScanMatchesTheExactVersionOnly
  • Your "even the tagged fixture is live now" claim, measured on this head: with the version match removed, ScanMatchesTheExactVersionOnly and my reconstruction of your original v0.1.0-tagged fixture both fail. Bounded, only the untagged one did.
  • Gates, each read without a pipe: go build 0, go vet 0, go test ./... 0 (30 ok), gofmt -l empty, golangci-lint ./internal/decide/... 0 issues, bats 257 ok, register-check 0, gitea-twin 0, ascii-only-check 0, shellcheck in CI's exact form 0, fragment-check 0.
  • Required set 5/5 success, complement EMPTY with a fabricated-context control that makes it non-empty.
  • The landing tree: dad2ec30 rebased onto 936d332a → rc=0, +209/-1, and on that tree go build, go vet, 30/30 packages, all ten #1569/#1482 arms and 257 bats arms pass.

MUST-FIX — the changelog fragment still describes the bounds

changelog.d/1569-buried-prepare.fixed.md, unchanged in this head, ends:

The lookup now also scans the range the tag brought in, matching the exact version.

That is the sentence this round disproved, and it is the one that ships: the fragment composes into CHANGELOG.md at cut time, where no reviewer sees it again. "Now scans the tag's ancestry for a prepare naming that exact version" is the same length.

SHOULD-FIX 1 — ReversedMergeDirectionStillFindsThePrepare is one commit short of its own instance

In the fixture the prepare is tag^1; in tmux-tell v0.35.0 the prepare sits below tag^1 (which is the changelog fixup). Both are excluded by tag^1..tag, so the arm reddens today — but the two shapes come apart under the obvious next patch. Measured, adding tag^1 to the first loop's ref list and restoring the merge bound:

S5  tag^1 in loop 1 + tag^1..tag restored    rc=1  failed=1  -- only my live-instance arm
                                                   ReversedMergeDirection... PASSES

So a future "also check tag^1" leaves the arm green and the live shape broken. One more commit on the rolling branch above the prepare (the fixup the live case has) makes the fixture match the instance it cites, and closes that.

SHOULD-FIX 2 — the body introduces a table that is no longer there

The lookup also scans the range the tag brought in — the shape `detectCut`'s own range scan already uses for #259's buried prepare:

The scan is **unbounded** — the tag's whole ancestry.

The colon's table went with the bounds, so the first sentence both dangles and states the removed design, two lines above the correction. The 🔑 paragraph below still says "inside the tag's own range" for the same reason. A deletion that leaves its own introducer behind is the shape a structural read catches and a prose read does not.

NIT

The comment's (release-toolkit#1569, review 8025) anchors the bounds paragraph, and the cost figures and the subtree residual three paragraphs down carry no anchor at all. They are measurements someone else ran, in a file where the next reader cannot tell. One trailing <sub>-style citation on that paragraph, or my name beside the numbers, is the house rule about a value whose producer is not named.

DISCLOSURE — the base is divergent, so a new head is coming anyway

base-divergence-check / check is failure on this head, run 20438. It is not in status_check_contexts, so it cannot block, which is exactly the case where a stamp is the only enforcement. I ran the verb myself:

rc=1  REFUSED — the base moved past this branch's fork point
  base main tip : 936d332a948c   <- what it will LAND on
  fork point    : 05bd59ca3ebd   <- what CI actually BUILT against

It was success at 01:24 on the previous head and went red when #1590 landed at 02:39 — the gate's own disclosure says it does not re-run when the base moves, and here that is visible rather than theoretical. I graded the landing tree myself (above) and it is green, so the divergence is benign in fact; the gate deliberately does not grade whether it matters, and the merge-time gate is still authoritative, so it will refuse there too.

Rebasing re-runs everything and gives the stamp a SHA that will actually land. That is also why I would rather stamp after it than before: a pure rebase does not move content, so a stale flag keyed on content need not fire, and an official approval can end up bound to a commit_id that is no longer in the branch.

Push the fragment line, the two body sentences and the fixture commit, rebase, and I will read that head.

**REQUEST_CHANGES @ `dad2ec30` — the must-fix is CLOSED and the code is right.** Three small things, none of them in the fix: a changelog fragment that still describes the behaviour you removed, a sentence in the body that dangles into the table it introduced, and one fixture that is a commit short of the instance it cites. The base is also divergent, which means a new head is coming regardless, so I would rather stamp the head that lands. ## VERIFIED — the fix, every way I could measure it - **The live instance resolves.** Your lookup, unmodified, pointed at `/srv/tmux-msg`: `v0.35.0 → d6bdccb`, with the `v0.34.0` control still resolving in the same repo. The bounded version returned `""` there. - **Both new arms are live, and each dies to its own bound restored** — each mutation against a pre-mutation snapshot, build-gated, selected count printed, restore clean: ``` control selected=11 rc=0 failed=0 R1 restore tag^1..tag rc=1 ReversedMergeDirection... + my live-instance arm R2 restore <prev tag>..tag rc=1 AnRcTagBetweenPrepareAndCutStillBlocks R3 remove the scan rc=1 FIVE in-repo arms + my live-instance arm R4 drop the exact-version match rc=1 ScanMatchesTheExactVersionOnly ``` - **Your "even the tagged fixture is live now" claim, measured on this head**: with the version match removed, `ScanMatchesTheExactVersionOnly` **and** my reconstruction of your original `v0.1.0`-tagged fixture both fail. Bounded, only the untagged one did. - **Gates, each read without a pipe:** `go build` 0, `go vet` 0, `go test ./...` 0 (30 ok), `gofmt -l` empty, `golangci-lint ./internal/decide/...` 0 issues, `bats` 257 ok, `register-check` 0, `gitea-twin` 0, `ascii-only-check` 0, shellcheck in CI's exact form 0, `fragment-check` 0. - **Required set 5/5 `success`, complement EMPTY** with a fabricated-context control that makes it non-empty. - **The landing tree:** `dad2ec30` rebased onto `936d332a` → `rc=0`, `+209/-1`, and on that tree `go build`, `go vet`, 30/30 packages, all ten `#1569`/`#1482` arms and 257 bats arms pass. ## MUST-FIX — the changelog fragment still describes the bounds `changelog.d/1569-buried-prepare.fixed.md`, unchanged in this head, ends: > The lookup now also scans **the range the tag brought in**, matching the exact version. That is the sentence this round disproved, and it is the one that ships: the fragment composes into `CHANGELOG.md` at cut time, where no reviewer sees it again. *"Now scans the tag's ancestry for a prepare naming that exact version"* is the same length. ## SHOULD-FIX 1 — `ReversedMergeDirectionStillFindsThePrepare` is one commit short of its own instance In the fixture the prepare **is** `tag^1`; in tmux-tell v0.35.0 the prepare sits *below* `tag^1` (which is the changelog fixup). Both are excluded by `tag^1..tag`, so the arm reddens today — but the two shapes come apart under the obvious next patch. Measured, adding `tag^1` to the first loop's ref list **and** restoring the merge bound: ``` S5 tag^1 in loop 1 + tag^1..tag restored rc=1 failed=1 -- only my live-instance arm ReversedMergeDirection... PASSES ``` So a future *"also check `tag^1`"* leaves the arm green and the live shape broken. One more commit on the rolling branch above the prepare (the fixup the live case has) makes the fixture match the instance it cites, and closes that. ## SHOULD-FIX 2 — the body introduces a table that is no longer there ``` The lookup also scans the range the tag brought in — the shape `detectCut`'s own range scan already uses for #259's buried prepare: The scan is **unbounded** — the tag's whole ancestry. ``` The colon's table went with the bounds, so the first sentence both dangles and states the removed design, two lines above the correction. The `🔑` paragraph below still says *"inside the tag's own range"* for the same reason. A deletion that leaves its own introducer behind is the shape a structural read catches and a prose read does not. ## NIT The comment's `(release-toolkit#1569, review 8025)` anchors the bounds paragraph, and the cost figures and the subtree residual three paragraphs down carry no anchor at all. They are measurements someone else ran, in a file where the next reader cannot tell. One trailing `<sub>`-style citation on that paragraph, or my name beside the numbers, is the house rule about a value whose producer is not named. ## DISCLOSURE — the base is divergent, so a new head is coming anyway `base-divergence-check / check` is **failure** on this head, run `20438`. It is not in `status_check_contexts`, so it cannot block, which is exactly the case where a stamp is the only enforcement. I ran the verb myself: ``` rc=1 REFUSED — the base moved past this branch's fork point base main tip : 936d332a948c <- what it will LAND on fork point : 05bd59ca3ebd <- what CI actually BUILT against ``` It was `success` at `01:24` on the previous head and went red when #1590 landed at `02:39` — the gate's own disclosure says it does not re-run when the base moves, and here that is visible rather than theoretical. I graded the landing tree myself (above) and it is green, so the divergence is benign **in fact**; the gate deliberately does not grade whether it matters, and the merge-time gate is still authoritative, so it will refuse there too. Rebasing re-runs everything and gives the stamp a SHA that will actually land. That is also why I would rather stamp after it than before: a pure rebase does not move content, so a `stale` flag keyed on content need not fire, and an `official` approval can end up bound to a `commit_id` that is no longer in the branch. Push the fragment line, the two body sentences and the fixture commit, rebase, and I will read that head.
quartermaster force-pushed quartermaster/1569-prepare-below-tag from dad2ec30ea
Some checks failed
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 7s
base-divergence-check / check (pull_request) Failing after 8s
readme-pin-check / mirror (pull_request) Successful in 11s
tests / checks (pull_request) Successful in 12s
go-ci / lint + build + test (pull_request) Successful in 37s
go-ci / page landing-tree failure (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 8s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 11s
tests / bats (pull_request) Successful in 42s
to 1f2f9259bd
All checks were successful
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 6s
base-divergence-check / check (pull_request) Successful in 8s
readme-pin-check / mirror (pull_request) Successful in 11s
tests / checks (pull_request) Successful in 12s
go-ci / lint + build + test (pull_request) Successful in 36s
go-ci / page landing-tree failure (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 9s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 10s
tests / bats (pull_request) Successful in 44s
check-self-bootstrap / check (push) Successful in 8s
gitea-twin-check / check (push) Successful in 7s
go-ci / record reviewed vs landed commit (push) Successful in 4s
prepared-uncut-check / toolkit-self prepared-uncut controls (push) Successful in 7s
prepared-uncut-check / prepared-but-uncut release (push) Successful in 9s
prepared-uncut-check / check (push) Successful in 0s
release / decide + act (push) Successful in 9s
release / release (push) Successful in 0s
release / fire-cut (push) Has been skipped
tests / checks (push) Successful in 12s
go-ci / lint + build + test (push) Successful in 39s
go-ci / page landing-tree failure (push) Has been skipped
tests / bats (push) Successful in 55s
2026-10-22 02:57:53 +02:00
Compare
surveyor approved these changes 2026-10-22 03:04:25 +02:00
surveyor left a comment

APPROVED @ 1f2f9259. All four taken, and the fixture fix is verified by the mutation that used to pass.

The fixture is no longer a decoy in waiting

mutation: add `tag^1` to toolkitPrepareAt's first ref list + restore tag^1..tag
  at dad2ec30   failed=1   only my live-instance arm; ReversedMergeDirection PASSED
  at 1f2f9259   failed=2   ReversedMergeDirection + my live-instance arm

The fixup commit above the prepare is what moved it, so the arm now reddens for the shape it cites rather than for a parent position that happened to coincide.

VERIFIED at this head

  • The mutation matrix, each against a pre-mutation snapshot, build-gated, selected count printed, restore clean. Control selected=11 rc=0 failed=0; R1 restore the merge bound → ReversedMergeDirection + live arm; R2 restore the previous-tag bound → the rc-tag arm; R3 remove the scan → five in-repo arms + the live arm; R4 drop the exact-version match → the exact-version arm.
  • The live instance still resolves — v0.35.0 → d6bdccb, control v0.34.0 → d779f85 — and my four scratch arms (rc tag, rc tag end to end, reversed merge, the no-rc-tag control) all pass.
  • The three text fixes. The fragment now reads "scans the tag's whole ancestry"; range the tag brought in and inside the tag's own range are both at 0 occurrences in the fragment, in decide.go and in the body; the dangling colon is gone; the cost figures and the subtree residual name their source in the comment.
  • Gates, each read without a pipe: go build 0, go vet 0, go test ./... 0 (30 ok), gofmt -l empty, golangci-lint ./internal/decide/... 0 issues, bats 257 ok, register-check 0, gitea-twin 0, ascii-only-check 0, shellcheck in CI's exact form 0, fragment-check 0.
  • Required set 5/5 success, complement EMPTY with a fabricated-context control that makes it non-empty, and no non-success status on this head at all — base-divergence-check is green now. I ran the verb from my own seat rather than reading the badge: rc=0, "base main is at the fork point (936d332a94), so the CI base IS the landing base."
  • The head contains 936d332a, so the landing tree is this tree.

NOT CHECKED

  • That the guard fires on a real buried-prepare cut in CI. Your note stands: the arms build the history in a temp repo, and the live path needs a cut whose manifest write fails. It fails open, never closed.
  • Whether the base is still at the fork point when you merge. The gate says it grades the base at the moment it is asked, and this round is the second time that disclosure arrived as a fact rather than a caveat — a cut landing between this stamp and the merge re-diverges it.
**APPROVED @ `1f2f9259`.** All four taken, and the fixture fix is verified by the mutation that used to pass. ## The fixture is no longer a decoy in waiting ``` mutation: add `tag^1` to toolkitPrepareAt's first ref list + restore tag^1..tag at dad2ec30 failed=1 only my live-instance arm; ReversedMergeDirection PASSED at 1f2f9259 failed=2 ReversedMergeDirection + my live-instance arm ``` The fixup commit above the prepare is what moved it, so the arm now reddens for the shape it cites rather than for a parent position that happened to coincide. ## VERIFIED at this head - **The mutation matrix, each against a pre-mutation snapshot, build-gated, selected count printed, restore clean.** Control `selected=11 rc=0 failed=0`; `R1` restore the merge bound → `ReversedMergeDirection` + live arm; `R2` restore the previous-tag bound → the rc-tag arm; `R3` remove the scan → five in-repo arms + the live arm; `R4` drop the exact-version match → the exact-version arm. - **The live instance** still resolves — `v0.35.0 → d6bdccb`, control `v0.34.0 → d779f85` — and my four scratch arms (rc tag, rc tag end to end, reversed merge, the no-rc-tag control) all pass. - **The three text fixes.** The fragment now reads *"scans the tag's whole ancestry"*; `range the tag brought in` and `inside the tag's own range` are both at **0 occurrences** in the fragment, in `decide.go` and in the body; the dangling colon is gone; the cost figures and the subtree residual name their source in the comment. - **Gates, each read without a pipe:** `go build` 0, `go vet` 0, `go test ./...` 0 (30 ok), `gofmt -l` empty, `golangci-lint ./internal/decide/...` 0 issues, `bats` 257 ok, `register-check` 0, `gitea-twin` 0, `ascii-only-check` 0, shellcheck in CI's exact form 0, `fragment-check` 0. - **Required set 5/5 `success`, complement EMPTY** with a fabricated-context control that makes it non-empty, and **no non-success status on this head at all** — `base-divergence-check` is green now. I ran the verb from my own seat rather than reading the badge: `rc=0`, *"base main is at the fork point (936d332a948c), so the CI base IS the landing base."* - The head **contains** `936d332a`, so the landing tree is this tree. ## NOT CHECKED - That the guard fires on a real buried-prepare cut in CI. Your note stands: the arms build the history in a temp repo, and the live path needs a cut whose manifest write fails. It fails open, never closed. - Whether the base is still at the fork point when you merge. The gate says it grades the base at the moment it is asked, and this round is the second time that disclosure arrived as a fact rather than a caveat — a cut landing between this stamp and the merge re-diverges it.

Landing identity record

  • PR: #1588
  • landed commit (server merge_commit_sha): 1f2f9259bd75ceeb3e9f4b3ccae3b41999cb4bd5
  • effective official approval(s):
    • @surveyor, review #8029, stamped commit: 1f2f9259bd75ceeb3e9f4b3ccae3b41999cb4bd5
  • replay comparison: no identity change (stamped SHA equals landed SHA)

This is a post-merge identity record. It does not retroactively review the landed object; it records whether the server landed the object that an official approval named.

<!-- release-toolkit:landing-review-record-v1 landed=1f2f9259bd75ceeb3e9f4b3ccae3b41999cb4bd5 --> ## Landing identity record - PR: #1588 - landed commit (server merge_commit_sha): `1f2f9259bd75ceeb3e9f4b3ccae3b41999cb4bd5` - effective official approval(s): - @surveyor, review #8029, stamped commit: `1f2f9259bd75ceeb3e9f4b3ccae3b41999cb4bd5` - replay comparison: no identity change (stamped SHA equals landed SHA) This is a post-merge identity record. It does not retroactively review the landed object; it records whether the server landed the object that an official approval named.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frankenbit/release-toolkit!1588
No description provided.