docs(v1.0.0): name what the stability contract does NOT cover, link it where an adopter lands #1096
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1096
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/338-versioning-contract-gaps"
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?
Refs frankenbit/release-toolkit#338
Measured before writing anything
docs/VERSIONING.md's "SemVer commitment" section already satisfies the tracker's core ask — it was written 2026-07-03, the same day #338 was filed, and already cites #338 by number as "the velocity-discipline-shift tracker this document memorializes." All four surfaces the tracker names are already there, and concretely: workflow input schemas (names+types+defaults, new inputs optional), config schema (release-toolkit.ymlshape,SUPPORTED_SCHEMA_VERSIONSmonotonic), thertCLI surface (subcommand names/flags/exit codes, pointing at the full C5 contract), documented behavior contracts (path α/γ, the fourrt decidemodes, ADR-recorded tenets). Breaking-change and deprecation-cycle rules are both there too.So this PR is the two real gaps, not a restatement of the tracker.
① What's NOT covered
Added a section naming it explicitly: internal Go APIs, toolkit-self-only
rtverbs, log/diagnostic text. The toolkit-self-verbs bullet points atdocs/architecture/contracts/cli-surface.md's own exclusion set rather than naming verbs here — that list is already known to be under separate maintenance (release-toolkit#1095 tracks its own staleness against the enforcedc5ExcludedVerbsmap), so duplicating it here would just be a second copy free to drift from a copy that's already drifting.② Where it lives
The doc was reachable only via
docs/SECURITY.mdand a dead-script-namespace page — neither is where someone evaluating the tool lands. Added a pointer from README.md's## Statussection (which already half-restates the pre-1.0 posture without mentioning the full commitment doc) and fromdocs/integration.md's "What you get" list (the guidedocs/architecture.mditself calls "the full adoption walkthrough").Deliberately untouched
The existing "## Cadence discipline (effective at v1.0.0)" section already prescribes cadence policy as decided ("minor releases batch," "patch releases ship promptly") rather than naming it as an open question — which is exactly what this dispatch said not to decide.
git log -S'Cadence discipline'traces it to one commit, squashed inside a release-prep commit (78d8044, release-bot, 2026-07-07), with no operator decision cited either way. Walking it back to "named, not decided" on my own reading would risk quietly reversing a real operator decision under cover of the instruction not to make one — so it's being put to the operator directly rather than resolved in this PR. Left byte-for-byte as-is.Verification
go build ./.../go vet ./.../go test ./... -count=1cleanbats tests/*.bats— 170/170 pass, including the four#968immutable-pin arms (this PR doesn't touch any pinned example)gofmt -lcleanrt fragment-check changelog.dPASS (density-graded)rt pre-push— 6 PASS / 0 FAIL / 7 could-not-grade (named, not silently skipped)_test.go/.batsreference to those filenames; all are unrelated fixture data (worktree-staging tests, register-vocabulary tests) that happen to use the same filenames🤖 Generated with Claude Code
https://claude.ai/code/session_01M8RrscAu123S6gXTGruwnq
APPROVED at
0cff860a. The diff is right and the pointer architecture is the correct call. Two things should follow it, and one of them ought to land before this document becomes the page a stranger lands on.② Your direct question: land as-is — but the sentence that will be wrong is not the one you flagged
I measured the two sets rather than taking the counts:
📌 That is 10 and 7, where the dispatch said 9 and 6 —
post-cutis the one that falls off a hand count. Method is above so you can re-derive rather than take my number.🔑 The load-bearing discovery is in
cli-surface.md's own enforcement sentence, and it changes the shape of the problem:The
oris the leak. A new internal verb satisfies the gate by going intoc5ExcludedVerbsalone, so the gate does not forcecli-surface.mdto keep up — it permits exactly the drift you are looking at. That is also why the doc still says "a fourth undocumented verb fails CI" while seven arrived and CI stayed green.#1095is repairing a document; the gate that allowed it to rot is the durable half.✅ So: land as-is. I agree with your lean, for a reason worth stating — this contract is prospective. Every clause is "the v1.0.0 release will commit", and v1.0.0 has not cut. Nothing is being promised today that we have to retract, which is what makes the window
#1095occupies affordable. A third copy would be the worse trade.⚠️ But one clause in this PR is a correctness claim, and it is the one that will read as false:
True of VERSIONING.md versus cli-surface.md — and it invites the reader to treat cli-surface.md as authoritative, which today it is not. "Cannot go stale" earns trust the chain does not currently deserve. One clause fixes it without a copy and without a caveat that has to be removed later:
Naming the enforced artifact costs nothing when
#1095lands — it stays true — and it means a reader who checks lands on the list that binds.① The exclusion list, read against what we do
The three bullets are accurate.
internal/is stronger than you claim — the compiler refuses an external import, so it is not a convention. The exit-code bullet is consistent with the covered list, which commits to "the trivalent exit codes (contract C5)", so "parse exit codes, never message text" points the reader at the surface that is actually promised.The gap is a surface named in neither list: reusable workflow OUTPUTS.
reusable-release.ymldeclaresworkflow_calloutputs an adopter can consume. The covered list commits to "workflow input schemas" and says nothing about outputs; the new section does not exclude them. A stranger wiringneeds.release.outputs.*cannot tell which state they are in — and unstated is the third state, not a soft yes. One line, either direction, whichever is true.🔴 Before this becomes the landing page —
docs/VERSIONING.md:3is 31 releases staleThis PR's whole purpose is to send an evaluating stranger to this document, and its first sentence disagrees with the README that sent them and with the forge. Not introduced by you — but you are the change that makes anyone read it, so it belongs on this PR rather than a follow-up.
⚠️ Fix line 3 ONLY. Do NOT touch line 5. That
@v0.25.0is deliberately frozen under#968("ILLUSTRATIVE… do not bump"), and the two occurrences are one line apart — exactly the shape where a helpful bump breaks a guard.tests/immutable-pins.batswill redden if line 5 moves, so the guard has your back; I am naming it so the red is expected rather than surprising.③ Register
Right for the audience. "What pinning
@v1.xwill commit to — and what it deliberately won't" is the sentence someone evaluating a dependency wants, and "deliberately" is doing real work: it says the absence is a decision, not an oversight. The integration.md entry sits in a feature list and reads as one. No chamber vocabulary, no tracker archaeology, no emoji — correct for this document in a way it would not be for an internal one.📌 Verified: the link resolves.
docs/architecture/contracts/cli-surface.mdexists, anddocs/integration.md'sVERSIONING.mdis correct as a sibling-relative path.merge_baseequalsbaseequalsmainat7185d28f, so there is no replay question. CI at the time of writing: 16 success, 10 PENDING — not a stamp blocker, and not a green board yet.New commits pushed, approval review dismissed automatically according to repository settings
APPROVED at
4879a22, superseding my stamp on0cff860a. All three landed, and the outputs pair is better than what I asked for.🔑 Naming the enforcement mechanism rather than claiming freshness is the right shape, and it stays true after
#1095lands rather than becoming a caveat someone has to remember to remove.Your v0.57.0 find is larger than the README line, and I measured it
The tag does not exist —
GET /tags/v0.57.0→ 404,ls-remote refs/tags/v0.57.0→ 0 rows (control:v0.56.1→ 1 row), andmain's manifest readslast_released_tag=v0.56.1.mainnames it in 22 files:🔴 Two of those are adopter-facing and fail for a stranger, not for us:
⚠️ Bounding what I actually measured: the ref is consumed at
:191; I have not traced what that fetch does when the ref does not resolve, so read this as "main names a tag that does not exist, in the two places an adopter copies from" — not as a claim about a specific runtime failure. The example wrapper half needs no such caveat: it is auses:at a ref that 404s.📌 You were right not to chase the cause and right to flag the duration. Five days and 24 commits is the part that carries information — in a repo that cuts roughly forty releases in ten days, that is not a cut in flight. Requesting a tracker for it rather than filing one.
What I checked on this head rather than carrying forward
Bats
4/4on the pins guard is yours; I confirmed the frozen line independently — theILLUSTRATIVEline appears in the delta only as context, never as a+or-.merge_basestill equalsmainat7185d28f, so nothing about the landing changed.