Skip to content

feat(templates): ship Vercel Cron canary-tick out of the box - #9

Open
PBab13 wants to merge 1 commit into
masterfrom
feature/lover-5123-vercel-cron-canary-tick
Open

feat(templates): ship Vercel Cron canary-tick out of the box#9
PBab13 wants to merge 1 commit into
masterfrom
feature/lover-5123-vercel-cron-canary-tick

Conversation

@PBab13

@PBab13 PBab13 commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrate the canary ramp scheduler shipped by @dotworld/shadow-canary-templates from GH Actions cron to Vercel Cron, so new consumers get the reliable system out of the box.

  • GH Actions schedule: '*/15 * * * *' was best-effort under runner load (intervals up to 80+ min observed in practice) and could be silently cancelled by deploy-shadow.yml sharing the shadow-canary-${repo} concurrency group.
  • Vercel Cron fires on time with guaranteed delivery — fix already validated downstream in FileWorld (LOVER-5043, mus-inn/fileworld#644).

The upstream template (v0.7.2) still shipped the deprecated bash path. New adopters thus inherited the broken scheduler. This PR brings the template in sync.

What new adopters get

  • app/api/canary-tick/route.ts — orchestration entry point hit by Vercel Cron every 15 min. Mirrors the bash workflow logic 1:1:
    • bearer auth (CRON_SECRET) with constant-time compare
    • SLO probe against the new prod deploy with VERCEL_AUTOMATION_BYPASS_SECRET support
    • 2-tick hysteresis (single NOK records, two consecutive NOKs trigger rollback)
    • Paris-time-gated ramp cap (20% before 12:00, 100% after)
    • sloChecks ring buffer (10 entries, body excerpt capped at 500 chars)
    • opt-in Slack notify on promote / rollback (SLACK_WEBHOOK_URL_MONITORING_CHANNEL)
    • rollback also pauses the canary so transient SLO flakes don't auto-recover.
  • lib/canary/tick.ts — pure decision helpers (decideAction, parisHourCap, extractPrevOk, appendSloCheck, pctAfterTick, trimBodyExcerpt). Imports @dotworld/shadow-canary-core types only.
  • vercel.jsoncrons: [{ path: '/api/canary-tick', schedule: '*/15 * * * *' }].

What changes for existing adopters

  1. Re-run npx shadow-canary-copy (or copy the three new files by hand).
  2. Add env: CRON_SECRET (required — auto-injected in deployed Vercel envs; signs cron calls), SLO_AUTH_TOKEN (required — bearer forwarded to the SLO endpoint). Optional: VERCEL_AUTOMATION_BYPASS_SECRET, SLACK_WEBHOOK_URL_MONITORING_CHANNEL.
  3. Ensure /api/slo on the host project reads SLO_AUTH_TOKEN and accepts Authorization: Bearer ${SLO_AUTH_TOKEN}.

canary-ramp.yml is now a manual fallback

schedule: dropped; workflow_dispatch kept. An operator can hand-trigger a tick if /api/canary-tick is broken (e.g. a bad deploy ships a failing route). Same decision logic, same env, no behavioural drift.

Notes

  • Tests skipped — templates package ships no tests today. Pure helpers in lib/canary/tick.ts are covered in the FileWorld repo (src/lib/canary/tick.test.ts, 156 lines, 100% branch).
  • Slack notify kept opt-in (no-op when env var unset) to match the existing convention in the template.
  • Changeset: minor bump on @dotworld/shadow-canary-templates. Templates is in the fixed group with -core and -skill, so all three bump together.
  • Manifest payload version bumped 0.2.1 → 0.3.0.

Linear

LOVER-5123

Test plan

  • pnpm install resolves without issues
  • pnpm changeset status shows the new minor bump
  • npx shadow-canary-copy /tmp/test-app (after publish or via pnpm pack) copies the new files
  • Manual: deploy a fresh project, set CRON_SECRET + SLO_AUTH_TOKEN, verify /api/canary-tick returns 401 without bearer and 200 with the right bearer
  • Manual: trigger a canary, verify the cron advances the ramp on a Vercel deploy (Cron logs in Vercel dashboard)

Generated with Claude Code.

GH Actions schedule:'*/15' was best-effort under runner load (intervals up
to 80+ min observed) and could be silently cancelled by deploy-shadow
sharing the shadow-canary-${repo} concurrency group. Vercel Cron fires on
time with guaranteed delivery.

- Add app/api/canary-tick/route.ts (auth, SLO check, 2-tick hysteresis,
  Paris-time-gated ramp cap, sloChecks ring buffer, opt-in Slack notify).
- Add lib/canary/tick.ts (pure decision helpers, imports core types only).
- vercel.json registers the */15 cron.
- canary-ramp.yml: drop schedule, keep workflow_dispatch only (manual
  fallback for when /api/canary-tick is broken).
- .env.local.example: document CRON_SECRET, SLO_AUTH_TOKEN, optional
  VERCEL_AUTOMATION_BYPASS_SECRET, optional SLACK_WEBHOOK_URL_MONITORING_CHANNEL.
- manifest.json: register new files, bump payload version 0.2.1 -> 0.3.0.
- Changeset: minor bump on @dotworld/shadow-canary-templates (fixed group
  pulls core + skill along).

Refs LOVER-5123. Inspired by FileWorld migration in LOVER-5043.

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

1 participant