F2: cut-release.sh learns v<major>-<tier> channels [#657] #1184
Description
Phase F2 of the major-scoped-channels epic #657 (Option 1 decided 2026-07-13; model documented in agentic-release-strategy.md via F1). Teach cut-release.sh the v<major>-<tier> channel model. .github-private only — no .github tooling change here.
Context
Today (scripts/cut-release.sh): channel_ref(agent, channel) = <agent>/<channel> and --channel <tier> moves <agent>/<tier> to the new <agent>/vX.Y.Z release. The tiers are next/ring0/ring1/stable.
Change
Introduce major-scoped channel names: --channel values become v<MAJOR>-<tier> (e.g. v1-stable, v2-next). Derive <MAJOR> from the <version> arg's major component when the caller passes a bare tier, OR accept the fully-qualified v<M>-<tier> directly.
-
channel_ref(or a new resolver): given<agent> <version> <tier>, emit<agent>/v<major(version)>-<tier>. When--channelis alreadyv<M>-<tier>, pass through; when it's a bare tier (stable), prefix withv<major(version)>-. -
--promote --channel <tier>moves<agent>/v<major>-<tier>(within the release's major). - Keep immutable
<agent>/vX.Y.Zrelease tags exactly as-is. - Update the usage/header examples to the
v<M>-<tier>form. - Preserve the App-token gh-api path for protected channel moves (GH013 avoidance).
Tests
cut-release.sh <agent> 2.0.0 --channel stable --dry-run→ plans a move of<agent>/v2-stable(not<agent>/stable).- explicit
--channel v1-ring0passes through unchanged. - release tag
<agent>/v2.0.0still created. - bump of major is reflected in the channel prefix (1.x → v1-, 2.x → v2-).
Out of scope
F3 ring-pins.sh (.github), F4 engine, F5 audit/drift + live migration + consumer re-pins. Backward-compat with existing bare-tier channels is handled at migration time (F5), not here — F2 just makes the tool capable of the new names.
Acceptance
cut-release.shcuts/promotesv<major>-<tier>channels, deriving the major from the version; release tags unchanged; usage docs updated; tests green.
Activity
github-actions commentedon Jul 13, 2026
Thanks for the detailed spec and for linking this back to the F1 decision — really helpful context! One clarifying question: should
cut-release.shemit a warning (or hard error) when a bare tier likestableis passed without a version argument, since the major prefix can't be derived in that case, or is the version argument already required/guaranteed by existing usage?don-petry commentedon Jul 13, 2026
Dev-Lead Implementation Plan
Issue: #1184 — F2: cut-release.sh learns v- channels [#657]
Scope
Teach
scripts/cut-release.shthe major-scoped channel model:--channel <tier>resolves to<agent>/v<major(version)>-<tier>, while a fully-qualifiedv<M>-<tier>passes through unchanged. Immutable<agent>/vX.Y.Zrelease tags and the App-token gh-api path are untouched.Implementation Checklist
major_of <version>pure helper (extracts MAJOR from MAJOR.MINOR.PATCH)channel_reftochannel_ref <agent> <version> <channel>: bare tier →<agent>/v<major>-<tier>;v<M>-<tier>→ pass throughchannel_refcall site inmain()to pass$versionv<M>-<tier>form; addmajor_ofto the sourced-helpers listtests/test_cut_release_cross_repo.batsintolint.yml's bats list (currently omitted) so integration tests run in CITests to Write
major_of(1.2.3→1, 2.0.0→2, 12.4.37→12)channel_refbare tier prefixes major (dev-lead 2.0.0 stable → dev-lead/v2-stable)channel_refpasses through explicitv1-ring0unchangeddev-lead 2.0.0 --channel stable --dry-runplans move ofdev-lead/v2-stable--channel v1-ring0passes through<agent>/v2.0.0still created on--pushTest Command
scripts/run-bats.sh tests/test_cut_release.bats tests/test_cut_release_cross_repo.batsandbash .dev-lead/scripts/dev-lead-lint.shdon-petry commentedon Jul 13, 2026
Dev-Lead: Implementation Complete
Plan Execution
major_of <version>pure helper (extracts MAJOR from MAJOR.MINOR.PATCH)channel_reftochannel_ref <agent> <version> <channel>: bare tier →<agent>/v<major>-<tier>; fully-qualifiedv<M>-<tier>passes through unchanged (its own major wins)channel_refcall site inmain()to pass$version(covers both cut and--promotepaths)<agent>/vX.Y.Zrelease tags and the App-token gh-api path untouchedv<M>-<tier>formtests/test_cut_release_cross_repo.batsintolint.yml's bats list (it was previously omitted from CI)Test Results
All 72 tests pass across
tests/test_cut_release.bats+tests/test_cut_release_cross_repo.bats.Repo lint (
.dev-lead/scripts/dev-lead-lint.sh) passes: shellcheck clean on 80 files, agent profiles + CODEOWNERS OK.Files Changed
scripts/cut-release.sh: newmajor_ofhelper;channel_refnow major-scoped (3-arg); call site + usage/header docs updated. Release-tag creation, immutability guard, and thegh apiApp-token path are unchanged.tests/test_cut_release.bats:major_ofunit tests + rewrittenchannel_reftests for the 3-arg major-scoped signature.tests/test_cut_release_cross_repo.bats: existing channel assertions updated to major-scoped names; added acceptance tests (dry-run plansv2-stable;v1-ring0passthrough;v2.0.0release tag still created;--promotemovesv2-ring1)..github/workflows/lint.yml: addedtest_cut_release_cross_repo.batsto the bats run list so the integration path is CI-gated.Notes
v<M>-<tier>wins over the version's major — e.g.--channel v1-ring0with version2.0.0pinsv1-ring0, so a patch can be cut against an older major's ring without repointing it to the new major. This matches the F1 model (a bare tier is prefixed; a fully-qualified channel is authoritative).ring-pins.sh, F4 engine, F5 audit/drift + live migration + consumer re-pins. Backward-compat with existing bare-tier channels is an F5 migration concern; F2 only makes the tool capable of the new names..dev-lead/scripts/cut-release.shwas intentionally not modified — it is a frozen snapshot already out of sync and is not linted/sourced by the repo's checks (onlyscripts/**/*.shis).feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
4 remaining items
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1184 — F2: cut-release.sh learns v<major>-<tie…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1436 — [bug] seed-repo-template.sh repins call…
feat: implement issue #1493 — [Phase 2 follow-up] Complete the #1184 …
feat: implement issue #1493 — [Phase 2 follow-up] Complete the #1184 …