docs: fix Task 8 rollout notes — never s3 rm --recursive the generations prefix
Review Critical: the old-key deletion step's \`s3 rm --recursive\` on
control/registry-snapshots/ deletes the NEW per-box generation trees too
(control/registry-snapshots/<box>/<stamp>.db) — S3 prefixes aren't
directories, and the step's own precondition ("both deployments run this
build") guarantees that live per-box DR history exists exactly when an
operator would run it. Replaced with a delimited list-then-delete: query
Contents (direct children only = the old flat <stamp>.db keys) and
CommonPrefixes (the per-box trees to leave alone) separately, delete only
what Contents listed, explain why --recursive is forbidden here.
Review Minor, folded in: made the "verify each box has snapshotted"
precondition executable — an \`aws s3 ls\` per deployment with the expected
shape (one <box>.db + one <box>.json per live box) and a sidecar-eyeball
instruction, instead of leaving it as unstructured prose.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+63
−13
docs/superpowers/plans/2026-08-20-multi-region-writer-map-and-certs.md+63 −13
diff --git a/docs/superpowers/plans/2026-08-20-multi-region-writer-map-and-certs.md b/docs/superpowers/plans/2026-08-20-multi-region-writer-map-and-certs.md| index ce724a806..a2bc2c735 100644 |
| --- a/docs/superpowers/plans/2026-08-20-multi-region-writer-map-and-certs.md |
| +++ b/docs/superpowers/plans/2026-08-20-multi-region-writer-map-and-certs.md |
| @@ -556,24 +556,74 @@ checklist for the rollout that follows. |
| `control/registry-snapshot.{db,json}` + `control/registry-snapshots/` |
| keys with per-box ones; the old keys are abandoned in place, not |
| migrated, and stay live in both deployment buckets until every box in |
| - both deployments has converged onto a release containing this branch |
| - (verify each box has written its own `control/registry-snapshot/<box>.db` |
| - before deleting the fixed keys — there is no CLI/console surface for |
| - this today, so it's a direct-bucket check, consistent with CLAUDE.md's |
| - carve-out for platform-internal infra work). Exact commands, one pair |
| - of buckets (flagship profile `keymail`, tito profile `titogo` — |
| - coordinates per CLAUDE.md/session memory): |
| + both deployments has converged onto a release containing this branch. |
| + |
| + **Verify first, per deployment** (no CLI/console surface for this |
| + today, so it's a direct-bucket check, consistent with CLAUDE.md's |
| + carve-out for platform-internal infra work): |
| + |
| + ```bash |
| + aws --profile keymail s3 ls s3://carlos-flagship-271376211898/control/registry-snapshot/ |
| + aws --profile titogo s3 ls s3://carlos-tito-platform-665106592142/control/registry-snapshot/ |
| + ``` |
| + |
| + Expect exactly one `<box>.db` + one `<box>.json` per box currently live |
| + in that deployment (a single-box deployment shows one pair). Open each |
| + `.json` and eyeball its `Box`/`CreatedAt` fields match the box that |
| + should have written it before touching anything below. |
| + |
| + **Deletion — do NOT use `s3 rm --recursive` on |
| + `control/registry-snapshots/`.** S3 prefixes are not directories: |
| + `--recursive` on that prefix deletes everything under it, including the |
| + NEW per-box generation trees at `control/registry-snapshots/<box>/<stamp>.db` |
| + — and the precondition above ("both deployments run this build") |
| + guarantees those trees hold live, real DR history at exactly the moment |
| + this step runs. A recursive delete here destroys precisely what the |
| + per-box scheme exists to protect. Instead, list only the DIRECT |
| + children of the prefix (the old flat `<stamp>.db` objects have no |
| + further `/` in their key; the new per-box trees do) with a delimited |
| + list, review that the output is old flat keys only — `CommonPrefixes` |
| + in the same listing are the per-box trees, and must not appear in what |
| + gets deleted — then delete exactly those keys plus the two fixed |
| + top-level keys: |
| ```bash |
| # flagship (carlos-flagship-271376211898) |
| - aws --profile keymail s3 rm s3://carlos-flagship-271376211898/control/registry-snapshot.db |
| - aws --profile keymail s3 rm s3://carlos-flagship-271376211898/control/registry-snapshot.json |
| - aws --profile keymail s3 rm s3://carlos-flagship-271376211898/control/registry-snapshots/ --recursive |
| + BUCKET=carlos-flagship-271376211898 |
| + # Review: Contents = old flat <stamp>.db keys to delete. CommonPrefixes |
| + # (query separately) = per-box trees to LEAVE ALONE. |
| + aws --profile keymail s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'Contents[].Key' --output text |
| + aws --profile keymail s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'CommonPrefixes[].Prefix' --output text |
| + # Delete only the direct-child keys the first query listed: |
| + aws --profile keymail s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'Contents[].Key' --output text | tr '\t' '\n' | \ |
| + while read -r key; do |
| + [ -n "$key" ] && aws --profile keymail s3 rm "s3://$BUCKET/$key" |
| + done |
| + aws --profile keymail s3 rm "s3://$BUCKET/control/registry-snapshot.db" |
| + aws --profile keymail s3 rm "s3://$BUCKET/control/registry-snapshot.json" |
| # tito (carlos-tito-platform-665106592142) |
| - aws --profile titogo s3 rm s3://carlos-tito-platform-665106592142/control/registry-snapshot.db |
| - aws --profile titogo s3 rm s3://carlos-tito-platform-665106592142/control/registry-snapshot.json |
| - aws --profile titogo s3 rm s3://carlos-tito-platform-665106592142/control/registry-snapshots/ --recursive |
| + BUCKET=carlos-tito-platform-665106592142 |
| + aws --profile titogo s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'Contents[].Key' --output text |
| + aws --profile titogo s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'CommonPrefixes[].Prefix' --output text |
| + aws --profile titogo s3api list-objects-v2 --bucket "$BUCKET" \ |
| + --prefix control/registry-snapshots/ --delimiter / \ |
| + --query 'Contents[].Key' --output text | tr '\t' '\n' | \ |
| + while read -r key; do |
| + [ -n "$key" ] && aws --profile titogo s3 rm "s3://$BUCKET/$key" |
| + done |
| + aws --profile titogo s3 rm "s3://$BUCKET/control/registry-snapshot.db" |
| + aws --profile titogo s3 rm "s3://$BUCKET/control/registry-snapshot.json" |
| ``` |
| 2. **teamtito runbook PR is owed at that same moment** (Task 1 ledger). |