All posts

By Dan · June 9, 2026 · updated July 10, 2026

Three Things We Haven’t Figured Out

Most posts on this blog end with a working answer. This one doesn’t, and it keeps changing: we first wrote it in June, and a month later the list looks different — one problem got demoted, two got bigger. So here is the honest July version. Three problems we work on constantly and still don’t have clean solutions to.

1. Generating a lot of plans that are all good

Generating one good training plan is easy. A coach does it on a napkin. Our problem is that the app generates a lot of them — every distance, every level, every plan length from twelve weeks to thirty-six, every fitness a runner might show up with — and every single one has to make sense to the person actually running it, not just on average.

The rules fight each other, quietly. Cap the long run at a sensible distance and the recovery week after it stops looking like recovery. Fix the recovery week and the race rehearsal falls out of the schedule. Raise the beginner volume so week one isn’t insultingly easy, and week seven suddenly jumps 75% after a deload — which we shipped, and a user could have found. Every one of those fixes was reasonable on its own. Together they kept producing surprises.

What we do now: the engine is deterministic, so we render whole plan catalogs to text and diff them after every change, then read the suspicious ones like a coach would, week by week. We’ve done somewhere north of twenty of these full audits. Every round still finds something — a threshold session hotter than the time trial it’s based on, a “10K pace” interval faster than the runner’s projected 10K, two hill sessions in a row for three weeks straight. The plans are much better than a year ago. They are not done.

2. Haptics

A watch app talks to a runner mid-interval through exactly one channel: taps on the wrist. And watchOS gives us about nine canned tap patterns to do it with, no volume control.

And we keep getting it wrong in both directions. Too soft, and the interval ends without you noticing — you’re sweating, your sleeve is over the watch, the tap just disappears. Too much, and the wrist turns into noise. Our pursuit mode — you race a ghost of your own past run — buzzed on every lead change, which sounds right until you run level with your ghost and the thing vibrates like a phone in a bag. We only caught that by going for a run with it.

The deeper problem is that events compete. A kilometer split, an interval ending, a pace warning, the ghost passing you — if two of them land together, the taps smear into one confused buzz, so now there’s a queue with priorities, and a rate limiter, and a dead-band. It works better. It still isn’t right, and every runner’s wrist reads differently — some feel everything, some feel nothing. We don’t want to ship a settings page with five sliders. We’re still trying to work out which events are actually worth a tap, and which should just wait on the screen until you look.

3. Getting the app onto the watch, and keeping the two talking

This is the one we’re least in control of. Installing the iPhone app is supposed to bring the Watch app along. Often it does. Sometimes it quietly doesn’t, and the runner stands at the start line with a watch that has never heard of us. There is no API that tells us this happened — we just get the support email.

Then there’s the pipe itself. WatchConnectivity offers three ways to send data, with three different sets of promises: a “latest state” snapshot that overwrites itself, instant messages that only work while the watch app is awake, and a durable queue that delivers “eventually” — where eventually can mean minutes, or, on simulators, never. We’ve landed on sending anything important through several channels at once, with dedup keys on the other side so nothing shows up twice. It works. It also feels like implementing TCP on top of carrier pigeons.

We’re not sure Apple’s pipe lets anyone do this cleanly today — if you’ve shipped a watch app and know better, we would love to be wrong.

If any of this resonates — you’ve solved one, you’ve seen a paper on it, you know what we’re missing — we’re both reachable. The contact email is on the home page.

Download on the App Store

No sign-ups • No ads