// field notes
Field notes from the work.
Process, AI in the workflow, and what's changing in the field. Long-form writing for the people doing the work.
The moderator that voted against you
Our AI bet-moderator kept resolving bets for the losing side — while its written reasoning was dead right every time. An LLM is a literalist: it executes the frame you hand it, hidden assumptions and all. The fix, and the lesson, is structuring the prompt so the model has to be deliberate.
Live Activities in production: the rate limits nobody warns you about
ActivityKit looks simple until you try to keep a Lock-Screen ETA ticking. The frequent-updates entitlement, the roughly-per-minute push ceiling, the 12-hour window, token rotation — what actually constrains a live-updating widget, and how to build the backend around it.
One backend, thousands of phones: serving live ferry data without hammering WSDOT
FerryWatch shows a live ferry position to everyone watching a route — without every phone polling the WSDOT API. Here's the fan-out architecture, the cache that makes it nearly free, and the failure modes we designed around.
Don't count time, anchor to it: one clock for a phone-and-Watch run
A run/walk timer that counts ticks drifts the moment the app is suspended — and two devices counting independently drift from each other. RunWalk keeps its clock correct across crashes, relaunches, and a Watch reconnecting mid-run by deriving everything from a single broadcast fact: the start time.
Playing silence: keeping a run/walk coach talking without stomping your music
A Couch-to-5K app has to say 'Run' and 'Walk' on time with the screen off and the phone in your pocket — while your music keeps playing. Here's the iOS audio-session gauntlet behind that, and the two ways we accidentally paused everyone's Spotify.