← Queen of San Diego — Tech Blog
2026-07-13

Charter Time, Wrong Window

Small bug today, small in the way that a misplaced decimal is small. A guest event page had the charter window listed as 11am–2pm. The actual charter is 5:30–8:30pm. Same day, wrong six hours, and if nobody catches it, forty guests show up for a sunset sail at lunchtime. The fix itself was a one-line edit to a rendered HTML page. The lesson was upstream: the time field on our proposal pipeline gets typed once by a human, then propagates to the guest page, the calendar hold, and eventually a captain's dispatch text. One typo, three places it can go wrong. We didn't rebuild anything over this — just confirmed the correction, re-rendered, and re-deployed. But it's a reminder that "deterministic pipeline" doesn't mean "typo-proof." The humans are still upstream of the machine.

Photos, from a Phone, Onto a Guest Page

A guest asked for photos to be added to her post-charter page. The workflow: she connects her iPhone, the photos land locally, and a deterministic script — not a model improvising HTML — resizes, optimizes, and slots them into the existing page template, then re-uploads to S3. The "standing rules" bit matters here: there's a fixed contract for what image sizes, alt text, and layout the guest pages use, so the agent's job is to invoke the tool correctly, not to design a new gallery each time. Once the photos were live, the natural next ask came in: get her a QR code (or a plain link, since she may not be QR-fluent) pointing at our Google review page. That's now a standard two-line request-response — page done, ask for the review nudge — and it's worth turning into a checklist item on every guest-photo job rather than waiting to be asked.

The Memorial Name Bug

This one was the sharpest edge of the day. We do memorial-at-sea charters, and one guest page had gotten a name wrong — attributing a passing to the wrong person, with a surname that belonged to a marriage, not a birth name, and mixing up which family member had actually passed versus which one is very much alive. The guest caught it and sent screenshots, including some unrelated genealogy research screenshots that helped untangle the family tree. Nothing about this is a "coding" problem — it's a data provenance problem. Somewhere between an earlier draft and the current one, a name got carried forward from a stale version instead of the corrected one. The fix was straightforward once traced, but it's a hard reminder that for memorial content, there is zero tolerance for a stale field surviving into a live guest page. We don't have automated tests for "is the deceased's name correct," and we probably shouldn't pretend we ever could — this is exactly the kind of thing that needs a human review gate before publish, every time, no exceptions.

Reconciliation: Zelle vs. Stripe

A guest believed she'd paid; our Zelle ledger didn't show it. Rather than guess, the answer was to check the other payment rail — Stripe — where the charge turned up. Two payment methods means two ledgers, and "did they pay" is a join across both, not a lookup in one. Minor process note we're tightening: any payment-status question should check both rails before answering, not just the one that's habitually checked first.

Campaigns Start and Stop

Also stood up, then killed, a landing page for a themed event campaign gated on a minimum paid-passenger count — the page went live, and word came back before the count was reached to shut it down. Standing up a page is cheap; tearing it down cleanly (so a dead link doesn't linger indexed somewhere) is the part worth automating next. And a small memory win: crew phone numbers already live in the SMS utility, so the agent doesn't need to ask for them again. Small thing, fewer round-trips.