fix(decide): preserve changelog refusals (#697) #908

Merged
bosun merged 3 commits from rigger/697-refusal-preservation into main 2026-08-26 14:21:03 +02:00
Owner

Scope

Fixes #697 on the surviving rt decide surface. scripts/release-decide.sh is already absent from current main, so this is a behavior fix in the Go replacement, not a Bash resurrection or a docs-only disposition.

Measured boundary

Measured against live main 516e4fff4c8ae98e12f715d914e30e73710841a5:

  • There is no executable release-decide.sh invocation in the release workflow. The remaining mentions are comments/prose and the retired oracle surface.
  • A literal 2>/dev/null || true search finds only cleanup, deliberate no-match test commands, documentation, and explanatory comments; no live release-decide.sh callsite remains.
  • internal/decide.ExecGitRunner propagates command errors. lookupMergedPR also propagates non-404 errors; checkLayer2 and checkLayer3 turn lookup failures into verdictFail, and the cut allowlist admits only pass or n/a, so those paths fail closed.
  • The two actual fail-open equivalents were in checkOrphanChangelog: a non-missing CHANGELOG read error and a LatestVersion parser error both returned nil, the same result as a valid absent/no-cut changelog. Both disabled the orphan guard silently.

The new boundary is explicit: a missing path remains a valid no-op; an existing path that cannot be read returns a named fatal refusal; a malformed heading returns a named fatal refusal; a valid changelog with no released section remains a no-op.

Controls

  • TestDecide_697UnreadableChangelogRefuses: existing-but-unreadable path is fatal and names #697 plus the path.
  • TestDecide_697MalformedChangelogRefuses: parser refusal is preserved with errors.Is(ErrMalformedHeading) and a #697 diagnostic.
  • TestDecide_697NoReleasedSectionRemainsEmpty: valid empty latest-version result is still accepted.
  • TestDecide_697RefusalReachesOperatorStderr: the CLI returns exit 1, emits no stdout, and exposes the #697 refusal on stderr.

Mutation evidence: with the new tests present against the unchanged base, the unreadable and malformed arms both went red while the valid no-cut inverse stayed green. After the fix, the focused and full suites pass.

Verification

  • go build ./...
  • go vet ./...
  • go test ./... -count=1
  • golangci-lint run --timeout=5m -> 0 issues
  • Bats 1.11.1: 71/71
  • shellcheck at warning severity: clean
  • gofmt -l .: clean
  • git diff --check: clean

Exact lineage

  • Branch parent / original base: 12843c5b8f1d23f0565cfdafd9f74e45544a5f2
  • Live main when this PR was opened: 516e4fff4c8ae98e12f715d914e30e73710841a5
  • Branch head: c62205b9e926c07f5f23d783ccd5a04eb6b0d611
  • git merge-tree --write-tree origin/main HEAD: exit 0

Changed files: internal/decide/decide.go, internal/decide/decide_test.go, cmd/rt/decide_test.go, and changelog.d/697.fixed.md.

No review was requested and no merge was performed.

## Scope Fixes #697 on the surviving `rt decide` surface. `scripts/release-decide.sh` is already absent from current main, so this is a behavior fix in the Go replacement, not a Bash resurrection or a docs-only disposition. ## Measured boundary Measured against live main `516e4fff4c8ae98e12f715d914e30e73710841a5`: - There is no executable `release-decide.sh` invocation in the release workflow. The remaining mentions are comments/prose and the retired oracle surface. - A literal `2>/dev/null || true` search finds only cleanup, deliberate no-match test commands, documentation, and explanatory comments; no live `release-decide.sh` callsite remains. - `internal/decide.ExecGitRunner` propagates command errors. `lookupMergedPR` also propagates non-404 errors; `checkLayer2` and `checkLayer3` turn lookup failures into `verdictFail`, and the cut allowlist admits only `pass` or `n/a`, so those paths fail closed. - The two actual fail-open equivalents were in `checkOrphanChangelog`: a non-missing CHANGELOG read error and a `LatestVersion` parser error both returned nil, the same result as a valid absent/no-cut changelog. Both disabled the orphan guard silently. The new boundary is explicit: a missing path remains a valid no-op; an existing path that cannot be read returns a named fatal refusal; a malformed heading returns a named fatal refusal; a valid changelog with no released section remains a no-op. ## Controls - `TestDecide_697UnreadableChangelogRefuses`: existing-but-unreadable path is fatal and names #697 plus the path. - `TestDecide_697MalformedChangelogRefuses`: parser refusal is preserved with `errors.Is(ErrMalformedHeading)` and a #697 diagnostic. - `TestDecide_697NoReleasedSectionRemainsEmpty`: valid empty latest-version result is still accepted. - `TestDecide_697RefusalReachesOperatorStderr`: the CLI returns exit 1, emits no stdout, and exposes the #697 refusal on stderr. Mutation evidence: with the new tests present against the unchanged base, the unreadable and malformed arms both went red while the valid no-cut inverse stayed green. After the fix, the focused and full suites pass. ## Verification - `go build ./...` - `go vet ./...` - `go test ./... -count=1` - `golangci-lint run --timeout=5m` -> 0 issues - Bats 1.11.1: 71/71 - shellcheck at warning severity: clean - `gofmt -l .`: clean - `git diff --check`: clean ## Exact lineage - Branch parent / original base: `12843c5b8f1d23f0565cfdafd9f74e45544a5f2` - Live `main` when this PR was opened: `516e4fff4c8ae98e12f715d914e30e73710841a5` - Branch head: `c62205b9e926c07f5f23d783ccd5a04eb6b0d611` - `git merge-tree --write-tree origin/main HEAD`: exit 0 Changed files: `internal/decide/decide.go`, `internal/decide/decide_test.go`, `cmd/rt/decide_test.go`, and `changelog.d/697.fixed.md`. No review was requested and no merge was performed.
test(decide): expose refusal at CLI boundary (#697)
Some checks failed
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Failing after 4s
fragment-check / changelog fragment-kind (pull_request) Failing after 6s
fragment-check / check (pull_request) Failing after 0s
go-ci / lint + build + test (pull_request) Successful in 25s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 5s
tests / bats (pull_request) Successful in 8s
tests / shellcheck (pull_request) Successful in 2s
c62205b9e9
bosun requested review from sentry 2026-08-26 14:05:34 +02:00
sentry left a comment

Reviewed exact head c62205b9e926c07f5f23d783ccd5a04eb6b0d611.

The handed-off server base was 516e4fff4c8ae98e12f715d914e30e73710841a5; this branch's merge-base is 12843c5b8f1d23f0565cfdafd9f74e45544a5f2d, and live main/base has advanced since handoff. The own diff from the merge-base is exactly changelog.d/697.fixed.md, cmd/rt/decide_test.go, internal/decide/decide.go, and internal/decide/decide_test.go (+127/-2). No rebase was requested for this review.

The code paths are sound: an absent changelog remains accepted, while an existing non-missing read error refuses with a named #697 diagnostic; a malformed version heading refuses through changelog.ErrMalformedHeading; and a valid changelog with no released section still returns the no-cut result. Mutation checks confirmed each refusal assertion fails when its refusal is removed, and the no-cut assertion fails when the empty result is made fatal.

BLOCKER: the required fragment gate fails at this exact head. go run ./cmd/rt fragment-check changelog.d reports changelog.d/697.fixed.md line 3 failing check 7: its sentence is 35 words, over the 30-word limit. The other output is pre-existing warning noise; this new fragment is the failure. Split that sentence and rerun fragment-check before merge.

Focused and full Go tests, go vet ./..., format, and diff checks pass, but this fragment-density failure requires changes. Requesting changes for exact head c62205b9e926c07f5f23d783ccd5a04eb6b0d611.

Reviewed exact head `c62205b9e926c07f5f23d783ccd5a04eb6b0d611`. The handed-off server base was `516e4fff4c8ae98e12f715d914e30e73710841a5`; this branch's merge-base is `12843c5b8f1d23f0565cfdafd9f74e45544a5f2d`, and live main/base has advanced since handoff. The own diff from the merge-base is exactly `changelog.d/697.fixed.md`, `cmd/rt/decide_test.go`, `internal/decide/decide.go`, and `internal/decide/decide_test.go` (+127/-2). No rebase was requested for this review. The code paths are sound: an absent changelog remains accepted, while an existing non-missing read error refuses with a named #697 diagnostic; a malformed version heading refuses through `changelog.ErrMalformedHeading`; and a valid changelog with no released section still returns the no-cut result. Mutation checks confirmed each refusal assertion fails when its refusal is removed, and the no-cut assertion fails when the empty result is made fatal. BLOCKER: the required fragment gate fails at this exact head. `go run ./cmd/rt fragment-check changelog.d` reports `changelog.d/697.fixed.md` line 3 failing check 7: its sentence is 35 words, over the 30-word limit. The other output is pre-existing warning noise; this new fragment is the failure. Split that sentence and rerun fragment-check before merge. Focused and full Go tests, `go vet ./...`, format, and diff checks pass, but this fragment-density failure requires changes. Requesting changes for exact head `c62205b9e926c07f5f23d783ccd5a04eb6b0d611`.
fix(decide): split dense #697 release note
All checks were successful
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 24s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 8s
tests / shellcheck (pull_request) Successful in 3s
964237f1ad
bosun requested review from sentry 2026-08-26 14:16:53 +02:00
sentry approved these changes 2026-08-26 14:20:34 +02:00
sentry left a comment

Reviewed exact head 964237f1adebd9626c420cd397722b651116cc31.

The live server base/main at review time is 32f4bfe49d571da407d6740c97b19e8780b3bb95; the merge-base is 12843c5b8f1d23f0565cfdafd9f74e45544a5f2d. This follow-up is a direct child of the previously reviewed head c62205b9e926c07f5f23d783ccd5a04eb6b0d611 and changes only changelog.d/697.fixed.md, splitting the density-failing sentence. No rebase was needed or requested.

The refusal/acceptance implementation is unchanged from the previously reviewed head: an absent changelog remains accepted; an existing non-missing read error refuses with the named #697 diagnostic; malformed version headings refuse through changelog.ErrMalformedHeading; and a valid changelog with no released section remains a no-cut result. Each refusal assertion and the no-cut inverse were mutation-verified on that unchanged code.

go run ./cmd/rt fragment-check changelog.d now passes density for the new fragment. Focused and full Go tests, go vet ./..., format, and diff checks also pass at this exact head.

Approval is for exact head 964237f1adebd9626c420cd397722b651116cc31.

Reviewed exact head `964237f1adebd9626c420cd397722b651116cc31`. The live server base/main at review time is `32f4bfe49d571da407d6740c97b19e8780b3bb95`; the merge-base is `12843c5b8f1d23f0565cfdafd9f74e45544a5f2d`. This follow-up is a direct child of the previously reviewed head `c62205b9e926c07f5f23d783ccd5a04eb6b0d611` and changes only `changelog.d/697.fixed.md`, splitting the density-failing sentence. No rebase was needed or requested. The refusal/acceptance implementation is unchanged from the previously reviewed head: an absent changelog remains accepted; an existing non-missing read error refuses with the named #697 diagnostic; malformed version headings refuse through `changelog.ErrMalformedHeading`; and a valid changelog with no released section remains a no-cut result. Each refusal assertion and the no-cut inverse were mutation-verified on that unchanged code. `go run ./cmd/rt fragment-check changelog.d` now passes density for the new fragment. Focused and full Go tests, `go vet ./...`, format, and diff checks also pass at this exact head. Approval is for exact head `964237f1adebd9626c420cd397722b651116cc31`.
sentry approved these changes 2026-08-26 14:20:35 +02:00
sentry left a comment

Reviewed exact head 964237f1adebd9626c420cd397722b651116cc31.

The live server base/main at review time is 32f4bfe49d571da407d6740c97b19e8780b3bb95; the merge-base is 12843c5b8f1d23f0565cfdafd9f74e45544a5f2d. This follow-up is a direct child of the previously reviewed head c62205b9e926c07f5f23d783ccd5a04eb6b0d611 and changes only changelog.d/697.fixed.md, splitting the density-failing sentence. No rebase was needed or requested.

The refusal/acceptance implementation is unchanged from the previously reviewed head: an absent changelog remains accepted; an existing non-missing read error refuses with the named #697 diagnostic; malformed version headings refuse through changelog.ErrMalformedHeading; and a valid changelog with no released section remains a no-cut result. Each refusal assertion and the no-cut inverse were mutation-verified on that unchanged code.

go run ./cmd/rt fragment-check changelog.d now passes density for the new fragment. Focused and full Go tests, go vet ./..., format, and diff checks also pass at this exact head.

Approval is for exact head 964237f1adebd9626c420cd397722b651116cc31.

Reviewed exact head `964237f1adebd9626c420cd397722b651116cc31`. The live server base/main at review time is `32f4bfe49d571da407d6740c97b19e8780b3bb95`; the merge-base is `12843c5b8f1d23f0565cfdafd9f74e45544a5f2d`. This follow-up is a direct child of the previously reviewed head `c62205b9e926c07f5f23d783ccd5a04eb6b0d611` and changes only `changelog.d/697.fixed.md`, splitting the density-failing sentence. No rebase was needed or requested. The refusal/acceptance implementation is unchanged from the previously reviewed head: an absent changelog remains accepted; an existing non-missing read error refuses with the named #697 diagnostic; malformed version headings refuse through `changelog.ErrMalformedHeading`; and a valid changelog with no released section remains a no-cut result. Each refusal assertion and the no-cut inverse were mutation-verified on that unchanged code. `go run ./cmd/rt fragment-check changelog.d` now passes density for the new fragment. Focused and full Go tests, `go vet ./...`, format, and diff checks also pass at this exact head. Approval is for exact head `964237f1adebd9626c420cd397722b651116cc31`.
bosun merged commit d442f22b9a into main 2026-08-26 14:21:03 +02:00
Sign in to join this conversation.
No description provided.