Semver push-CD - cutover runbook¶
Date: 2026-06-28 Companion to docs/superpowers/specs/2026-06-28-semver-push-cd-design.md. Covers the gated, one-time, mostly out-of-repo steps the implementation workflow could NOT perform (tag pushes, repo settings, Harbor policy, secrets, the enable-auto-merge cutover). The code lives on feat/semver-push-cd in every component repo; this is what makes it live.
Do the steps IN ORDER. Steps 1-5 are safe to do anytime (they do not change runtime behavior). Step 6 is the irreversible cutover.
0. Pre-flight: review + merge the branches¶
feat/semver-push-cd exists locally in: operator, helmfile, cli, wrapper, memory, ingester, chat, agent-skills, observability. Review each diff, then merge to each repo main (normal CI builds + publishes current-style artifacts; nothing auto-deploys yet because auto-merge/tagging is not active until step 6). NOTE: the very first merge that LANDS release.yml will not itself trigger a release run (workflow_run/push release jobs only fire once the workflow is already on main) - expected GitHub behavior.
1. Seed semver tags (before any release run)¶
cd-release mode=tag computes the next version from the latest tag matching ^v?[0-9]+\.[0-9]+\.[0-9]+$ (stray non-semver tags such as memory's wave-N-merged are ignored by design). Repos lacking a clean vX.Y.Z tag must be seeded once, or the first release cuts from v0.0.0 -> v0.0.1 and goes backwards from the static chart/plugin version.
Recommended seeds (use max(existing clean semver tag, static version)):
| repo | seed | source of truth |
|---|---|---|
| tatara-operator | v0.4.10 | Chart.yaml |
| tatara-claude-code-wrapper | v0.1.0 | (no version today) |
| tatara-memory-repo-ingester | v0.2.9 | Chart.yaml |
| tatara-chat | v0.1.0 | static Chart.yaml 0.1.0 |
| tatara-agent-skills | v0.1.0 | plugin.json 0.1.0 |
| tatara-memory | v0.4.0 | Chart.yaml (only wave-N-merged tags exist) |
| tatara-cli | already v0.4.0 | leave as-is |
2. TATARA_CD_TOKEN (bot PAT) as an Actions secret¶
Add TATARA_CD_TOKEN (the szymonrychu-bot PAT) as a repo (or org) Actions secret on all 9 repos. Scope: push tags on the repo itself + clone / open PR / enable-auto-merge on its PARENT repo (cli->wrapper, skills->wrapper, wrapper->helmfile, operator/memory/ingester/chat->helmfile). The terminal helmfile needs it only to be a bump target (no parent).
3. Branch protection + Allow auto-merge (all 7 deploy-flow repos)¶
For operator, cli, wrapper, memory, ingester, chat, helmfile: - Enable "Allow auto-merge" in repo settings (the action calls gh pr merge --auto; it errors if this is off). - Protect main with the repo's CI as a REQUIRED status check (helmfile diff is the required check on tatara-helmfile). Auto-merge only fires once required checks pass.
4. Harbor retention policy¶
Add a Harbor retention rule that PROTECTS vX.Y.Z (image) and X.Y.Z (chart) tags from GC, separate from the churning :SHORT_SHA tags. Without this the recurring chart-not-found class (operator-ci-partial-chart-publish, helmfile MEMORY #45/#46) recurs with semver tags.
5. Observability alert (safe to land early)¶
tatara-observability/alerts/tatara-cd.yaml (tatara_cd_cascade_failed / _stalled, gauge semantics) stays inert (value 0) until the operator emits the gauges - which ships with the operator branch. Merge observability whenever; it reconciles once operator is deployed.
6. CUTOVER (irreversible - do auto-merge enablement and the no-self-merge¶
docs together)¶
Order matters: enabling auto-merge BEFORE the docs forbid self-merge is fine; landing the docs BEFORE auto-merge exists freezes all merges. So:
- Deploy the operator branch (bot-gated
EnableAutoMerge+ significance gate +Deployingphase + deploy-supervision + deploy-ledger + cdScan + issue-close) via a tatara-helmfile bump (the LAST hand-edited pin bump - after this, bumps are automated). Set the Project CRdeployBudgetSeconds(default 3300; single-hop override 2100) if tuning the 1.2x budget. - In the SAME cutover, land the agent-facing doc edits forbidding self-merge: add the CD section to each component
CLAUDE.md(agents declarechange_significance; NEVER self-merge; the pipeline merges/tags/deploys/ closes) and theMEMORY.mdnote. (These edits were intentionally NOT made by the build - they belong here.) - From now on: every component merge auto-cuts a tag, auto-propagates, and auto-applies; the originating issue auto-closes on apply success.
7. Post-cutover cleanup¶
- Retire each repo's legacy
ci.ymlimage/chart publish job once its helmfile pin has moved tovX.Y.Z(the workflow left them in place, so during cutover each merge double-builds::SHORT_SHAvia ci.yml then:vX.Y.Zvia release.yml - buildkit cache makes the second cheap, but the duplicate is removable once pins are semver). - Confirm the ingester
chartjob was dropped (vestigial; pinned nowhere). - Reconcile the live
mem-infrastructure-pgio_method=syncdrift and any other open helmfile drift before the first automated apply.
Known operational caveats (by design, not bugs)¶
- mode=tag is not idempotent on a re-run: re-running a release job after a tag was cut computes from the now-latest tag and cuts another bump. Do not blindly re-run a green release job.
- Propagation (bump) PRs are always labeled
semver:patch- a dependency bump is a patch by definition. Component significance does NOT propagate past the first hop; that is intended (the parent's own version reflects "a dep moved"). - The cli/skills build-guard runs on push-to-main, not at PR time, so a guard-breaking bump auto-merges then fails post-merge CI - deploy-supervision / cdScan catch the stalled cascade and reroll. If a PR-time guard gate is wanted later, add it as a required check.