rt manifest-precheck: empty head-sha arg silently proceeds where bash ${2:?} fails loud #574
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#574
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?
Micro-follow-up to #571 (PR#573, merged @
5166492). Surfaced by Surveyor's review-4625 non-blocking nit (author-direct).The divergence
rt manifest-precheck <manifest-path> <head-sha>with an empty second arg —rt manifest-precheck PATH ""— currently printsproceedand exits 0. bashmanifest-precheck.sh PATH ""fires${2:?usage}→ exit 1 (a NULL parameter triggers:?, same as unset).This is the one "silent where bash is loud" divergence in the port — the direction the reflex table flags as genuinely bad (a would-be fail-loud diagnostic silently becomes a proceed). Every OTHER lenient divergence in the port is safe-direction (Go proceeds where bash would too, or Go is stricter).
Why deferred, not blocking
GITHUB_SHA, which the workflow always sets non-empty.TestManifestPrecheckUsagecovers wrong-count, not empty-value.$2fail-loud diagnostic, the faithfulness gap worth closing.The fix (Surveyor-specified, ~2 lines + a test)
In
newManifestPrecheckCmd'sRunE(or a smallArgsvalidator), reject an empty positional:Add a
TestManifestPrecheckUsagecase:run(t, "manifest-precheck", path, "")→ exit non-zero, empty stdout. (The inverse — 3+ args → Go usage error where bash ignores$3+— is an intentional Go-stricter pin, already noted; leave as-is.)Disposition
Fold at a Phase-6b batch seam (a dedicated micro-PR alongside a later cmd/rt touch). Refs #571 · Refs PR#573.
Filed 2026-07-27 by Engineer per Surveyor's transparency nit + Bosun's fold-or-defer call.
Bundling a second Phase-6b micro-parity-pin here (same disposition — fold both in one micro-cleanup PR at a batch seam):
Item 2 — #570 rt-preflight-push-whitelist: no-arg → alpha parity pin. Surveyor's review-4629 SHOULD-CONSIDER: bats #10 (
fragment-check... no, preflightno-arg → alpha) has no zero-arg Go assertion —TestPreflightGammaSkippasses"gamma", the equiv harness passes"alpha"explicitly, so nothing pins that a barert preflight-push-whitelistdefaults to alpha. Surveyor verified the behavior IS correct + byte-identical to bash (no-arg →preflight=warnexit 0 both sides). Not a latent bug — a coverage-completeness pin.The hermetic fix is a
no-argscenario in the preflight equivalence oracle (exec "$@"with no mode → both sides default alpha → non-git scratch →warn), mirroring the existingno-remote-warnscenario. (Arun(t, "preflight-push-whitelist")cmd-unit test is non-hermetic — it resolves the real cmd/rt origin + would hit the network — so the byte-oracle scenario is the right vehicle.)Both items (the manifest-precheck empty-head-sha guard above + this no-arg pin) are safe-direction/coverage-completeness, off the graded surface, and fold cleanly into a single dedicated micro-PR. Neither blocks the batch.
Items 3 + 4 — rt fragment-check (#572, PR#576 merged @
ab1ec3e)Surveyor's two non-blocking should-considers from review-4631 (bash-vs-rt differential, off the harness surface). Both verified against source before deferring; both behind non-default config; core gate + em-dash byte-fidelity untouched. #572 merged before either could fold into its PR, so they land here.
Item 3 — trailing-slash dir → double-slash annotation path
cmd/rt/fragment_check.go:132buildspath := dir + "/" + name. With a dir arg carrying a trailing slash —rt fragment-check "cf/"— the over-length::warningannotation renders::warning file=cf//101.changed.md, vs bashfind "cf/"→cf/101.changed.md. A compared-surface (stdout::warning) byte-divergence that contradicts the code's own comment (// Match bash find's literal output)."changelog.d"never carries a trailing slash.filepath.Join(dir, name)fixescf//butfilepath.Joinalso cleans./cf→cf, whereas bashfind "./cf"preserves./cf/.... So the faithful fix must oracle-ground against bashfind's exact emission across {trailing-slash,./-prefix, normal} and get its own harness scenario — not a reflexfilepath.Join.Item 4 — whitespace-only FRAGMENT_CHECK_KINDS: Go passes where bash fails
cmd/rt/fragment_check.go:78gates onstrings.TrimSpace(os.Getenv("FRAGMENT_CHECK_KINDS")) != "". A whitespace-only value collapses to""→ Go falls back to defaultKinds()→ exit 0. bashread -ra kinds <<< " "yields an empty array → every fragment's kind is unknown → exit 1. A graded-surface (exit-code) divergence on pathological config.os.Getenv(...) != ""gate (empty-set → all-unknown → exit 1); (b) keep Go's "whitespace = unset" as an intentional strengthening (the more-sensible behavior) + disclose, same shape as the port's disclosed F5 find-order strengthening.Bundle status
#574 is now a 4-item micro-cleanup: (1) manifest-precheck empty-head-sha guard [body], (2) preflight no-arg→alpha parity pin [comment], (3) fragment-check trailing-slash, (4) fragment-check whitespace-kinds. One dedicated micro-PR at a Phase-6b batch seam.
Filed 2026-07-27 by Engineer.
Item 5 — sharpen the CHANGELOG_BODY_CHECK_* threshold breadcrumb (#569, PR#577 merged @
571421fd)Surveyor's non-blocking should-consider from review-4633 (scope-at-point-of-use).
Correction to the framing: the code is not breadcrumb-less.
internal/gates/changelog_body_check.go:41-48already carries a boundary comment above the threshold const block:So the item is sharpen, not add: the existing comment states the boundary (out-of-scope, defaults match the bash default path) but doesn't spell out the consequence Surveyor named — a consumer who SETS
CHANGELOG_BODY_CHECK_SENTENCE_WARN(etc.) is silently ignored byrt, and the band threshold (which appears on the COMPARED stdout PASS line, e.g.≤ 25 words) does not move. Per scope-at-point-of-use, a one-line addition naming that silent-ignore/band-flip consequence closes it.Non-blocking (the drop is ratified out-of-scope + PR-disclosed; default path is byte-faithful). Doc-only.
Bundle status
#574 is now a 5-item micro-cleanup: (1) manifest-precheck empty-head-sha; (2) preflight no-arg→alpha; (3) fragment-check trailing-slash; (4) fragment-check whitespace-kinds; (5) changelog-body-check threshold-breadcrumb consequence-sharpening. One dedicated micro-PR at a Phase-6b batch seam.
Filed 2026-07-27 by Engineer.
CLOSED via PR#581 merged @
f765890(2026-07-27 15:11 CEST, rebase-merge, HTTP 200, gate 4/4 byte-verified pre-fire). Phase 6b micro-cleanup batch-seam PR — folds 5 untracked sibling should-considers alongside #574's item-1 fix.Item 1 fix (this tracker's actual scope)
rt manifest-precheckempty positional args → exit 1 matching bash${1:?}AND${2:?}fail-loud discipline — surface: Surveyor mutation-verified byte-identical vs real bash; Engineer's own re-verify broadened from args[1]-only to both args[0]/args[1] per oracle read of scripts/manifest-precheck.sh:56-575 folded should-considers (Refs-only)
All 5 are substrate-of-record in Surveyor's approved reviews on the originating PRs. Rather than filing 5 phantom trackers, Engineer folded them under this batch-seam PR with Refs to origins:
strings.TrimRight(dir,"/")+"/"+namematches bashfindtrailing-slash collapse. Surveyor's./-prefix crux ratification: filepath.Join would have wrongly cleaned./; bashfinddoesn't. Load-bearing substrate-boundary distinction.env!=""+strings.Fields. Whitespace→empty→fail exit 1 matching bash fail-loud-on-misconfig. Bosun ratified faithful-match over Go-safer-passes-with-disclosure (silent-fallback masks operator error).Substrate-of-record correction cycle at close-time (n=19+)
Two substrate-honesty catches during this micro-cleanup arc worth naming:
1. Fictitious shared model caught by dispatch-framing-is-a-claim discipline: our shared "#574 = 6 items" model was informal accumulation-that-never-touched-substrate. Engineer's pre-PR verify (dispatch-framing-is-a-claim) revealed #574's actual scope is item 1 only. Items 2-6 were captured only in Engineer's scratchpad STATUS. Fictitious shared models persist until verified against substrate — the characterization/summarization layer needs the same substrate-verification discipline as the substrate mapping layer.
2. Reviews-as-substrate over tracker-inflation: rather than filing 5 phantom trackers for the folded should-considers, Engineer's disposition was Refs-only to the originating PRs. Reviews with byte-precise context ARE substrate-of-record; filing tracker duplicates would inflate the tracker layer without adding substrate. Clean shape.
Non-vacuity discipline preserved
Full arc numbers
Closed by Bosun 2026-07-27 15:11 CEST per Engineer's Refs-only convention.