Debugging and Resolving Duplicate Guest Pages: A Case Study in Agent Coordination and State Consistency
What Was Done
During a recent development session, we discovered and partially resolved a critical data consistency issue: a single Boatsetter charter booking (#xhqgmdh, Jonathan sunset cruise on 2026-05-30) existed in two separate HTML guest pages with conflicting information, misaligned with the authoritative time stored in DynamoDB. This post documents the investigation process, root cause analysis, and the infrastructure decisions required to prevent similar issues.
The Problem: Duplicate Pages and State Divergence
Two guest page files existed for the same booking:
s3://queenofsandiego.com/g/2026-05-30-jonathan-sunset.html(created 2026-05-09, 568 lines) — featured complete photo-upload integration, CSRF token generation, Instagram profile pulls, and spam guardss3://queenofsandiego.com/g/2026-05-30-jonathan-afternoon.html(created 2026-05-20, 96 lines) — minimal feature set, likely rebuilt without awareness of the first page
Both showed the booking as 4:30–7:30 PM in the HTML. However, the authoritative source—the jada-crew-dispatch DynamoDB table—stored the correct time as 3:30 PM start (15:30 in 24-hour format), with a pointer to the "-afternoon.html" slug as the active guest page.
This revealed two independent failures:
- Agent-on-agent page stomping: A second agent, unaware of the original sunset page, rebuilt guest pages without cross-referencing existing assets or database state.
- HTML-to-DB divergence: The crew-dispatch DynamoDB record was updated with the correct time, but the corresponding HTML guest pages were never refreshed to match.
Root Cause Analysis
The investigation sequence revealed how state fragmentation occurred:
# Step 1: Lookup the kanban card
Look up kanban card xhqgmdh
# Step 2: Inspect the DynamoDB crew dispatch table
List dynamodb tables
# Found: jada-crew-dispatch, jada_funnel, progress (kanban state)
# Step 3: Pull the authoritative record
Find mclaughlin/2026-05-23 in state
Find May 30 crew dispatch events
# Confirmed: guest_code S2FJLN points to /g/2026-05-30-jonathan-afternoon.html
# start_time: 15:30 (3:30 PM)
# Step 4: Inspect both HTML files
Inspect jonathan pages
Compare photo-upload features between pages
# Found: -sunset.html has full features, -afternoon.html is stripped
# Step 5: Timeline reconstruction
Search activity_log for Jonathan
Find Jonathan in crew dispatch table
# Last update: 2026-05-20 (afternoon page creation)
# No SES send log for either page version
The timeline suggests:
- Original booking (May 9): created as 4:30–7:30 PM, sent sunset page with photo uploads to Jonathan
- Time correction (May 20): someone (likely an agent) updated the DynamoDB start_time to 15:30 and created a new "-afternoon.html" page, intending to replace the sunset page
- Oversight: the "-sunset.html" page was never deleted, and the new "-afternoon.html" page was not sent to the guest (no SES log)
- State confusion: two pages existed with the same booking, inconsistent times, and unclear which was authoritative
Technical Architecture: State Sources of Truth
This incident exposed a critical architectural gap. Our system has multiple state sources:
| Source | Technology | Priority | Risk |
|---|---|---|---|
jada-crew-dispatch (DynamoDB) |
DynamoDB | PRIMARY | Stores booking facts: time, guest_code, contact |
| Guest pages (S3) | S3 + CloudFront | SECONDARY (derived) | HTML rendering layer; can diverge from DB |
| Kanban board (progress/state.json) | S3 JSON | TASK TRACKING | Not a source of truth for booking details |
| Google Calendar (JADA Internal) | Google API | TERTIARY (crew ops) | Often updated manually; can lag DB |
The problem: when DynamoDB was updated (May 20), no cascade mechanism existed to update the derived guest pages or invalidate CloudFront caches. This is a classic eventual-consistency problem in a stateless, multi-layer architecture.
Infrastructure: Guest Page Generation and Caching
Our guest pages live in S3 with CloudFront distribution in front:
- S3 bucket:
s3://queenofsandiego.com/(web content origin) - CloudFront distribution:
d1a2b3c4d5e6f.cloudfront.net→queenofsandiego.com - Guest pages: stored as
/g/{date}-{name}.html - DynamoDB table:
jada-crew-dispatch