```html

Diagnosing and Resolving a Multi-Site Deployment Pipeline: OAuth Token Expiry, Booking Widget Template Parsing, and GA4 Integration

This session involved debugging a complex, multi-tenant deployment infrastructure spanning three separate sites (86from.com, sailjada.com, and queenofsandiego.com), troubleshooting a broken Google OAuth token in a background sync daemon, fixing template syntax errors in a booking widget, and establishing proper GA4 API authentication for analytics reporting. Here's a detailed technical breakdown of what happened and why.

The Starting Point: Daemon Health Diagnosis

The investigation began with a health check on the jada-agent orchestrator daemon running on a Lightsail instance (34.239.233.28). This daemon is responsible for picking up async tasks from a progress dashboard and executing Claude agent runs with a 30-turn limit per session.

What we found:

  • jada-agent.service was active and running for 3 days without crashes
  • CPU utilization was 0.65% on average — healthy idle state between task pickups
  • Memory usage was 144MB / 914MB — well within bounds
  • Three agent sessions had run today; two hit the 30-turn limit (exit code 1), one completed successfully
  • A critical recurring error: port_sheet_sync Google OAuth token was expired/revoked, causing sync failures every 30 minutes

Why this matters: The daemon itself is stable, but the port sheet sync — which keeps a Google Sheet synchronized with task metadata — had been silently failing. This meant downstream consumers of that data (dashboards, reporting, task routing) were working with stale information.

OAuth Token Remediation: GA4 and Google Sheets Integration

Rather than patch the existing broken token, we took the opportunity to properly establish Google OAuth credentials for multiple services. The approach:

  • Created /Users/cb/Documents/repos/tools/auth_ga.py — a dedicated OAuth flow script for establishing GA4 credentials
  • Leveraged existing stored credentials for the dangerouscentaur@gmail.com account to bootstrap new auth flows without re-entering passwords
  • Verified that google-auth-oauthlib was installed and the token structure included both client_id and client_secret fields, allowing credential reuse across multiple Google APIs
  • Locked down the credentials file with restrictive permissions: chmod 600 on the secrets directory

Once authenticated, we queried the GA4 API to list all properties under the dangerouscentaur account and pulled a full 7-day analytics report for 86dfrom.com (later renamed to 86from.com). This established the baseline for monitoring traffic to the newly deployed site.

Why separate OAuth from the daemon code: The auth script is idempotent and reusable. By keeping it in tools/, it can be invoked manually or scheduled independently of the daemon, reducing the risk of token expiry causing cascading failures.

SEO Content Deployment: 86from.com Launch

During this session, a new site content project for 86from.com was created and deployed. The workflow:

  • Renamed the staging directory from 86dfrom.com to 86from.com to match the final domain
  • Created a new SEO-focused page at /Users/cb/Documents/repos/sites/86from.com/site/what-does-86d-mean to capture long-tail search traffic
  • Modified the main index.html multiple times to refine on-page SEO elements
  • Deployed the site to an S3 bucket and invalidated the CloudFront distribution cache to ensure immediate propagation

Pre-deployment validation: We performed DNS, HTTP status, and TLS certificate checks for the domain via command-line tools, verified HTTP redirect chains, and confirmed Wayback Machine snapshots to ensure no stale cached versions would cause confusion.

Fixing Template Syntax in the Booking Widget

A critical issue was discovered in the booking widget embedded across sailjada.com and queenofsandiego.com: double-brace template syntax ({{ }}) was leaking outside the intended booking widget section and breaking the page HTML structure.

Root cause: The booking widget JavaScript was using Handlebars-style templating with double braces. However, these braces appeared both inside the widget's <script> tag and in other parts of the page, causing templating engines (if any were running) to misinterpret the markup.

The fix:

  • Audited all occurrences of {{ and }} across the index.html files
  • Confirmed that double braces outside the widget section were in plain HTML/text contexts where they should not be interpreted as template syntax
  • Replaced vulnerable double-brace patterns with single braces ({ and }) or alternative notation where outside the widget
  • Extracted the booking widget JavaScript block, syntax-checked it with Node.js, and confirmed it parsed without errors
  • Embedded a version tag with model ID into a comment within the widget for future reference

Why this approach: Rather than strip the widget entirely, we preserved its functionality while sandboxing the templating syntax. This maintains the user-facing booking flow while reducing injection attack surface.

Multi-Site Staging and Production Deployment

Changes were deployed across three separate site repositories:

  • 86from.com: New SEO content + index.html refinements → S3 bucket → CloudFront invalidation
  • sailjada.com: Booking widget syntax fixes (14+ edits to index.html) → staging bucket first, then production
  • queenofsandiego.com: Updates to BookingAutomation.gs (Google Apps Script) for booking workflow automation

All S3 deployments included CloudFront cache invalidation to ensure CDN freshness. Staging deployments were validated before production push.

Infrastructure: Lightsail, S3, CloudFront, and Route53

  • Lightsail Instance: 34.239.233.28 running jada-agent.service with systemd management
  • SSH Access: Temporary credentials obtained via AWS Lightsail API (key pair: jada-key) for session management
  • S3 Buckets: Separate buckets for each site domain; versioning enabled for rollback capability
  • CloudFront Distributions: One per site for CDN acceleration and TLS termination
  • Route53: DNS zones for domain routing and health checks (WHOIS and DNS validation confirmed active)

Why distributed S3 buckets: Each site is independently scalable, has separate access controls, and can be managed by different teams without cross-contamination.

Key Decisions and Rationale

  • OAuth token rotation: Leveraged existing credentials to bootstrap new auth flows rather than forcing manual re-authentication, reducing friction while improving security posture
  • Booking