Merge beta into main — nutrition track joins the trunk - #32
Merged
Conversation
Nutrition design for the beta branch: all-meals food weeks proposed by the coach, plan-first one-tap logging, carry-over waste loop, aisle-grouped shopping list with Amazon Fresh export (auto-cart Phase 9), MealPal/Grubhub lunch assist, household dinner semantics. Targets tuned for cholesterol: protein, fiber, sat-fat cap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Palette-native SVG plate illustrations (platefig, the formfig approach) as thumbnails on day/week/proposal rows and heroes on recipe screens; method steps rewritten with durations and done-when checkpoints; new cook mode - one step per screen, local countdown ring reusing the rest-ring pattern, batch checkpoints, finish logs the dinner. New mockup 43-cook-mode.html. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… HelloFresh cards (E16.11) Coach proposes only from the in-app pool; the pool grows via chat imports: paste a BBC Good Food link (single-page fetch, schema.org JSON-LD parse) or photograph HelloFresh cards (vision). Imports are normalized not copied - ingredients mapped, macros recomputed + cross-checked, steps rewritten in Forge voice with source attribution, adapt-don't-reject for sat-fat-heavy cards. Card-box amnesty before the HelloFresh cancel. Mockup 44. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Seven nutrition tables (create_all-provisioned, no column changes to
existing ones): recipes, ingredients, meal_revisions, meal_log, carryovers,
lunch_favorites. Food week is household-scoped (user_id NULL) with the demo
seat walled into its own scope; meal logs strictly per-user with macro
snapshots and client_id idempotency for the offline queue.
Seed: 58-item ingredient macro table, 25 recipes (16 dinners, 3 breakfasts,
3 lunches, 3 snacks) in the HelloFresh-card format with done-when steps and
platefig composition ids, per-user nutrition prefs defaults, and the
hand-written first household food week (batch traybake Mon->Wed, chili
batch->Fri lunch, Fri night out, order-assist lunch slots Tue-Thu).
Routes: GET /api/food/week (rolling 7-day, resolves leftovers/order/out
slots, per-day logged totals), GET /api/food/recipes/{slug} (steps +
aisle-joined ingredients), POST /api/food/log + DELETE (one-tap tick,
off-plan entries validated). Meals added to /api/export. Tests 33 -> 35.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fifth tab. Day view leads with the four cholesterol meters (protein, fiber, sat-fat cap, kcal) over one-tap tick rows with platefig thumbnails; offline ticks queue in localStorage and replay idempotently via client_id. Week menu reads dinner-first with honest planned-only averages. Recipe detail: plate art hero, why-it's-here, aisle-joined ingredients, done-when steps. Cook mode: one step per screen, kitchen-scale type, local countdown ring (rest- ring pattern), plated summary that logs the dinner. platefig.tsx: 16 token-native SVG compositions over shared plate/tray/bowl primitives (formfig approach) - adapts to Paper x Moss light mode free. Plan integration: tonight's dinner as one quiet hairline row on the hero, dim dinner notes on day rows. Settings -> Nutrition: coach-owned targets (read-only + chat CTA), cook nights, budgets, household toggle. Driven end-to-end headless (sign-in -> tick -> week -> recipe -> cook with running timer -> plated -> settings, dark + light): no page errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- delete_demo missed every nutrition table (+ push_subs, notification_log, withings_links): the public demo seat can log meals, so demo reset/remove would FK-crash on Postgres. Model list completed + regression test. - log_meal client_id idempotency had a check-then-insert race: concurrent offline retries could 500 on uq_meal_client. IntegrityError now resolves to the existing row. - flushFoodQueue index math re-queued already-sent ticks when a bad item was dropped mid-flush (harmless duplicates thanks to client_id, but the queue never drained). Rewritten with a plain index. - Cook mode logged every recipe into the dinner slot - a lunch recipe cooked step-by-step (e.g. chicken-grain-soup) landed as dinner. Slot now follows recipe.kind. - Double-tapping a tick while the optimistic write was in flight re-logged the meal (logged=true but log_id not yet known). Tap now ignored until the server id arrives. - Recipe/cook/week screens left the Plan tab highlighted when entered from Plan's dinner line; they now light the Food tab. Tests 35 -> 36. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
body/.scroll/.sheet pin overflow-x (overflow-y:auto silently makes x scrollable — one wide child let the whole page drag sideways on iOS); .app inherits overflow-wrap:break-word so long unbroken strings wrap; .row name side flexes with min-width:0; .statchips wrap at narrow widths; img/video capped at container width. Verified 320–430 px and 800–1600 px dashboard with an element-overflow probe: zero offenders. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server: food_coach.py proposal machinery (validators: every slot planned, complete recipes only, ≥1 zero-cook dinner, weekly-average trio checks with the sat-fat cap absolute and −1 g banked for a night out) + carry-over helpers; /api/food/proposal get/approve/reject scoped by the household (demo walled into its own scope); coach tools get_food_week, get_recipes, get_food_proposal, propose_food_week, log_meal (chat estimates), get/update_carryovers; nutrition rules in the static prompt, targets + pending-proposal line in the dynamic prompt; Sunday review step 4 proposes the food week alongside training (no new push kinds). Web: FoodProposalBanner + FoodProposalCard (signed changes, rationale, dinner-by-dinner) on the Food day/week screens; coach screen refreshes food queries after replies and reviews. Tests: 38 pass — validator matrix, approve flow via API, one-pending invariant, household share (Shelby approves), demo segregation, coach-tool exec + carry-over keep/bin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…) + BETA badge Merge resolves: Screen union and screens/data imports keep both food and metric entries; test file keeps both branches' new tests (40 pass). Beta-only: a volt BETA tag next to every wordmark (app header, auth, onboarding, dashboard) so the beta stack is unmistakable next to the stable app. Dropped when features merge to main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…set countdown Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… icons, h/m durations
- /api/week and /api/food/week now serve the Mon-Sun calendar week containing
the requested date (snapping to Monday) and return `today`, so clients can
page weeks and mark the current day.
- Plan and Food week screens gain prev/next week chevrons (capped one week
ahead) with a "this week" jump; the current week still leads with today's
hero card, so no scrolling to find it. Past plan days with nothing logged
show "missed" (warn) in the list and the weekstrip.
- Food day screen fetches the week containing the viewed date, so days opened
from a paged food week resolve.
- /api/history is offset-paginated (limit<=100, default 30); the History
screen loads pages on demand ("Earlier sessions") and shows a per-entry
activity glyph (barbell / run / walk / hike / ride / swim / generic cardio).
- Cardio and session durations display as hours+minutes ("46 min", "1h 24m")
via fmtDur; fmtT stays mm:ss for live timers.
- run-forge driver: optional --no-sandbox via CHROME_NO_SANDBOX, updated Plan
kick text wait.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mg83Arymf6QnmLBTy5qBku
Calendar-week paging for Plan + Food, paginated History, h/m durations
Extends meal macros from the coached trio (protein / fiber / sat fat + kcal) to the standard label set: carbs, sugar, total fat and sodium join everywhere macros flow — recipes, ingredients (per-100), meal-log snapshots, lunch favorites, day/week totals, coach tools and the chat context export. - models: MACRO_FIELDS tuple is the single source of truth; new Float columns on recipes, ingredients, meal_log and lunch_favorites - main: startup additive ALTERs provision the new columns on existing DBs (create_all can't); generalized the benefit-column migration helper - food_seed: authored carbs/sugar/fat/sodium for all 59 ingredients and sugar/sodium for all 25 recipes (carbs/fat were already authored); seed now backfills the new fields on existing rows; default targets gain carbs 250 g, fat 80 g and sugar 65 g / sodium 2300 mg caps - food router: cards, totals and log snapshots iterate MACRO_FIELDS; off-plan logs accept the full set - coach: log_meal tool takes/records all eight macros, get_recipes exposes them, the grounding line states targets and caps - web: full-set Macros type, four new day meters (carbs, sugar cap, fat, sodium cap), richer recipe chips, plated stats and settings targets; old stored prefs merge under the new defaults Historical meal_log rows keep zeroed new columns — snapshots are never rewritten. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeKgMxcKNJZNaafS4jceBt
…pansion-nmbrnh Track the full nutrition-label macro set on meals
…orts
- /mcp: hand-rolled stateless Streamable-HTTP JSON-RPC endpoint (no SDK
dep, plain JSON responses), authed with the per-user ingest token
- tools: log_food (venue/cost/currency/photos, client_id idempotent,
slot inferred from coach_tz time), get_food_log, delete_food_log,
import_recipe, search_recipes, get_recipe
- import_recipe: source_url is the import identity (re-import updates in
place), seed slugs write-protected, done-when steps required, unknown
ingredients / hard / 0 kcal park the recipe complete=0
- media_blobs + app/media.py: photos materialized on-box (3 MB cap,
data-URI or URL fetch, keep-URL fallback, src_url dedupe), served at
/api/food/media/{id}; recipe imagery household-shared, meal photos
private per owner
- meal_log gains venue/cost/currency/note/photos; recipes gain
images/rating/rating_count (+ lifespan ALTERs)
- PWA: extras rows show photo thumb + venue·cost; recipe detail shows
hero image, rating, step images, source link; cook mode step images
- tests 45: MCP handshake/auth, log round-trip + photo privacy, import
semantics; fix clock-flaky pull-forward test leaving a dangling session
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gress explorer - previews: OG/Twitter meta + description in index.html, og.png 1200x630 Void x Volt card, PNG apple-touch + 512 manifest icons (crawlers/iOS don't take SVG); manifest description updated - coach notes: day whys are session notes, dinner whys are plate notes — prompt specs with examples + validators (_validate_day_notes / _validate_dinner_notes): changed day needs a note, no two alike, never the rationale restated, never the previous revision's line on a changed day; unchanged days may carry notes over (amend flow intact) - Progress: Health chip grid drives one inline MetricPanel (band chart + zone description + blurb) — no more per-KPI drill-down screens; VO2max keeps raw-dots+trend via chartOverride; selection persisted; BandChart gains per-reading dots; metric route kept for deep links - tests 45 incl. note-gate coverage; verified headless dark+light Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- /welcome 404'd on any browser without the app loaded: StaticFiles only matches welcome.html exactly and the SW denylists /welcome from the SPA fallback — dedicated route now serves the file (like /dashboard) - content: OG/Twitter share meta for the page itself, Food-beta badge, new tile band (food week macro meters, cook-mode step + timer ring, coach chat bubbles), "week three" grid (plate math, swaps, niggles, PR ledger, offline, units, dashboard, notifications), library strip copy updated to 65 movements Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # CLAUDE.md # server/tests/test_smoke.py # web/src/api.ts # web/src/screens/today.tsx
…ing demos - demo._seed_demo_food: own-scope active food week, pending food proposal with diff rows, three weeks of meal logs (plan ticks with macro snapshots, order-out lunches with venue/cost, the Friday night-out estimate, an off-plan snack), carry-overs, two lunch favorites; dates follow config.local_today() so overnight the half-logged "today" stays on the app's calendar, not the OS zone's - demo.enrich_demo: idempotent per-block top-up for demos created before newer features (currently food) — never touches training history; POST /api/admin/demo/enrich + "Top up data" button in the Settings demo card; full reset seeds food too - delete_demo also clears media_blobs (demo can attach meal photos via MCP) - demo-wall test updated: demo food week must come from the demo's own revision and never contain a member's logs; new seed/enrich test; suite at 47 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/.well-known/security.txt + legacy /security.txt alias. Contact derives from the admin seat at request time (no personal data in the tracked repo), Expires rolls six months out, Canonical from BASE_URL. 404 until an admin exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HTML entry points (index, welcome, dashboard) now carry a __BASE_URL__ token in their OG/share meta; main.py::_html_page substitutes the real BASE_URL from the compose override at serve time. The previously hardcoded hostname is scrubbed from index.html, welcome.html and CLAUDE.md, and the rule is recorded in CLAUDE.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RouteMap on run detail: lazy-loaded Leaflet with CARTO dark_all/light_all raster basemaps (keyless), volt route line with start/finish markers, tiles + stroke swap live when the app theme changes. The tile-free RouteTrace SVG stays as the offline/import-failure fallback. Palette- native chrome (transparent attribution, contained stacking context). Reverses the earlier no-tiles rule per James — CLAUDE.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The visual-viewport keyboard handler treated any >80px-short viewport as "keyboard up" — but iOS standalone reports transiently short visual viewports during the launch animation, and with no follow-up viewport event the short --vvh stuck, leaving the app pinned above a dead strip. Keyboard mode now also requires an actually-focused editable element, focus changes and visibility changes re-sync, and two delayed syncs clear whatever the launch transients left behind. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # web/src/styles.css
# Conflicts: # CLAUDE.md
…screens) Swept every beta surface at 320/1440 under the new responsive shell — recipe detail, cook mode, food week menu, food proposal dialog, session logger, Progress health explorer, settings. All compose from the shell primitives and needed nothing; the one finding was the run map looking squat at the 700px column, now 360px tall on desktop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ning-beta-vjj92h
…beta-mhy06x # Conflicts: # server/app/main.py # web/index.html
Conflicts resolved by combining branches: today.tsx keeps the food dinner lines, now rendered inside each week pane (three food-week queries so dinners slide with their week); main.py adopts beta's _add_missing_columns helper and adds the favorite migration through it; models.py imports the union; both branches' appended tests kept. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BguP3L1hBLWEQt5XSnBaYH
…ning-beta-vjj92h
New GET /api/connections/token returns the owner's full ingest token (scoped by current_user) so the config can be copied without rotating. The Connections screen gains a Claude Desktop card rendering a paste- ready claude_desktop_config.json snippet — mcp-remote bridging stdio to /mcp with the bearer header, origin from location.origin, token masked on screen and only real on the clipboard. Also mirrors main's one-line card-title fix (8be11d3) so the next merge resolves clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hand-rolled auth server for /mcp (no SDK, no new deps): RFC 9728/8414 discovery, RFC 7591 dynamic registration, consent page riding the app session (Google login gains a validated next= hop), token endpoint with mandatory PKCE S256, single-use codes, 7d access + 180d rotating refresh tokens in three new tables. /mcp accepts fgm_ bearers alongside ingest tokens and 401s with the resource_metadata pointer that triggers client discovery. Settings → Connections lists grants with instant revoke; the config-file path stays as fallback. SW navigateFallback now excludes /mcp and /.well-known — it was serving the app shell over the consent page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conflict resolutions: auth.py keeps the post-login next= hop on top of host-derived redirect URIs; both new test blocks kept. MCP OAuth discovery and the 401 resource_metadata pointer now build from public_base_url(request) instead of BASE_URL so every allowed domain self-describes correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erence - GET /api/food/recipes lists the whole library (parked included, q/kind filters), sharing query_recipes with the MCP search tool - RecipeLibraryScreen: Food → Recipes › — search-as-you-type, kind chips, rating stars, warm 'parked' badge; detail Back honours foodFrom - import_recipe: an unknown ingredient supplied with per-100g reference macros (kcal_100 gate, optional aisle/pantry) joins the canonical ingredients table instead of parking the recipe; macro-less unknowns still park, with a warning that points at the fix Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ent seed Four new MCP tools on /mcp for the canonical ingredient reference (the 'pantry'): list_ingredients (read, demo-visible), bulk_import_ingredients (upsert-by-name, overwrite default true — the bulk path), update_ingredient (partial patch), delete_ingredient (reports recipe references). All writes reject the demo seat and share _apply_ingredient_fields/_new_ingredient with import_recipe's inline creation. Expand food_seed.INGREDIENTS 58→102 with common staples (USDA FoodData Central / McCance per-100g values) so fewer recipe imports park incomplete. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… timers, food-week swipe Settings: - Move Appearance (theme + accent) into its own submenu (set-appearance) - Move About you (sex + birth year) into its own submenu (set-about) - Collect sex + birth year in onboarding's Welcome step (optional) Recipes / cook: - Recipe detail: servings slider scales ingredient amounts (per-plate macros unchanged); fix long-note/amount row overflow (note wraps, amount width-capped) - 'Plan into a day' sheet swaps a recipe into a given date's dinner via new PATCH /api/food/week/slot (weekday-keyed active-week edit; demo edits own week) - Cook mode: background/parallel steps — start a timer and move on; timers persist across steps and show in a running-timer strip. New import_recipe step.parallel flag (implies timer), threaded through model + app Food week menu: finger-tracked prev/cur/next week swipe, mirroring the Plan screen (4-week forward cap, rubber-band, eased prev/next buttons) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cook-something-else
Fixes:
- Coach/logged meal now REPLACES the planned option in its slot (day view shows
what was actually eaten, off-plan label+macros) and non-snack slots hold one
meal so re-logging replaces instead of double-counting (server food_week +
log_meal; client FoodSlot render). Snacks stay additive.
- Apple Health sleep: iOS 16+ reports stages with an empty legacy 'asleep'
bucket, so ingest now sums core+deep+rem (falls back to a single total),
honors minute units, and accepts sleepStart/inBedStart timestamps.
Features:
- Food day view: compact per-meal macros ('520 · P42 C48 F13') — dropped the
verbose kcal/fib/sat spellout that dominated the rows
- 'Cook something else': day view → full recipe library in replace mode →
tap a dinner to swap it into that day (reuses PATCH /api/food/week/slot)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pantry staples showed only the word 'pantry', hiding how much the recipe needs. Now the row shows the actual (scaled) amount with a small 'pantry' tag as the not-on-the-shopping-list marker; the dimmed name still signals staple. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…de slot labels
- Cook mode 'Plated' screen shows the recipe's own hero image (imported photo)
instead of the generic plate figure
- 'Cook something else' is now a ONE-DAY action: it opens the chosen dinner
scoped to that date so cooking/logging replaces only that day's dinner — it no
longer edits the recurring weekday template (which changed every future week).
('Plan into a day' on the recipe detail remains the deliberate recurring
planner.) Replace mode offers complete dinners only.
- Cook mode finish button / toast / plated card use the recipe's actual slot
word instead of hardcoding 'dinner'
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the 8 full-width meter rows (which filled the whole first screen) with a compact 4-column grid — two rows of four, tiny label + value + thin bar. Cuts the macro card's height by ~60%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…wipe - SEED_RECIPES (default true) gates seeding of the curated recipes AND the first food week; the pantry/ingredient reference always seeds so MCP imports complete - DELETE /api/admin/recipes (admin) empties the library and retires the shared household food week (meal logs + ingredients untouched); Settings → Server → Recipe library exposes it behind a ConfirmSheet - Set SEED_RECIPES=false + wipe once to run a fully MCP-populated library Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The build had drifted to full-bleed hairline rows because `.tap .card` stripped card chrome from anything tappable; the original mockups put every item on its own raised card. Bring that back and unify the row primitives. - styles.css: delete the `.tap .card` transparent override (tappable = raised again); add `--hair-in` for separators inside cards; new `.daycard`/`.group`/`.lt`/`.lsub`/`.mtag` list anatomy; `.dimrow` dims decoration not text; bold status-coded week calendar; flat accent wash on the today hero (was a gradient); visible meal ticks; deepen the light theme a step (paper #eef0ea, stronger tints, soft card shadows) + bump all five palette light --volt-dim values - today.tsx: Plan renders card-per-day; "Missed" is a warm tag, not orange row text - data.tsx: History groups sessions into month cards; rows lead with the name, friendly date + metrics on one sub line - food.tsx: day meals collapse into one grouped card under a Meals label - docs/mockups/45-design-refresh-options.html: options sheet Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a delete_recipe MCP tool to the Forge food surface so an MCP-populated recipe library can shed recipes it no longer wants — including the curated `source="seed"` starter set. - `slug` deletes one recipe; `source` clears every recipe from one origin label at once (e.g. source="seed"). Exactly one is required. - Unlike import_recipe's overwrite guard, delete is not blocked on seed recipes — removing them is the point. - Demo seat is rejected, matching the shared-library write rules. - Deleting a recipe leaves meal-log macro snapshots intact and planned slots degrade to "unplanned" (already handled by _resolve_slot); the reach is reported back as logs_referencing. Note: recipes reappear on boot while SEED_RECIPES is enabled (insert-missing seed). Set SEED_RECIPES=false to keep them gone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TPvHbVAFs88GE8t2N5KoS
Brings main's Jul 2026 design work forward onto the beta (nutrition) track: volt eased off its luminance peak, the accent-palette picker removed, the week strip redesigned as typed status cells, higher-contrast mode, Space Grotesk display numerals, coach markdown replies, the welcome-page work, and the card-language restoration. Conflict reconciliations (beta features preserved throughout): - Palettes: main's removal wins — dropped the [data-palette] blocks, picker CSS, PALETTES/applyPalette/storedPalette, and prefs.palette sync. Beta's separate Appearance screen kept, now Theme + Contrast (no accent picker). - Week strip: main's typed cells replace beta's bar chart; KindGlyph now renders in currentColor. Beta's per-day dinner line kept in the day rows. - /welcome route: kept beta's _html_page (__BASE_URL__ link-preview substitution) and folded in main's SPA-shell fallback when the page is absent, so all four test_welcome_page cases pass. - Landing page: beta's food-showcase + "week three" grid kept over main's generic feature grid (which duplicated content beta already presents). - Docs: beta's E16 Nutrition keeps the E16 slot; main's Appearance epic renumbered E17 and rewritten to drop the removed palettes (Theme + Contrast). CLAUDE.md run-detail note keeps main's palette-free wording plus beta's food-MCP line. Verified: web build clean, 78 server tests pass, driver clean run across all screens in dark + light (typed strip and food dinner lines coexist; Appearance shows Theme + Contrast, no palette picker). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UDSDwFbiMsvr32p2Q9mJ7D
Merge main into beta — Jul 2026 design work onto the nutrition track
Day view meal rows, week view day rows, and the recipe library search already had per-recipe `image` data (imported recipes) but only the library list and recipe detail screen rendered it — the rest always drew the PlateFig icon. A shared MealMedia helper now renders the recipe/meal's own photo everywhere it exists, falling back to the icon only when there's no photo on file.
Matches the round-plate shape of the PlateFig icon they sit alongside (and the header avatar badge), so photo and icon rows read as one consistent shape language instead of two.
Nights the Apple Watch wasn't worn to bed, HealthKit has no core/deep/rem or asleep data — both are a literal 0, not missing — so sleep_h was being stored as 0 hours slept every such night instead of falling back to the only real signal left (inBed, iPhone motion detection). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
64px was too small for a photo to read as anything but a smudge, and a circular crop that size throws away most of the frame. Switched to a 64px rounded-square tile (matches the rounding already used on hero/ step images) with a muted background behind the icon fallback, so photo rows and icon rows sit in the same shape instead of two systems.
Brings E16 (recipes, meal planning, cook mode, pantry, macros), the MCP food endpoint with OAuth 2.1, and the Settings reorganisation onto main so there is one trunk again. 68 commits from beta; main's 22 (iOS N0/N1 + the coach usage dashboard) stay. Also recovers four commits that had been merged to beta but never to main: the immersive desktop shell, the coach weekly-note fix, the muted accent palettes, and day-swipe in the day view. Conflict resolutions, all keeping both sides: - auth.py — beta's post_login_next (MCP consent redirect) and main's native=1 branch are orthogonal. Both kept; the native path clears post_login_next rather than leaving it primed to fire on the session's next browser sign-in. - main.py — took beta's _add_missing_columns helper and expressed main's agent_runs token columns through it. - admin.py, test_smoke.py, App.tsx, ui.tsx — additive on both sides, unioned. One conflict was a real disagreement, not a mechanical one: the two branches had opposite policies on naming the public host in tracked files. beta forbade it (21 Jul); main had written it into five files. James chose beta's policy, so this merge also scrubs it: - The iOS client now reads its origin at runtime from a gitignored ServerDefaults.plist (example committed) instead of a baked-in literal. No Xcode step — synchronized groups bundle it. Absent, the app falls back to localhost and shows the server picker in any build configuration, so a fresh clone still builds and says so honestly. - Docs describe the value rather than spelling it; the link-preview test uses a reserved example domain. Not scrubbed: the bundle identifier still spells the host backwards, in project.pbxproj, the App Group and the Keychain service. Renaming is Xcode work that invalidates registered App IDs, so it is recorded as handover A6 to settle before signing rather than guessed at here. Tests: 85 server, iOS suite green, web builds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings E16 (recipes, meal planning, cook mode, pantry, macros), the MCP food endpoint with OAuth 2.1, and the Settings reorganisation onto main so there's one trunk again. 68 commits from beta; main's 22 (iOS N0/N1, coach usage dashboard) stay.
It also recovers four commits that had reached beta but never main: the immersive desktop shell, the coach weekly-note fix, the muted accent palettes, and day-swipe in the day view.
Conflict resolutions — all kept both sides
routers/auth.pypost_login_next(MCP consent redirect) and main'snative=1branch are orthogonal. Both kept; the native path clearspost_login_nextrather than leaving it primed to fire on the session's next browser sign-in.main.py_add_missing_columnshelper, expressed main'sagent_runstoken columns through it.routers/admin.pytests/test_smoke.pyApp.tsx,ui.tsxOne conflict was a real disagreement
The branches had opposite policies on naming the public host in tracked files. beta forbade it (
chore: never name the public host in tracked files, 21 Jul); main had written it into five files on 26 Jul. On a public repo those can't both stand, so I asked rather than picking — James chose beta's policy.So this merge also scrubs it:
ServerDefaults.plist(example committed) instead of a baked-in literal. No Xcode step — synchronized groups bundle it automatically. When absent the app falls back to localhost and shows the server picker in any build configuration, so a fresh clone still builds and says plainly that it doesn't know where production is.Not scrubbed — needs your decision
The bundle identifier still spells the host backwards, in
project.pbxproj, the App Group, and the Keychain service. Renaming isproject.pbxprojwork that invalidates registered App IDs, so I left it and recorded it as handover A6 — worth settling before A1 registers anything with Apple, when it's still just a build setting.Already-published commit messages and PR #30/#31 descriptions still contain the host. Undoing that needs a force-push over published history; I haven't done it and wouldn't without you asking explicitly.
Verification
xcodebuildclean.npm run buildsucceeds.Note on PR #31
#31 (APNs device registration) will conflict on
main.pyonce this lands — beta refactored the migration block that #31 adds to. Merge this first and I'll update #31.🤖 Generated with Claude Code