Debugging and Reconciling Duplicate Guest Pages: A Case Study in Agent-on-Agent Data Conflict
During a recent development session, we discovered a subtle but instructive problem: the same guest booking existed in two different S3 objects with conflicting content, misaligned metadata, and diverging update histories. This post walks through how we diagnosed the issue, traced its root cause, and the infrastructure patterns we use to prevent similar conflicts in the future.
The Problem: Two Pages, One Booking
Our guest experience flow generates personalized booking pages and stores them in S3 under predictable slug patterns:
s3://queenofsandiego.com/g/{date}-{guest-name}.html
For a May 30, 2026 sunset charter with a guest named Jonathan (Boatsetter crew booking), two files existed:
s3://queenofsandiego.com/g/2026-05-30-jonathan-sunset.html(created 2026-05-09, 568 lines)s3://queenofsandiego.com/g/2026-05-30-jonathan-afternoon.html(created 2026-05-20, 96 lines)
Both claimed to represent the same booking. Both displayed conflicting information:
| Attribute | -sunset.html |
-afternoon.html |
|---|---|---|
| Display time | 4:30–7:30 PM | 4:30–7:30 PM |
| Photo upload feature | ✓ (full implementation) | ✗ (stripped, 96 lines) |
| Linked from crew-dispatch DB | No | Yes (guest_code: S2FJLN) |
| DB stored start time | — | 15:30 (3:30 PM) |
Root Cause Analysis
The conflict emerged from an agent workflow on 2026-05-20. During that session:
- An agent discovered the original booking time in DynamoDB was actually 3:30 PM (15:30 epoch), not 4:30 PM as the oldest guest page claimed.
- Rather than update the existing
-sunset.htmlpage, the agent created a new-afternoon.htmlpage with the correct time. - The agent linked this new page in the crew-dispatch table (
jada-crew-dispatchDynamoDB table) via theguest_codepointer. - The agent did not realize the two pages represented the same booking, and did not check whether the existing
-sunset.htmlcontained important functionality (like the photo upload feature with token validation and Instagram pull).
This is a classic "agent-on-agent stomping" scenario: in a system with multiple autonomous agents or scripts making edits, without strict ordering or locking mechanisms, later agents can unknowingly overwrite or bypass earlier work.
Technical Details: The Investigation Flow
Our diagnostic approach used a layered search strategy:
Step 1: Kanban State & Metadata
We started by examining the kanban card in the progress board:
Look up kanban card xhqgmdh
→ Found in state.json, "needs-you" lane, title: "move to 3:30"
This told us the task itself existed and was incomplete. The card stored references to both the booking ID and the cloud resource slug.
Step 2: Multi-Source Guest Page Lookup
We pulled the guest page from S3 and searched for time references:
aws s3 cp s3://queenofsandiego.com/g/2026-05-30-jonathan-sunset.html /tmp/
grep -i "4:30\|arrive\|utc" /tmp/2026-05-30-jonathan-sunset.html
We found 3 occurrences:
- Guest display: "4:30 PM – 7:30 PM"
- Crew arrival time: "4:00 PM"
- UTC cutoff for late replies: "Monday 8:00 PM PT" (which is 4:00 PM + 4 hours)
Step 3: Cross-Reference with DynamoDB
We queried the crew-dispatch table to find the source-of-truth booking record:
aws dynamodb query \
--table-name jada-crew-dispatch \
--key-condition-expression "booking_id = :id" \
--expression-attribute-values '{":id": {"S": "xhqgmdh"}}'
The crew-dispatch record showed:
start_time: 15:30(3:30 PM)guest_code: S2FJLN(pointing to-afternoon.html)boatsetter_id: jonathan-crew-booking
Step 4: Artifact Comparison
We then discovered both guest pages existed. A line-count comparison revealed the -afternoon.html was stripped:
wc -l 2026-05-30-jonathan-*.html
568 2026-05-30-jonathan-sunset.html
96 2026-05-30-jonathan-afternoon.html
Inspection showed -sunset.html contained the complete photo upload implementation:
- CSRF token generation and validation
- Multipart form-data upload handling
- Instagram hashtag/account linking via OAuth token
- Spam filter and content-type validation
The -afternoon.html had none of this.