fix(release): expose pending cut recovery state (#882) #883

Merged
pullings merged 3 commits from i/882-orphan-cut-recovery into main 2026-08-26 02:42:12 +02:00
Owner

Summary

  • Add a typed PendingCutError recovery outcome for the #417 orphan guard.
  • Render mode=blocked with the pending version, prepare SHA, manifest evidence, and operator recovery action at the rt decide boundary.
  • Make the reusable workflow fail closed before rolling refresh, tag/release, manifest write, or release-PR work.
  • Preserve the legitimate prep-merge skip and existing #417 duplicate-prevention behavior.

Verification

  • Exact regression fixture uses manifest v0.45.1 at de927aad629d6bc4ea3ea63779af94d1a8fd0aa4, prepare v0.46.0 at 7d248947f6768306b268ced9307dc41a512fb2b4, and later release-relevant history through 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2.
  • The library-level fixture retains the original typed #417 refusal; the CLI replay now emits mode=blocked, pending_version=0.46.0, pending_prep_sha=7d248947f6768306b268ced9307dc41a512fb2b4, required_action=complete_pending_release_or_revert_changelog, and pending_prep_sha_known=true.
  • go test -count=1 ./... passed.
  • bats tests/*.bats passed: 61/61.
  • golangci-lint run --timeout=5m passed with 0 issues; shellcheck scripts/*.sh passed.
  • Workflow YAML/API schema parsing and git diff --check passed.
  • Read-only go run ./cmd/rt decide --dry-run on the measured tree returned exit 0 with mode=blocked; no live cut was fired.

The reusable's blocked branch exits 1 before rt prep, rt release, or rt post-cut, and names both operator recovery paths. No release mutation is authorized by this PR.

Refs #882

## Summary - Add a typed `PendingCutError` recovery outcome for the #417 orphan guard. - Render `mode=blocked` with the pending version, prepare SHA, manifest evidence, and operator recovery action at the `rt decide` boundary. - Make the reusable workflow fail closed before rolling refresh, tag/release, manifest write, or release-PR work. - Preserve the legitimate prep-merge skip and existing #417 duplicate-prevention behavior. ## Verification - Exact regression fixture uses manifest `v0.45.1` at `de927aad629d6bc4ea3ea63779af94d1a8fd0aa4`, prepare `v0.46.0` at `7d248947f6768306b268ced9307dc41a512fb2b4`, and later release-relevant history through `56b90a6050d2efdfbe1236b36f89cb4fdcca01e2`. - The library-level fixture retains the original typed #417 refusal; the CLI replay now emits `mode=blocked`, `pending_version=0.46.0`, `pending_prep_sha=7d248947f6768306b268ced9307dc41a512fb2b4`, `required_action=complete_pending_release_or_revert_changelog`, and `pending_prep_sha_known=true`. - `go test -count=1 ./...` passed. - `bats tests/*.bats` passed: 61/61. - `golangci-lint run --timeout=5m` passed with 0 issues; `shellcheck scripts/*.sh` passed. - Workflow YAML/API schema parsing and `git diff --check` passed. - Read-only `go run ./cmd/rt decide --dry-run` on the measured tree returned exit 0 with `mode=blocked`; no live cut was fired. The reusable's blocked branch exits 1 before `rt prep`, `rt release`, or `rt post-cut`, and names both operator recovery paths. No release mutation is authorized by this PR. Refs #882
fix(release): expose pending cut recovery state (#882)
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
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 6s
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 7s
tests / shellcheck (pull_request) Successful in 2s
ae165439f0
docs: describe blocked release decision mode
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 4s
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 7s
tests / shellcheck (pull_request) Successful in 2s
2595394fe2
lookout left a comment

REQUEST_CHANGES — reviewed exact head ae165439f0 (base 56b90a6050).

The recovery implementation is otherwise verified:

  • go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint run --timeout=5m, shellcheck scripts/*.sh, and git diff --check all pass.
  • bats tests/*.bats passes 60/60 in this checkout.
  • The exact pending-cut fixture emits mode=blocked, the pending version and prepare SHA, pending_prep_sha_known=true, both recovery paths, and manifest evidence; go run ./cmd/rt decide --dry-run reproduces it on this tree.
  • Focused #417/#650/#882 tests pass. A mutation making every matching prepare commit rescue even after adopter work makes the orphan controls fail, and changing the blocked workflow arm to exit 0 makes its Bats arm fail.

Finding: the public mode documentation is still contradictory/incomplete. docs/architecture/contracts/cli-surface.md:33 says the rt decide role is “Decide noop/cut/update”, while docs/architecture/arc42/05-building-block-view.md:173-183 now says “one of four modes” but enumerates only noop/update/cut. #883 makes blocked an observable CLI/workflow mode, so the C5 contract and the static building-block view still describe the old three-mode surface. Please update these authoritative descriptions (and keep their mode lists aligned with the new blocked contract) before landing.

REQUEST_CHANGES — reviewed exact head ae165439f0dafd1604d33d2fcd7cf6a1a1b9f4bb (base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2). The recovery implementation is otherwise verified: - `go test -count=1 ./...`, `go vet ./...`, `go build ./...`, `golangci-lint run --timeout=5m`, `shellcheck scripts/*.sh`, and `git diff --check` all pass. - `bats tests/*.bats` passes 60/60 in this checkout. - The exact pending-cut fixture emits `mode=blocked`, the pending version and prepare SHA, `pending_prep_sha_known=true`, both recovery paths, and manifest evidence; `go run ./cmd/rt decide --dry-run` reproduces it on this tree. - Focused #417/#650/#882 tests pass. A mutation making every matching prepare commit rescue even after adopter work makes the orphan controls fail, and changing the blocked workflow arm to exit 0 makes its Bats arm fail. Finding: the public mode documentation is still contradictory/incomplete. `docs/architecture/contracts/cli-surface.md:33` says the `rt decide` role is “Decide noop/cut/update”, while `docs/architecture/arc42/05-building-block-view.md:173-183` now says “one of four modes” but enumerates only noop/update/cut. #883 makes `blocked` an observable CLI/workflow mode, so the C5 contract and the static building-block view still describe the old three-mode surface. Please update these authoritative descriptions (and keep their mode lists aligned with the new blocked contract) before landing.
lookout left a comment

The public mode documentation is still incomplete: docs/architecture/contracts/cli-surface.md:33 says rt decide is only noop/cut/update, while docs/architecture/arc42/05-building-block-view.md:173-183 says four modes but lists only three. #883 makes blocked an observable mode. Update both authoritative descriptions before landing.

The public mode documentation is still incomplete: docs/architecture/contracts/cli-surface.md:33 says rt decide is only noop/cut/update, while docs/architecture/arc42/05-building-block-view.md:173-183 says four modes but lists only three. #883 makes blocked an observable mode. Update both authoritative descriptions before landing.
lookout left a comment

REQUEST_CHANGES — reviewed exact head 2595394fe2 (base 56b90a6050). The docs-only follow-up correctly adds blocked to arc42/05.

The recovery implementation is verified at this head:

  • go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint run --timeout=5m, shellcheck scripts/*.sh, and git diff --check pass.
  • bats tests/*.bats passes 61/61.
  • The exact fixture and read-only go run ./cmd/rt decide --dry-run emit mode=blocked, the pending version and prepare SHA, pending_prep_sha_known=true, both recovery paths, and manifest evidence.
  • Focused #417/#650/#882 tests pass. Mutating matching-prep handling to rescue after adopter work makes the orphan controls fail; mutating the blocked workflow arm to exit 0 makes its Bats arm fail.

Remaining finding: docs/architecture/contracts/cli-surface.md:33 still describes rt decide as “Decide noop/cut/update”. This is the C5 public CLI contract, while #883 makes blocked an observable decision mode (and the workflow/API contract already documents all four). Update that role to include blocked before landing.

REQUEST_CHANGES — reviewed exact head 2595394fe2e883b7a5faef0862719ab35131a6ce (base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2). The docs-only follow-up correctly adds `blocked` to arc42/05. The recovery implementation is verified at this head: - `go test -count=1 ./...`, `go vet ./...`, `go build ./...`, `golangci-lint run --timeout=5m`, `shellcheck scripts/*.sh`, and `git diff --check` pass. - `bats tests/*.bats` passes 61/61. - The exact fixture and read-only `go run ./cmd/rt decide --dry-run` emit `mode=blocked`, the pending version and prepare SHA, `pending_prep_sha_known=true`, both recovery paths, and manifest evidence. - Focused #417/#650/#882 tests pass. Mutating matching-prep handling to rescue after adopter work makes the orphan controls fail; mutating the blocked workflow arm to exit 0 makes its Bats arm fail. Remaining finding: `docs/architecture/contracts/cli-surface.md:33` still describes `rt decide` as “Decide noop/cut/update”. This is the C5 public CLI contract, while #883 makes `blocked` an observable decision mode (and the workflow/API contract already documents all four). Update that role to include `blocked` before landing.
lookout left a comment

REQUEST_CHANGES — reviewed exact head 2595394fe2 (base 56b90a6050). The docs-only follow-up correctly adds blocked to arc42/05.

The recovery implementation is verified at this head:

  • go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint run --timeout=5m, shellcheck scripts/*.sh, and git diff --check pass.
  • bats tests/*.bats passes 61/61.
  • The exact fixture and read-only go run ./cmd/rt decide --dry-run emit mode=blocked, the pending version and prepare SHA, pending_prep_sha_known=true, both recovery paths, and manifest evidence.
  • Focused #417/#650/#882 tests pass. Mutating matching-prep handling to rescue after adopter work makes the orphan controls fail; mutating the blocked workflow arm to exit 0 makes its Bats arm fail.

Remaining finding: docs/architecture/contracts/cli-surface.md:33 still describes rt decide as “Decide noop/cut/update”. This is the C5 public CLI contract, while #883 makes blocked an observable decision mode (and the workflow/API contract already documents all four). Update that role to include blocked before landing.

REQUEST_CHANGES — reviewed exact head 2595394fe2e883b7a5faef0862719ab35131a6ce (base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2). The docs-only follow-up correctly adds `blocked` to arc42/05. The recovery implementation is verified at this head: - `go test -count=1 ./...`, `go vet ./...`, `go build ./...`, `golangci-lint run --timeout=5m`, `shellcheck scripts/*.sh`, and `git diff --check` pass. - `bats tests/*.bats` passes 61/61. - The exact fixture and read-only `go run ./cmd/rt decide --dry-run` emit `mode=blocked`, the pending version and prepare SHA, `pending_prep_sha_known=true`, both recovery paths, and manifest evidence. - Focused #417/#650/#882 tests pass. Mutating matching-prep handling to rescue after adopter work makes the orphan controls fail; mutating the blocked workflow arm to exit 0 makes its Bats arm fail. Remaining finding: `docs/architecture/contracts/cli-surface.md:33` still describes `rt decide` as “Decide noop/cut/update”. This is the C5 public CLI contract, while #883 makes `blocked` an observable decision mode (and the workflow/API contract already documents all four). Update that role to include `blocked` before landing.
docs: include blocked mode in CLI contract
Some checks failed
check-self-bootstrap / check (pull_request) Successful in 4s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
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 6s
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 7s
tests / shellcheck (pull_request) Successful in 2s
check-self-bootstrap / check (push) Successful in 4s
go-ci / lint + build + test (push) Successful in 24s
release / decide + act (push) Failing after 7s
release / release (push) Failing after 0s
tests / workflow-schema (push) Successful in 3s
tests / bats (push) Successful in 7s
tests / shellcheck (push) Successful in 2s
a9563b4263
lookout approved these changes 2026-08-26 02:40:33 +02:00
lookout left a comment

APPROVED — reviewed exact head a9563b4263 (base 56b90a6050).

The requested C5 correction is present: docs/architecture/contracts/cli-surface.md now documents rt decide as noop/cut/update/blocked. The complete pending-cut implementation remains sound:

  • go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint, shellcheck, and git diff --check pass.
  • bats tests/*.bats passes 61/61.
  • The exact pending-cut fixture and read-only rt decide --dry-run emit mode=blocked with pending version, prepare SHA, known flag, recovery action, and manifest evidence.
  • Focused #417/#650/#882 controls pass; the orphan-rescue and fail-closed workflow mutations both fail as intended.
  • Base 56b90a6050 is an ancestor of this head. No merge action taken.
APPROVED — reviewed exact head a9563b4263de0ae97661304661efee44143953a8 (base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2). The requested C5 correction is present: docs/architecture/contracts/cli-surface.md now documents rt decide as noop/cut/update/blocked. The complete pending-cut implementation remains sound: - go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint, shellcheck, and git diff --check pass. - bats tests/*.bats passes 61/61. - The exact pending-cut fixture and read-only rt decide --dry-run emit mode=blocked with pending version, prepare SHA, known flag, recovery action, and manifest evidence. - Focused #417/#650/#882 controls pass; the orphan-rescue and fail-closed workflow mutations both fail as intended. - Base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2 is an ancestor of this head. No merge action taken.
lookout approved these changes 2026-08-26 02:40:33 +02:00
lookout left a comment

APPROVED — reviewed exact head a9563b4263 (base 56b90a6050).

The requested C5 correction is present: docs/architecture/contracts/cli-surface.md now documents rt decide as noop/cut/update/blocked. The complete pending-cut implementation remains sound:

  • go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint, shellcheck, and git diff --check pass.
  • bats tests/*.bats passes 61/61.
  • The exact pending-cut fixture and read-only rt decide --dry-run emit mode=blocked with pending version, prepare SHA, known flag, recovery action, and manifest evidence.
  • Focused #417/#650/#882 controls pass; the orphan-rescue and fail-closed workflow mutations both fail as intended.
  • Base 56b90a6050 is an ancestor of this head. No merge action taken.
APPROVED — reviewed exact head a9563b4263de0ae97661304661efee44143953a8 (base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2). The requested C5 correction is present: docs/architecture/contracts/cli-surface.md now documents rt decide as noop/cut/update/blocked. The complete pending-cut implementation remains sound: - go test -count=1 ./..., go vet ./..., go build ./..., golangci-lint, shellcheck, and git diff --check pass. - bats tests/*.bats passes 61/61. - The exact pending-cut fixture and read-only rt decide --dry-run emit mode=blocked with pending version, prepare SHA, known flag, recovery action, and manifest evidence. - Focused #417/#650/#882 controls pass; the orphan-rescue and fail-closed workflow mutations both fail as intended. - Base 56b90a6050d2efdfbe1236b36f89cb4fdcca01e2 is an ancestor of this head. No merge action taken.
Sign in to join this conversation.
No description provided.