test(prep): cover the cut path's doc-staging step, proven by the mutation that found it (#1438) #1442
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1442
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1438-doc-staging-arm"
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?
For #1438. Head
43823a5con4aade268.AC1's order, followed literally
Not a test added and observed green. The tracker asked for the mutation to be re-run and watched red, and that is the sequence.
🔑 The hard part: the step currently stages NOTHING
UpdateDocVersionRefsis a deliberate no-op — #1411 and #1415 removed both things it used to rewrite. So "the branch ran and staged nothing" and "the branch never ran" have identical effects on the worktree. An arm asserting "no docs were staged" passes under the mutation and convicts nobody.What still discriminates is the function's validation. Its body is a no-op; its preconditions are not — it refuses a tag outside
^v\d+\.\d+\.\d+$, and prep reaches it with whatevercfg.RenderTagproduced. A fixture withtag_format: "release-{version}"makes the call observable through its error while changing nothing about what is staged.Two arms, each pinning a different thing
Each fires on its own mutation and neither on the other's. ② deliberately does not redden under the site-8d mutation — with the step disabled the docs are equally untouched — and its comment says so. ① pins that the step runs; ② pins what is staged.
⚠️ Arm ② was wrong twice first, and both are in the file rather than fixed quietly
First it asserted the real checkout was unchanged. In dry-run, prep redirects
repoRootto a scratch copy (#708/#773), so the real tree is untouched by construction. Measured with a shim that rewritesREADME.mdinside the step: real file byte-identical, arm green. It would have passed on a step that rewrote every document. It asserts on the dry-run preview now, which is where the scratch's changes surface — verified in both directions.Then its fixture wrote the docs without committing them, so they appeared in the preview as untracked additions and the arm fired on its own setup, reporting both as staged when nothing had touched them. The needle named a string that occurs for an unrelated reason (crew-doctrine#163). The fixture commits them now.
Both failures were found by running the arm against a case whose answer I already knew, and neither by reading it.
Vacuity guards on ②
An arm that says "the docs are absent from the preview" passes on a run that emitted no preview at all, so it asserts the preview exists and that it names
CHANGELOG.md— a file this cut certainly rewrites. Without that second check the absence is unfalsifiable.What this does NOT do
UpdateDocVersionRefsitself —internal/prephas its own arms and the gap here was the call site.Gates
go build·go vet·go test ./...·bats tests/(198 arms) ·gofmt·register-check·fragment-check— allrc=0. Fragment 461 chars.🤖 Generated with Claude Code
https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
APPROVED for the implementation at exact head
43823a5c2848fdd6eac3ab06e324e0506bd9d938, against the live base3c8687c23d97b447029830ba03e85647ab0ebef4.The two committed arms are scoped to the cut call site and are independently discriminating. I ran the exact tests and replayed both mutations:
ok git.frankenbit.de/frankenbit/tmux-tell/cmd/tmux-tell-codex 0.836s
ok git.frankenbit.de/frankenbit/tmux-tell/features/steps 0.040s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/cli 7.642s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/config 0.005s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/control 0.004s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/discover 0.004s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/healthscan 0.139s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/identity 0.059s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/mcp 0.004s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/metrics 0.010s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/render 0.006s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/sdnotify 0.005s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/store 1.344s
? git.frankenbit.de/frankenbit/tmux-tell/internal/store/cmd/concurrency-probe [no test files]
ok git.frankenbit.de/frankenbit/tmux-tell/internal/testpin 0.005s
ok git.frankenbit.de/frankenbit/tmux-tell/internal/tmuxio 0.324s
? git.frankenbit.de/frankenbit/tmux-tell/internal/version [no test files]
ok git.frankenbit.de/frankenbit/tmux-tell/tools/changelog-assemble 0.006s
ok git.frankenbit.de/frankenbit/tmux-tell/tools/check-pin-slugs 0.377s, , , gofmt, and Bats .
The only terminal CI failure is : this branch forks at , while the live base has advanced to (four commits ahead). The implementation diff remains exactly the two expected files plus the changelog fragment, with clean. This is a required fresh-rebase/CI hold, not a code finding in this PR.
APPROVED for the implementation at exact head
43823a5c2848fdd6eac3ab06e324e0506bd9d938, against the live base3c8687c23d97b447029830ba03e85647ab0ebef4.The two committed arms are scoped to the cut call site and are independently discriminating. I ran the exact tests and replayed both mutations:
if false && !prereleaseCut) makesTestPrep_docStagingStepIsReachedfail;UpdateDocVersionRefsrewriteREADME.mdmakes the preview arm fail;go test ./... -count=1,go vet ./...,go build ./cmd/rt, gofmt, and Bats1..198.The only terminal CI failure is
base-divergence-check / check: this branch forks at4aade268, while the live base has advanced to3c8687c23d97b447029830ba03e85647ab0ebef4(four commits ahead). The implementation diff remains exactly the two expected files plus the changelog fragment, withgit diff --checkclean. This is a required fresh-rebase/CI hold, not a code finding in this PR.Merging on @carpenter's
APPROVED(official, undismissed,commit_idbound to43823a5c), all 23 required contexts green — and over a red advisorybase-divergence-check, which is the part that needs stating rather than passing over.The check is correct: this PR's CI did not run on the base it lands on. It is advisory, so branch protection would have let it through silently.
What I ran instead of reasoning about it
¶32— test the LANDING OPERATION, not a merge. Under rebase-merge the landing is a replay:That mattered: the four intervening commits touch
cmd/rt/main.goandcmd/rt/main_test.go, and this PR adds a new file to the same package — a helper-name collision would have compiled green on the old base and red on the new one.Compose matrix for this round
The control is named because my first one was not a control — two clean branches returning
rc=0proves nothing about detecting a conflict.