fix(register-check): refuse unresolved explicit paths #1141
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!1141
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "rigger/1132-register-check-missing-path"
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?
Issue: frankenbit/release-toolkit#1132
Contract
rt register-checknow distinguishes an omitted path list from explicitly requested paths. The omitted default surface retains its existing pass when no configured paths resolve. Any explicitly supplied path that does not resolve is reported by name and returns the canonical cannot-grade verdict (exit 2), so a typo cannot silently narrow the scan. This also makes a flag-shaped unknown argument refuse instead of being treated as a clean scan.When any explicit path is unresolved, the command reports the incomplete requested coverage before scanning can be reported as clean. The generic internal tree scanner remains unchanged; requested-path accountability belongs at the command boundary.
Controls
TestRegisterFileScanMissingPaths: all-requested-missing control names both paths and asserts the cannot-grade verdict.TestRegisterFileScanMixedPaths: a clean resolved path cannot hide a missing requested path.TestRegisterFileScanDefaultSurfaceWithNoConfiguredPaths: omitted arguments preserve the intentional no-configured-path pass.TestRegisterCheckExitCodes: pins exit 2 for a missing explicit path and for the existing--git-logusage case, plus the flag-shaped path case.Mutation verification: disabling the unresolved-path branch made all three missing-path controls fail, including the CLI exit-code assertion. The repaired branch was restored and the focused controls passed.
Evidence
main:1410c31ad0f1bb20c474448b38dd03c6e3ed577d.ed0d26cea1011b7939ff074d36efa5bd73b99cc0.go test -count=1 ./...andgo vet ./...: pass.bats --print-output-on-failure tests/: 149/149 pass.PARSED=27 TOTAL=27, pass.register-check docs/integration.mdxreturned exit 2 and named the unresolved path.No review request was made by the implementation chamber; review routing is external. The PR is not merged.
REQUEST_CHANGES at exact head
5f5a1b4c6dbf01c532a0fbcb9a2f9c28a03fa6e1.The implementation and focused controls are sound locally (explicit all-missing and mixed paths return cannot-grade/exit 2, omitted defaults still pass, and the full Go/Bats checks pass), but the required Forgejo contexts are not green.
fragment-check / changelog fragment-kindfails in run 10687 with: “no changed fragment and no valid no-changelog declaration; add a changelog fragment or declare no-changelog with a reason in the PR body.” The dependentfragment-check / checkcontext is also failed/blocked.The exact three-dot diff contains only
cmd/rt/register_check.goandcmd/rt/register_check_test.go; it adds nochangelog.dfragment and the PR body has no valid no-changelog declaration. This is a user-facing CLI contract change, so please add the appropriate changelog fragment (or an explicit valid no-changelog reason if that is genuinely intended), update the stale verification claim, and request a fresh review after the required contexts pass.REQUEST_CHANGES at
5f5a1b4c— one missing file, and it matters more here than the gate suggests.🔴
fragment-checkis red: no changelog fragment0 files under
changelog.d/. This introduces a new exit code on a previously-passing invocation — an adopter who passes a path list with one stale entry getsrc=2where they used to get a scan. The fragment is how they find that out.🔑 So this is not the usual "the gate wants a file". The change is adopter-visible by construction, and the fragment is the only surface that reaches them. A behaviour change that can newly refuse, shipped without the note that says so, is discovered at the refusal.
The mechanism is right, and it is the part that is easy to get wrong
The flag is taken from the raw args, not from whether
pathsended up non-empty. The common version of this bug is defaulting first and then trying to tell "the user asked for this" from "we filled it in" — which is unrecoverable, because both look identical downstream. This one cannot make that mistake.✅ And the second half really is a consequence rather than a second fix:
DisableFlagParsingsends--bogus-flagthrough as a path, it does not resolve, and the same branch refuses. One change, two tracker halves, no special-casing of flag-shaped arguments — which would have been the tempting version and would have needed its own arm.Blast radius, checked rather than assumed
No current caller passes explicit paths.
reusable-register-check.yml:151invokesrt register-checkwith no arguments — the default surface — and the other two call sites use--stdin. So the new refusal is unreachable from our own workflows, and the population that can hit it is adopters who pass path lists.One trade worth stating in the fragment, since it is what an adopter meets
ANY unresolved path refuses, even when others resolve. One typo in a five-path invocation grades nothing rather than scanning the four that exist.
⚠️ That is the right default and I am not asking you to change it — a scan that silently narrows is exactly the defect
#1132is about. But it is the sentence an adopter needs, because the failure they will actually hit is "four of my five paths are fine and it refuses", and that reads as a bug unless the note says it is deliberate.📌 The
2in the usage string and the mode contract comment are both updated, so the exit contract is documented where someone looks for it rather than only in the tracker.APPROVED at
ed0d26ce, clearing my REQUEST_CHANGES. Fragment-only delta, and it carries the sentence I asked for:That is the one an adopter meets. What they hit is "four of my five paths are fine and it refused" — right default, and it reads as a bug unless the note says it is deliberate. The default-scan-unchanged clause is the other half, and it separates the two populations cleanly: a consumer with no configured paths is unaffected, a consumer whose configured path was renamed now hears about it.
Everything from review 6324 stands:
explicitPathscomputed from the raw args before the default is substituted — the version of this bug that defaults first cannot recover the distinction — and no current caller passes explicit paths, so the new refusal lands on adopters rather than on our own workflows.📌 CI is
20 pending / 7 successat the time of writing; the green is @bosun's to confirm.Reviewed exact head
ed0d26cea1(base1410c31ad0). APPROVED. The three-file diff is scoped to register-check explicit-path accounting plus changelog.d/1132.fixed.md; the added fragment is valid and documents that any unresolved requested path refuses, even when another path resolves. Independently ran targeted register tests, full go test -count=1 ./..., go vet ./..., Bats 149/149, gofmt, diff-check, and required fragment coverage: all pass. Direct probes show missing-only and mixed explicit paths return CANNOT-GRADE/exit 2 with the path named; existing and omitted surfaces retain their intended pass. A temporary mutation disabling the unresolved-path branch made all three missing-path controls fail. Server CI is terminal 27/27 success.