The run I lost to a beta OS
A 6 km run in the July heat where my own app would not record and would not stop, the 1.5 km it cost me, and the watchOS 27 beta bug I had to fix in a build compiled against the old SDK.

Last Tuesday I went for a 6 km run and could not use my own app. It was hot, the kind of July afternoon where Lieboch turns into a frying pan, and I set off with my watch on my wrist and Runara on the screen like always. I hit start. The countdown popped, GO flashed, and then nothing. No heart rate. No pace that meant anything. And when I gave up and tried to stop it, Stop did nothing either; the workout just sat there, frozen, refusing to end, the little green workout dot glued to the top of the screen.
I stood at the side of the road, sweating, jabbing at a watch that would not listen, and did the one thing that genuinely stung: I opened Apple's Workout app instead and started again from there. I had already run a kilometre and a half. That distance is gone. It never made it into Apple Health, it never made it anywhere, because my app never actually started recording it. I finished the run properly annoyed, which is a generous word for it.
The app I built so I would never have to fall back to someone else's had just made me fall back to someone else's. On a run. In the heat. That is the sort of thing that gets fixed the same week.
Why it could not just wait for autumn
Here is the part that makes this urgent rather than academic: the bug only happens on the watchOS 27 beta, and I was running the watchOS 27 beta. So were a surprising number of the people using Runara.
I think I underestimated this. The developer-and-enthusiast corner of the App Store skews heavily toward people who put the beta on their personal watch the day it drops, and a privacy-first, one-time-purchase running app that shows up in exactly that corner attracts exactly those people. When the public betas seed out over the summer, a real slice of my actual users are on next year's OS months before it ships. "It'll work when watchOS 27 launches in September" is not an answer to someone whose Tuesday run just failed in July.
To be fair to Apple, the beta itself is good. For an early developer beta, watchOS 27 has been remarkably solid on my own watch: smooth, no battery horror stories, nothing that made me want to roll back. Which is part of what made this bug so nasty. Everything else worked, so nothing warned me. The one thing that broke was the one thing my app is for.
Testing a bug that only exists on the future
Debugging this was its own small ordeal, for a reason that sounds backwards until you sit with it.
You cannot ship an app built against a beta SDK. The App Store only accepts builds compiled against the released SDK, which for me is the watchOS 26 SDK, the shipping one. So the constraint was strict and slightly absurd: I had to diagnose a bug that only appears on watchOS 27, and then fix it in a binary compiled against watchOS 26, the OS where the bug does not even happen. I could not "target the beta." The thing I was allowed to build could not see the problem. The thing that could see the problem, I was not allowed to build.
Which means the whole feedback loop is indirect. Reproduce on the beta watch. Read the Console logs streaming off it. Form a theory about what the newer OS is doing differently. Change code that compiles against the older SDK. Ship it to the beta watch. Run again, in the heat, to see if it took. There is no unit test for "does Apple's private HealthKit state machine behave differently this year," so the first thing I actually did was pour logging into the workout lifecycle: every session state change, every collection call, every single time the builder handed me data, and specifically whether it ever handed me a heart-rate sample at all. If that line never printed, the OS was not collecting HR, and it was not my parsing. That log stream is how I found it.
What was actually broken
Two things, and the first one is almost funny in how small it is.
When a workout starts, there is an order to the HealthKit dance: you tell the builder to begin collecting data, and you open the workout's main activity. On every watchOS up to now, the exact order of those two calls did not matter, and mine happened to open the activity first. watchOS 27 stopped tolerating that. It now insists collection comes first (begin collection, then open activities), and if you do it my old way it throws "Cannot find main activity for workout" and quietly refuses to collect anything. No heart rate. No metrics. A session you cannot even finalise. One reordered pair of lines, invisible for years, load-bearing overnight.
The second was the Stop hang, and it is why the workout would not end on the roadside. Finishing a workout waits on HealthKit to close the books: end collection, finish the workout. On the beta, those calls can simply never return. My code awaited them with no time limit and only ended the session afterward, so a call that never came back meant a session that never ended: app pinned to the foreground, workout dot stuck, and a second Stop tap walking away with no summary at all. So now finalisation runs on a stopwatch. It gets ten seconds; if HealthKit has not come back by then, I stop waiting, force the session to end anyway, and build the summary card from the numbers I already have in memory. You still get your run. You still get your result. The OS does not get to hold your workout hostage because one system call went out for coffee.
I pulled that timeout into a tiny, plain function with its own tests, well away from any watch-only code, because the one thing I trust less than a beta OS is a fix I cannot test on solid ground. And I added a real regression test that starts an actual workout session on the watch simulator and asserts the ordering bug can never come back; it gets far enough to prove the sequence is right, which also proved the reorder is perfectly safe on the shipping OS, so nobody on watchOS 26 pays for a fix aimed at 27.
Out now
This is version 1.1.1, and if you are on the watchOS 27 beta it is the one you want: it puts heart rate and a Stop button that actually stops back where they belong. If you are on the shipping OS, you were never affected, and the update changes nothing you will notice except that it is quietly more paranoid about ever hanging on you.
Same deal as always: no account, no subscription, nothing collected. The run stays on your wrist, which I promise I now care about more than ever.
I lost a kilometre and a half to this one. You should not have to. See you on the trails, and if it is as hot where you are as it is here, go early.