Preventing S3 Regression: Hard Rules for Multi-Environment Deployments on queenofsandiego.com
Over a three-hour development session, a regression in production exposed a critical gap in deployment safety guardrails. A stale local index.html was deployed to S3, wiping three unrelated working features: the hero crossfade animation (JADA → BOOK NOW), the Stripe embedded checkout booking flow, and inadvertently resurrecting a deleted hero section. The session also violated the staging-first rule by deploying both staging and prod in a single command. This post documents the hard rules now enforced to prevent that pattern, the infrastructure decisions that made it possible, and how to recover when S3 is ahead of local code.
What Went Wrong
- Stale local code: The working Stripe checkout and hero animations existed in S3 prod but not in the local git checkout. No pre-deploy diff was run against S3 before editing.
- Single-command dual deploy: Both
stagingandprodCloudFront distributions were invalidated in one command, bypassing the staging-review gate. - Ignored prior warnings: The previous session summary explicitly warned about stale local files. The warning was not re-read before proceeding.
- No feature registry: Working features in S3 had no canonical list to grep against after deploy, so the loss went undetected until manual testing.
Hard Rules: D1–D8
These eight rules are now embedded in /Users/cb/Documents/repos/sites/queenofsandiego.com/CLAUDE.md and auto-load at the start of every QOS development session:
- D1: Pull and Diff Before Edit. Before modifying any file that will be deployed to S3, run
aws s3 cp s3://queenofsandiego.com/index.html ./index.html.prodand diff it against local. If they differ and you didn't author both versions, stop and ask CB which is canonical. This prevents deploying over untracked changes. - D2: Staging Only, Single File Per Change. Every deploy targets staging CloudFront distribution
E123ABC456DEF(prod isE789XYZ012GHI). Deploy one logical change at a time:aws s3 cp index.html s3://staging.queenofsandiego.com/index.html, test, then promote to prod. Never deploy to both in the same command. - D3: Obey Your Own Prior Session Warnings. Before starting work, re-read the last session summary in
CLAUDE.md. If it warns about stale local files, S3 drift, or unresolved features, treat it as a blocker until resolved. Copy the warning into your working context. - D4: Snapshot Prod Before Overwrite. S3 has no versioning enabled. Before any
cpto prod, download and timestamp the current prod version:aws s3 cp s3://queenofsandiego.com/index.html ./backups/index.html.prod.$(date +%s). Keep the last five snapshots. - D5: Six-Line Proof Block Before Deploy. Print this exact format in chat before running any S3
cpcommand:
If you cannot honestly fill in "Features preserved," do not deploy.DEPLOY PROOF — queenofsandiego.com/index.html → staging File: index.html | Size: 12,456 bytes | MD5: abc123def456 Changes: Hero animation fade, Stripe Session ID handling Features preserved: [list 3+ existing features not touched] Staging dist: E123ABC456DEF | Prod dist: E789XYZ012GHI (DO NOT TOUCH) Ready? [yes/no] - D6: Feature-Token Registry. Maintain a grep-able list of canonical features in
sites/queenofsandiego.com/FEATURES.md:
After any deploy to prod, grep the S3 HTML for these tokens. If missing, roll back immediately using the timestamped backup.## Active Features (as of [date]) - Hero crossfade animation: data-animation="jada-to-book" + CSS @keyframes fade-in-sequence - Stripe embedded checkout: window.Stripe('pk_live_...').elements().create('payment') - Referral code input: - Crew uniform email preview: /crew-uniform-reminder-preview.html - D7: Escalate to CB If S3 Is Ahead. Before any commit that modifies a file already live in S3, run:
aws s3 sync s3://queenofsandiego.com . --dryrun. If it shows files that would be deleted or overwritten, post the diff to CB in Slack with the subject "⚠️ S3 AHEAD OF LOCAL" and wait for approval before proceeding. - D8: One-File-Per-Logical-Change. A single git commit should change one feature or fix one bug, not bundle unrelated edits. This prevents rolling back a working animation while trying to fix a typo. Use separate commits for hero fade, Stripe checkout, crew uniform email—then merge only the commits you've tested to staging.
Infrastructure & File Paths
- S3 bucket:
queenofsandiego.com(static site root) - CloudFront staging distribution:
E123ABC456DEF(CNAME:staging.queenofsandiego.com) - CloudFront prod distribution:
E789XYZ012GHI(CNAME:queenofsandiego.com) - Git repo:
/Users/cb/Documents/repos/sites/queenofsandiego.com - Session memory:
/Users/cb/.claude/projects/-Users-cb-Documents-repos/memory/MEMORY.md - Guardrails document:
/Users/cb/Documents/repos/sites/queenofsandiego.com/CLAUDE.md - Backup directory:
./backups/(git-ignored, timestamped snapshots)
Why These Rules Work
Each rule targets a specific failure mode from the regression:
- D1 & D4 catch stale-local bugs before they ship.
- D2 enforces the staging gate so CB can review before prod goes live.
- D3 prevents repeating known mistakes in the same session.
- D5 forces explicit proof that you understand what you're shipping.
- D6 lets you detect feature loss post-deploy (and recover within minutes).
- D7 escalates decisions about conflicting state to the human owner.
- D8 makes rollback surgical instead of blunt.
What's Next
The same eight rules have been