You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reached 2026-09-26. 2.4.0+66 shipped: release PR #1270, v2.4.0, Play internal via the API and TestFlight. Store promotion and review submission remain by hand, past this map.
A verified go/no-go for 2.4.0+66. Every feature area has a verdict from the Pixel 6; each failure is triaged against the bar; changelogs/66.txt is written and the two pre-PR checks from docs/RELEASING.md are done — so the next step is opening the develop → main PR with nothing left to remember. The PR itself, the release-ship approval and the store consoles are past the destination. Unlike most maps here this one carries execution: building, installing and running the test are task tickets on the route, because the verdict cannot exist without them.
Notes
Domain. Flutter app, conventions in AGENTS.md; docs/RELEASING.md is the checklist this map feeds — a release is a merge of develop into main, and the pipeline does the rest. Sessions reach for /grilling and /domain-modeling on the triage and changelog tickets. Task tickets that need the phone in hand are HITL: the maintainer taps, the session hands over a script and records what came back.
The candidate.develop at 86cd09d9 (2026-09-19), frozen. Both main and develop read 2.3.0+65; v2.3.0 shipped 2026-09-10 as build 65. The real delta is the diff of lib/ against the v2.3.0 tag (89 files) — git log main..develop is polluted by squash-merge and lists the 2.3.0 release's own commits. What changed, by area:
Area
Since v2.3.0
add-meal search
food names requested in the app's language, not the device's (#1215); Spanish and Hungarian names from Open Food Facts and the backend (#1213, #1229); canonical FDC sibling + full backend descriptions (#1170); has_portion read at the search cut (#1209); scan / create-custom actions on the no-results state (#995)
AI meal assistance
the model's portion word matched on the English label, bare ties broken toward the middle rung, misses marked (#1208); elapsed time, hint and cancel while an own server answers (#1149)
Open Food Facts data
micronutrients converted into app units on new writes (#775); niacin read from vitamin-pp_100g (#1168); a startup repair rewrites OFF rows logged before #775 (#1193, OffMicronutrientRepair, keyed on MealDBO.dataVersion)
meal detail
quick-serving chips 0.5×/1×/2×/100 g (#1101); opt-in Settings toggle for grams-first default (#1195); hydrated record kept across the unit menu (#1221)
profile
7-day moving-average overlay on the weight-trend chart (#1197)
recipes
totalWeightOverridden threaded through JSON and CSV import (#1169, #1196)
settings
export/import failures logged and explained to the user (#1150); grams-first toggle; Spanish + Hungarian in the language picker
l10n
Spanish and Hungarian shipped; Weblate pipeline live (#1171), 15 locale files updated
launcher artwork inset inside the adaptive mask (#1161)
Untouched since v2.3.0, smoke depth only: diary, fasting, add-activity / activity detail, Health Connect, scanner UI, onboarding (on the candidate, after pm clear of .develop), theme, notifications.
Known issues the candidate carries — recorded here so a tester does not re-find them, and none is a blocker under the bar: the weight-trend chart windows by 24-hour spans, so a DST change inside the window drops a day (#1207, fix in #1222); several activity picker rows share an English name (#1200, fix in #1223); a cleared per-app language override is re-pushed on the next cold start (#810, fix in #1230). All three PRs wait for the next release.
The phone. Pixel 6 (oriole, 18101FDF60010M) on Android 17, running the app in German. Its history matters: at charting it held full 2.2.0 with the maintainer's real data and .develop 2.3.0; both were wiped on 2026-09-19, so the 2.2.0 real-data upgrade is gone for good. It now carries one install — full, first installed 2026-09-19 as v2.3.0, upgraded in place to the candidate on 2026-09-25 — over a box holding two Open Food Facts intakes and the product cache, and nothing else. Since 2026-09-25 the session drives the phone itself via adb, re-checking mCurrentFocus after every event and stopping if it leaves the package; the system file picker during export is the one expected hand-off. The maintainer is still needed for the AI provider key and a barcode.
Builds. Debug-signed (0bdae1d6…5ff5), which is the key every install on this phone carries, so adb install -r is a true upgrade. Recipe: scratch worktree with .env copied in, then flutter pub get, flutter gen-l10n, dart run build_runner build --delete-conflicting-outputs, flutter build apk --flavor full --debug — about four minutes. The scratchpad is tmpfs: APKs and worktrees do not survive a reboot and have been rebuilt twice; durable evidence goes to ~/Documents/ont-release-2.4.0-evidence/.
Evidence. The exports (ont-develop-230.zip, ont-full-220.zip, pulled to the session) are the numeric baseline for the #1193 repair — the screens round pre-#775 values to 0.0 — and the repair recomputes a recipe's aggregate while leaving recipe-sourced intakes alone. Scripts live on research/release-2.4.0-pixel-test under docs/release-tests/2.4.0/.
Reporting. A HITL run reports per area: pass / fail (what you did, what you saw, what you expected) / skipped (why). The ticket's resolution comment holds that table; the triage ticket reads it.
Decisions so far
What is the release candidate, and which version does it become? — develop at 86cd09d9, frozen; it becomes 2.4.0+66. The five open PRs wait for the next release; the three bugs they fix are known issues of the candidate, not blockers. The bump commit is the only thing allowed on top.
Build the v2.3.0 and candidate debug APKs, and install v2.3.0 on the Pixel — three debug APKs built (candidate as develop and full, v2.3.0 as a spare), nothing installed. The target is a Pixel 6 on Android 17 already carrying .develop 2.3.0-develop (65) and full 2.2.0 (63), both on this machine's debug key; the route became upgrade .develop, then full on real data, then onboard on a cleared .develop.
Does any change since v2.3.0 add or alter a network destination? — no: same hosts, same RPCs, same payloads; the declarations stand with no console edit.langs= and fields= changed value only (asking Open Food Facts to return more, not sending more); every AI transport file is untouched; Sentry's gate and config are unchanged; the Android manifest has zero diff. One honest limit: whether a bumped SDK turned on a new default cannot be proved from the repo.
Which main-only lines are real gaps in develop? — none; nothing to cherry-pick. Of ~95 files with main-only lines, 82 match the merge base outright and the 13 independent ones all check out — the Weblate hotfix pair is byte-identical, the ARB diffs are key reordering (zero main-only keys), and develop is newer everywhere else. Turned up two non-gaps that matter: develop is still at 2.3.0+65, and RELEASING.md's Notes section misdescribes the workflow sets.
Go or no-go: rule the Pixel's report against the bar — NO-GO as frozen, and not because of the test. Nothing on the device hit a Blocks if and both pre-PR checks are clean; but #1254 (a custom meal with base quantity 0 stores NaN and blanks Home, Diary and Trends) was reported after the freeze, and its fix #1259 is green. Verified it is not a regression — edit_meal/ is unchanged since v2.3.0 — so the bar's fourth clause misses it; ruled in anyway rather than knowingly shipping data corruption. Re-freeze scope is fix(edit-meal): stop a zero base quantity from storing NaN nutriments #1259 only.
Nothing — the map closed at its destination. The three patches still open at the end were settled on the way:
The grams-first toggle shipping untranslated — ruled at Go or no-go: ships, as the Weblate pipeline working as designed. Its semantics identifier was added in #1270 / #1271 after the Codex review.
The lost 2.2.0 install — accepted: the 65 → 66 upgrade is verified on device, the 63 → 66 jump by the migration's unit suite only.
Health Connect on Android 17 — the smoke passed (screen renders, disclosure before any system UI); the permission grant stayed the maintainer's and was not exercised.
Out of scope
Opening and merging the release PR, and approving release-ship.docs/RELEASING.md scripts it; the map ends where that checklist begins.
Store console work — listing text, the Play data-safety record (the re-check here only decides whether it changed), the Health apps declaration, App Store submission and the Android hand-upload fallback.
Destination
A verified go/no-go for 2.4.0+66. Every feature area has a verdict from the Pixel 6; each failure is triaged against the bar;
changelogs/66.txtis written and the two pre-PR checks fromdocs/RELEASING.mdare done — so the next step is opening thedevelop → mainPR with nothing left to remember. The PR itself, therelease-shipapproval and the store consoles are past the destination. Unlike most maps here this one carries execution: building, installing and running the test are task tickets on the route, because the verdict cannot exist without them.Notes
Domain. Flutter app, conventions in
AGENTS.md;docs/RELEASING.mdis the checklist this map feeds — a release is a merge ofdevelopintomain, and the pipeline does the rest. Sessions reach for/grillingand/domain-modelingon the triage and changelog tickets. Task tickets that need the phone in hand are HITL: the maintainer taps, the session hands over a script and records what came back.The candidate.
developat86cd09d9(2026-09-19), frozen. Bothmainanddevelopread2.3.0+65;v2.3.0shipped 2026-09-10 as build 65. The real delta is the diff oflib/against thev2.3.0tag (89 files) —git log main..developis polluted by squash-merge and lists the 2.3.0 release's own commits. What changed, by area:has_portionread at the search cut (#1209); scan / create-custom actions on the no-results state (#995)vitamin-pp_100g(#1168); a startup repair rewrites OFF rows logged before #775 (#1193,OffMicronutrientRepair, keyed onMealDBO.dataVersion)totalWeightOverriddenthreaded through JSON and CSV import (#1169, #1196)hive_ce2.19.3→2.20.0,mobile_scanner7.4.0→7.4.1,sentry_flutter9.26→9.30,cached_network_image3→4,archive4.0.9→4.2.0,flutter_local_notifications22.3.0→22.3.1Untouched since v2.3.0, smoke depth only: diary, fasting, add-activity / activity detail, Health Connect, scanner UI, onboarding (on the candidate, after
pm clearof.develop), theme, notifications.Known issues the candidate carries — recorded here so a tester does not re-find them, and none is a blocker under the bar: the weight-trend chart windows by 24-hour spans, so a DST change inside the window drops a day (#1207, fix in #1222); several activity picker rows share an English name (#1200, fix in #1223); a cleared per-app language override is re-pushed on the next cold start (#810, fix in #1230). All three PRs wait for the next release.
The phone. Pixel 6 (
oriole,18101FDF60010M) on Android 17, running the app in German. Its history matters: at charting it heldfull2.2.0 with the maintainer's real data and.develop2.3.0; both were wiped on 2026-09-19, so the 2.2.0 real-data upgrade is gone for good. It now carries one install —full, first installed 2026-09-19 asv2.3.0, upgraded in place to the candidate on 2026-09-25 — over a box holding two Open Food Facts intakes and the product cache, and nothing else. Since 2026-09-25 the session drives the phone itself via adb, re-checkingmCurrentFocusafter every event and stopping if it leaves the package; the system file picker during export is the one expected hand-off. The maintainer is still needed for the AI provider key and a barcode.Builds. Debug-signed (
0bdae1d6…5ff5), which is the key every install on this phone carries, soadb install -ris a true upgrade. Recipe: scratch worktree with.envcopied in, thenflutter pub get,flutter gen-l10n,dart run build_runner build --delete-conflicting-outputs,flutter build apk --flavor full --debug— about four minutes. The scratchpad is tmpfs: APKs and worktrees do not survive a reboot and have been rebuilt twice; durable evidence goes to~/Documents/ont-release-2.4.0-evidence/.Evidence. The exports (
ont-develop-230.zip,ont-full-220.zip, pulled to the session) are the numeric baseline for the #1193 repair — the screens round pre-#775 values to0.0— and the repair recomputes a recipe's aggregate while leaving recipe-sourced intakes alone. Scripts live onresearch/release-2.4.0-pixel-testunderdocs/release-tests/2.4.0/.Reporting. A HITL run reports per area: pass / fail (what you did, what you saw, what you expected) / skipped (why). The ticket's resolution comment holds that table; the triage ticket reads it.
Decisions so far
developat86cd09d9, frozen; it becomes 2.4.0+66. The five open PRs wait for the next release; the three bugs they fix are known issues of the candidate, not blockers. The bump commit is the only thing allowed on top.full --debugbuilds,v2.3.0first, the candidate over it; the maintainer drives. Same debug certificate makesadb install -ra real upgrade, so hive_ce, the DBO changes and the fix(data): bring Open Food Facts micronutrients logged before #775 into app units #1193 repair run on a v2.3.0 box. The session installs and reads logs, sends no input.developandfull, v2.3.0 as a spare), nothing installed. The target is a Pixel 6 on Android 17 already carrying.develop2.3.0-develop (65) andfull2.2.0 (63), both on this machine's debug key; the route became upgrade.develop, thenfullon real data, then onboard on a cleared.develop.research/release-2.4.0-pixel-test; the exports are the numeric baseline, not the screens. Do → Expect → Note over both installs; six accidental-write paths named;.developgets reinstalled as truev2.3.0first because its build has fix(add-meal): convert Open Food Facts micronutrients into the app's units #775 without the stamp; the recipe aggregate is recomputed by the repair (map corrected).research/release-2.4.0-pixel-test. 27 adversarial findings applied, including an export-filename blocker and three near-miss data hazards; fix(add-meal): convert Open Food Facts micronutrients into the app's units #775/fix(off): read niacin from vitamin-pp_100g, not niacin_100g #1168 were silently uncovered and now are; fix(add-meal): read has_portion at the search cut for the resolver's page, so a portionless exact title no longer pushes the survey record out of the twenty #1209 is recorded as not verifiable on device. Seeding is step 1, and a fourth verdict,inconclusive, exists for evidence that does not decide.langs=andfields=changed value only (asking Open Food Facts to return more, not sending more); every AI transport file is untouched; Sentry's gate and config are unchanged; the Android manifest has zero diff. One honest limit: whether a bumped SDK turned on a new default cannot be proved from the repo.main-only lines, 82 match the merge base outright and the 13 independent ones all check out — the Weblate hotfix pair is byte-identical, the ARB diffs are key reordering (zeromain-only keys), anddevelopis newer everywhere else. Turned up two non-gaps that matter:developis still at2.3.0+65, andRELEASING.md's Notes section misdescribes the workflow sets.0.5x/hyphen because the file is pasted into the consoles by hand.edit_meal/is unchanged since v2.3.0 — so the bar's fourth clause misses it; ruled in anyway rather than knowingly shipping data corruption. Re-freeze scope is fix(edit-meal): stop a zero base quantity from storing NaN nutriments #1259 only.680eafaa(2.4.0+66); clean on device; scanner passes. Both startup repairs behaved correctly (silent no-ops), and a full export scan found zero non-finite values. The zero-base-quantity path itself was not exercised on device and is accepted on fix(edit-meal): stop a zero base quantity from storing NaN nutriments #1259's unit tests, which reproduce the reported case by name.Not yet specified
Nothing — the map closed at its destination. The three patches still open at the end were settled on the way:
Out of scope
release-ship.docs/RELEASING.mdscripts it; the map ends where that checklist begins.flutter_secure_storage11 bridge (fix(storage): move the Android keystore entries out of the options flutter_secure_storage 11 removes #1210 / chore(deps): bump flutter_secure_storage from 10.3.1 to 11.0.0 #809). It touches the AES-key path and gets its own release; the keystore migration is deliberately not on this candidate and not tested here.