Repository navigation
[Phase 2] SC2 regression guard: assert self-review duty stays pinned to a stable channel #1624
Description
Story
As a release manager,
I want an automated assertion that this repo's own agentic review/merge duty runs a stable-tier channel pin,
so that SC2 (a broken in-dev version cannot block its own fix PR) is enforced continuously rather than proven once in a drill and left to erode.
Why this is the automatable half of #503
#503 is the SC2 game-day: ship a deliberately broken next and prove the fix PR still merges. Its "Done when" has two halves — demonstrated (a human drill, which stays on #503) and a regression test asserts the circular dependency stays broken (this issue).
The structural property already holds today. The pinned-version-report run 33409266607 (2026-08-31) shows this repo — which sits in ring next — pinning its own duty agents to stable-tier channels:
.github-private | dev-lead | next | v1-stable | v139.2.0 | (flagged: ring expects next)
.github-private | agent-shield | next | v2-stable | v2.1.2 | (flagged: ring expects next)
The report flags these as ring mismatches, but for the self-hosted review/merge path that is exactly the SC2 property: production duty in the development repo runs stable, so a broken next cannot block its own fix. It is currently undocumented and untested, so nothing stops a well-meaning "fix the drift" PR from repinning dev-lead to v1-next and silently restoring the circular dependency.
Acceptance Criteria
- A bats test asserts that this repo's self-review-duty caller stubs (at minimum
dev-lead.yml; includepr-review's stub if it pins a first-party reusable) resolve to a stable-tier channel — nevernext,ring0,@main, or a bare SHA. - The assertion is written against the stub's
uses:pin (parse the@<agent>/<channel>ref), not against a hardcoded version, so cutting a new release does not break it. - The test fails with a message that names SC2 and explains why a
nextpin here is a regression — so a future contributor "fixing the ring drift" is told the constraint rather than deleting the test. - The intentional-exception is documented:
docs/initiatives/agentic-release-strategy.md(or the versioning doc) records that.github-private's stable pin for self-review duty is a deliberate SC2 requirement, and cross-references thepinned-version-reportring-mismatch flag so the two surfaces do not contradict each other. - The test is registered in the existing bats job;
shellcheck --severity=warning -xstays clean.
Tasks / Subtasks
- Add the stub-pin parse + stable-tier assertion as a bats test (AC: test issue from agent #1, Go-live improvements for PR review agent #2)
- Write the failure message to explain the SC2 constraint (AC: Add @claude delegation, auto-merge, and rebase handling #3)
- Document the deliberate exception and cross-reference the ring-mismatch flag (AC: Optimize review: small-PR and incremental fast paths #4)
- Register the test and confirm shellcheck (AC: feat: add Copilot engine support via REVIEW_ENGINE toggle #5)
Dev Notes
- Follow the repo's sourceable-helper + fixture bats convention (see
tests/template_stub_drift.bats): parse the pin from a fixture stub, assert over it, no network. - Do not repin anything. This issue asserts the current state is preserved; it does not change any pin.
- Treat "stable-tier" as the channel tier, not a literal string —
v1-stableandstableboth qualify;v1-nextandnextdo not. The tier vocabulary is instandards/ci-standards.md(Reusable workflow versioning) andscripts/lib/ring-pins.sh. - The
pinned-version-reportflags these pins as⚠️ ring mismatches. That flag is correct from the ring-rollout perspective and this test is correct from the SC2 perspective; AC4 exists so the contradiction is written down rather than rediscovered.
References
docs/initiatives/agentic-release-strategy.md(SC2)scripts/pinned-version-report.sh(petry-projects/.github)tests/template_stub_drift.bats
Activity
don-petry commentedon Sep 1, 2026
Dev-Lead Implementation Plan
Issue: #1624 — [Phase 2] SC2 regression guard: assert self-review duty stays pinned to a stable channel
Scope
Add a bats regression guard that parses the
uses:channel pin of this repo's self-review/dev-duty caller stub (dev-lead.yml) and asserts it resolves to a stable-tier channel (nevernext/ring*/@main/bare SHA), with an SC2-naming failure message, plus documenting the deliberate stable-pin exception and reconciling it with thepinned-version-reportring-mismatch flag.Key design decision (pr-review scope)
AC1 says "include
pr-review's stub if it pins a first-party reusable."pr-review-trigger.ymldoes pin a first-party reusable — but to@pr-review/v1-next, the deliberate ring-0 canary (per its header +versioning.md). Its SC2 safety net is the break-glass (sc2-game-day.mdmechanism 2), not channel decoupling. Asserting it "stable" would fail current state and violate the "do not repin / preserve current state" Dev Note. So the stable assertion targetsdev-lead.yml(the SC2-via-channel-decoupling duty);pr-review-trigger.ymlis documented as the intentionalnextexclusion (a guard records that it parses tonext, not that it must be stable).Implementation Checklist
scripts/lib/self-review-channel.sh— new pure sourceable helper: parse@<agent>/<channel>from a stub'suses:pin, classify tier (stable/next/ring*),is_stable_tier, andassert_self_review_stablewith an SC2 failure message (AC test issue from agent #1, Go-live improvements for PR review agent #2, Add @claude delegation, auto-merge, and rebase handling #3)tests/fixtures/self-review-channel/*.yml— minimal fixture stubs (stable, next, @main, bare-SHA) for pure parser/asserter teststests/test_sc2_self_review_channel.bats— pure unit tests + live guard over.github/workflows/dev-lead.yml(AC test issue from agent #1, Go-live improvements for PR review agent #2, Add @claude delegation, auto-merge, and rebase handling #3)docs/release/versioning.md(§ring membership, line ~74) — record the deliberate stable pin as an SC2 requirement + cross-reference thepinned-version-reportring-mismatch flag + the new regression test (AC Optimize review: small-PR and incremental fast paths #4)docs/initiatives/agentic-release-strategy.md— short SC2 cross-reference to the guard (AC Optimize review: small-PR and incremental fast paths #4)docs/release/sc2-game-day.md— fix stale line statingdev-lead.ymlpinsnext(it pinsv1-stable) so surfaces don't contradict (AC Optimize review: small-PR and incremental fast paths #4).github/workflows/lint.yml— register the new test in thebatsjob (AC feat: add Copilot engine support via REVIEW_ENGINE toggle #5)Tests to Write
v1-stable/stablepass;v1-next/next/v2-ring0/@main/bare-SHA failstub_uses_refparses the pin from a fixture stubnextpin is a regression (AC Add @claude delegation, auto-merge, and rebase handling #3).github/workflows/dev-lead.ymlresolves to stable-tier (the real regression guard)pr-review-trigger.ymlparses tonext(records the deliberate ring-0 exclusion)Test Command
scripts/run-bats.sh tests/test_sc2_self_review_channel.bats(full: thebatsjob list) +bash .dev-lead/scripts/dev-lead-lint.shNote
Per the guardrail: this issue adds no
with:forwards and repins nothing — it only asserts and documents the current state.don-petry commentedon Sep 1, 2026
Dev-Lead: Progress (in progress — not yet durable)
Plan execution (intended)
uses:@<agent>/<channel>pin and classifies its tier (stable/next/ring*), plus a stable-tier assertion whose failure message names SC2..github/workflows/dev-lead.ymlresolves to a stable tier (the actual regression guard), parsing the pin rather than a hardcoded version.pinned-version-reportring-mismatch flag; also corrected a stale line insc2-game-day.mdthat claimeddev-lead.ymlpinsnext(it pins@dev-lead/v1-stable).lint.ymlbatsjob.Design decision worth a reviewer's eye (pr-review scope)
AC1 says "include
pr-review's stub if it pins a first-party reusable."pr-review-trigger.ymldoes pin a first-party reusable, but to@pr-review/v1-next— the deliberate ring-0 canary (per its header +versioning.md; its SC2 net is the break-glass, mechanism 2). Asserting it "stable" would fail current state and violate the "do not repin / preserve current state" Dev Note. So the stable assertion targetsdev-lead.yml; a separate guard records thatpr-review-trigger.ymlintentionally parses tonext(documenting the exclusion rather than silently dropping it). If the intent was to also force pr-review to stable, that would require a repin, which this issue forbids.Files touched (this workspace, not yet pushed)
scripts/lib/self-review-channel.sh(new): pure channel-tier parse/assert helpers.tests/test_sc2_self_review_channel.bats(new) +tests/fixtures/self-review-channel/*.yml(new): unit + live guards.docs/release/versioning.md,docs/initiatives/agentic-release-strategy.md,docs/release/sc2-game-day.md: AC4 documentation + stale-line fix..github/workflows/lint.yml: registered the test in thebatsjob.Local checks (provisional — not the pushed run)
batssuite green locally;.dev-lead/scripts/dev-lead-lint.sh(shellcheck --severity=warning -x + agent frontmatter) clean; markdownlint clean on the changed docs. These are local, pre-push signals only.Notes
with:forward added (per the channel-skew guardrail). The change only asserts + documents the current state.don-petry commentedon Sep 1, 2026
Dev-Lead: Implementation Complete — PR #1626
The implementation for issue #1624 is durable: commits are pushed and a pull request is open. This record is backed by verifiable artifacts you can confirm in one click.
f487fa9bfe4cc234419955a28f187a3cb884cfa3Review happens on the PR. Acceptance criteria and test results are evidenced by the PR's diff and CI checks — not asserted here. If a later stage fails, this claim is retracted in place.
feat: implement issue #1624 — [Phase 2] SC2 regression guard: assert …
fix: repin to dev-lead/v139-stable, not v139-next — SC2 self-host guard
chore(dev-lead): repin stub from dev-lead/v1-stable to dev-lead/v139-…