Skip to content

[Phase 2] Release-ring confirmation + central-config registration in the bootstrap #968

Closed

Description

@github-actions

Story

As a org maintainer,
I want have the bootstrap confirm the new repo's release ring (default stable) and, for a non-stable ring, register it in both central files and repin its stubs,
so that ring membership becomes a deliberate, auditable choice instead of a silent wildcard default that audit/deploy would later flag as drift.

Acceptance Criteria

  1. The bootstrap accepts a ring selection (e.g. --ring stable|ring1|ring0|next) defaulting to stable, and records the confirmed ring (operator + value + timestamp) — auditable even when the answer is stable.
  2. For a non-stable ring, it registers the repo in BOTH standards/canary-rings.json (this repo) AND scripts/lib/ring-pins.sh (petry-projects/.github), keeping them in sync, and repins the shipped stubs to the matching channel (@<agent>/<ring>).
  3. For stable, no central-file edit is required, but the confirmation is still recorded.
  4. After a non-stable registration, the compliance audit / fleet drift check sees no ring drift — both central files name the repo in the same ring and the stubs match that channel.
  5. A bats test covers the stable (record-only) path and the non-stable (edits both files + repins stubs) path under DRY_RUN.

Tasks / Subtasks

Dev Notes

  • standards/canary-rings.json (this repo) is the documented single source of ring membership (per-channel members arrays under agents..rings); scripts/canary-rollout.sh reads it. Default today is silent stable via a * catch-all member token — the whole point of this story is to turn that into a recorded decision.
  • scripts/lib/ring-pins.sh lives in petry-projects/.github and is NOT present in this repo (verified) — a non-stable registration is a CROSS-REPO edit. Use the aw-standards-sync.sh cross-repo PR pattern (STANDARDS_REPO=petry-projects/.github) rather than a direct push; both files must stay in sync because the audit and the deploy sweep read both.
  • Stub repin: a non-stable repo's caller stubs must pin @<agent>/<ring> to match its ring, or fleet_stub_drift/audit flags drift; mirror the channel-tag model used by scripts/canary-rollout.sh.

Project Structure Notes

Extends scripts/bootstrap-new-repo.sh and edits standards/canary-rings.json in this repo; the ring-pins.sh edit is cross-repo into petry-projects/.github.

References

Likely target surface

  • new script scripts/bootstrap-new-repo.sh
  • standards/canary-rings.json
  • new test tests/test_bootstrap_new_repo.bats

Story prepared by the BMAD Scrum Master (Bob) for epic #964. Status: ready-for-dev.

