Skip to content

feat(rollout): add the rollout ticker, its workflow and promotion's rollout input - #88

Open
scott-lowe-vapi wants to merge 1 commit into
gradual-deploy-rollout-pin-around-applyfrom
gradual-deploy-rollout-ticker
Open

scott-lowe-vapi wants to merge 1 commit into
gradual-deploy-rollout-pin-around-applyfrom
gradual-deploy-rollout-ticker

Conversation

@scott-lowe-vapi

@scott-lowe-vapi scott-lowe-vapi commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Support partial GitOps promotions using traffic splitting

Part of DEPLOY-205. 3 of 5: the ticker that moves ramps forward, and the workflows that run it.

What changes

  • npm run rollout -- advance|abort|status (src/rollout-cmd.ts; decisions in src/rollout-tick.ts, pure):
    • A step whose interval has passed moves to the next step.
    • The last step is an explicit 100%. The next tick hands back to follow-latest, or holds if a newer, un-ramped version was published meanwhile, because follow-latest would send that version every call.
    • A pin older than 6h (the promotion step's cap is 330 min, and a test ties the two) is adopted if its run published, released if it replaced the default, and otherwise flagged.
    • Any split changed by someone else stops that ramp.
    • An abort is retried once on a race.
  • .github/workflows/rollout.yml:
    • cron every 15 min, behind VAPI_ROLLOUT_ENABLED; dispatch always runs;
    • its own vapi-rollout concurrency group, never vapi-promotion, so a tick can't cancel a pending promotion;
    • a dispatched abort gets a group of its own;
    • timeout-minutes: 15, read-only, commits nothing.
  • promotion.yml gains a rollout dispatch input (default, no-rollout, override; override needs pipeline/from/to). Push-triggered runs are unchanged.
  • Docs: the rollout workflow in docs/guides/promotion.md, npm run rollout in commands.md and the README, and the per-write labels in how-it-works.md.

Evidence

  • tests/rollout-tick.test.ts covers every row of the decision table, including the killed-before-publish pins over an abort, a hold and an override, which are not adopted.
  • tests/rollout-cmd.test.ts covers advance, a foreign change, an idempotent 409, the probe skip, abort and its race, and status.
  • tests/rollout-workflow.test.ts runs both workflows' real shell steps with an npm stub, plus the 6h-vs-330-min check.

672 tests pass. actionlint runs in CI; I didn't run it locally.

🤖 Generated with Claude Code

…ollout input

npm run rollout -- advance|abort|status moves each ramp one step once its
interval has passed, using the assistant's newest traffic allocation as the
ramp's only state. The last step is an explicit 100%, handed back to
follow-latest only while no newer, un-ramped version exists. A pin left by a
killed promotion is picked up after 6h (longer than the promotion step's
330-minute cap). Any split changed by someone else stops that ramp.

.github/workflows/rollout.yml runs advance every 15 minutes behind
VAPI_ROLLOUT_ENABLED, in its own concurrency group so it can never cancel a
pending promotion; a dispatched abort is never queued. promotion.yml gains a
rollout dispatch input (default, no-rollout, override).

Part of DEPLOY-205.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

scott-lowe-vapi commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor Author

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.

1 participant