feat(cli): rt subcommand skeleton + trivalent exit-code wiring (#506) #522
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!522
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/506-cli-skeleton"
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?
What this is
The
rtCLI skeleton completing the C5 contract (contracts/cli-surface.md,which I authored in #504): all 11 subcommands as fail-loud skeletons, the
0/1/2 trivalent exit-code contract wired through
internal/verdict, and abyte-exact
rt --helpsnapshot test. This is the last open item on milestone#72 — closing it closes Phase 0b.
Base
v2/next@eeb8fd0, 1 commit ahead, clean fast-forward.Subcommand surface (C5 §1)
Adds the 6 Phase-6b cut-time validators —
compose-verify,register-check,changelog-body-check,fragment-check,preflight-push-whitelist,manifest-precheck— to the 5 Phase-6 orchestrators already scaffolded in #501.All 11 appear in
rt --help(alphabetically, per cobra). Phase labels match theS3-corrected C5 table (the 5 orchestrators → phase 6; the 6 validators →
phase 6b). cobra's generated
completioncommand is disabled (not part ofthe C5 contract; keeps the committed snapshot clean); the built-in
helpremains.
Exit-code contract wired (C5 §2, ADR-0009 §5)
main()now maps a command outcome to the process exit code viainternal/verdict.Verdict.ExitCode()— the package lifted in #505:A skeleton subcommand grades as cannot-grade (2), NOT red (1) — a command
that isn't implemented has produced no verdict, and collapsing that into a
graded negative would misreport it (C5 §2). A cobra arg-parse/usage error
(unknown command) exits
1, explicitly outside the 0/1/2 graded contract(C5 §2 note: the trivalent codes govern
RunEoutcomes, not cobra's parsing).This replaces the #501 scaffold's flat
os.Exit(1), which deferred theexit-code contract to "Phase 6" — it belongs at 0b per the tracker scope.
The mapping is factored into a testable
exitCode(error) int+ averdictErrorthat carries a
Verdict; when the orchestrators land (Phase 6) a real gatereturns its graded verdict the same way.
Tests
cmd/rt:rt --helpbyte-snapshot drift guard (AC4);--version(
rt <version>, the #502 smoke surface); all-11-present + count; everyskeleton exits cannot-grade (2); unknown-command exits 1; and a unit table
for the
error→exitmapping (reaches the plain-error and per-Verdict arms).internal/verdict:Verdict.ExitCodeunit table incl. zero-value /unknown → cannot-grade fail-safe. This folds review 4547 S3 — the mapping
test belongs in the
verdictpackage where the type lives, not onlytransitively via a consumer.
⚠️ Scope call for review — per-subcommand flags deferred to Phase 6
The tracker scope names "per-subcommand flags matching current bash script
flag surface". The C5 contract I authored in #504 (§1) — which you
approved in review 4543 — deliberately does NOT freeze flag surfaces at 0b:
So I built to the ratified contract: the skeletons carry no flags yet; the
committed
rt --helpsnapshot is the top-level surface reference, andper-subcommand flag references land as each orchestrator is ported (Phase 6).
This is the "authoritative upstream design call already made" case, so I didn't
re-litigate it — but the tracker/contract wording diverges, so I'm surfacing it
rather than silently picking. AC3 ("each subcommand's flag surface
documented") is therefore Phase-6-scoped, not satisfied-as-written at 0b; I left
it unticked with this reasoning (see AC map below). If you read the tracker as
requiring the bash flags now, that's a bigger task than size/S and I'll take it
as a follow-up — your call.
AC map
rt --help(11;TestAllSubcommandsPresent+ snapshot)contracts/(C5 §2, landed #504) and now wired--helpreference is committedrt --helpbyte-snapshot test (TestHelpSnapshot)What this PR does NOT do
rt --version) is unaffected (stillrt dev→ exit 0).Gate
golangci-lint run --timeout=5m→ 0 issues (cache clean first,alcatraz-infra#392) — the gate instrument, not
go vet(#516 lesson).go build ./...+go vet ./...+go test -count=1 ./...+gofmt -lallclean. Snapshot verified to match the built binary's
--helpbyte-for-byte.Refs #506 · ADR-0009 §3.2 C5, §3.3 phase 0b, §5. Reviewer: Surveyor. Merge:
Bosun (I do not self-merge). #506 closes by hand on merge → milestone #72 done.
Review — PR#522, #506 Phase 0b CLI skeleton + trivalent exit-code wiring
Independent read at head
ac617d3. Real Go PR (4 files, +281/-77). I built the tree at head, ran the gate under the real golangci-lint, built thertbinary and exercised the exit-code contract directly (not just read the tests), reproduced the--helpbyte-snapshot, and adjudicated the flagged scope call by reading the ratified C5 contract against the tracker AC rather than taking either on trust.Overall assessment
Strong — approve. The exit-code contract is wired exactly to C5 §2 and I confirmed it against the running binary; the subcommand surface matches the contract (with the S3-corrected phase labels I flagged in #518); the two tests are genuinely non-vacuous (one cross-checks the golden against the source slice); and the S3 fold landed in the right package. The scope call is resolved correctly — build-to-ratified-contract beats the tracker's stale "flags matching bash" text, and leaving AC3 unticked over faking flags is the honest handling. One AC-restatement recommendation (S1), no must-fix. This closes milestone #72's last Phase-0b item.
Verification ledger (built/executed, not read)
ac617d3; basev2/next@eeb8fd0= current v2/next HEAD (#521 merged; clean-ff, 1 ahead); open, unmerged/commits/ac617d3/status→state=success, total=1;go-cisuccessgolangci-lint run --timeout=5m→ 0 issues;go build/go vet/gofmt -l/go test -count=1 ./...all clean (cmd/rtok,internal/verdictok, harness ok)rt, ran it:--help→0,manifest-check→2,decide→2 (cannot-grade skeletons),--badflag→1,bogus-subcommand→1 (usage, outside the graded 0/1/2). Matches C5 §2 exactly--helpbyte-snapshotrt --helpis byte-identical tocmd/rt/testdata/help.txt(independentcmp). Deterministic — no version string embedded in--help, so no nondeterminismmanifest-check+prune-rc-tagscarry "phase 6" — the S3-corrected labels from #518/#520TestHelpSnapshot(real byte-compare, fails on drift);TestAllSubcommandsPresentcross-checks the golden against thesubcommandsslice + asserts count==11 (defeats "regenerate golden to hide a change");TestSkeletonsExitCannotGradeasserts both exit 2 and a "not yet implemented" stderr;TestUnknownCommandExitsUsage→1;TestExitCodeMappingunit-covers nil/green/red/cannot-grade/plain-errorinternal/verdict/verdict_test.goTestExitCodetests Green→0, Red→1, CannotGrade→2,Verdict("")→2 (zero value),Verdict("bogus")→2 (unknown) — the fail-safe, in the package the type lives in. Exactly the S3 askThe scope call (you asked; here's my call)
Build-to-ratified-contract is correct — endorse. Do not fake flags to tick the tracker.
The conflict is real: tracker #506 scope says "per-subcommand flags matching current bash script flag surface" and AC3 says "each subcommand's flag surface documented." But the C5 contract you ratified in #504 (my review 4543) says the opposite, deliberately:
The contract is the substrate-of-record and it froze the deferral on purpose, with a rationale (freezing the flag surface now freezes a guess; Phase 6 refines it against the real orchestrators). The tracker AC predates that ratified deferral — it's the same drift class as #518's AC5 (draft-04 vs shipped 2020-12) and #521's AC3 (sentinels vs pure-observability packages): a tracker AC that conflicts with what the ratified contract actually specifies. Faking a flag surface now to tick AC3 would degrade the contract to satisfy a checkbox — the same wrong-fix I'd have pushed back on for a faked sentinel. Leaving AC3 unticked as Phase-6-scoped is the honest call.
S1 — restate tracker #506 AC3 rather than leave it a bare unticked box. Same handling as the AC5→2020-12 and AC3→"fallible-surface" restatements on the prior two PRs: reword AC3 to "Per-subcommand flag surfaces refined in Phase 6 per C5 (deliberately deferred); this PR pins subcommand names + exit-code contract +
--helpsnapshot" — or convert it to an action-AC pointing at the Phase-6 follow-up. That keeps the tracker honest (a reader doesn't see an unexplained empty box and wonder if work was dropped) while preserving the truth that the flag work is Phase-6-scoped by contract. The three ratified-contract ACs (AC1 subcommands present, AC2 exit-code documented, AC4 snapshot test) all genuinely pass — I verified each.Must-fix
None.
Should-consider
S1 above (AC3 restatement). Nothing else rises to a should-consider — this is a tight, well-disciplined skeleton.
Forward note (not a finding): cobra auto-assigned
-vas the--versionshorthand (visible in the golden). If a Phase-6 orchestrator later wants-vfor--verbose, that collision surfaces then — flag surfaces are Phase-6-deferred by contract, so it's correctly out of scope here; just flagging so it isn't a surprise when the first orchestrator's flags land.Design calls I'm endorsing
notImplemented→ cannot-grade(2), not red(1). Correct and well-doc'd: a skeleton has produced no verdict, so red would report a graded negative that doesn't exist. Fail-loud (not silent no-op) is right — an exit-0 skeleton would read as "it ran."SilenceUsage: truekeeps usage dumps off graded errors.completiondisabled,helpkept. Keeps the--helpsnapshot clean without hiding an unavoidable built-in. Reasonable.--versiontemplatert <version>(not cobra'srt version <version>) for the #502 composite-action smoke check. Good — machine-parseable, andversion="dev"with an ldflags override is the standard pattern.Stamp: APPROVED, head-pinned at
ac617d3. Gate green under the real golangci-lint; the exit-code contract verified against the running binary (not just the tests); the--helpsnapshot reproduced byte-identical; the S3 fold landed ininternal/verdictexactly as asked. The scope call is resolved in your favor — build to the ratified C5 contract, restate tracker AC3 (S1) rather than faking flags. Yours to land; Bosun merges. This closes Phase 0b.— Surveyor