← Queen of San Diego — Tech Blog
2026-09-22

Deploying a Lambda, Triaging Texts, and Teaching a Model to Curate Wedding Photos

Tuesday started with a one-liner: bash lambda/deploy-via-lightsail.sh against the ixi site. The whole deploy loop is dumb on purpose — zip the function, ship it to the Lightsail box, rezip in place, print DONE. No CI pipeline, no dashboard to babysit. When the terminal echoed back "code updated (rezipped on the box) / DONE," that was the entire status report, and it was enough. Small-business infra doesn't need observability theater; it needs a script that either says DONE or doesn't.

SMS triage without auto-reply

Next ask: read today's SMS thread and flag what actually needs action — not reply to everything, just surface the items that matter. This is a deliberately narrow permission boundary. The model gets read access to the day's messages and a mandate to summarize, but sending stays a human decision. That split shows up everywhere in this stack now: drafting is cheap and automatable, sending is not. The crew-schedule and captain-status skills work the same way — they pull live from DynamoDB, render a draft into a local folder, and stop. A person still has to run send-sms.

The proposal pipeline's one honest sentence

Somewhere in the middle of the day I re-read the description of the PDF proposal skill, and it's worth repeating because it's the clearest design principle in this whole system: "everything is deterministic except Step 4." Ten facts go in, a fixed template and a chain of scripts handle layout, rendering, link-fixing, and QR generation, and the model is only trusted to write about three short bespoke copy blocks. Everything that can be a script is a script. The model's surface area is deliberately tiny — just the part that actually requires judgment about language, not the part that requires correctness.

Curating a guest gallery, one crop at a time

The bulk of the afternoon was photo curation for a charter's private guest gallery — dozens of images off the classic yacht, each one read individually with a prompt roughly like: "decide if this image belongs." Displayed resolution came back scaled down from the originals (1536×2048 crops shown at 1500×2000, a 1.02 multiplier to map coordinates back), so every accept/reject/crop decision had to account for the resize before it touched the original file. It's a good example of a task that resists full automation: a deterministic pipeline can resize, watermark, and upload, but "is this the shot a guest will want in their gallery" is a taste call, frame by frame. The pipeline does the boring 95% — file discovery, resizing, path management — and hands the model only the part where eyes matter.

The pattern, again

Four unrelated tasks, one shape repeating:

The lesson isn't new but it keeps proving itself: the model earns its keep on the narrow slice of each workflow that's actually ambiguous — copy, taste, triage — and everything else should be boring, scripted, and reproducible enough that "DONE" printed to a terminal is a satisfying end to the story.