Repository navigation
[obvious-fleet] Integration preview: combined stack of the 8 open product PRs (do not merge) - #17
Draft
obvious-autobuild[bot] wants to merge 82 commits into
Draft
obvious-autobuild[bot] wants to merge 82 commits into
obvious-autobuild[bot] wants to merge 82 commits into
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>
- Add meal-photo-confirmation-v1: an exact verdict preselects the top dish (one tap to log), review preselects it and asks the user to check dish and portion, and estimate-only preselects nothing and shows no computed macros until the user picks a dish. - Show the no-match template's rough range only when the user asks; it can't be logged. - Logging still always takes an explicit tap, and logged amounts follow the confirmed dish, servings and portion whatever the verdict. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ith Decisions - Run the app's Bayesian learner on frozen evaluation inputs: the backend copy for the original 18 diagnostic cases, and the real iOS ConfidenceLearningService (Swift, fresh migrated database per case) for the reverse-meal family. Each has a cold-prior arm and fixed development-only warm replays, and SQL row-count checks catch writes that try? would hide. - Cross-check Swift against the TypeScript service on every case (identical modes, score difference 0). - Build Decisions requests for gpt-6-luna from the derived request only, and parse named choices, refusals, malformed bodies, HTTP errors and timeouts into explicit statuses. Only a mock transport exists here. - Lock normalized outputs and a sha256 manifest before any labels are read, and score them with a separate script that takes the labels path as an argument. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… derivative The report names its parent manifest by SHA and leaves that manifest unchanged. It records the scorer commit and input hashes, the move of the locked files from the original worktree to this branch, and the evaluation owner's interpretation notes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Run the main scan's recognition on the fridge and pantry photos separately, route results through ConfidenceRouter, and preselect only sure items. The 14 hard-coded detections are gone, so nothing the photos didn't show can reach the Kitchen. - Show honest states: no photos, nothing found, and a failed scan with Try Again and Continue. If one location fails, the other's items stay reviewable and only the failed one is retried. A failed scan commits nothing. - Keep one intake session per onboarding run, so coming back and adding again reconciles the Kitchen instead of adding a second copy. Choices for items already shown survive a rescan. - Record whether each photo came from the camera or the library in FLCaptureView, and prepare library imports like other scan inputs. - Give the photo remove and retry controls 44 pt targets and specific names, and announce scan results to VoiceOver. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…iases Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…parts Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The report's pass-error count only covers crops where both requests failed, so a classification failure with working text recognition was invisible. List classification and text failures separately. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… files - Await the GRDB write inside the async VisionService test; the simulator build rejected the synchronous call. - Apply the repository's swift-format configuration to the files this branch added. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The remove button was a 16 pt icon offset outside the thumbnail. It now has a 44 pt target inside the thumbnail and names the photo it removes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… failures - Reconcile fridge and pantry as separate intake sessions, and only for locations whose latest scan succeeded, so a failed rescan can't remove food the user already confirmed. - File onboarding lots under the location they were photographed in. Intake now takes an explicit location; the main scan keeps inferring it. - Keep the user's check and uncheck choices for the whole run, so a failed scan and retry don't reset them. - Rescan when a late photo import changes the photos, drop stale results, and stop work when the user leaves mid-scan. - Warn when some photos couldn't be read instead of reporting nothing found. - Back from the final step returns to the review instead of replaying setup. - Show an empty circle, not a check, when nothing is selected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The "Meal logged" alert always said "inventory updated", including when none of the recipe's ingredients were in stock and nothing was consumed. The message now comes from the consumption results logMeal returns: how many ingredients came out, that none were in the Kitchen, or that the recipe has no ingredient list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
…ducts The Inventory Deduction preview and the "Log Meal · Deduct N items" count listed each detection at 100 g, but logging deducts the chosen recipe's required ingredients. The preview now comes from the same requests applyConsumption makes (shared consumptionRequests and servingFactor), each capped at what the Kitchen holds, and leaves out ingredients with nothing in stock. With no recipe chosen there is no preview and no count. The ingredient breakdown uses the same servingFactor. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Prevent descriptor and truncated OCR tokens from becoming ingredient identities through catalog prefix aliases. Preserve prefix matching for multi-word windows and cover curated olive oil and black beans recognition. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The meal-photo recipe picker showed stored keys like "high_protein" and "one_pot". RecipeTags.labels is only used for display, so it now returns readable words, and the two screens that patched underscores themselves use it directly. 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>
Logging re-resolves the chosen recipe, so picking an ingredientless recipe logged and deducted a same-title recipe with ingredients while the screen previewed the one picked. The lookup half of resolvePersistedRecipeID is now a read-only existingRecipeID, and resolveForLogging returns that recipe with its macros. The meal-photo screen resolves the choice once and uses the result for the breakdown, macros, deduction preview and the log call. Logging keeps its own recovery. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The alert said "no ingredient list" whenever consumption was empty, but a recipe with only optional ingredients or zero-gram rows gives the same result, and "none were in your Kitchen" for all-zero consumption. The results don't say which, so the alert now reads "Your Kitchen didn't change." in every zero case. 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>
…4 (combined-stack preview)
…bined-stack preview)
…ined-stack preview)
… (combined-stack preview) # Conflicts: # apps/ios/Feature/Estimate/ReverseScanResultsSections.swift
…bined-stack preview)
…ned-stack preview)
…ned-stack preview)
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
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.
INTEGRATION PREVIEW ONLY — THIS BRANCH MUST NOT BE MERGED. It exists solely to verify that the currently open product PRs merge and coexist in one tree. It will be closed once verification completes; it is not an integration to main.
What changed and why
Combined-stack verification preview: merges the eight currently open product PR branches into one branch so their interactions can be built, tested and reviewed in a single tree. Individual PR checks pass, but the children predate #4's latest fixes and no existing branch contains the full current stack. Merged with normal
--no-ffmerges, in this order, from basemain@1151588d6bc6f5dcc3e848b6115813ff36ffbf0d:8c9c88fed3007b8ce0f81f8b5684461f5ff698bc30f341847cec43b2788301ee07ee1e6a8cddb568a9df6aa39e450c0f6d704acaf99baec6b36041afbe5aecafcfc622117d3fee0d7c0552adcf1eb0439886dda994fad2f6bf9651b2adc759537a6ce46cf63affc542b70e73c6a30d3d9e0be0ea15babe2c954d6c63c79b744061b2973959fa414dd0f64a163e6d321f1a405be4b96aab37dd69aa7ac3df5491Merge commits on first-parent:
026cb3a,48bd273,28ba318,4470931,60725e2,bca9e6c,6c94f98,343ab09(final head). PR #6 (fix/notification-settings-sendable) and allobv/*branches were intentionally excluded.Conflict resolution (the one expected conflict):
apps/ios/Feature/Estimate/ReverseScanResultsSections.swiftconflicted when merging #11 into a tree containing #5. Both sides implement the same singular/plural count fix in different structures. Resolution: retained #5's version — theMealBreakdownContent-basedif case .ingredients(let rows)block whose count line already carries therows.count == 1 ? "" : "s"ternary — and verified #11's other change in that file (thepreviews.countsingular/plural ternary) survives: it had auto-merged cleanly and was re-applied explicitly rather than lost to a wholesale--ours. Both ternaries are present in the merged file; no conflict markers remain. No other conflicts occurred.How I verified it
git merge-base --is-ancestorfor each of the eight tips above against this branch: all eight OK;obv/fridgeluck-walk-iconconfirmed excluded.git diff --check origin/main...HEAD: clean (no whitespace errors or conflict markers).struct|class|enum|actor|protocoldeclarations acrossapps/iosfor duplicate type names — none found.SpotlightTutorialOverlay.controls/skipButton), andCookingGuideSteps(apps/ios/FeatureLogic/Recipe/CookingGuideSteps.swift) with its cleaning logic andCookingGuideStepsTestssurvive.RecipePreviewDrawerSectionsFlowLayoutText(tag)overrecipe.recipeTags.labels, plusRecipeTagsTests) and the Reduce Motion press-dim change survives.MealPhotoConfirmationPolicy(exact/reviewRequired/estimateOnly) is intact and still wired intoReverseScanMealView, withMealPhotoConfirmationPolicyTests..envand no live keys (GEMINI_API_KEY/USDA_FDC_API_KEY/Google creds absent from the environment):bun run check(tsc --noEmit): exit 0, no type errors.bun test src/__tests__: 298 pass, 0 fail across 20 files, fully offline.What is not verified
macos-26build-and-testworkflow run on this PR is the live verification of that; see its status below / in the checks section. Status at time of writing: pending — treat "pending" as unverified until it shows "passed".dead-code-advisory(Periphery) job is advisory only; its output was not evaluated.Assumptions
.env, no live API keys); the repo contains no literalenv-ifile or script.026cb3a) was created by a concurrent duplicate dispatch of this same task working in the same shared sandbox directory; I adopted it after verifying its parents are exactlymain(1151588) and fix(ios): make the scan-to-meal loop work and log what was confirmed #4's tip (8c9c88f) with a clean tree, rather than duplicating the merge.