Skip to content

feat(cut-release): add --promote for ring-to-ring channel moves (#501) - #992

Merged
don-petry merged 2 commits into
mainfrom
feat/cut-release-promote-mode
Jun 30, 2026
Merged

don-petry merged 2 commits into
mainfrom
feat/cut-release-promote-mode

Conversation

@don-petry

Copy link
Copy Markdown
Collaborator

Summary

cut-release.sh --channel always tries to create the immutable <agent>/vX.Y.Z release tag, so promoting an already-cut version to the next ring aborts on the immutability check. This blocked every ring0→ring1→stable advance during the #870 soak (worked around with raw git/refs PATCH calls).

--promote adds the missing channel-move-only primitive:

  • Moves <agent>/<channel> to the existing release commit; never recreates the tag.
  • Requires --channel; errors if the release tag is absent (can't promote what wasn't cut); ignores --ref.
  • Works for cross-repo (.github via gh api) and this-repo (local git) agents; honors --dry-run/--push.
cut-release.sh agent-shield 2.1.0 --channel ring1 --promote --push   # ring0 → ring1, no re-cut

Tests

New gh_release_commit() helper (dereferences the annotated tag → commit). +4 bats (requires --channel; errors when release absent; moves channel without recreating the tag; dry-run no-op). 50 cut-release bats pass, shellcheck --severity=warning clean. Verified live in --dry-run against the in-flight agent-shield/v2.1.0.

This is the advance primitive the #501 auto-promoter consumes.

Refs #501, #870.

🤖 Generated with Claude Code

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.
@don-petry
don-petry requested a review from a team as a code owner June 30, 2026 20:12
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@don-petry

Copy link
Copy Markdown
Collaborator Author

@donpetry-bot please review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@don-petry, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6498320a-9faa-46d9-850c-651c40ac6e12

📥 Commits

Reviewing files that changed from the base of the PR and between 1ae3209 and 91908a6.

📒 Files selected for processing (2)
  • scripts/cut-release.sh
  • tests/test_cut_release_cross_repo.bats
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cut-release-promote-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@donpetry-bot

Copy link
Copy Markdown
Contributor

@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new --promote flag to the cut-release.sh script, enabling ring-to-ring channel promotions to an existing release tag without cutting a new release. This includes a new gh_release_commit helper function to resolve the commit SHA of a release tag via the GitHub API, along with corresponding integration tests. The review feedback suggests optimizing gh_release_commit to reduce network overhead by combining multiple API calls into a single request, and recommends guarding the gh_release_commit call in the promotion logic to prevent silent failures under set -e.

Comment thread scripts/cut-release.sh
Comment thread scripts/cut-release.sh Outdated
@don-petry
don-petry disabled auto-merge June 30, 2026 20:14
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 30, 2026
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — fix-reviews (applied)

Changes committed and pushed.

@sonarqubecloud

Copy link
Copy Markdown

@donpetry-bot

Copy link
Copy Markdown
Contributor

CI checks on this PR are still running. Once they complete, re-mention @donpetry-bot to trigger a fresh review.

Posted by the donpetry-bot PR-review cascade.

@donpetry-bot

Copy link
Copy Markdown
Contributor

@donpetry-bot I'm on it — starting a fresh review now. Results will appear in a few minutes.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — waiting on PR blockers (intent: review-changes)

PR: #992
No changes were committed, but the PR still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews). The retry cron will re-attempt automatically. Next attempt after: 2026-06-30T20:50:13Z

@don-petry

Copy link
Copy Markdown
Collaborator Author

Note

@don-petry I reviewed this PR and no code changes were needed, but it still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews), so I cannot mark it done yet. I'll re-check automatically.
Next attempt after: 2026-06-30T20:50:13Z

@don-petry
don-petry enabled auto-merge (squash) June 30, 2026 20:20

@donpetry-bot donpetry-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review — APPROVED ✓

Risk: MEDIUM
Reviewed commit: 91908a67952fb43014847bb98548c54ef0823a5c
Cascade: triage → deep (triage: haiku 4.5 → deep: opus 4.8 + duck: o4-mini → audit: fable 5)

Summary

Adds a --promote (ring-to-ring channel-move) mode to scripts/cut-release.sh plus 4 bats tests; no auth/secret/migration surface. The triage escalation signal — gemini's HIGH that gh_release_commit()'s second gh api call could silently exit under set -e — is resolved at head SHA 91908a6: the caller invokes the helper inside an if ! condition (suppressing set -e in the function body) and guards both a non-zero return and empty output, and the this-repo path uses guarded git rev-parse. All CI checks are green (shellcheck, bats, CodeQL, SonarCloud, gitleaks); the remaining BLOCKED/REVIEW_REQUIRED state is the org-leads human review gate, not an automated failure. No downstream consumers impacted (DOWNSTREAM_IMPACT: none).

Findings

  • info: Triage's HIGH signal addressed: gh_release_commit() is called as if ! pcommit="$(gh_release_commit ...)" || [ -z "$pcommit" ]. Because the function runs in an if-condition, set -e is suppressed inside it, so a failing second gh api returns non-zero rather than silently exiting; the caller then handles both non-zero and empty results. No silent-exit path remains.
  • minor: gemini also suggested collapsing the two sequential gh api .../git/ref/tags/$2 lookups (sha + type) into one request. Non-blocking efficiency nit; current two-call form is correct and now properly guarded.
  • info: The bats stub returns a bare sha (no type) for git/ref/tags/, so tests exercise the lightweight-ref (else) branch but not the annotated-tag deref branch (type=="tag", second git/tags/$obj call). Real release tags are annotated, so the deref path is untested by the stub — acceptable fidelity gap, not a code defect.
  • info: run_secret_scanning MCP tool not available in this environment; relied on gitleaks CI check (SUCCESS) plus manual diff inspection. Diff is pure shell control-flow — no credentials, tokens, or .env content.

Reviewed by the PR-review cascade (triage: haiku 4.5 → deep: opus 4.8 + duck: o4-mini → audit: fable 5). Reply if you need a human review.

@don-petry
don-petry merged commit d3099c1 into main Jun 30, 2026
30 of 31 checks passed
@don-petry
don-petry deleted the feat/cut-release-promote-mode branch June 30, 2026 20:24
@donpetry-bot

Copy link
Copy Markdown
Contributor

Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-06-30T21:24:40Z.

don-petry added a commit that referenced this pull request Aug 2, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 3, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 3, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 3, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 7, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 8, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 8, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 8, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 8, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Aug 18, 2026
#992)

* feat(cut-release): add --promote for ring-to-ring channel moves (#501)

cut-release.sh --channel always tries to CREATE the immutable <agent>/vX.Y.Z
release tag, so promoting an already-cut version to the next ring aborts on the
"immutable tags are never overwritten" check (hit on every ring0→ring1→stable
advance during the #870 soak — worked around with raw git/refs PATCH calls).

Add --promote: move <agent>/<channel> to the EXISTING release commit without
recreating the tag. Requires --channel, errors if the release tag is absent
(can't promote what wasn't cut), ignores --ref (the release's own commit is
authoritative). Works for both cross-repo (.github via gh api) and this-repo
(local git) agents; respects --dry-run / --push.

New helper gh_release_commit() dereferences the annotated release tag to its
commit. Tests: +4 (requires --channel, errors when absent, moves channel
without recreating the tag, dry-run no-op). 50 cut-release bats pass,
shellcheck clean.

This is the channel-move primitive the #501 auto-promoter needs; until it lands
the soak loop moved channels via raw API.

Refs #501, #870.

* fix(reviews): address review comments [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <bot@petry-projects>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry pushed a commit that referenced this pull request Sep 26, 2026
… promotion text

Addresses CodeAnt review findings on #1956:

- AGENTS.md: an existing release tag does not prove `next` moved, because
  autocut creates the release before moving the channel. Tell readers to
  compare `<agent>/v<M>-next` with the release's commit and to use
  `--promote` (not a new cut) if it lags.
- AGENTS.md channel-skew step 2: show `cut-release.sh --promote --channel`
  for moving to an existing release. Without `--promote` it always cuts a
  new tag and fails when the version exists.
- docs/release/runbook.md: add a "current state" note pointing at the
  Release Manager automation and at the AGENTS.md section. Replace the
  "Phase-1 human-driven" promotion rule, the stale "no channel-only-move
  mode / use git tag -f + push --force" gap (superseded by --promote
  #992; a force-push of a protected channel is rejected with GH013), the
  stale cross-repo "refuses a live cut" note (#872 wired), and the
  "#501 is future work" bullets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015fdDZDb4mhT65MU1izeA4R
don-petry added a commit that referenced this pull request Sep 26, 2026
…tes release tags (#1956)

* docs(agents): document Release Manager automation that cuts and promotes release tags

AGENTS.md told contributors that a merge stays inert until someone runs
`cut-release.sh`, and called the health-gated promotion workflow
"forthcoming". In practice the Release Manager (the `Canary Rollout`
workflow in petry-projects/.github, acting as the
petry-projects-release-manager[bot] App) already auto-cuts
`<agent>/vX.Y.Z` and moves `<agent>/v<MAJOR>-next` every 4h sweep, and
promotes through the rings when armed. That left sessions hand-cutting
after merges and colliding with tags the bot had already created.

- Reframe "Merging to main does not activate agent code": still inert on
  merge, but `next` catches up on the next autocut sweep and later rings
  move by gated promotion. The rule is now to state when a change reaches
  each channel.
- New "Release automation — who cuts and moves tags" subsection:
  autocut / promote-all / sync-issues, their arm variables
  (CANARY_AUTO_CUT, CANARY_AUTO_PROMOTE), bump detection, watched paths,
  require_confirmation (today only dev-lead ring1->stable), when to
  hand-cut, rollback paths, and that a human go/no-go must be configured
  in canary-rings.json before the candidate reaches the ring.
- Replace the stale "(forthcoming) promotion workflow" bullet and update
  the channel-skew sequencing step accordingly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015fdDZDb4mhT65MU1izeA4R

* docs(release): fix tag-check race, --promote usage, and stale runbook promotion text

Addresses CodeAnt review findings on #1956:

- AGENTS.md: an existing release tag does not prove `next` moved, because
  autocut creates the release before moving the channel. Tell readers to
  compare `<agent>/v<M>-next` with the release's commit and to use
  `--promote` (not a new cut) if it lags.
- AGENTS.md channel-skew step 2: show `cut-release.sh --promote --channel`
  for moving to an existing release. Without `--promote` it always cuts a
  new tag and fails when the version exists.
- docs/release/runbook.md: add a "current state" note pointing at the
  Release Manager automation and at the AGENTS.md section. Replace the
  "Phase-1 human-driven" promotion rule, the stale "no channel-only-move
  mode / use git tag -f + push --force" gap (superseded by --promote
  #992; a force-push of a protected channel is rejected with GH013), the
  stale cross-repo "refuses a live cut" note (#872 wired), and the
  "#501 is future work" bullets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015fdDZDb4mhT65MU1izeA4R

---------

Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants