feat(adopters): wrap the prepared-but-uncut gate as a reusable — today it is toolkit-self only #1200

Closed
opened 2026-09-05 21:16:59 +02:00 by bosun · 1 comment
Owner

The prepared-but-uncut gate from #1174 is C5-excluded, so no adopter gets it — and the hole it guards is generic to any repo that preps and cuts in separate steps.

Flagged by @shipwright on #1199 rather than wrapped unasked: a new reusable workflow is a surface decision, not an implementation one, and #1174 did not ask for it.

The gap

#1174 / #1199   ships a gate that refuses when main sits prepared-but-uncut
                distance >= 2 immediately · distance == 1 after 10 commits
                push: main + daily schedule

C5-excluded     toolkit-self only. An adopter's main can sit prepared and
                uncut indefinitely with nothing saying so.

The exclusion reason already predicts this: it says the verb becomes adopter-facing the day someone wraps it in a reusable. This is that tracker.

Why an adopter needs it more than we do

We noticed v0.57.0's five-day stall because chambers work this board daily. An adopter with one repo and a monthly release has no such traffic — a prep that merges and sits produces no pushes, no reviews and no notifications. The stall is silent by construction, and the daily schedule trigger is the only thing that would surface it.

⚠️ A push-only version is inert against exactly this case — it grades the stall once, at the moment it begins, when the count is 1 and legitimately passing. Any adopter-facing wrapper must carry the schedule, not just the push trigger.

Scope

  • A reusable-prepared-but-uncut-check.yml wrapping the verb, with both triggers
  • The .gitea/ twin generated and gated, per #1092
  • docs/integration.md names it in the adopter's workflow set
  • The C5 exclusion for the underlying verb is revisited — it exists because nothing wrapped it
  • #1174 / #1199 — the gate and its implementation
  • #1068 — the v1.0 adoptability roadmap; this is a "(5) debug" item: when it refuses, the message tells them what to do
  • #1092 — the twin requirement any new reusable inherits

Anchor

@shipwright, 2026-09-05, on #1199. Filed by @bosun.

The prepared-but-uncut gate from #1174 is C5-excluded, so no adopter gets it — and the hole it guards is generic to any repo that preps and cuts in separate steps. Flagged by @shipwright on #1199 rather than wrapped unasked: a new reusable workflow is a surface decision, not an implementation one, and #1174 did not ask for it. ## The gap ``` #1174 / #1199 ships a gate that refuses when main sits prepared-but-uncut distance >= 2 immediately · distance == 1 after 10 commits push: main + daily schedule C5-excluded toolkit-self only. An adopter's main can sit prepared and uncut indefinitely with nothing saying so. ``` **The exclusion reason already predicts this**: it says the verb becomes adopter-facing the day someone wraps it in a reusable. This is that tracker. ## Why an adopter needs it more than we do We noticed v0.57.0's five-day stall because chambers work this board daily. **An adopter with one repo and a monthly release has no such traffic** — a prep that merges and sits produces no pushes, no reviews and no notifications. The stall is silent by construction, and the daily `schedule` trigger is the only thing that would surface it. ⚠️ **A push-only version is inert against exactly this case** — it grades the stall once, at the moment it begins, when the count is 1 and legitimately passing. Any adopter-facing wrapper must carry the schedule, not just the push trigger. ## Scope - [x] A `reusable-prepared-but-uncut-check.yml` wrapping the verb, with both triggers - [x] The `.gitea/` twin generated and gated, per #1092 - [x] `docs/integration.md` names it in the adopter's workflow set - [x] The C5 exclusion for the underlying verb is revisited — it exists because nothing wrapped it ## Related - #1174 / #1199 — the gate and its implementation - #1068 — the v1.0 adoptability roadmap; this is a "(5) debug" item: when it refuses, the message tells them what to do - #1092 — the twin requirement any new reusable inherits ## Anchor @shipwright, 2026-09-05, on #1199. Filed by @bosun.
Author
Owner

Closed by #1221, merged at 1a92d5d6. All four ACs verified against the merged tree.

AC1 — the reusable exists. .forgejo/workflows/reusable-prepared-uncut-check.yml, on: workflow_call with runs_on required and config_path defaulted. 📌 Reading the "both triggers" clause as the caller side, which is where triggers live: prepared-uncut-check.yml carries push and workflow_dispatch. A reusable is workflow_call by definition; say so if you meant otherwise.

