Repository navigation
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) - #1056
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
|
Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-07-03T18:22:10Z. |
There was a problem hiding this comment.
Code Review
This pull request introduces a fleet-wide promotion feature (promote-all) and adds support for cross-repository agents in canary-rollout.sh by moving channel tags on their respective hosts via the GitHub API instead of local git commands. Comprehensive tests have also been added to verify these changes. The review feedback highlights several critical shell scripting improvements: explicitly propagating failures in cmd_promote and cmd_rollback to prevent silent failures when set -e is suspended, validating positional parameters in _gh_move_tag to avoid crashes under set -u, and utilizing robust jq patterns (such as optional chaining and null-coalescing) to safely handle missing or null values in the JSON registry.
There was a problem hiding this comment.
Pull request overview
This PR extends the canary rollout automation to (1) support a gated, scheduled fleet-wide auto-promotion path and (2) correctly promote/rollback cross-repo agents by moving channel tags on the agent’s host repository via the GitHub API (fixing the nonexistent object failure mode for #482 reusables).
Changes:
- Add
promote-allorchestration to sweep all registry agents and attempt gated promotion (one ring per agent per run). - Make
promote/rollbackhost-aware for cross-repo agents by introducing_gh_move_tag(PATCH then POST fallback) and using it whenhost != THIS_REPO. - Update the
canary-rollout.ymlschedule to runpromote-allwhenvars.CANARY_AUTO_PROMOTE == 'true', otherwise runevaluate-all; add Bats coverage for fleet iteration and cross-repo tag moves.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/canary_rollout.bats | Adds Bats tests for promote-all fleet iteration and cross-repo promote behavior (dry-run + real tag move). |
| scripts/canary-rollout.sh | Implements _gh_move_tag, host-aware promote/rollback paths, and new cmd_promote_all sweep command. |
| .github/workflows/canary-rollout.yml | Arms the 4h schedule to run gated promote-all behind the CANARY_AUTO_PROMOTE org variable; expands dispatch commands accordingly. |
Dev-Lead — rate-limited (intent: fix-reviews)PR: #1056 |
Dev-Lead — fix-reviews (applied)Changes committed and pushed. |
Dev-Lead — waiting on PR blockers (intent: fix-reviews)PR: #1056 |
|
Auto-rebase failed — merge conflict — this branch has conflicts with dev-lead will attempt to resolve this automatically. If it cannot, a follow-up comment will explain what needs manual attention. To resolve manually instead: |
Superseded by automated re-review at
|
Superseded by automated re-review at
|
|
Auto-rebase failed — merge conflict — this branch has conflicts with dev-lead will attempt to resolve this automatically. If it cannot, a follow-up comment will explain what needs manual attention. To resolve manually instead: |
|
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: 27896e819399ae83b75b6335273dcd874a12a3eb
Review mode: triage-approved (single reviewer)
Summary
Re-review at 27896e8 (cycle 2/3) after the cycle-1 fix-requested review at 3aea9b9. The sole blocking finding from the prior review — merge conflicts (mergeable=CONFLICTING / DIRTY) — is resolved: the branch was rebased onto main and is now MERGEABLE (state BEHIND, no conflicts). All shell-safety guards the prior review verified survive the rebase at the current head: _gh_move_tag validates arg count, cmd_promote/cmd_rollback use the null-safe jq host lookup (.agents[$a].host // "" | tostring) and explicitly guard both the gh-api and local git move paths with || { ...; return 1; } so failures cannot fall through under a suspended set -e in the promote-all sweep. All 7 review threads are resolved and CI is green (bats 55/55, shellcheck, CodeQL, gitleaks, SonarCloud quality gate).
Linked issue analysis
No formal closingIssuesReferences, but the PR body targets #1045 part b (gated scheduled fleet auto-promote) and #1054 (cross-repo PROMOTE via host gh api instead of local git). Both are substantively implemented: cmd_promote_all iterates the registry and forwards to the gated cmd_promote (one ring per run, per-agent failures logged and skipped), the schedule arm is gated on org var CANARY_AUTO_PROMOTE with read-only evaluate-all as the default, and cmd_promote/cmd_rollback are host-aware with _gh_move_tag (PATCH-then-POST) for cross-repo agents. Three new bats tests cover the fleet sweep, the cross-repo dry-run path, and the real cross-repo move + GITHUB_OUTPUT recording.
Findings
- RESOLVED (prior MAJOR): merge conflicts against main — branch rebased and pushed (head 27896e8); PR is now MERGEABLE. mergeStateStatus is BEHIND (main moved again), which auto-rebase handles; not a blocking gate.
- RESOLVED (prior advisory findings, verified at head): _gh_move_tag guards [ $# -lt 3 ] && return 1; jq host lookups use --arg with // "" | tostring (no literal "null" mis-setting cross=true); both promote and rollback move paths return 1 explicitly on failure with ::error output.
- NO NEW ISSUES since the prior review: the rebase reconciled this PR with main's #1055 (which merged a first cut of the #1054 fix); this PR's simplified _gh_move_tag (PATCH-then-POST fallback instead of GET-then-PATCH/POST) is functionally equivalent with one fewer API call, and callers guard its failure.
- MINOR (carried, by design): when org var CANARY_AUTO_PROMOTE=='true', the 4h schedule performs REAL force tag moves (DRY_RUN=false) gated only by the promotion gate; the single org variable is the kill-switch and dispatch promote/promote-all default to --dry-run. Intended per #1045b/#548.
- Secret scan: run_secret_scanning MCP tool not available in this environment; skipped. Gitleaks CI check passed and the diff contains no secret material.
CI status
All required checks SUCCESS: shellcheck (x2), bats, unit-tests, Lint, CodeQL (actions + python), gitleaks, SonarCloud quality gate, AgentShield, Agent Security Scan, holdout-guard, template-drift, gh-aw-compile, validate-agent-profiles, CodeRabbit. CANCELLED entries (dev-lead / dispatch, dev-lead / ci-relay) are superseded automation reruns, not failures; dependency-audit language jobs SKIPPED (no matching ecosystems).
Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: 27896e819399ae83b75b6335273dcd874a12a3eb
Review mode: triage-approved (single reviewer)
Summary
PR #1056 implements the gated scheduled fleet auto-promote (#1045 part b) and fixes cross-repo PROMOTE/rollback (#1054) by making tag moves host-aware (_gh_move_tag via gh api for cross-repo agents, local git otherwise). This is a cycle-2 re-review: the prior review's sole blocking finding (merge conflict against main) is resolved — the branch was rebased and is now MERGEABLE. All advisory-bot findings from cycle 1 remain fixed at the current head, all 7 review threads are resolved, and CI is green (shellcheck, bats 55/55, CodeQL, gitleaks, SonarCloud all SUCCESS).
Linked issue analysis
- #1045 (part b): substantively addressed. The 4h schedule now runs
promote-allwhen org varCANARY_AUTO_PROMOTE == 'true'(real move, gate-decided, one ring per run, no--overrideon the sweep) and falls back to read-onlyevaluate-allotherwise — the arm variable is the single kill-switch, matching the issue's gated-scheduled-promote model. Part a (dispatch agent list) was handled in #1047. - #1054: substantively addressed.
cmd_promoteandcmd_rollbackare host-aware: cross-repo agents (host ≠ THIS_REPO) move channel tags on their host viagh apiPATCH-then-POST (_gh_move_tag), fixing the "nonexistent object" failure; this-repo agents keep the local git path. Covered by 3 new bats tests including a real-move assertion that the host API is hit and local git never is.
Findings
- RESOLVED (prior MAJOR): merge conflict against main — the branch was rebased (dev-lead rebase applied) and the PR is now
mergeable=MERGEABLE.mergeStateStatus=BEHINDis not blocking; the repo's auto-rebase automation brings branches up to date before merge. - VERIFIED (prior cycle-1 advisory findings, still fixed at head): git/gh-api moves guarded with
|| { ::error; return 1; }so failures cannot fall through under promote-all's suspendedset -e; jq host lookups use.agents[$a].host // "" | tostring(null-safe, --arg — no injection);_gh_move_tagvalidates arg count underset -u. All 7 gemini/copilot review threads are marked resolved. - MINOR (non-blocking):
_gh_move_tagsuppresses gh api stderr (2>&1 >/dev/null), so PATCH/POST error details are lost — callers do emit::errorwith agent/tag context, which is sufficient for triage. - NOTE (by design): the scheduled arm performs REAL cross-repo force tag moves (
DRY_RUN=false) wheneverCANARY_AUTO_PROMOTE=='true'; only PROMOTE-ready agents advance and BLOCKED/REGRESSION agents are untouched. Intentional per #1045b/#548; dispatch inputs are choice-constrained and passed as quoted env vars — no injection surface. - Secret scan:
run_secret_scanningMCP tool not available in this environment — skipped; gitleaks CI check is SUCCESS and the diff contains no secret material.
CI status
Green at head 27896e81: shellcheck, ShellCheck, bats, unit-tests, Lint, CodeQL, Analyze (actions/python), SonarCloud quality gate, Secret scan (gitleaks), AgentShield, Agent Security Scan, holdout-guard, template-drift, guard, gh-aw-compile, validate-agent-profiles — all SUCCESS. The two CANCELLED checks (dev-lead / dispatch, dev-lead / ci-relay) are superseded automation-agent concurrency duplicates, not correctness checks; dependency-audit jobs SKIPPED (no matching ecosystems).
Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…b) + host-aware cross-repo tag moves (#1054) (#1056) * feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part b) + host-aware cross-repo tag moves (#1054) Implements #1045 part b — the timer advances the fleet, no manual step. Automation: - promote-all subcommand (cmd_promote_all): iterates every registry agent and forwards to cmd_promote, so each PROMOTE-ready agent advances exactly one ring per run while BLOCKED/REGRESSION agents are left untouched by the gate. A per-agent failure is logged and skipped so one agent cannot halt the fleet sweep. Human approval stays OVERRIDE-ONLY, never a required gate. - workflow: schedule now runs the gated auto-promote when the org variable CANARY_AUTO_PROMOTE == 'true' (promote-all, real move), else read-only evaluate-all. The arm variable is the single kill-switch. dispatch gains evaluate-all/promote-all options (promote-all defaults to --dry-run). Cross-repo fix (#1054): - _gh_move_tag: force-move/create a channel tag on a cross-repo agent's HOST via gh api (PATCH then POST), the counterpart of `git tag -f` + push. - cmd_promote / cmd_rollback are now host-aware: an agent hosted in THIS repo moves its tag via local git; a cross-repo agent (the 6 #482 reusables on petry-projects/.github) moves it on its host via gh api — local `git tag -f` failed with "nonexistent object" for a host commit absent from this checkout. Tests: +3 bats (promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path not local git; real cross-repo promote moves the host tag via gh api PATCH + records the GITHUB_OUTPUT). 55/55 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(reviews): address review comments [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>



What & why
Closes #1045 part b (gated scheduled auto-promote — the timer advances the fleet, no manual step) and #1054 (cross-repo PROMOTE failed with
nonexistent object).Part a (#1047) expanded the dispatch agent list. Part b makes the schedule do the promoting, gated by the soak standard (#548) — human approval is override-only, never a required gate.
Automation (#1045b)
promote-all(cmd_promote_all): iterates every registry agent and forwards tocmd_promote. Each PROMOTE-ready agent advances one ring per run; BLOCKED/REGRESSION agents are left untouched by the gate (no--overrideon the sweep). A per-agent failure is logged and skipped so one agent can't halt the fleet.CANARY_AUTO_PROMOTE == 'true'(promote-all, real move), else read-onlyevaluate-all. The arm variable is the single kill-switch. Dispatch gainsevaluate-all/promote-alloptions (promote-all defaults to--dry-run).Cross-repo fix (#1054)
_gh_move_tag: force-move/create a channel tag on a cross-repo agent's host viagh api(PATCH then POST) — the counterpart ofgit tag -f+ push.cmd_promote/cmd_rollbackare now host-aware: THIS-repo agents move tags via local git; the 6 feat: implement issue #398 — Compliance: secret_scanning_ai_detection #482 reusables (hosted onpetry-projects/.github) move viagh api. Localgit tag -ffailed withnonexistent object <sha>for a host commit absent from this checkout.Tests
+3 bats — promote-all fleet iteration; cross-repo promote dry-run takes the host gh-api path (not local git); real cross-repo promote moves the host tag via
gh api PATCH+ recordsGITHUB_OUTPUT. 55/55 passing.bash -n+ shellcheck clean; workflow YAML validated.Rollout after merge
promote-alldry_run=true(observe verdicts), thendry_run=false— the two ring1→stable PROMOTE-ready reusables (dependabot-automerge,dependabot-rebase) advance onpetry-projects/.githubvia cross-repogh api.gh variable set CANARY_AUTO_PROMOTE --org petry-projects --body true. Kill-switch = unset/flip to false.🤖 Generated with Claude Code