Activity

  1. don-petry commented on Jun 27, 2026

    @don-petry
    Collaborator

    Dev-Lead Implementation Plan

    Issue: #968 — [Phase 2] Release-ring confirmation + central-config registration in the bootstrap

    Scope

    Extend scripts/bootstrap-new-repo.sh with a --ring selection (default stable) that records an auditable ring decision (operator + value + timestamp) and, for a non-stable ring, registers the repo in both central files (standards/canary-rings.json here + scripts/lib/ring-pins.sh cross-repo in petry-projects/.github) and repins the shipped caller stub to @<agent>/<ring> — asserting no ring drift.

    Implementation Checklist

    • scripts/bootstrap-new-repo.sh: add --ring/--agent arg parsing (default stable/dev-lead) + jq dependency check (AC#1)
    • Add _record_ring_decision (operator+value+timestamp), emitted for every ring incl. stable (AC#1, Add @claude delegation, auto-merge, and rebase handling #3)
    • Stable path: record-only, no central-file edit (AC#3)
    • Non-stable path: add repo to matching channel members in standards/canary-rings.json (real local edit; DRY_RUN prints intent) (AC#2)
    • Non-stable path: register in scripts/lib/ring-pins.sh cross-repo via the aw-standards-sync.sh PR pattern (STANDARDS_REPO=petry-projects/.github) — DRY_RUN prints intent (AC#2)
    • Non-stable path: repin shipped caller stub to @<agent>/<ring> (DRY_RUN prints intent) (AC#2)
    • _assert_ring_consistency: both central files place the repo in the SAME ring (no drift) — repo in named ring, absent from all others (AC#4)
    • Wire step_ring into main as the first step; renumber step labels

    Tests to Write

    • tests/test_bootstrap_new_repo.bats: stable (record-only) path under DRY_RUN — emits audit record, no central-file edits, no write API calls
    • non-stable path under DRY_RUN — emits audit record, prints intent to edit canary-rings.json + ring-pins.sh + repin stub, consistency assertion passes, real canary-rings.json unchanged
    • --ring defaults to stable; unknown ring is rejected

    Test Command

    bats tests/test_bootstrap_new_repo.bats (full suite: bats tests/); lint: bash .dev-lead/scripts/dev-lead-lint.sh

  2. don-petry commented on Jun 27, 2026

    @don-petry
    Collaborator

    Dev-Lead: Implementation Complete

    Plan Execution

    • --ring/--agent arg parsing (default stable/dev-lead) + jq dependency check (AC#1)
    • _record_ring_decision emits an auditable record (operator + value + timestamp) for every ring, incl. stable (AC#1, Add @claude delegation, auto-merge, and rebase handling #3)
    • Stable path is record-only — no central-file edit (AC#3)
    • Non-stable path edits standards/canary-rings.json (adds repo to the channel members; real local write, DRY_RUN prints intent) (AC#2)
    • Non-stable path registers in cross-repo scripts/lib/ring-pins.sh (petry-projects/.github) via the aw-standards-sync.sh contents-API + gh pr create pattern; DRY_RUN prints intent (AC#2)
    • Non-stable path repins the shipped caller stub to @<agent>/<ring> (DRY_RUN prints intent) (AC#2)
    • _assert_ring_consistency enforces no drift — repo lands in the named ring and no other — checked on the proposed state before any write (AC#4)
    • step_ring wired as the first bootstrap step (steps renumbered to /5)
    • bats coverage for the stable (record-only) and non-stable (edits both files + repins stub) paths under DRY_RUN (AC#5)

    Test Results

    1..17
    ok 1 pr-quality.json: valid, branch target, active enforcement
    ok 2 pr-quality.json: bypass = OrganizationAdmin + Integration, both bypass_mode always
    ok 3 pr-quality.json: Integration bypass uses the dependabot-automerge app id (3167543)
    ok 4 pr-quality.json: pull_request rule — 1 approval, code-owner review, thread resolution, dismiss-stale, squash-only
    ok 5 pr-quality.json: targets the default branch — no legacy/ad-hoc 'main' literal
    ok 6 DRY_RUN: exits 0 and makes no write API calls
    ok 7 DRY_RUN: prints intent and a PASS summary
    ok 8 DRY_RUN: bridges the flag onto both sub-scripts (DEV_LEAD_DRY_RUN + DRY_RUN)
    ok 9 sequence: invokes apply-repo-settings then apply-rulesets --repo on success
    ok 10 fail-fast: apply-repo-settings failure stops before apply-rulesets and exits non-zero
    ok 11 fail-fast: apply-rulesets failure exits non-zero with a FAIL summary
    ok 12 summary: success prints a PASS summary naming the repo
    ok 13 errors when no repo argument is given
    ok 14 ring: defaults to stable and records an auditable decision (record-only)
    ok 15 ring: rejects an unknown ring value
    ok 16 ring: non-stable (DRY_RUN) records the decision and prints both-file + stub intent
    ok 17 ring: non-stable consistency holds — repo lands in the named ring and no other
    

    Lint (.dev-lead/scripts/dev-lead-lint.sh — shellcheck on 82 scripts + agent frontmatter + CODEOWNERS):

      [lint] validating .github/CODEOWNERS...
    OK: .github/CODEOWNERS
      [lint] all checks passed
    

    Full tests/*.bats sweep: 918 passing. The single unrelated failure (test_batch_fallback.bats — Gemini→Copilot fallback) also fails on clean HEAD and is environment-dependent, not introduced here.

    Files Changed

    • scripts/bootstrap-new-repo.sh: added the release-ring confirmation step (--ring/--agent, audit record, canary-rings.json registration, cross-repo ring-pins.sh + stub repin via the standards-sync PR pattern, no-drift consistency assertion); renumbered the existing steps to /5.
    • tests/test_bootstrap_new_repo.bats: 4 new tests covering default/stable record-only, unknown-ring rejection, and the non-stable DRY_RUN path (both-file + stub intent, audit record, no SoT mutation, consistency OK).

    Notes

    • scripts/lib/ring-pins.sh is not present in this repo (it lives in petry-projects/.github), so its registration is a genuine cross-repo edit — implemented via the aw-standards-sync.sh PR pattern. Per AC#5 the verified path is DRY_RUN (intent-only); the live cross-repo edit assumes a per-ring <ring>=( … ) array anchor and fails loudly (no silent corruption) if that anchor is absent, rather than guessing an unverified format.
    • Stable demotion of an already-non-stable repo is out of scope (AC#3 is record-only for stable); the consistency assertion still guarantees a freshly-registered repo never sits in two rings.
  3. added a commit that references this issue on Jun 27, 2026
  4. added 18 commits that reference this issue on Aug 2, 2026
  5. added a commit that references this issue on Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev-leadFor dev-lead agent pickupinitiativeEpic / initiative tracking issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions