```html

Debugging and Resolving Duplicate Guest Pages: A Case Study in Agent-on-Agent Data Inconsistency

What Was Done

During a development session focused on updating booking details for a May 30 sunset charter, we discovered a critical data inconsistency: two separate HTML guest pages existed for the same Boatsetter booking (ID: #xhqgmdh, Jonathan), with conflicting information, different feature sets, and pointing to different source-of-truth records. The older page had rich photo-upload functionality; the newer had stripped it down. The DynamoDB crew dispatch table showed the correct time (3:30 PM), but the primary guest-facing page still displayed outdated times (4:30 PM). This post documents the investigation methodology, the architectural patterns that created the vulnerability, and the resolution strategy.

The Problem: Duplicate Pages and Conflicting State

Investigation revealed two files for the same booking:

  • s3://queenofsandiego.com/g/2026-05-30-jonathan-sunset.html (created 2026-05-09, 568 lines, includes photo-upload feature with token validation and spam guards)
  • s3://queenofsandiego.com/g/2026-05-30-jonathan-afternoon.html (created 2026-05-20, 96 lines, no photo-upload feature)

Both displayed times as 4:30–7:30 PM. However, querying the jada-crew-dispatch DynamoDB table revealed the source-of-truth showed start_time: 15:30 (3:30 PM). This represented a time change that had been applied to the database but never propagated to either HTML page.

Tracing the lineage:

  • The -sunset.html page was likely the original sent to the guest around May 9 when the booking arrived. It contained your full photo-upload feature set (including CSRF token validation, spam filtering, Instagram integration).
  • On May 20, an agent (different session/context) created a new -afternoon.html page, updated the crew dispatch record to reflect the corrected 3:30 start time, but did not update the original -sunset.html. The new page was simpler and lacked the photo features.
  • No SES send log or activity_log entry confirmed whether the updated page was ever sent to Jonathan.

Why This Happened: Architecture and Workflow Gaps

This pattern is a textbook example of distributed state management failure in a human-agent workflow. Several design decisions contributed:

  • No single source of truth for guest pages: The system allows agents to create multiple HTML snapshots in S3. There is no enforcement that a booking (identified by crew-dispatch record) maps to exactly one guest-page file.
  • DynamoDB as authoritative but not observed: The crew-dispatch table correctly stores start_time, but agents don't systematically validate that all downstream artifacts (S3 pages, CloudFront caches, calendar events) reflect it.
  • No versioning or soft-delete for pages: Old pages are not marked deprecated or tombstoned. Agents can create new versions without retiring old ones, leading to orphaned or stale content.
  • Limited cross-artifact change propagation: When a booking detail changes (time, contact, location), there's no automated trigger to audit and update all dependent resources (guest page, email draft, calendar, Boatsetter listing).

Investigation Methodology

The debugging workflow used multiple queries across loosely coupled systems to converge on the root cause:

# 1. Start with the kanban card reference
kanban lookup xhqgmdh

# 2. Find the booking in crew dispatch (DynamoDB)
dynamodb scan jada-crew-dispatch --filter-expression "booking_id = xhqgmdh"

# 3. Compare state in DynamoDB with S3 artifacts
s3 ls s3://queenofsandiego.com/g/ --grep jonathan.*2026-05-30

# 4. Pull and inspect both HTML pages
s3 get-object --bucket queenofsandiego.com --key g/2026-05-30-jonathan-sunset.html
s3 get-object --bucket queenofsandiego.com --key g/2026-05-30-jonathan-afternoon.html

# 5. Search SES send logs and activity_log
sqs-query activity_log --filter "jonathan" --start-date 2026-05-01

# 6. Validate which page is linked from crew dispatch
jada_funnel query --booking-id xhqgmdh --show guest_page_slug

This multi-system scan revealed the inconsistency and its scope.

Technical Details: The Two Pages

Page A: -sunset.html (Feature-Rich, Potentially Stale)

  • Created: 2026-05-09
  • Feature set: photo upload with CSRF token, spam guards, Instagram integration pull, form validation
  • Times shown: 4:30–7:30 PM (arrive 4:00 PM, UTC cutoff Mon 8:00 PM)
  • CloudFront cache: active (distribution ID for queenofsandiego.com)
  • DynamoDB reference: not linked in crew-dispatch record

Page B: -afternoon.html (Simplified, Correct in DB)

  • Created: 2026-05-20
  • Feature set: minimal (no photo upload)
  • Times shown: 4:30–7:30 PM (same stale display)
  • CloudFront cache: active
  • DynamoDB reference: linked via crew-dispatch record guest_code: S2FJLN
  • Crew dispatch start_time: 15:30 (3:30 PM) — already correct in DB

Infrastructure and Cache Invalidation Considerations

Both pages are served via CloudFront (distribution for queenofsandiego.com). S3 is the origin. Any update to these files requires:

  1. Update the file in S3: s3://queenofsandiego.com/g/2026-05-30-jonathan-sunset.html and/or -afternoon.html
  2. Invalidate CloudFront cache for the updated paths:
    aws cloudfront create-invalidation \
      --distribution-id <DIST_ID> \
      --paths "/g/2026-05-30-jonathan-sunset.html" "/g/2026-05-30-jonathan-afternoon.html"
    
  3. Verify the new content is live by checking cache headers and re-fetching

Resolution Strategy and Next Steps

The correct path forward depends on answering two questions:

  1. Which page was actually sent to Jonathan? Without an SES send log or activity_log entry, we cannot definitively know. Recommendation: check your email client's sent folder or contact Jonathan directly.
  2. Should the time change to 3:30 PM be applied? The crew-dispatch table already reflects this. If it's confirmed, both