Sprint 50 / M9 — built is not the same as on


Until now, the web app and the phone each got their own sprint write-up. This time there is one, because what happened in the two repositories only makes sense side by side. The whole sprint comes first, then web, then mobile.

The short version: a lot got built this sprint, and I want to be precise about how much of it is on.

The whole sprint

Eight days, from the Sprint 49 close on September 22nd to the last merge in the early hours of September 30th.

Web (gailleur/domi)Mobile (gailleur/domi-mobile)
Pull requests merged74 in the repository, 42 of them the web station’s13, 6 substantive and 7 dependency bumps
Time to mergemedian 0.7 h for the web station’s PRs (p90 20.1 h)median 42.5 min for substantive work
Automated review71 rounds of changes requested, across 25 of the 4225 review runs, 4 asked for changes
Releases5 production promotes, v1.0.197 → v1.0.2041 internal iOS staging build, 0 production builds
Tokens, and what they would cost at API list price1.73 B · $528.71129.5 M · $43.90

That last row needs a sentence. The dollar figures are what those tokens would cost at an API’s list price. They are not what I paid. The agents run on subscriptions, so the real bill for the whole factory for all of September — every station, plus $254.45 of CI minutes — was $604.45. I would rather print a smaller true number than a bigger impressive one.

Built, and switched off

The sprint’s stated focus was billing, and billing is built: subscribe, change plan, cancel at the end of the period, change your mind, and a household’s Stripe customer deleted when the household is deleted. Underneath it sits the part nobody sees: every AI call reserves its budget before it goes out, so spending is checked before it happens rather than counted after.

It is not live. The switch is off in production, on purpose. Turning it on is next sprint’s job.

The demo

On September 29th, with a demo about thirty minutes away, I asked for a feature out loud:

“In the calendar, you have the weather widget, but it’s only the current city for the home residence. We want to have a selection where I can choose a city when I’m traveling, for example. […] Obviously, it has to work on the web and the mobile app. We are in a hurry because we have only 30 minutes, so you need to go fast, very fast. Quality is still important as usual, but go fast.”

The web station sent the mobile station the shape of the new endpoints fifty seconds after the ask, before either had written a line of code. That is the whole trick. With the contract agreed first, the server, the web page and the phone screen were built at the same time instead of one after another. Their messages crossed twice in the first minute; the phone was written to accept every version of the contract, so the crossing cost nothing.

  • About 40 minutes from the ask to the server and web page answering on staging.
  • About 90 minutes to the phone half being merged.
  • That evening I asked for the search button to go and for cities to autocomplete as you type. About 25 minutes from that ask to staging.

The automated reviewer — a different model from the one writing the code — raised findings on every one of those pull requests. Across the two web PRs, all seven were correct, and three were bugs a real person would have hit: a “Back to home” button that vanished if a forecast failed to load, leaving you stuck on a city you had left; old search results you could still pick while new ones loaded; and a list you had just dismissed reopening itself.

I tried it on staging and asked for it to go to production. On the web, it went live that night as v1.0.204.

The factory

The factory is the set of AI agents that builds Domi, and it got more of the attention this sprint than it usually does.

  • One way to merge. A station now merges with a single command that checks it has the right, checks the tests are green on the exact version being merged, and merges that version and nothing newer. Green on an older version is how a pull request with failing checks once landed here.
  • A health check for the whole plant, every two minutes, that restarts anything it can restart without losing work — and never restarts an agent that is alive, because a quiet agent and a busy one look identical from outside, and a restart throws away everything it was holding in mind.
  • Then the health check killed itself. A minute after a pause was lifted, it read its own heartbeat from before the pause, concluded it had hung, and shut itself down mid-repair. The factory ran for a day without its healer. The fix is two guards and one principle: the thing that heals is the one thing that cannot heal itself.
  • Waiting is not stuck. An agent watching a deployment, or waiting on me, now reads as waiting on the board rather than stalled. The difference sounds cosmetic. It is the difference between a board I can trust and one I learn to ignore.
  • Agents can hand work to each other. In fourteen days before this change, the stations sent each other 52 requests and answered all 52, with a median reply of one minute — and handed off nothing, because every piece of work had to come from me. Now a station holding a task can file part of it for a peer, inside limits the tool enforces.

Next sprint

In my words, as I said them: “resubmit the mobile app to apple, and activate stripe in production and open the software registration”.

Web

The travel city is on. Pick a city on the weather page and it becomes your weather on the weather page and in the calendar, in that city’s own timezone, until you press “Back to home”. It is per person: the rest of the household keeps the weather at home. And it is weather only: your address, currency and timezone do not move.

One honest caveat. The automatic check after a production release only exercises public pages; the signed-in check was skipped. My own test on staging was the signed-in proof, and I have said so here rather than let the green light say more than it checked.

Billing is built and off, as above. It took the sprint and a lot of review: 71 rounds of changes requested across the web work, and the most on any single pull request — eight — went to the one that deletes a household’s Stripe customer when the household is deleted. That is the right place for the reviewer to be most stubborn.

Consent can no longer be skipped. Accepting it is now a real record, written together with the household, including for people who join by invitation. Nobody reaches Domi without it.

The whole-household export works. It can now actually be requested, built and delivered.

Invoices turn into things to do. An unpaid invoice now gets its own “Pay” task, and marking it paid works. The part of Domi that guesses upcoming payments stopped inventing tasks the invoice already owns. Service invoices keep their total, odometer and the work done, appliance nameplates become details on the appliance, and maintenance reminders run from the dates.

Models chosen by evidence. Two newer models were tried as challengers for reading uploaded documents. A comparison across 21 test documents kept the incumbent. Newer did not win.

Five production releases in eight days, and a schema that moved seven migrations forward.

Mobile

The travel city is merged, and nobody has seen it on a phone yet. The weather screen has a city search, a pick that becomes your weather, and “Back to home”; today’s weather strip follows the pick without restarting the app, in English and French. The reviewer went four rounds on it and found seven things. Six were real bugs — a slow search answer could overwrite a newer one, so a tap could save the wrong city — and all six were fixed before merge. The seventh contradicted the round before it. We fixed its wording point, kept the behaviour, and handed the disagreement to a person instead of “fixing” the same thing twice.

It is merged. It has not been tried on a device. I am not going to call it shipped until it has.

The first iOS staging build. Every iOS build until now was built for production. This sprint I ran the first internal staging build — it needed my own Apple sign-in, which is why it was mine to run. It is what the travel city will be tried on.

The reply to Apple got more careful. Apple sent the last submission back. The fix was on a web page, so the app itself was already right. The work was the reply, and the most useful change to it was cutting two sentences. One said we had re-tested with a fresh account. We had not. The other said the problem only affected brand-new accounts, which is probably false. A reply to a reviewer is a public claim like any other, and it gets checked like one.

The app on TestFlight is unchanged: build 10, version 1.0.3. The iOS app has not been publicly released, and resubmitting it is the first item of next sprint.


So, the status at close. The travel city is on, on the web. Billing is built and off. The phone half of the travel city is merged and unseen. Those are three different sentences, and keeping them different is most of the job.