Skip to main content

← Back to Journal

The bug flow on video, and what a real check-in found

There is a new video up, and it is the first look at something I have not written about here at all: Build Studio's bug flow.

The flow itself is only a few weeks old. It takes a bug from a sentence someone typed to a merged fix, without me steering it, and this is the first time it has been shown rather than described.

Report a bug, get a merged fix

It starts with a plain report — no template, no severity dropdown, just what you noticed in your own words.

The bug in the video is a planted one, on the throwaway hello-world project I keep for demos. A Swedish greeting renders as värden instead of världen — a single dropped letter turning "the world" into "the host".

Triage picks it up and reads the actual source. The first question it answers is not how do I fix this but is this even a bug — as opposed to a feature request, or something working exactly as designed. That distinction is the part I would keep if I had to throw the rest away. A pipeline that treats every report as a defect will confidently "fix" your intended behaviour. Here it correctly identifies a genuine defect and files it as a precise backlog item pointing at the exact fault.

From there one click runs fix → QA → code review → merge. QA does not merely re-test; it adds a regression test, so that specific bug cannot quietly come back. Then the run closes with the step that is easiest to skip and most valuable to keep: asking why this slipped through in the first place, and writing the answer down.

The video runs about two minutes end to end. If you have been reading these entries and wondering what "the studio ran it" actually looks like, that is what it looks like. Build Studio is open source, so you can also just go and read it: github.com/My-Next-Studio/build-studio.

Fazon: a week of eating my own cooking

Fazon took the overwhelming majority of the period's work — 227 commits against DeskRhythm's 30 — and almost all of it circles one feature: the weekly check-in.

The check-in is the moment the app earns its keep, and not mainly because it reports how the week went. Its real job is the decision that follows: the coach reads the week and decides whether the plan still holds, or whether the weekly calorie and step targets need to move. A verdict that misreads the week does not just produce a discouraging screen — it retargets the following week on bad evidence.

Getting it right has a lead time unlike anything else I build, because the only honest way to test it is to actually use it. Log real meals for seven days. Step on the scale. Run the check-in. See what it says about a week I actually lived, and notice what is wrong.

You cannot shortcut that with fixtures. A seeded database tells you the code does what the code does. It does not tell you the verdict is absurd.

So I ran one on a week that had gone well. The app told me it had not — and pulling that apart took five separate findings:

  • The weight trend was never computed. The check-in offered a fresh weigh-in, asked for it, read it — and then derived no trend at all. A real loss exported as weight_trend: null. The single outcome the whole phase exists to move was invisible to the verdict that judged it.
  • The protein target was computed from the wrong number. It scaled with total bodyweight rather than lean body mass, which means it rises with exactly the fat you are trying to lose, and the more you have to lose the less reachable it gets. That produces a target you essentially cannot hit, and therefore a low-adherence verdict that is permanent by construction. A verdict that cannot come out any other way is not a verdict.
  • The verdict measured the wrong things. Calorie adherence — for a calorie-deficit app — was excluded from the weekly score entirely. The step axis scored whether the phone recorded step data, not whether the goal was met. And a shortfall on one secondary axis could veto a week that had actually hit its primary outcome.
  • Two exported fields lied about their own units. protein_attainment and step_attainment are days-ratios wearing percentage-shaped names. A downstream importer read protein_attainment: 0 as "0 % protein" against a food log that plainly showed otherwise. step_attainment: 1 does not mean "goal met"; it means "the phone recorded something."
  • The window moved when I did. The check-in period ran from the instant I last tapped the button, not from a calendar boundary. Which meant a weigh-in five minutes early fell outside its own window and did not count.

That last one is fixed: the window is now whole calendar days, and the evaluated dates print in the UI so you can see exactly which days were judged. The rest are queued as bugs to fix next.

Most of those could have been caught by a test, in principle. None of them were. They are the software being internally consistent and externally wrong, and that is an easy thing to miss right up until someone with a stake in the answer reads the output and finds it does not match the week they just lived.

Alongside the fixes, I have started looking at what an AI layer could add on top of the coaching engine. The engine itself is deterministic — targets, adherence, a verdict — and it is deliberately narrow. The open question is whether a model can sit beside it and offer the kind of insight the rules cannot: noticing a pattern across weeks, explaining why a week went the way it did, saying something useful about what to try next. That work is at the experiment stage rather than the shipping stage. More on it in the coming weeks.

DeskRhythm starts on Android

DeskRhythm is still in beta on iOS, and Android has moved from a hedge to a commitment — promoted in the vision from a gated maybe to Phase 1.5 proper. This is early: research, architecture decisions, a parity matrix, a build-and-launch runbook. No shipping app.

One platform difference has already surfaced, and it goes straight at the core of what the app does.

DeskRhythm runs a timer that tells you when to switch between sitting and standing across a workday. That requires the app to reliably do something at a specific time while nobody is looking at it — which on Android is not one problem but a different problem per manufacturer.

Google provides an official answer: exact alarms, plus a battery-optimization exemption the user can grant. Fine in theory. The catch is that the standard exemption only addresses Google's own Doze and App Standby. It does not override manufacturer battery managers at all. Samsung's deep-sleep classification and Xiaomi's autostart blocking are untouched by the thing that looks like it should govern them.

The obvious reflex is a foreground service — pay the persistent-notification cost, keep the process alive. Two things came out of examining that. First, an ongoing notification does not require a foreground service; those are separate mechanisms, and conflating them makes the service look free when it is not. Second, and worse: the aggressive OEMs kill and defer foreground services too. So the plan is to pay a real battery cost and a real Play-policy cost for protection that does not hold on the exact devices it was meant to protect against.

The decision is exact alarms, no foreground service, with the exemption strongly recommended but never a blocking gate — and honest documentation of what happens when it is denied. What I find interesting is that this is not a hard engineering problem. It is a problem of finding out what is actually true across a fragmented platform, where the official documentation describes a world that vendor firmware does not implement.

Elsewhere

Build Studio. Gate reporting can now distinguish a gate that failed from one that could not run — previously indistinguishable, and the difference is the difference between a broken product and a broken pipeline. It also detects agents that are alive but will never progress, which is a far more annoying failure than a crash, because nothing looks wrong. PRD reviewers now switch to closure mode after the fresh-lens rounds instead of relitigating the same points.

My Next. The privacy policies for Todo, List and Note needed updating. The apps now send an anonymous, optional app-open analytics event, and the policies still described a world with none of it. They now say what is sent, that it can be switched off completely in Settings, and that your todos, lists and notes stay on your device — which remains true, and is worth protecting by not overstating it.

Välkomna, Finance Studio and Launch Studio each took a dependency sweep. Sickla tunneln, Skrivhjälp and Life Graph were quiet.

What's next

Fazon's four remaining check-in defects get fixed, and then I log another week and run another check-in, because that is the only instrument that works. I expect it to find more. The interesting question is not whether the verdict is bug-free but whether it is believable — whether what it tells me matches the week I remember having, and whether the target change it makes on the back of that is one I would have made myself.

On Android, the next step is proving the background execution story on real hardware from the aggressive vendors, rather than on an emulator that behaves the way the documentation says it should.

If you watch the bug-flow video and something about it does not add up — or you have fought Android's OEM battery managers and know something I do not — I would like to hear it. Open an issue, email [email protected], or find me at @MyNextStudio.