feat: structural backstop for self-bootstrap re-pin trigger (mechanism-of-touch CI check) #124

Closed
opened 2026-06-26 18:05:23 +02:00 by quartermaster · 0 comments

Why

Per Surveyor 116b (PR #123 review): the self-bootstrap re-pin pattern (AGENTS.md §2 mechanism-of-touch criterion) has the right discipline in principle, but at-action-time engagement has slipped twice in a row:

  • v0.8.0 cut: hit OWNER-unbound (the manifest-update step's path-α/γ split introduced in ADR-0007 left OWNER/REPO γ-scoped). Fix landed in v0.8.1 sprint #119.
  • v0.9.0 cut: hit the SAME OWNER-unbound (same code path, same fix exists on main, but the consumer-side pin still pointed at @v0.8.0-rc.1 — pre-fix code). Re-pinned in #123 after the fact.

The pattern surfacing twice with the same root cause (compose-script-fix on main + not in pinned ref) means the discipline is sound but the engagement-at-action-time is the missing piece. Surveyor's framing: "A manual step missed twice is a candidate for a structural backstop."

Proposed: mechanism-of-touch CI check

A check workflow that fails red when the consumer's release.yml pinned @toolkit_ref is behind a compose-script change on main that hasn't been incorporated into a *-rc.N tag yet. Specifically:

  1. On every PR to main that touches _release.yml / release-decide.sh / release-prep.sh / draft-release.sh / fragments.sh / changelog.sh / forgejo-api.sh / manifest-check.sh:
    • Surface a warning that "this PR touches a compose-script; a self-bootstrap re-pin will be needed BEFORE the next cut"
  2. On main:
    • The check fails if _release.yml's pinned @v<X.Y.Z>-rc.N ref's compose-scripts differ from main's HEAD compose-scripts (i.e., main has substrate-changes the pinned ref doesn't include)
  3. The check passing requires either:
    • A fresh *-rc.N tag at main's HEAD that includes the substrate-changes, AND
    • Consumer-side release.yml re-pinned to that fresh ref

Alternative considered

Auto-re-pin trigger (workflow that opens a re-pin PR automatically when compose-scripts merge to main): more machinery, more failure modes, harder to reason about timing relative to the cut sequence. The check-and-fail approach is simpler — surfaces the problem, lets operator engage.

Implementation surface

  • New .forgejo/workflows/check-self-bootstrap-rc-tag.yml workflow
  • New scripts/check-self-bootstrap.sh doing the comparison (also bats-testable directly)
  • Compose-script glob is configurable in release-toolkit.yml (default to the existing list)
  • The check fires on PR + on push:main

What this would have prevented

  • The v0.9.0 cut's OWNER-unbound workflow-failure (would have failed PR CI on #119's merge: "you touched _release.yml; tag a new rc.N and re-pin before next cut")
  • Future repeat-bugs of the same shape

Worth banking calibration

Surveyor's framing in 116b: "discipline-EXISTING ≠ discipline-ENGAGING at action-time". When a sound discipline keeps slipping at engagement, the structural backstop converts it from a manual remember-to-do into an automated check-or-fail.

Worth banking this as a META-pattern across the toolkit's discipline-pin framework: every discipline that catches X bugs in N action-times has a candidate structural backstop. Most don't need automation; the ones that slip multiple times do.

Refs

  • Surfacing: Surveyor 116b advisory on PR #123 (the re-pin that closes the v0.9.0 instance of the same gap)
  • Prior instances: v0.8.0 cut OWNER-unbound (#119 fix), v0.9.0 cut OWNER-unbound (this PR's re-pin)
  • Pattern: AGENTS.md §2 (mechanism-of-touch self-bootstrap re-pin); §10 forward-prediction (clean cuts as prior, divergence as signal — including divergence from operator-engagement-discipline)
  • Sequencing: not blocking; substantive design + implementation work for a future sprint (v0.10.x?)
## Why Per Surveyor 116b (PR #123 review): the self-bootstrap re-pin pattern (AGENTS.md §2 mechanism-of-touch criterion) has the right discipline _in principle_, but at-action-time engagement has slipped twice in a row: - **v0.8.0 cut**: hit OWNER-unbound (the manifest-update step's path-α/γ split introduced in ADR-0007 left OWNER/REPO γ-scoped). Fix landed in v0.8.1 sprint #119. - **v0.9.0 cut**: hit the SAME OWNER-unbound (same code path, same fix exists on main, but the consumer-side pin still pointed at `@v0.8.0-rc.1` — pre-fix code). Re-pinned in #123 after the fact. The pattern surfacing twice with the same root cause (compose-script-fix on main + not in pinned ref) means the discipline is sound but the engagement-at-action-time is the missing piece. Surveyor's framing: "A manual step missed twice is a candidate for a structural backstop." ## Proposed: mechanism-of-touch CI check A check workflow that **fails red** when the consumer's `release.yml` pinned `@toolkit_ref` is behind a compose-script change on `main` that hasn't been incorporated into a `*-rc.N` tag yet. Specifically: 1. On every PR to `main` that touches `_release.yml` / `release-decide.sh` / `release-prep.sh` / `draft-release.sh` / `fragments.sh` / `changelog.sh` / `forgejo-api.sh` / `manifest-check.sh`: - Surface a warning that "this PR touches a compose-script; a self-bootstrap re-pin will be needed BEFORE the next cut" 2. On `main`: - The check fails if `_release.yml`'s pinned `@v<X.Y.Z>-rc.N` ref's compose-scripts differ from main's HEAD compose-scripts (i.e., main has substrate-changes the pinned ref doesn't include) 3. The check passing requires either: - A fresh `*-rc.N` tag at main's HEAD that includes the substrate-changes, AND - Consumer-side `release.yml` re-pinned to that fresh ref ## Alternative considered **Auto-re-pin trigger** (workflow that opens a re-pin PR automatically when compose-scripts merge to main): more machinery, more failure modes, harder to reason about timing relative to the cut sequence. The check-and-fail approach is simpler — surfaces the problem, lets operator engage. ## Implementation surface - New `.forgejo/workflows/check-self-bootstrap-rc-tag.yml` workflow - New `scripts/check-self-bootstrap.sh` doing the comparison (also bats-testable directly) - Compose-script glob is configurable in `release-toolkit.yml` (default to the existing list) - The check fires on PR + on push:main ## What this would have prevented - The v0.9.0 cut's OWNER-unbound workflow-failure (would have failed PR CI on #119's merge: "you touched _release.yml; tag a new rc.N and re-pin before next cut") - Future repeat-bugs of the same shape ## Worth banking calibration Surveyor's framing in 116b: **"discipline-EXISTING ≠ discipline-ENGAGING at action-time"**. When a sound discipline keeps slipping at engagement, the structural backstop converts it from a manual remember-to-do into an automated check-or-fail. Worth banking this as a META-pattern across the toolkit's discipline-pin framework: every discipline that catches X bugs in N action-times has a candidate structural backstop. Most don't need automation; the ones that slip multiple times do. ## Refs - **Surfacing**: Surveyor 116b advisory on PR #123 (the re-pin that closes the v0.9.0 instance of the same gap) - **Prior instances**: v0.8.0 cut OWNER-unbound (#119 fix), v0.9.0 cut OWNER-unbound (this PR's re-pin) - **Pattern**: AGENTS.md §2 (mechanism-of-touch self-bootstrap re-pin); §10 forward-prediction (clean cuts as prior, divergence as signal — including divergence from operator-engagement-discipline) - **Sequencing**: not blocking; substantive design + implementation work for a future sprint (v0.10.x?)
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#124
No description provided.