You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
canary-rollout can't promote the #482 reusables: agent dispatch input hardcoded to [dev-lead] + no scheduled promote pathΒ #1045
#1044 populated the registry (7 agents now). But the automation still can't COMPLETE the rollout β it can only evaluate, and only promote dev-lead:
π΄ The agent workflow_dispatch input is a hardcoded choice list of [dev-lead]
gh workflow run canary-rollout.yml -f command=evaluate -f agent=auto-rebase β HTTP 422: 'auto-rebase' not in the list of allowed values. So manual evaluate/promote/rollback can only ever target dev-lead. The 6 #482 reusables (4 at ring1 waiting to reach stable) cannot be promoted at all. Fix: the agent input options: must list every agent in canary-rings.json (or become a free-text input validated against the registry). Ideally generate it from the registry so it never goes stale again.
π‘ No path for the timer to promote (decide the model)
The 4h schedule is read-only evaluate-all (never promotes) by design. So promotion is ONLY manual workflow_dispatch command=promote agent=<x>. Per the owner directive earlier ("complete rollout unless there's a failure to meet criteria" β autonomous through stable, override-only), consider a gated scheduled promote: on the timer, for each agent whose gate PROMOTEs, advance one ring (respecting control holds/overrides), still hard-stopping on regression. Otherwise every ring hop for every reusable is a manual dispatch forever. If manual-only is intended, that's fine β but then "flip to auto" means a human dispatches promote per agent per ring, which should be documented.
Impact
Until at least the agent input lists all 7, the in-flight rollout (auto-rebase, dependabot-automerge, dependabot-rebase, pr-review-mention @ ring1) cannot be carried to stable by the automation. This is now the last blocker to finishing the #482 rollout.
Issue:#1045 β canary-rollout can't promote the #482 reusables: agent dispatch input hardcoded to [dev-lead] + no scheduled promote path
Scope
Make the canary-rollout.ymlagent dispatch input list every agent in canary-rings.json (registry-driven, drift-guarded so it never goes stale), and add a gated scheduled promote path so the 4h timer autonomously advances each agent one ring when its #548 gate PROMOTEs β hard-stopping on regression and respecting control holds/overrides (the owner directive: autonomous through stable, override-only).
Implementation Checklist
scripts/canary_agent_options.sh β new: list (emit sorted registry agent keys = canonical choice options) + check <workflow> (fail on drift vs the workflow's agent input options)
scripts/canary-rollout.sh β add cmd_promote_all (fleet-wide gated promote: PROMOTE-only, respects control.hold/control.allow_pre_existing, hard-stops on REGRESSION, honors --dry-run); add _require_agent registry validation to evaluate/promote/rollback; append each real promotion to CANARY_PROMOTIONS_LOG for multi-deploy recording; update usage header
.github/workflows/canary-rollout.yml β regenerate agent input options: to all 7 agents; switch the schedule from read-only evaluate-all to gated promote-all (real, not dry); loop the deployment-recording step over CANARY_PROMOTIONS_LOG; update header comments
AGENTS.md β document the manual "flip to auto" path + the control.hold pause switch
tests/canary_rollout.bats: canary_agent_options.sh list emits all 7 sorted keys; check passes on the real workflow and fails on an injected drift
tests/canary_rollout.bats: promote-all iterates the registry and advances a PROMOTE-ready agent (dry-run), skips a control.hold agent, and refuses a BLOCKED+REGRESSION agent
tests/canary_rollout.bats: unknown agent is rejected with a clear error (registry validation)
Test Command
scripts/run-bats.sh tests/canary_rollout.bats and bash .dev-lead/scripts/dev-lead-lint.sh
π΄ agent dispatch input now lists all 7 registry agents (was hardcoded [dev-lead]) β dispatching -f agent=auto-rebase etc. no longer 422s
Registry-derived + drift-guarded so it never goes stale: scripts/canary_agent_options.sh (list regenerates, check fails on drift vs canary-rings.json)
Runtime _require_agent validation in canary-rollout.sh (evaluate/promote/rollback reject an unknown agent instead of silently resolving to an empty frontier)
promote-all skips gate.control.hold agents, honours gate.control.allow_pre_existing, hard-stops on REGRESSION, never auto---overrides
Each real promotion journaled to CANARY_PROMOTIONS_LOG; deployment-recording step loops it so a fleet tick that advances several agents records a Deployment for each
Documented the "flip to auto" model + the control.hold pause switch in AGENTS.md
Test Results
62 tests, 0 failures (tests/canary_rollout.bats β 11 new)
52 evaluate rejects an agent not in the registry
53 promote rejects an agent not in the registry
54 canary_agent_options: list emits every registry agent, sorted
55 canary_agent_options: default (no args) behaves like list
56 canary_agent_options: check PASSES against the live canary-rollout.yml (no drift)
57 canary_agent_options: check FAILS when the workflow options drift from the registry
58 canary-rollout.yml: agent dispatch options == registry keys (drift guard)
59 promote-all advances a PROMOTE-ready agent (dry-run), iterating the registry
60 promote-all skips an agent held by control.hold
61 promote-all does NOT advance a BLOCKED+REGRESSION agent
62 promote-all records each real promotion to CANARY_PROMOTIONS_LOG
dev-lead-lint.sh: all checks passed (shellcheck 86 files @ warning + agent frontmatter)
YAML parse OK Β· deployment-step heredoc bash -n OK + functional (valid JSON body per journal line)
Files Changed
.github/workflows/canary-rollout.yml: agent options β all 7 (sorted); schedule evaluate-all β gated promote-all (real, not dry); CANARY_PROMOTIONS_LOG env; deployment step loops the journal (one Deployment per promoted agent); header/comment updates
The choice-input options: list must stay a single-line flow sequence ([a, b, ...]); the drift checker enforces sync but expects that format. Regenerate with scripts/canary_agent_options.sh list.
Concurrency: scheduled promote-all groups under canary-rollout-fleet while manual per-agent promotes group under canary-rollout-<agent>, so a manual promote of the same agent could overlap a fleet tick. Pre-existing group design (fleet was already read-only evaluate-all); tag moves are -f idempotent so the window is low-risk, but a follow-up could tighten it if desired.
gate.control.hold is read with a // false default and is not added to the shipped registry β an operator sets it per-agent to pause scheduled promotion without a workflow edit.
Owner decision: A β gated scheduled auto-promote (truly hands-off, override-only)
Build both parts:
1. agent dispatch input lists all registry agents
Generate the options: from canary-rings.json (or free-text validated against it) so manual evaluate/promote/rollback can target any of the 7 and it never goes stale.
2. Gated scheduled auto-promote (the timer advances the fleet)
If gate = PROMOTE (dwell + sample + cumulative-health all pass, benign-allowlist applied) AND no control hold/pin/pause for that agent β advance ONE ring (cut-release.sh <agent> <ver> --channel <next> --promote --push via the App token) and record a GitHub Deployment.
Advance at most one ring per agent per run β let each tier soak its own dwell before the next hop.
Hard-stop on REGRESSION: never promote; auto-write a control hold + alert (open/label an issue). This is the ONLY thing that stops the rollout β a genuine criteria failure.
PRE_EXISTING/benign failures β the benign allowlist already excludes configured classes; anything left un-excluded holds that agent (report, don't promote) and surfaces for a human β do not auto-rollback.
Safety / control
Honor control.yml (or the equivalent): global pause, per-agent hold_at, pin, rollback, force. Default = fully autonomous through stable (override-only).
Keep an explicit arm switch (e.g. auto_promote: true default, or a repo variable) so a human can flip the whole loop back to evaluate-only in one place.
Still emit the evaluate report every run (observability) whether or not it promotes.
This is the "complete the rollout unless there's a failure to meet criteria" model the owner asked for. It completes the in-flight #482 rollout (4 reusables at ring1 β stable, one ring per timer as each soaks) without any manual dispatch, while a regression or a control hold stops it cleanly.
Activity
don-petry commentedon Jul 3, 2026
Dev-Lead Implementation Plan
Issue: #1045 β canary-rollout can't promote the #482 reusables: agent dispatch input hardcoded to [dev-lead] + no scheduled promote path
Scope
Make the
canary-rollout.ymlagentdispatch input list every agent incanary-rings.json(registry-driven, drift-guarded so it never goes stale), and add a gated scheduled promote path so the 4h timer autonomously advances each agent one ring when its #548 gatePROMOTEs β hard-stopping on regression and respectingcontrolholds/overrides (the owner directive: autonomous through stable, override-only).Implementation Checklist
scripts/canary_agent_options.shβ new:list(emit sorted registry agent keys = canonical choice options) +check <workflow>(fail on drift vs the workflow'sagentinput options)scripts/canary-rollout.shβ addcmd_promote_all(fleet-wide gated promote: PROMOTE-only, respectscontrol.hold/control.allow_pre_existing, hard-stops on REGRESSION, honors--dry-run); add_require_agentregistry validation to evaluate/promote/rollback; append each real promotion toCANARY_PROMOTIONS_LOGfor multi-deploy recording; update usage header.github/workflows/canary-rollout.ymlβ regenerateagentinputoptions:to all 7 agents; switch the schedule from read-onlyevaluate-allto gatedpromote-all(real, not dry); loop the deployment-recording step overCANARY_PROMOTIONS_LOG; update header commentsAGENTS.mdβ document the manual "flip to auto" path + thecontrol.holdpause switchTests to Write
tests/canary_rollout.bats: workflowagentoptions == registry keys (drift guard)tests/canary_rollout.bats:canary_agent_options.sh listemits all 7 sorted keys;checkpasses on the real workflow and fails on an injected drifttests/canary_rollout.bats:promote-alliterates the registry and advances a PROMOTE-ready agent (dry-run), skips acontrol.holdagent, and refuses a BLOCKED+REGRESSION agenttests/canary_rollout.bats: unknown agent is rejected with a clear error (registry validation)Test Command
scripts/run-bats.sh tests/canary_rollout.batsandbash .dev-lead/scripts/dev-lead-lint.shdon-petry commentedon Jul 3, 2026
Dev-Lead: Implementation Complete
Plan Execution
agentdispatch input now lists all 7 registry agents (was hardcoded[dev-lead]) β dispatching-f agent=auto-rebaseetc. no longer 422sscripts/canary_agent_options.sh(listregenerates,checkfails on drift vscanary-rings.json)_require_agentvalidation incanary-rollout.sh(evaluate/promote/rollback reject an unknown agent instead of silently resolving to an empty frontier)promote-all: for every agent, advance one ring per tick iff its feat: implement issue #545 β Compliance: non-stub-dependency-audit.ymlΒ #548 gate is PROMOTEpromote-allskipsgate.control.holdagents, honoursgate.control.allow_pre_existing, hard-stops on REGRESSION, never auto---overridesCANARY_PROMOTIONS_LOG; deployment-recording step loops it so a fleet tick that advances several agents records a Deployment for eachcontrol.holdpause switch inAGENTS.mdTest Results
Files Changed
.github/workflows/canary-rollout.yml:agentoptions β all 7 (sorted); scheduleevaluate-allβ gatedpromote-all(real, not dry);CANARY_PROMOTIONS_LOGenv; deployment step loops the journal (one Deployment per promoted agent); header/comment updatesscripts/canary-rollout.sh:_require_agent,cmd_promote_all,promote-allsubcommand, promotion journaling (replaces the single-tripleGITHUB_OUTPUT), usage headerscripts/canary_agent_options.sh(new):list/checkβ the registry-driven option generator + drift gatetests/canary_rollout.bats: 11 new testsAGENTS.md: new "Canary rollout automation" subsectionNotes
-f agent=<x>dispatch and autonomously by the timer.options:list must stay a single-line flow sequence ([a, b, ...]); the drift checker enforces sync but expects that format. Regenerate withscripts/canary_agent_options.sh list.promote-allgroups undercanary-rollout-fleetwhile manual per-agent promotes group undercanary-rollout-<agent>, so a manual promote of the same agent could overlap a fleet tick. Pre-existing group design (fleet was already read-only evaluate-all); tag moves are-fidempotent so the window is low-risk, but a follow-up could tighten it if desired.gate.control.holdis read with a// falsedefault and is not added to the shipped registry β an operator sets it per-agent to pause scheduled promotion without a workflow edit.don-petry commentedon Jul 3, 2026
Owner decision: A β gated scheduled auto-promote (truly hands-off, override-only)
Build both parts:
1.
agentdispatch input lists all registry agentsGenerate the
options:fromcanary-rings.json(or free-text validated against it) so manualevaluate/promote/rollbackcan target any of the 7 and it never goes stale.2. Gated scheduled auto-promote (the timer advances the fleet)
On the schedule, for each agent in the registry:
controlhold/pin/pause for that agent β advance ONE ring (cut-release.sh <agent> <ver> --channel <next> --promote --pushvia the App token) and record a GitHub Deployment.controlhold + alert (open/label an issue). This is the ONLY thing that stops the rollout β a genuine criteria failure.Safety / control
control.yml(or the equivalent): globalpause, per-agenthold_at,pin,rollback,force. Default = fully autonomous throughstable(override-only).auto_promote: truedefault, or a repo variable) so a human can flip the whole loop back to evaluate-only in one place.This is the "complete the rollout unless there's a failure to meet criteria" model the owner asked for. It completes the in-flight #482 rollout (4 reusables at ring1 β stable, one ring per timer as each soaks) without any manual dispatch, while a regression or a
controlhold stops it cleanly.Refs #1036/#1044 (registry), #1025/#1026, #548, #502 (Deployments/observability).
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat: implement issue #1045 β canary-rollout can't promote the #482 rβ¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
19 remaining items
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
ci(canary-rollout): list all registry agents in the dispatch input (#β¦
feat(canary-rollout): gated scheduled fleet auto-promote (#1045 part β¦
don-petry commentedon Oct 21, 2026
Closing after the 2026-10-21 backlog triage.
Why: Fixed: agent choice lists all registry agents; scheduled promote-all exists.
Evidence: combsmith/.github canary-rollout.yml:72-84; PRs #1047,#1056,#1060
Reopen if this still reproduces on main.