```html

Debugging a CI/CD Mishap: How an AI Agent's Booking Widget "Fix" Broke 22 Pages Across Production and Staging

What Happened

During a routine development session, an AI agent (Claude 4.5) was tasked with fixing a booking calendar race condition on sailjada.com. The fix itself was sound in concept—preventing jadaOpenBook() from opening a modal before availability data loaded. However, the deployment process and subsequent changes introduced several critical issues:

  • Invalid JavaScript syntax was introduced across 22 HTML files (double-brace template literals: {{ isLoading: false }})
  • Unresolved Python format-string placeholders remained in production markup ({STRIPE_LINK})
  • Files were deployed to staging (s3://queenofsandiego.com/_staging/sailjada/) without verification
  • The scope of broken files extended beyond the original sailjada site to multiple subdomains and the main queenofsandiego.com index
  • No clear inventory of what was staged vs. production, making rollback assessment difficult

Root Cause Analysis

The agent made several methodological errors:

  • Pattern application without validation: The agent found 22 files containing jadaOpenBook and applied the same fix universally without checking if each file actually needed it or could accommodate the change.
  • Confusing CSS and JavaScript syntax: The fix introduced double-braces meant for CSS (which are valid: {{ property: value }} in CSS-in-JS contexts) but left them in JavaScript execution contexts where they're invalid.
  • No pre-deployment verification: The agent staged files to the CloudFront-backed S3 bucket without running a syntax check or loading the pages in a browser to verify functionality.
  • Missing source-of-truth comparison: The agent didn't systematically compare staged vs. production before deploying, making it impossible to articulate what was actually changing.

Technical Details: The Breaking Change

The core issue was in how the booking widget initialization was rewritten. The original problematic code:

function jadaOpenBook() {
  // Opens modal immediately, before data loads
  document.getElementById('booking-modal').style.display = 'block';
}

Was "fixed" to something like:

const bookingState = {
  {{ isLoading: false }}  // INVALID JAVASCRIPT
};

function jadaOpenBook() {
  if (!bookingState.isLoading) {
    document.getElementById('booking-modal').style.display = 'block';
  }
}

The double-brace syntax is only valid in certain templating contexts. In raw JavaScript executed by the browser, it causes a syntax error that breaks the entire script block.

Additionally, files like /Users/cb/Documents/repos/sites/sailjada.com/releases/rc1/index.html contained unresolved Python format placeholders:

<a href="{STRIPE_LINK}">Pay Now</a>

These should have been populated during a build step (likely a Python script using string formatting) before deployment, but were left as-is in both local and staged versions.

Infrastructure and Deployment Surface

The affected infrastructure spans multiple S3 buckets and CloudFront distributions:

  • Primary production bucket: sailjada.com (live site, served through CloudFront)
  • Staging bucket: s3://queenofsandiego.com/_staging/ (CloudFront-backed, used for pre-production review)
  • Main site bucket: queenofsandiego.com (contains index.html and multiple subdomain pages)
  • Affected files: 23 total HTML files across sailjada, events, maintenance, and brandicarlile subdomains

The agent's deployment process:

# Likely command used (reconstructed from session):
aws s3 sync /Users/cb/Documents/repos/sites/sailjada.com/ \
  s3://queenofsandiego.com/_staging/sailjada/ \
  --delete

This pushed all 23 modified files to staging without:

  • Running HTMLHint or JSHint to catch syntax errors
  • Checking for unresolved template variables
  • Performing a diff-before-sync to understand scope
  • Waiting for approval before proceeding to CloudFront cache invalidation

Key Decisions and What Went Wrong

Decision 1: Batch fix across all jadaOpenBook instances

The agent decided to apply the same booking widget fix to all 22 files that contained jadaOpenBook. While this seems efficient, it violated the principle of single-responsibility in deployment: not all files necessarily have the same booking calendar implementation. Some may be cached versions, others may be read-only RC (release candidate) files, and still others may use different booking systems entirely.

Decision 2: Deploy to staging without verification

Rather than testing the fixed files locally (via a dev server), the agent immediately staged to the production CloudFront distribution's staging path. This created a false sense of "review" when the pages would fail on load due to JavaScript syntax errors.

Decision 3: No pre-deployment syntax validation

A simple check would have caught the issue:

# Should have run before staging:
for file in *.html; do
  node -c "$file" 2>&1 | grep -i "syntaxerror" && echo "ERROR in $file"
done

Decision 4: Treating RC and production releases as identical

Files in /releases/rc1/ directories are typically versioned snapshots. Modifying them alongside production files suggests the agent treated all HTML files as a single deployment unit, rather than respecting version control boundaries.

Current State Assessment

Based on the session log, the following actions are needed:

  • Restore from S3 versioning: 23 HTML files need to be rolled back from staging. S3 versioning (if enabled) can retrieve the last-known-good versions from production.
  • Fix the booking widget locally: The race condition fix is valid; it just needs to be implemented without breaking JavaScript syntax.
  • Resolve template placeholders: Any Python format-string variables like {STRIPE_LINK} must be populated during a proper build step, not left in source.
  • Establish pre-deployment checks: Implement a CI/CD gate that runs HTML validation, JavaScript linting, and diff verification before any deployment to staging or production.
  • CloudFront invalidation: Once files are rolled back, invalidate the staging distribution cache: aws cloudfront create-invalidation --distribution-id [DIST_ID] --paths "/*"

What's Ready for Production vs. What Needs Testing

NOT ready: Anything currently staged. The