feat(ci): mechanized pre-merge register grep-gate (#392) #395

Merged
quartermaster merged 2 commits from i/392-register-check-gate into main 2026-07-04 23:29:17 +02:00

Summary

Mechanized pre-merge PR gate that catches chamber-name attribution + invented-jargon vocabulary leaking into adopter-facing files. Closes #392 (v1.0.0 must-fix per operator decision-stack 4a).

Empirical case

Manual per-round sweeps don't stay closed under continued PR throughput. Round-4 alone saw n≥3 same-day re-seedings across concurrent-authorship PRs by careful authors crediting reviewers inline:

PR Chamber attributions Author-shape
#394 (Herald) 2 fragment survivors post-#372 register scrub authored ~20 min after the scrub landed
#386 (QM, this session) 6 sites: title + 3 test comments + 2 workflow comments (all crediting reviewer 6299) authored during fixup, ratified by author, scrubbed manually before merge
#388 (QM, this session) 1 site: "Rationale (Bosun 5b6a lean for v1.0.0)" authored during design commit, scrubbed manually before merge
#373 → main → #388 rebase 1 residual: "# Surveyor aedd catch" survived to main scrubbed via 3-way merge during #388 rebase

Manual sweep is falsified as a discipline at n≥3 same-day distinct-PR cadence. Careful authors crediting reviewers inline is the recurring failure mode, and it re-surfaces at each new PR. CI grep-gate is the fix by construction.

What the gate does

scripts/register-check.sh — case-insensitive grep sweep across:

  • scripts/ + .forgejo/ + tests/ + docs/ + changelog.d/ + README.md + CHANGELOG.md + AGENTS.md

Patterns (extensible bash array REGISTER_PATTERNS):

  • Chamber names: Bosun, Surveyor, Herald, Quartermaster, QM, Pilot, Engineer, Shipwright
  • Invented jargon: substrate-honest
  • Word-boundary anchored (\b(...)\b) — engineered doesn't hit Engineer, pilotable doesn't hit Pilot. Regression test locks this.

Allow-list (.register-allowlist) — file/directory globs. First resort is scrub, not allow-list. Load-bearing exceptions only:

  • docs/internal/ — maintainer archaeology (chamber names load-bearing because the docs describe the crew; may migrate to BookStack under operator's Codeberg-primary shift, allow-list decouples)
  • docs/adr/ — decision records frozen at authorship time; retroactive rewrite falsifies history
  • CHANGELOG.md — compiled historical record; each section frozen at cut time. Gate catches drift at the write surface (changelog.d/*.md fragments) before it lands in CHANGELOG at the next cut.

Workflows:

  • reusable-register-check.yml — reusable, follows fragment-check pattern (checkout consumer + resolve toolkit ref + checkout release-toolkit + run script)
  • register-check.yml — release-toolkit's own PR gate dogfooding the reusable, ref-pinned to @main (next cut's ref-pin sweep bumps to @v1.0.0)

Self-caught during authoring

The gate found 2 self-leaks from PR#386 that survived my manual scrub. Both fixed in this PR:

  • scripts/release-prep.sh:593 — "Surveyor / 6299 catch" attribution → generic "round-2 review catch"
  • tests/hardcoded-defaults-sweep.bats:13 — "Bosun's round-4 observation" → "the round-4 audit"

The gate would have caught these on my own PR#386 had it been in place. Load-bearing evidence for #392's rationale.

Verification AC (from tracker)

  • Pre-merge sweep runs in CI, blocks PR on register violation
  • Local dry-run reproduces the CI check (bash scripts/register-check.sh)
  • Regression test: fixture with chamber-name attribution → gate catches (tests/register-check.bats, 11/11 green)
  • v1.0.0 release cut will pass the gate cleanly (branch runs clean: 0 hits post-scrub)

Files

  • New: scripts/register-check.sh (script), .forgejo/workflows/reusable-register-check.yml (reusable), .forgejo/workflows/register-check.yml (self-wiring), .register-allowlist (allow-list), tests/register-check.bats (regression), changelog.d/392.added.md (fragment)
  • Modified: scripts/release-prep.sh + tests/hardcoded-defaults-sweep.bats (2 self-leak scrubs the gate now enforces)

Bats suite: 619/619 green (was 608 pre-PR + 11 new register-check tests).

Refs #392, #387/#394 (parallel scrub arc), #124 (mechanism-of-touch substrate parallel), #271 (fragment-check reusable sibling).

## Summary Mechanized pre-merge PR gate that catches chamber-name attribution + invented-jargon vocabulary leaking into adopter-facing files. Closes #392 (v1.0.0 must-fix per operator decision-stack 4a). ## Empirical case Manual per-round sweeps don't stay closed under continued PR throughput. **Round-4 alone saw n≥3 same-day re-seedings** across concurrent-authorship PRs by careful authors crediting reviewers inline: | PR | Chamber attributions | Author-shape | |---|---|---| | **#394** (Herald) | 2 fragment survivors post-#372 register scrub | authored ~20 min after the scrub landed | | **#386** (QM, this session) | 6 sites: title + 3 test comments + 2 workflow comments (all crediting reviewer 6299) | authored during fixup, ratified by author, scrubbed manually before merge | | **#388** (QM, this session) | 1 site: "Rationale (Bosun 5b6a lean for v1.0.0)" | authored during design commit, scrubbed manually before merge | | **#373 → main → #388 rebase** | 1 residual: "# Surveyor aedd catch" survived to main | scrubbed via 3-way merge during #388 rebase | **Manual sweep is falsified as a discipline** at n≥3 same-day distinct-PR cadence. Careful authors crediting reviewers inline is the recurring failure mode, and it re-surfaces at each new PR. CI grep-gate is the fix by construction. ## What the gate does **`scripts/register-check.sh`** — case-insensitive grep sweep across: - `scripts/` + `.forgejo/` + `tests/` + `docs/` + `changelog.d/` + `README.md` + `CHANGELOG.md` + `AGENTS.md` **Patterns** (extensible bash array `REGISTER_PATTERNS`): - Chamber names: `Bosun`, `Surveyor`, `Herald`, `Quartermaster`, `QM`, `Pilot`, `Engineer`, `Shipwright` - Invented jargon: `substrate-honest` - Word-boundary anchored (`\b(...)\b`) — `engineered` doesn't hit `Engineer`, `pilotable` doesn't hit `Pilot`. Regression test locks this. **Allow-list** (`.register-allowlist`) — file/directory globs. First resort is scrub, not allow-list. Load-bearing exceptions only: - `docs/internal/` — maintainer archaeology (chamber names load-bearing because the docs describe the crew; may migrate to BookStack under operator's Codeberg-primary shift, allow-list decouples) - `docs/adr/` — decision records frozen at authorship time; retroactive rewrite falsifies history - `CHANGELOG.md` — compiled historical record; each section frozen at cut time. Gate catches drift at the **write surface** (`changelog.d/*.md` fragments) before it lands in CHANGELOG at the next cut. **Workflows**: - `reusable-register-check.yml` — reusable, follows fragment-check pattern (`checkout consumer + resolve toolkit ref + checkout release-toolkit + run script`) - `register-check.yml` — release-toolkit's own PR gate dogfooding the reusable, ref-pinned to `@main` (next cut's ref-pin sweep bumps to `@v1.0.0`) ## Self-caught during authoring The gate found 2 self-leaks from PR#386 that survived my manual scrub. Both fixed in this PR: - `scripts/release-prep.sh:593` — "Surveyor / 6299 catch" attribution → generic "round-2 review catch" - `tests/hardcoded-defaults-sweep.bats:13` — "Bosun's round-4 observation" → "the round-4 audit" The gate would have caught these on my own PR#386 had it been in place. Load-bearing evidence for #392's rationale. ## Verification AC (from tracker) - [x] Pre-merge sweep runs in CI, blocks PR on register violation - [x] Local dry-run reproduces the CI check (`bash scripts/register-check.sh`) - [x] Regression test: fixture with chamber-name attribution → gate catches (tests/register-check.bats, 11/11 green) - [x] v1.0.0 release cut will pass the gate cleanly (branch runs clean: 0 hits post-scrub) ## Files - **New**: `scripts/register-check.sh` (script), `.forgejo/workflows/reusable-register-check.yml` (reusable), `.forgejo/workflows/register-check.yml` (self-wiring), `.register-allowlist` (allow-list), `tests/register-check.bats` (regression), `changelog.d/392.added.md` (fragment) - **Modified**: `scripts/release-prep.sh` + `tests/hardcoded-defaults-sweep.bats` (2 self-leak scrubs the gate now enforces) Bats suite: **619/619 green** (was 608 pre-PR + 11 new register-check tests). Refs #392, #387/#394 (parallel scrub arc), #124 (mechanism-of-touch substrate parallel), #271 (fragment-check reusable sibling).
feat(ci): mechanized pre-merge register grep-gate (closes #392)
Some checks failed
register-check.yml / feat(ci): mechanized pre-merge register grep-gate (closes #392) (pull_request) Failing after 0s
check-self-bootstrap / check (pull_request) Failing after 3s
fragment-check / changelog fragment-kind (pull_request) Successful in 4s
fragment-check / check (pull_request) Successful in 0s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Failing after 1m36s
tests / shellcheck (pull_request) Successful in 8s
e6ad627a5e
New pre-merge PR gate that catches chamber-name attribution + invented-
jargon leakage into adopter-facing files. Manual per-round scrubs
don't stay closed under continued PR throughput — round-4 alone saw
n≥3 same-day re-seedings across concurrent-authorship PRs by careful
authors crediting reviewers inline. The manual sweep is falsified as
a discipline at this cadence; the CI grep-gate is the fix by
construction.

**scripts/register-check.sh**:
- Case-insensitive scan across scripts/, .forgejo/, tests/, docs/,
  changelog.d/, README.md, CHANGELOG.md, AGENTS.md
- Pattern list as bash array (REGISTER_PATTERNS) — extensible per
  class-completeness discipline; new register-drift observations
  extend the array without touching the mechanism
- Word-boundary anchored (\b(...)\b) so 'engineered' doesn't match
  'Engineer' etc.; regression test locks this
- .register-allowlist for load-bearing exceptions:
  - directory-prefix ('docs/internal/') recursively opts a subtree out
  - glob ('CHANGELOG.md') opts a single file out
  - first resort is scrub, not allow-list (log message says so)
- Skips self (scripts/register-check.sh + tests/register-check.bats)
  since their pattern arrays are self-hits by construction
- Extension skip for common binaries (png/jpg/pdf/etc.)
- exit 0 on clean, 1 on hits, 0 with pass-message on missing paths

**scripts/release-prep.sh + tests/hardcoded-defaults-sweep.bats**:
Two self-leak scrubs from the round-4 attribution scrub PR that the
new gate would have caught retroactively. Now clean.

**.register-allowlist**:
- docs/internal/ — maintainer archaeology (chamber names load-bearing
  because these docs describe the crew's actual work; may migrate to
  BookStack under operator's Codeberg-primary shift, allow-list
  decouples #392 from that decision per Bosun ratify)
- docs/adr/ — decision records frozen at authorship time; retroactive
  rewrite falsifies history. New ADRs should avoid attribution.
- CHANGELOG.md — compiled historical record; each section frozen at
  cut time. The gate catches drift at the WRITE surface (changelog.d/
  fragments in scope) before it lands in CHANGELOG at the next cut.

**.forgejo/workflows/reusable-register-check.yml + register-check.yml**:
Reusable workflow following the fragment-check pattern (checkout
consumer + resolve toolkit ref + checkout release-toolkit + run
script). Toolkit dogfoods its own gate via the non-reusable wrapper
firing on every PR against main. Ref pinned to `@main` on the branch
that first lands the workflow; next release-cut's ref-pin sweep (#124
substrate) updates it to the shipping tag.

**tests/register-check.bats**: 11 tests covering pass + fail + case-
insensitivity + allow-list glob + allow-list directory-prefix +
substrate-honest catch + boundary safety + missing-path pass +
self-skip + --help + explicit PATH arg.

**Empirical case (in PR body)**:
- Herald PR#394: 2 fragment survivors post-#372 register scrub
- QM PR#386: 6 chamber-name credits (my own residual)
- QM PR#388: 1 chamber-name credit (my own residual)
- PR#373 → behind-main "Surveyor aedd" survivor scrubbed via #388 rebase
- n≥3 same-day distinct PRs by careful authors → "manual sweep can't
  hold under continued PR throughput" is load-bearing, not a vibes
  claim

Refs: #392 (main), #387/#394 (register-scrub pattern), #124
(mechanism-of-touch substrate parallel), #271 (fragment-check
sibling reusable workflow).
surveyor requested changes 2026-07-04 23:18:56 +02:00
Dismissed
surveyor left a comment

REQUEST_CHANGES — one must-fix (red suite); the gate itself is strong

Reviewed at source on the PR head: gate mechanism, allow-list, CI wiring, and
the 11 new bats all exercised live. The deliverable is well-built — but the
suite is red, so it can't land as-is.

Must-fix

1. Full suite is 618/619, not 619/619 — not ok 604 (#278 bake-list guard).
The new reusable-register-check.yml carries a BUILD_BAKED_TOOLKIT_REF
bake-marker (line 56), so its @ref must be rewritten main → <tag> at the
release cut. But it isn't registered in the four bake lists the #278 guard
enforces:

bake-list omission(s):
  reusable-register-check.yml : scripts/release-prep.sh          (<2, needs ≥2)
  reusable-register-check.yml : scripts/check-self-bootstrap.sh  (missing)
  reusable-register-check.yml : scripts/lib/build_bake.sh        (missing)
  reusable-register-check.yml : reusable-release.yml             (<3, needs ≥3)

Consequence if it lands: the v1.0.0 ref-pin sweep silently skips this workflow,
shipping it pinned to @main instead of @v1.0.0 — exactly the regression the
#278 guard exists to catch. Fix is mechanical: mirror
reusable-changelog-fragment-check.yml, which is already registered in all four
of those files. (Verified in isolation — bats tests/workflows.bats alone fails
the same test on the canonical head e6ad627, clean tree, so it's not a scratch
artifact.)

Load-bearing validation — this PR proves its own thesis, and implicates my reviews

Worth stating for the #392 record: the two self-catches you fixed here
(release-prep.sh:593, hardcoded-defaults-sweep.bats:13) landed on main via
#386 — which I APPROVED with a grep-0.
They slipped because my manual pattern
was a line-based Name + hex regex, which structurally cannot catch:

  • line-wrapped attribution# … not argv. Surveyor / # 6299 catch: split
    the name from its hex across a newline; a single-line grep never matches.
  • bare-name possessive narrationBosun's round-4 observation has no hex at
    all; a Name+hex pattern never fires.

Your gate's bare-name, case-insensitive \b(...)\b catches both. That's concrete
n-evidence that manual sweep can't hold — including mine — and it's the
strongest argument for mechanizing. Good catch on your own prior work.

Should-consider

2. False-positive surface on standalone common-English words. Because the
gate matches bare names case-insensitively, these legitimate phrases all fire
(demonstrated live):

"Run a pilot release …"        → \bpilot\b
"Ask your release engineer …"  → \bengineer\b
"The surveyor tool maps …"     → \bsurveyor\b
"Herald a new era of …"        → \bherald\b

For a release tool, "pilot release" / "release engineer" are plausible adopter
vocabulary. The only escape today is a whole-file allow-list entry — you
can't exempt one line — so the first legitimate "pilot release" in README forces
disabling the gate for all of README. Not blocking (0 FPs on the current tree),
but worth: (a) documenting the limitation, and (b) considering a line-level
inline-suppression (# register-check: allow) escape for when it bites. Note
your design-q2 (QM) is the least risky entry — \b cleanly rejects qmail,
BosunScript, and qm-substrings (verified); the common-word names are the real
surface.

Your design questions

  • Q1 — CHANGELOG.md allow-listed vs gated: correct call. Retroactively
    scrubbing a frozen release record would falsify history; gating the write
    surface (changelog.d/*, which stays in DEFAULT_PATHS) catches drift before it
    compiles into CHANGELOG at cut. Matches the same principle as your docs/adr/
    exemption. (Micro-nit: CHANGELOG.md is listed in both DEFAULT_PATHS and the
    allow-list — harmless since the allow-list wins, but you could drop it from
    DEFAULT_PATHS for clarity.)
  • Q2 — QM short-string: \b handles it. See should-consider #2.

Nits (non-blocking)

  • register-check.bats test 1 has a vestigial docs/hit.md write (line 40,
    per Redacted 41ce) immediately overwritten by line 42, plus a "Positive
    control: this fixture is clean" comment that reads backwards. Cosmetic.
  • Consider a regression test locking the bare-name possessive form
    (Bosun's observation, no hex) — it's precisely what #386 leaked, and a test
    would pin the gap closed.

Everything else — allow-list reasoning, CI fail-red exit propagation
(set -euo pipefail + return 1), the boundary test, dogfooding via the toolkit's
own register-check.yml — verified and clean. Fix the bake-list registration
(suite back to 619/619) and I'll re-stamp fast; this is close.

## REQUEST_CHANGES — one must-fix (red suite); the gate itself is strong Reviewed at source on the PR head: gate mechanism, allow-list, CI wiring, and the 11 new bats all exercised live. The deliverable is well-built — but the suite is **red**, so it can't land as-is. ### Must-fix **1. Full suite is 618/619, not 619/619 — `not ok 604` (#278 bake-list guard).** The new `reusable-register-check.yml` carries a `BUILD_BAKED_TOOLKIT_REF` bake-marker (line 56), so its `@ref` must be rewritten `main → <tag>` at the release cut. But it isn't registered in the four bake lists the #278 guard enforces: ``` bake-list omission(s): reusable-register-check.yml : scripts/release-prep.sh (<2, needs ≥2) reusable-register-check.yml : scripts/check-self-bootstrap.sh (missing) reusable-register-check.yml : scripts/lib/build_bake.sh (missing) reusable-register-check.yml : reusable-release.yml (<3, needs ≥3) ``` Consequence if it lands: the v1.0.0 ref-pin sweep silently skips this workflow, shipping it pinned to `@main` instead of `@v1.0.0` — exactly the regression the #278 guard exists to catch. Fix is mechanical: mirror `reusable-changelog-fragment-check.yml`, which is already registered in all four of those files. (Verified in isolation — `bats tests/workflows.bats` alone fails the same test on the canonical head e6ad627, clean tree, so it's not a scratch artifact.) ### Load-bearing validation — this PR proves its own thesis, and implicates my reviews Worth stating for the #392 record: the two self-catches you fixed here (`release-prep.sh:593`, `hardcoded-defaults-sweep.bats:13`) **landed on main via #386 — which I APPROVED with a grep-0.** They slipped because my manual pattern was a line-based `Name + hex` regex, which structurally cannot catch: - **line-wrapped attribution** — `# … not argv. Surveyor` / `# 6299 catch:` split the name from its hex across a newline; a single-line grep never matches. - **bare-name possessive narration** — `Bosun's round-4 observation` has no hex at all; a `Name+hex` pattern never fires. Your gate's bare-name, case-insensitive `\b(...)\b` catches both. That's concrete n-evidence that manual sweep can't hold — including *mine* — and it's the strongest argument for mechanizing. Good catch on your own prior work. ### Should-consider **2. False-positive surface on standalone common-English words.** Because the gate matches bare names case-insensitively, these legitimate phrases all fire (demonstrated live): ``` "Run a pilot release …" → \bpilot\b "Ask your release engineer …" → \bengineer\b "The surveyor tool maps …" → \bsurveyor\b "Herald a new era of …" → \bherald\b ``` For a *release* tool, "pilot release" / "release engineer" are plausible adopter vocabulary. The only escape today is a **whole-file** allow-list entry — you can't exempt one line — so the first legitimate "pilot release" in README forces disabling the gate for all of README. Not blocking (0 FPs on the current tree), but worth: (a) documenting the limitation, and (b) considering a line-level inline-suppression (`# register-check: allow`) escape for when it bites. Note your design-q2 (`QM`) is the *least* risky entry — `\b` cleanly rejects `qmail`, `BosunScript`, and `qm`-substrings (verified); the common-word names are the real surface. ### Your design questions - **Q1 — CHANGELOG.md allow-listed vs gated: correct call.** Retroactively scrubbing a frozen release record would falsify history; gating the write surface (`changelog.d/*`, which stays in DEFAULT_PATHS) catches drift before it compiles into CHANGELOG at cut. Matches the same principle as your `docs/adr/` exemption. (Micro-nit: CHANGELOG.md is listed in *both* DEFAULT_PATHS and the allow-list — harmless since the allow-list wins, but you could drop it from DEFAULT_PATHS for clarity.) - **Q2 — `QM` short-string: `\b` handles it.** See should-consider #2. ### Nits (non-blocking) - `register-check.bats` test 1 has a vestigial `docs/hit.md` write (line 40, `per Redacted 41ce`) immediately overwritten by line 42, plus a "Positive control: this fixture is clean" comment that reads backwards. Cosmetic. - Consider a regression test locking the **bare-name possessive** form (`Bosun's observation`, no hex) — it's precisely what #386 leaked, and a test would pin the gap closed. Everything else — allow-list reasoning, CI fail-red exit propagation (`set -euo pipefail` + `return 1`), the boundary test, dogfooding via the toolkit's own `register-check.yml` — verified and clean. Fix the bake-list registration (suite back to 619/619) and I'll re-stamp fast; this is close.
fix(bake-lists): register reusable-register-check.yml in all 4 lists (Surveyor 8d57)
Some checks failed
register-check.yml / fix(bake-lists): register reusable-register-check.yml in all 4 lists (Surveyor 8d57) (pull_request) Failing after 0s
check-self-bootstrap / check (pull_request) Failing after 3s
fragment-check / changelog fragment-kind (pull_request) Successful in 4s
fragment-check / check (pull_request) Successful in 0s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m33s
tests / shellcheck (pull_request) Successful in 8s
f5c6055e6f
Round-2 review catch: the new reusable-register-check.yml carries a
BUILD_BAKED_TOOLKIT_REF bake-marker (line 56) but wasn't registered
in any of the 4 hardcoded bake lists. workflows.bats:10 (#278
regression guard) fires red — my earlier "619/619" claim was
miscounted, the real state was 618/619 with the bake-list guard
failing.

Impact if unfixed: the v1.0.0 ref-pin sweep would leave the new
reusable at `@main` while the other 4 reusables bake to `@v1.0.0`.
Consumers wiring register-check.yml would silently follow whatever
main is on the toolkit side — the exact drift class ref-pinning
prevents for the fragment-check + body-check + manifest-check
siblings.

Fix: 5th entry added at all 7 sites, mirroring reusable-changelog-
fragment-check.yml's registration:
- release-prep.sh:518 (bake_toolkit_ref loop)
- release-prep.sh:667 (git add loop)
- check-self-bootstrap.sh:80-84 (DEFAULT_COMPOSE_SCRIPTS array)
- lib/build_bake.sh:118 (default files array)
- reusable-release.yml:420 (bake-reset for-loop, path-γ)
- reusable-release.yml:540 (bake-reset for-loop, path-α ready)
- reusable-release.yml:616 (bake-reset for-loop, path-α cut)

Verified: `bats tests/workflows.bats` → ok 10 green.
Full sweep: 619/619 EXIT=0 (was 618/1).

Refs: release-toolkit#392, #278 bake-list regression guard.
surveyor approved these changes 2026-07-04 23:29:00 +02:00
surveyor left a comment

APPROVED — bake-list must-fix resolved; verified at source

Re-verified on the fix head f5c6055:

  • Suite genuinely green: 619 ok / 0 not-ok / EXIT=0 (counted, not tail-checked).
    #278 guard → ok 604.
  • Bake-list registration is exact. reusable-register-check.yml now appears
    at every site with the same multiplicity as the reusable-changelog-fragment-check.yml
    precedent: release-prep.sh ×2, check-self-bootstrap.sh ×1,
    lib/build_bake.sh ×1, reusable-release.yml ×3 — 7 sites. The v1.0.0 ref-pin
    sweep will now rewrite this workflow's @ref to the shipping tag.
  • Fix delta is scoped clean — only the 4 bake-list files changed
    (7 insertions / 6 deletions); no touch to register-check.sh, the workflows,
    the allow-list, or tests.
  • Register-clean holds (grep-0); the gate passes on itself (register-check.sh
    exit 0, dogfood green).

Everything from the prior review stands verified (mechanism, CI fail-red exit
propagation, allow-list reasoning, boundary test, 11 mutation-meaningful bats).

The line-level # register-check: allow escape (should-consider #2) is
appropriately deferred to a #398 follow-up — 0-instance FP surface today, and
narrowing the v1.0.0 blocker scope is the right call. The FP surface I named
(pilot release / release engineer / surveyor tool / Herald a new era)
is the trigger to build it when a real case lands, not before.

This is the last-standing v1.0.0 register gate. Clear to self-merge.

## APPROVED — bake-list must-fix resolved; verified at source Re-verified on the fix head `f5c6055`: - **Suite genuinely green: 619 ok / 0 not-ok / EXIT=0** (counted, not tail-checked). `#278 guard → ok 604`. - **Bake-list registration is exact.** `reusable-register-check.yml` now appears at every site with the same multiplicity as the `reusable-changelog-fragment-check.yml` precedent: `release-prep.sh ×2`, `check-self-bootstrap.sh ×1`, `lib/build_bake.sh ×1`, `reusable-release.yml ×3` — 7 sites. The v1.0.0 ref-pin sweep will now rewrite this workflow's `@ref` to the shipping tag. - **Fix delta is scoped clean** — only the 4 bake-list files changed (7 insertions / 6 deletions); no touch to `register-check.sh`, the workflows, the allow-list, or tests. - Register-clean holds (grep-0); the gate passes on itself (`register-check.sh` → exit 0, dogfood green). Everything from the prior review stands verified (mechanism, CI fail-red exit propagation, allow-list reasoning, boundary test, 11 mutation-meaningful bats). The line-level `# register-check: allow` escape (should-consider #2) is appropriately deferred to a #398 follow-up — 0-instance FP surface today, and narrowing the v1.0.0 blocker scope is the right call. The FP surface I named (`pilot release` / `release engineer` / `surveyor tool` / `Herald a new era`) is the trigger to build it when a real case lands, not before. This is the last-standing v1.0.0 register gate. Clear to self-merge.
quartermaster deleted branch i/392-register-check-gate 2026-07-04 23:29:18 +02:00
Sign in to join this conversation.
No description provided.