Release & CI Workflows
A one-glance map of every GitHub Actions workflow across the Playroll repos — what triggers it and what it does — plus which skill drives which workflow. Use it to answer "what actually happens when I push this tag?" without reading YAML.
How a release flows (the short version)
- cpp is tagged
vX.Y.Z→ its CI builds the core and uploads a zip to S3 (no user impact yet). - installer is tagged
playroll/<track>/vX.Y.Z(pinned to specific cpp/ui tags viarelease-manifest.yml) → its CI builds + signs the installer, publishes to the CDN, and writes a row in Supabaseapp_releases_v2. - A rollout (
rollout.yml/ an override) decides who receives it. Publishing and audience are separate steps — a published release reaches nobody until a rollout or override targets them.
The user-facing artifact is the signed Playroll_Setup_X.Y.Z.exe, not the cpp
core zip. The UI never releases on its own — it is pinned and built by the
installer.
Workflows by repo
| Repo | Workflow | Trigger | What it does |
|---|---|---|---|
| playroll-cpp | build-check.yml | push/PR on main,develop,ci/** | Compiles the core in Release as a check. No publish. |
| playroll-cpp | build-release.yml | tag v*, or manual dispatch | Builds the core and uploads playroll-core-build.zip to S3. If the artifact already exists for that tag, it skips the build (claim check). Does not roll out to users. |
| playroll-cpp | lambda-deploy.yml | push to main touching lambda_src/**, or dispatch | Deploys the AWS Lambda functions. |
| playroll-installer | build-check.yml | PR on main | Builds the full installer (no signing, no publish) as a check. Checks out cpp/ui at main. |
| playroll-installer | dry-run.yml | manual dispatch | Build-only trial of the installer; publishes nothing. |
| playroll-installer | release.yml | tag playroll/{stable,test,dev}/v* | Builds + signs + publishes the installer, writes app_releases_v2. On the test track only, it auto-rolls 100% forced to the entire staff tester cohort. dev/stable do not auto-roll. |
| playroll-installer | rollout.yml | manual dispatch | Decides who receives a published release — writes app_rollouts_v2 / overrides. |
| playroll-installer | promote.yml | manual dispatch from a tag ref | Re-publishes an existing release on another track without rebuilding or re-signing. |
| playroll-installer | hotfix-tester-smoke.yml | push/PR touching hotfix-tester.ps1, or dispatch | Runs hotfix-tester.ps1 -DryRun and asserts the plan invariants. A safety net so a rename/schema change breaks CI, not the next real hotfix. |
| playroll-ui | build-check.yml | push/PR on main,develop,ci/** | Lint + typecheck + test + build. The UI ships only as part of an installer release. |
Skills and the scripts/workflows they drive
The canonical, CI-driven release flow lives in workspace-level skills
(ec-workspace/.claude/skills/), inherited by every repo.
| Skill / script | Lives in | Drives | Concern |
|---|---|---|---|
playroll-doctor | workspace skill | nothing (read-only) | Verifies the release environment is set up. Run before releasing. |
playroll-release | workspace skill | git-flow on cpp/ui + installer release.yml; also promotion | What ships. Includes a "Targeted hotfix to specific tester(s)" section. |
playroll-rollout | workspace skill | installer rollout.yml → app_rollouts_v2 | Who receives it. |
/hotfix-release | playroll-cpp command | the cpp-side hotfix detail (branch from the release tag, verify it builds on the old base, pre-stage the S3 artifact) | Defers to playroll-release / hotfix-tester.ps1 for the installer release + rollout. |
hotfix-tester.ps1 | playroll-installer script | dev-track release + forced override to an explicit user list | Deterministic single/multi-tester hotfix. Track is hardcoded dev, so it can never auto-roll to everyone. -DryRun writes nothing. |
release-testers.ps1, rollout-testers.ps1, local-release.ps1 | playroll-installer scripts | local publish/rollout | Dev-machine fallbacks, not the default path. |
Gotchas worth knowing
testtrack fans out. Taggingplayroll/test/v*auto-rolls the build to all staff testers (hard-wired inrelease.yml). To target one or a few testers, use trackdev+ an override —hotfix-tester.ps1does exactly this and removes the choice (no-Trackparameter).- The cpp tag is not a rollout. It only stages the core artifact on S3. Nobody gets anything until the installer release + a rollout.
- Publishing ≠ audience.
release.yml/playroll-releasepublish;rollout.yml/playroll-rolloutchoose who receives it. Keep them separate. promote.ymlmust be dispatched from a tag ref. The OIDC trust policy onAWS_RELEASE_ROLE_ARNonly trusts tag refs, sogh workflow run promote.yml --ref "playroll/<from_track>/v<X.Y.Z>" ...works while a dispatch frommain(the default) fails at the "Configure AWS credentials" step.promote.yml's CloudFront wait is best-effort. Ifaws cloudfront wait invalidation-completedtimes out, the run logs[WARN] Timed out waitingand still succeeds — the cache refreshes on its own within minutes. (Before 2026-07-09 the timed-out waiter's exit code leaked into the step result, failing the run after a successful promotion.)