Status as of Mon 31 Aug 2026, 1:46pm PT · autonomous build loop, sweep 677 · HEAD ff15b726
Commits per day. The model switch (gpt-5.5 → claude-opus-5) landed midday Aug 27 and the cadence barely moved — the loop is doing the same volume of work at roughly zero marginal cost.
* Aug 31 is a partial day, measured to 1:46pm PT.
| Date | Commits | Note |
|---|---|---|
| Aug 25 | 143 | — |
| Aug 26 | 266 | peak; running on metered gpt-5.5 |
| Aug 27 | 180 | model switched to claude-opus-5 at 12:05pm |
| Aug 28 | 142 | lock reaper fixed, interval widened to 30 min |
| Aug 29 | 132 | — |
| Aug 30 | 135 | — |
| Aug 31 | 99 | partial, to 1:46pm |
Last 50 recorded runs, all after the Aug 28 lock fix.
| Measure | Value | Read |
|---|---|---|
| Runs OK | 50 / 50 | No failures. The claude-cli output-cap crashes did not come back. |
| Model | claude-opus-5 | via claude-cli — subscription, not metered API. |
| Median run | 18.1 min | Comfortably inside the 30-min slot. |
| p90 / max | 29.2 / 42.0 min | 4 of 50 overran 30 min. See the open risk below. |
| Overlapping starts | 0 | Scheduler skips a slot while a run holds it. |
| Lock early-exits | 0 | No run has been locked out since the guard was fixed. |
This was the open question blocking confidence in the release path. It's closed: minification is clean.
The finding worth keeping: not one failure in the entire campaign was actually caused by the shrinker. Every red R8 produced was a pre-existing test defect it happened to surface — a fake window charging 0dp, a pixel literal copied from a different handset.
The snapshot carried one saved-at stamp and every persist rewrote it — including the write that installs a restored snapshot. So opening the app once inside a two-hour window carried the same rows forever.
Bites hardest on FAILED rows, which have no backend id and so can never be reconciled away by a /dishes response. Their only exit is a DISMISS tap the user has already declined to give. Fixed by ageing each row against its own createdAt — the shutter time is the one field a restore doesn't rewrite.
One shutter press could produce two dishes if the process died between the PUT and the job id reaching disk.
Lifted the scrim-swallow guard from 9 copy-pasted sites into one modifier. 6 of those sites had been making whole cards a TalkBack / Tab focus stop that did nothing when activated.
Groundwork for "Use what I have" — the endpoint is live and verified 200 against prod. Android has never called it. Needs your placement decision below before UI work starts.
Two bug reports were retracted this weekend. Both are worth reading, because the pattern behind them is the thing that actually slows the loop down.
Reported Sunday afternoon with a recommendation and three options. Retracted 24 minutes later. It was the test, not the app.
The test read the height of the clickable row and then injected the tap through the text label inside it. Compose touch coordinates are local to whatever node you poke, so "1px above the row's bottom" got applied from the label's origin and landed ~30px past the row. It fired the next row because the finger was on the next row.
What came out of it: a general instrument that mounts a screen, finds every pair of controls whose expanded touch boxes overlap where the visible ones don't, and measures the candidates by actually tapping them. Swept 6 screens including everything with a Delete that reaches the backend — Clean deck, shopping list, Profile, saved recipes, dish log. Nothing destructive is reachable from a neighbour anywhere. The other five touch-injecting test files were audited for the same fault; all clean.
It faked a 300dp window while the screens read their real 832dp one, so "compact layout" gates were switched off while the layout was squeezed. Some past "N/N PASS" lines were never earned. Separately, a "3 known-red tests, don't read the suite as green" note sat in PARITY for 3.5 hours after the fix landed — a standing licence to wave through real regressions.
The loop catches these itself, usually within a sweep or two, and it's building permanent instruments out of them rather than one-off fixes. That's the right response. But a meaningful share of the last five days went into auditing its own instruments rather than shipping app changes — worth watching that it stays a phase and not the pattern.
iOS's COOK is four stacked cards and this is the first one — AI-generated recipes split into "make now" vs "need groceries". Android's COOK isn't card-based; it's a section bar: RECIPES | THIS WEEK | EXPLORE. None of those is this.
The loop wants your call rather than picking one and rewriting it next sweep. Data layer is already built and tested.
iOS is under its own 44pt minimum in the same way. Now that the mis-tap report is retracted, nothing is being dispatched wrongly — this is purely a spec/cosmetic question. Fixing it grows the menu ~45dp and visibly diverges from iOS.
So it can't reach the iOS agent over the relay and falls back to the repo channel, which is slow. That's why the eight questions below are sitting. Worth fixing if you want cross-agent findings to land in minutes instead of sweeps.
Eight questions filed, none answered. Two of them describe possible live iOS bugs, not Android parity gaps.
With the App Review kitchen emptied to zero, the document settled at status ready, is_stale false, versions agreeing — carrying 20 recipes built from deleted chicken/rice/broccoli and reporting 37 of their ingredients as "have" against an empty kitchen. Every freshness signal a client has said it was fresh.
Explicitly not called confirmed: the healthy capture has the same version offset, so from the client the correct document and the wrong one are indistinguishable. Three readings, and only one of them — generation genuinely running against the empty kitchen — is a real user-facing bug. That one means recommending food the user has thrown away.
BulkSessionManager's entire write path has zero call sites — addPhoto, startSession, startUpload. The ~20 remaining uses are all restores of a session blob nothing writes, and both gallery entry points gate on it being non-empty.
Either multi-photo bulk check-in was retired on purpose — fine, and it removes the biggest item on the port list — or it lost its entry point in a refactor and has silently stopped working for iOS users with no crash and no error. The bulkSessionReadyToReview push route is still wired, which is what makes the second reading plausible.
| Filed | Question |
|---|---|
| 08-30 09:40 | Does DishSessionManager.resumePollingIfNeeded re-save the snapshot it just restored? |
| 08-30 10:20 | Does the pending-jobs registry carry a registry-level saved-at stamp? Plus an image-folder question. |
| 08-30 11:45 | Duplicate-upload window measured at 0.42s per capture. |
| 08-30 12:15 | Does DishSessionManager write the capture's JPEG to disk on the main thread? |
| 08-30 12:20 | Does an iOS dish upload retry create a NEW presign, or re-PUT the same one? |
| 08-30 16:40 | Does resumePollingIfNeeded read the saved image on the main thread? |
| 08-31 09:20 | Is multi-photo bulk check-in retired, or did it lose its entry point? |
| 08-31 10:20 | Does recipe_generation_version describe the rows, or the kitchen they were generated against? |
The Aug 28 fix corrected the ownership guard, so a stale reaper can no longer delete another run's lock. But a long run's own reaper still deletes its own lock at the 25-minute mark while it's still working, and the next fire is 5 minutes later. 4 of the last 50 runs exceeded 30 minutes; the longest was 42.
Nothing has actually overlapped — the scheduler skips a slot while a run is in flight, which is doing the real work here. But the lock is not the thing protecting you, and it reads like it is.
The clean fix: the lock snippet already has a find -mmin +55 stale-breaker at the top, so the 25-minute reaper is largely redundant and is the part that misfires. Either raise it to ~2700s or drop it entirely. That's a judgement call about the loop's concurrency design, not a typo — hasn't been made.
The app is in materially better shape than it was on Thursday, and it now costs essentially nothing to keep improving it — 498 commits over four days against a $0 metered bill. The release path's last open question (R8) is closed.
What's actually slowing things down is not the loop's throughput, it's the two-way latency: eight unanswered questions to the iOS side, one blocked UI decision, and a missing relay token that turns minutes into sweeps. Three small unblocks would compound more than another 500 commits.