feat(gates): a refusal should name the repair, not just the discrepancy #1077

Closed
opened 2026-08-29 16:19:15 +02:00 by bosun · 2 comments
Owner

When a gate refuses, it names the discrepancy and not the repair. An adopter reading tag points at X but last_released_sha is Y has no way to know what to do next.

We spent an afternoon on exactly that: four candidate repairs tested against the shipped check before one was viable, and a fifth that passed the check while making the next cut wrong. An adopter has none of that context.

Scope

Refusals an adopter can actually reach. manifest_check.go has 22 fail() sites and most are toolkit-self; those are not on the road. Eight done properly and four named beats 22 done mechanically.

post_cut is in scope. This is about refusals naming repairs, not about one file — and the absent-manifest case is the first one an adopter hits, on their first cut.

The conditioning that makes this correct

bake-digest is invoked only by our own goreleaser.yml, never by reusable-release.yml, which is the wrapper adopters get. So TagPinsDigest can explain that failure as a digest-pin case only on this repo. An adopter reaching manifest_check.go:321 sees plain, unexplained drift.

this repo   "re-run the release for tag X"   (the rebuild; it invokes the unwind internally)
adopter     "the tag points somewhere other than the recorded sha — verify nothing
             unexpected landed on it"

Offering an adopter the specific repair would leak toolkit-self context into an adopter-facing message, which is the defect this tracker exists to remove.

AC

  • Each adopter-reachable refusal names its condition and the repair, or states that none exists
  • The repair named is one an adopter can run — never an internal verb
  • Toolkit-self-only explanations are conditioned, not emitted to adopters
  • Ambiguous sites are listed rather than guessed at
  • Where a legitimate condition is overridden, follow #1019's shape: a NAMED per-case flag

On the override question

The operator asked whether a "known outage" override belongs here, and refined it himself to a workflow-level flag rather than a repo variable — a variable set during an outage is one nobody unsets. That refinement is the whole distinction: a per-run dispatch input cannot persist. Our own record: a correct refusal left a chamber's rotation half-finished for 29 days because nothing retried it. No general skip.

Sequencing

--allow-first-manifest is landed in #1074; the unreadable-config follow-up is #1086. Neither is duplicated here.

Corrections in this body are @pilot's, from reading the code rather than the tracker: the 22-vs-3 count, post_cut being outside the original wording, the toolkit-self conditioning, and that #1074 was unmerged when the tracker was written; it is now landed. The original version named an internal verb as an adopter repair — the failure this tracker describes, inside the tracker.

When a gate refuses, it names the discrepancy and not the repair. An adopter reading `tag points at X but last_released_sha is Y` has no way to know what to do next. We spent an afternoon on exactly that: four candidate repairs tested against the shipped check before one was viable, and a fifth that passed the check while making the next cut wrong. An adopter has none of that context. ## Scope Refusals **an adopter can actually reach**. `manifest_check.go` has 22 `fail()` sites and most are toolkit-self; those are not on the road. Eight done properly and four named beats 22 done mechanically. `post_cut` is in scope. This is about refusals naming repairs, not about one file — and the absent-manifest case is the first one an adopter hits, on their first cut. ## The conditioning that makes this correct `bake-digest` is invoked only by our own `goreleaser.yml`, never by `reusable-release.yml`, which is the wrapper adopters get. So `TagPinsDigest` can explain that failure as a digest-pin case **only on this repo**. An adopter reaching `manifest_check.go:321` sees plain, unexplained drift. ``` this repo "re-run the release for tag X" (the rebuild; it invokes the unwind internally) adopter "the tag points somewhere other than the recorded sha — verify nothing unexpected landed on it" ``` Offering an adopter the specific repair would leak toolkit-self context into an adopter-facing message, which is the defect this tracker exists to remove. ## AC - [x] Each adopter-reachable refusal names its condition and the repair, or states that none exists - [x] The repair named is one an adopter can run — never an internal verb - [x] Toolkit-self-only explanations are conditioned, not emitted to adopters - [x] Ambiguous sites are listed rather than guessed at - [x] Where a legitimate condition is overridden, follow #1019's shape: a NAMED per-case flag ## On the override question The operator asked whether a "known outage" override belongs here, and refined it himself to a **workflow-level flag rather than a repo variable** — a variable set during an outage is one nobody unsets. That refinement is the whole distinction: a per-run dispatch input cannot persist. Our own record: a correct refusal left a chamber's rotation half-finished for 29 days because nothing retried it. No general skip. ## Sequencing `--allow-first-manifest` is **landed** in #1074; the unreadable-config follow-up is #1086. Neither is duplicated here. Corrections in this body are @pilot's, from reading the code rather than the tracker: the 22-vs-3 count, `post_cut` being outside the original wording, the toolkit-self conditioning, and that #1074 was unmerged when the tracker was written; it is now landed. The original version named an internal verb as an adopter repair — the failure this tracker describes, inside the tracker.
Owner

AC verification after release-toolkit PR #1078 merged at 9a09987eb0: all five criteria are DONE. Sentry review 6228 was official, non-stale, and exact-head-bound to 852500cc22; it verified the adopter-facing refusal/repair wording, toolkit-self conditioning, ambiguous-site handling, the #1019 named per-case override shape, and the inverse/mutation evidence. The tracker sequencing note now records #1074 and #1086 as landed.

AC verification after release-toolkit PR #1078 merged at 9a09987eb0688acc09692ccc74166d6fcd258704: all five criteria are DONE. Sentry review 6228 was official, non-stale, and exact-head-bound to 852500cc220e231f81ec2f16de3e5078887f8b90; it verified the adopter-facing refusal/repair wording, toolkit-self conditioning, ambiguous-site handling, the #1019 named per-case override shape, and the inverse/mutation evidence. The tracker sequencing note now records #1074 and #1086 as landed.
Owner

Record correction completed: the #1077 sequencing paragraph now renders Markdown bold correctly and the closing historical note says #1074 was unmerged only when this tracker was written. AC state and merge evidence are unchanged.

Record correction completed: the #1077 sequencing paragraph now renders Markdown bold correctly and the closing historical note says #1074 was unmerged only when this tracker was written. AC state and merge evidence are unchanged.
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#1077
No description provided.