Repository navigation
Conversation
- Open the offline cooking guide from "Start cooking", so finishing a recipe logs the meal and uses Kitchen inventory without the live backend. Cooking with Le Chef stays as a secondary option. - Save meals with a timestamp and return the history row ID, so they appear in today's nutrition and Apple Health sync names the right meal. - Scan each camera photo once, resolve camera labels to curated recipe ingredients before the USDA catalog, and stop OCR from mapping foods to different ones (oat milk to milk, mustard to soy sauce). - Keep demo and tutorial reviews and cooking out of the real Kitchen and meal history. - Reconcile a revisited scan review in one transaction, match recipes against the confirmed scan plus the Kitchen, and refresh Kitchen and Home after any inventory change. - Mark photo-estimated amounts in the Kitchen (migration v16), and log the confirmed portion (v17) and cooking swaps (v18) wherever nutrition or consumption is computed. Reports count required ingredients only, matching the recipe preview. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Onboarding's kitchen review showed name-based estimates (egg ~50 g), but scan intake stored a separate catalog-unit estimate with a 30 g floor (egg 120 g), so the Kitchen disagreed with what the user had just confirmed. Intake now uses the review's estimator and label, so a corrected detection is estimated from the chosen ingredient. The unused catalog-unit estimator is removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 7, 2026
Draft
On pushed screens such as Review Ingredients, Skip tour sat 88 pt from the top, inside the navigation bar. The bar takes every tap in that band, so Skip was visible but dead and the user had to page through all seven cards. The top placements now start below the top safe area, which includes the navigation bar on pushed screens and only the status bar on Home, so Home keeps its 88 pt offset. The placement logic moves into SpotlightSkipLayout so it can be tested. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
141 of the 166 bundled recipes start their instructions with "Source: https://www.bbcgoodfood.com/...", and all 166 number their steps. The guide used each line as a page, so step 1 was the URL and every later page printed "1." under its own "02 of 7". CookingGuideSteps now builds the pages: a "Source:" line becomes an attribution, and a leading "1. " or "1) " is removed (numbers like "1.5 cups" stay). The last step shows "Recipe from bbcgoodfood.com", linking to the original page, so the source stays visible. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The preview's green check meant "required", not "you have it", so an ingredient the results card listed as missing (Cucumber in the walk) appeared checked. The icon now follows the search's missing IDs: a check for a required ingredient the user has, the results card's exclamation glyph and a "Missing" line for one they don't. Optional and substituted rows get a dashed circle, which makes no claim about the kitchen. VoiceOver reads the same state. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The hero is the first exact match, else the first near match, and the grid and "Almost there" lists still contained it, so the same recipe appeared twice. RecommendationSections now owns the hero choice (bestMatch) and the lists under it (belowBestMatch); the header counts still use the full sections. When the hero is the only result, the divider and empty list are not drawn, and the tutorial replay skips its "Browse Alternatives" card instead of waiting for a list that never appears. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The chip row looped over fridge, pantry and freezer, while the On Hand list also showed an "Other" section for items with no known storage location, so that section had no chip. KitchenLocationOrder now gives one order to both, and the chip row shows a chip for every location with items, "Other" last. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4138a04 moved the corner Skip button below the top safe area, but that inset was never measured on a pushed screen, so its tests only proved the arithmetic. Skip now sits in the card's control row as a text button in the overlay's secondary white, so no navigation bar can cover it on any screen. It keeps the leading edge as Back appears, Back sits beside Next, and the step dots move to their own row above. At large text sizes Skip drops below the row. The label uses a scaling text style and a 44 pt minimum hit height. The corner button, its placement and collision code, and SpotlightSkipLayout with its tests are removed. SpotlightTourProgress holds the remaining rule: Skip on every step but the last, where "Let's go" ends the tour. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… trait The chips, including the new Other chip, were about 28 pt tall to the touch. The capsule keeps its size and the tappable area grows to 44 pt around it, which makes the chip row 16 pt taller. VoiceOver now hears which chip is selected through the isSelected trait. There is no unit test: a minimum frame and an accessibility trait have no pure logic to test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Recipe results, recipe preview, ingredient review and demo mode scrolled to each tutorial highlight with the spotlightMove spring even with Reduce Motion on. All four now call AppMotion.spotlightScroll(reduceMotion:), which returns no animation in that case, matching what Home already did. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The scroll callbacks on ingredient review, demo mode, recipe preview and recipe results read reduceMotion through the view, so the view's state held the spotlight coordinator, which held the callback, which held the view. SpotlightCoordinator.scrollToAnchors(with:reduceMotion:after:) now builds the callback capturing only the scroll proxy, the Bool and the delay. Each screen sets it again when Reduce Motion changes and clears it with stopScrolling() on disappear. No unit test: the change is which values a closure captures, with no pure logic to assert. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With no exact matches, the first near match becomes the hero and, since 9cc7418, leaves "Almost there", the only place that named its missing ingredients. The hero now shows a "Missing" label and the same muted chips. RecipeMissingIngredientChips holds the chip style for both places. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Selecting Other and then cooking away its last item removed the Other chip but left the filter on Other, hiding every remaining item with no chip to clear it. The view kept its own copy of the selection next to the view model's; now the view model's selectedLocation is the only one, and after each refresh or removal it falls back to All when its location has no items. The test drives the real path: an in-memory database, a depleting write, and the inventory observer's refresh. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
f206b2b put names(for:displayName:) on a View, so it inherited the main actor and its test failed to compile under Swift 6: the nonisolated test sent a non-Sendable closure across isolation. The helper is pure and touches no UI state, so it is now nonisolated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
InventoryActiveItem title-cases ingredient names ("Olive Oil"), so the test's lowercase name
assertions failed while the reset itself worked. IDs don't depend on display formatting.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 9, 2026
Draft
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.
What changed
Cooking from a real scan reaches the meal log again
Since d48f385 (March 16), "Start cooking" in the recipe preview saved the recipe for the live assistant and sent the user back to Home. Nothing presented
CookingGuideView. Its celebration screen is the only path that logs the meal and takes ingredients out of the Kitchen. Without the Gemini Live backend, a cooked meal couldn't be recorded at all."Start cooking" now opens the offline step-by-step guide after the preview sheet finishes dismissing. Finishing the guide returns Home; closing it early leaves the user on the results. "Cook hands-free with Le Chef" keeps the live-assistant route as a secondary action. The sheet-to-cover sequencing lives in
CookingLaunchFlow.Logged meals show up in today's numbers
CookingHistoryleftcookedAtnil, and GRDB writes nil as SQL NULL, which bypasses the column'sCURRENT_TIMESTAMPdefault. Those meals counted toward the streak but dropped out of today's nutrition and weekly history. The model now sets the time when the meal is created.recordCookingalso returnedlastInsertedRowIDafter inserting the day's streak row. On the first meal of a day it returned the streak's ID, and Apple Health sync used that as the meal identifier. It now returns the history row ID.A real photo resolves to ingredients that recipes use
ScanViewappended the last one again. Three photos were scanned as [2nd, 3rd, 3rd].IngredientIdentityResolution).The Kitchen matches what the user confirmed
IngredientReviewView(savesToInventory:)andRecipeResultsView(logsMeals:)are now explicit. Practice cooking says it isn't saved.MealLogService's in-transaction consumption, which never posted the change notification.Numbers follow what was confirmed
The Kitchen stores the amount the review showed
Onboarding's kitchen review showed name-based estimates such as egg ~50 g. Scan intake then stored a separate catalog-unit estimate with a 30 g floor, so the same egg was saved as 120 g. Intake now uses the review's estimator and label, so a corrected detection is estimated from the chosen ingredient, and the unused catalog-unit estimator is gone.
Why
These are the defects that stopped photo → confirmed ingredients → recipe → cooking → logged meal from working, or made its numbers disagree with what the user confirmed. The bar is the stage-4 direction in
planning/stage_4-gemini_live/user-direction-and-feature-intent.md(lines 52-60): the model proposes, the user confirms, and only confirmed amounts count as exact.UI changes
No captures. The app hasn't run on a device or simulator for this change, because heavy local builds are gated on shared-Mac disk admission. Visible changes:
Verification
MigrationUpgradeTests, which upgrades a populated v15 database (old NULL-timestamp meals; photo-intake, grocery and manual lots; consumption events) through v18. Every meal, lot and event survives, and only the photo-intake lots get the estimate flag. The UIKit-dependent suites and the source-string tutorial checks pass too.mainand pass here.swiftcagainst the iOS 27 SDK.maindoesn't build on the runner's Xcode 16.4 because of Sendable errors in notification code; fix(ios): read notification permission without sending UNNotificationSettings #6 fixes that. Tests also can't launch an iOS 26 target on that runner's iOS 18.5 simulator, which fix(ci): override simulator deployment target on Actions #2 addresses.Risk
cooked_at. Their real cooking time is unrecoverable, so they stay out of dated reports.Checklist