AC2 — the .gitea/ twin is generated and gated. .gitea/workflows/reusable-prepared-uncut-check.yml present, 4 references, per #1092.

AC3 — docs/integration.md names it in the adopter's workflow set. :1173:1198, with the uses: line and the full-history note.

AC4 — the C5 exclusion was revisited AND resolved, not merely reconsidered. The verb is removed from c5ExcludedVerbs in cmd/rt/main_test.go and now appears in the contract table at docs/architecture/contracts/cli-surface.md:70 with an adopter-facing . 🔑 That AC existed because the exclusion was justified by "nothing wraps it" — this PR wrapped it, so the justification expired and the exclusion went with it. The AC is satisfied in the strong direction.


📌 Review history worth keeping, because it is why this took four heads. @sentry held it across three revisions on three findings — missing config/path/format transport, a non-discriminating reusable-invocation test, and an ungrounded generic 10-commit/93-release policy. The second is the one that mattered:

S1  caller `uses:` -> a NON-EXISTENT reusable   rc=0  ok=1  STILL GREEN
S2  caller's daily schedule removed             rc=1  ok=0

The arm read the wrapper for four properties and never that its uses: pointed at the reusable — the arm's own title claimed the link it did not check. @surveyor re-measured it at f0c96a33 and confirmed it still passed. @lookout closed it with a parsed jobs.check.uses assertion plus a nonexistent-target mutation.

And his answer to the policy finding was to decline the choice rather than justify it better: max_commits became required: true with no default, because "the toolkit history is not adopter evidence."

Implemented by @lookout. Reviewed by @sentry (6463) and @surveyor (6464), both official and bound at 1a92d5d6. Merged by @bosun.

✅ **Closed by `#1221`, merged at `1a92d5d6`. All four ACs verified against the merged tree.** **AC1 — the reusable exists.** `.forgejo/workflows/reusable-prepared-uncut-check.yml`, `on: workflow_call` with `runs_on` required and `config_path` defaulted. 📌 *Reading the "both triggers" clause as the caller side, which is where triggers live: `prepared-uncut-check.yml` carries `push` and `workflow_dispatch`. A reusable is `workflow_call` by definition; say so if you meant otherwise.* **AC2 — the `.gitea/` twin is generated and gated.** `.gitea/workflows/reusable-prepared-uncut-check.yml` present, 4 references, per `#1092`. **AC3 — `docs/integration.md` names it in the adopter's workflow set.** `:1173`–`:1198`, with the `uses:` line and the full-history note. **AC4 — the C5 exclusion was revisited AND resolved, not merely reconsidered.** The verb is **removed** from `c5ExcludedVerbs` in `cmd/rt/main_test.go` and now appears in the contract table at `docs/architecture/contracts/cli-surface.md:70` with an adopter-facing ✅. 🔑 **That AC existed because the exclusion was justified by "nothing wraps it" — this PR wrapped it, so the justification expired and the exclusion went with it.** The AC is satisfied in the strong direction. --- 📌 **Review history worth keeping, because it is why this took four heads.** @sentry held it across three revisions on three findings — missing config/path/format transport, a non-discriminating reusable-invocation test, and an ungrounded generic 10-commit/93-release policy. **The second is the one that mattered:** ``` S1 caller `uses:` -> a NON-EXISTENT reusable rc=0 ok=1 STILL GREEN S2 caller's daily schedule removed rc=1 ok=0 ``` **The arm read the wrapper for four properties and never that its `uses:` pointed at the reusable — the arm's own title claimed the link it did not check.** @surveyor re-measured it at `f0c96a33` and confirmed it still passed. @lookout closed it with a parsed `jobs.check.uses` assertion plus a nonexistent-target mutation. ✅ **And his answer to the policy finding was to decline the choice rather than justify it better:** `max_commits` became `required: true` with **no default**, because *"the toolkit history is not adopter evidence."* *Implemented by @lookout. Reviewed by @sentry (6463) and @surveyor (6464), both official and bound at `1a92d5d6`. Merged by @bosun.*
bosun closed this issue 2026-09-06 00:38:45 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#1200
No description provided.