Repository navigation
iOS: fix bugs and logic issues found in the UX and functional reviews - #31
Merged
Merged
Conversation
…o today An AI 换一批/search card is an in-memory recipe (id ai-<name>), so adding it to today planned a recipe RecipeStore could not resolve: the plan could not be opened, cooked or shopped for. Home and the recommendation browser now route 加入今天 through HomeRecommendationPlanning, which saves the dish via the existing GeneratedRecipeMaterializer (reuse an identical recipe, else save a new home-ai-<uuid> recipe) and re-points the card at it. The missing-recipe placeholder no longer suggests that retrying helps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… loads Defaults computed from the two built-in samples before the online library arrived stayed for the whole day. They are now replaced once when the source switches to the real library, unless the member already searched, asked for 换一批, removed a card or browsed (moved off the first card, opened a recommended recipe or the 更多推荐 page). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The post-cook restock suggestions ran before markPlanCooked, so the meal on
the stove still read as a pending plan and asked for its own ingredients
("未来 7 天计划需要"). RestockSuggestionEngine.generate takes the consumed
plan IDs and leaves them out of the planned-meal horizon.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… sheet Stock held as 1 份 against a recipe line of 2 个 rendered as 库存 - 个 / 使用量 0 / 扣减后剩 0 and silently deducted nothing. The row now shows the stock in its own unit, says the units differ and is not deducted, and stays deselected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merging a stock-in into a status-mode staple (盐/油/葱姜蒜) only added quantity, so the shelf kept showing 缺货. The merge now resets the staple to available; quantity-mode staples are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A second AI 生成一周菜单 reused the previous menu's start date even after it was added to the Planner or its days had passed. The form now shows the target dates and starts from today (or the viewed week when it is ahead) unless an unadded draft is still ahead; 重新生成 on the result page keeps the menu's own dates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tities Adding the same meal's ingredients again merged the full amount in a second time. Shopping generation now subtracts what the pending list already holds (same or convertible units only) and shows fully covered items as 已在清单. Restock suggestions, the cook sheet's 补货建议 and Home's 还缺 row say 已在清单 instead of offering a second add. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ps skip user recipes 删除计划 on a special plan now asks first, and leaving a special plan with an unsaved AI menu draft asks before discarding it. The backup page and 清除全部本地数据 now warn prominently that kitchen backups do not include user recipes, favorites or 常做 records (copy only; backup contract unchanged). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The app-wide blue tint overrode the destructive role colour, so 删除 on inventory rows, 移出计划 on planner meals and 删除 in Kitchen AI history rendered blue. Tint them with AppTheme.danger, as Shopping already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The settings screen showed the 1-day and day-of lead times as on by default, but KitchenStore read the unset keys as false, so every inventory change and cold start rescheduled with no lead times and cancelled every pending reminder. Read the keys with the UI defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A batch in another unit (1 盒 vs a recipe's 个) was deducted as if it were in the recipe unit, so cooking could zero a whole box the sheet never showed. Skip unconvertible batches and say so on the sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preset staples (葱姜蒜、盐、油) saved in status mode kept quantity 0, so recipes, Home, shopping and AI treated them as missing while the shelf said 有货. Sync quantity with the status (缺货 0, otherwise at least 1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
df25377 subtracted every pending same-name row from a single dish's needs, so a second dish was under-bought by what another dish added. Shopping rows don't record their dish, so the per-dish sheet now keeps the full amount selected and notes what is already on the list; the all-meals views (restock, Home 已在清单) still subtract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a special-plan dish's recipe dropped the dish identity, so cooking there deducted as a direct recipe and ticking the dish later deducted again. Carry the dish through to the confirmation so the receipt is keyed to it (D-047). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Home's 还缺 row, readiness and its shopping list counted meals already cooked, so it asked to rebuy what was just used. Use pending meals only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lines without a quantity were always listed as 需要购买 even when the food was at home, and imported as "1 适量". Treat them as covered when present, like Home, and import with unit 份. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Library lines like "盐 2 g" missed the seasoning lookup, so most curated recipes always showed 还缺. Strip amounts with IngredientParser first and add common Sichuan seasoning names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picking an existing row did not pass its id, and saving overwrote the first same-name batch's quantity and expiry. Update the picked row; without a pick, refuse instead of overwriting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It added a plan pointing at a recipe that was never saved, so today's dish could not be opened or cooked. Keep 保存并加入计划 only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The draft lived only in memory until 加入用餐计划, so going back or quitting lost it. Commit it right after generation, except over a menu whose materialization is still pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Turning off 库存 for a message only skipped preloading; read tools still read and sent inventory. Refuse excluded kinds for that turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page said the device could keep being used as a guest but did not mention that local kitchen data is cleared. List it and suggest a backup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan, weekly-menu and special-plan save failures set notices no view read. Show them in Home module issues, and after a failed special-plan load refuse whole-table writes that would delete the unreadable records. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since 46821a2 leaving a special plan with an unsaved AI menu draft asks first, so testCreateSpecialPlanFlowIsOneRequestPlusOneSwitch tapped back and never reached 用餐计划. Tap 放弃并返回 in the alert, then check the plan itself is still listed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md gains a "Shared Mac resources" section: per-agent fixed simulators run through dev-sim-slot, no extra devices without approval, and task temp-file cleanup and cache reuse. CLAUDE.md imports AGENTS.md so Claude Code loads it directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PLANNING-1. Cooking a dish from the recipe library while today's plan held the same recipe deducted it as a direct recipe, and ticking the meal deducted it again. 开始烹饪 from a page not opened for a plan now asks 这是今天计划里的那道吗? when today has an uncooked meal of that exact recipe id; 是 cooks it as that meal. No name matching. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CONSUMPTION-1. Shopping and cooking mode scaled a meal by its servings, the deduction stayed as written, and every row claimed the recipe had no base yield. Deduction now uses RecipeQuantityScaler (planned: plannedServings, nil = as written; direct: the chosen servings; Special Plan dishes stay as written per D-047). The warning shows only when there is no base yield to convert from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RECIPES_LOGIC-9. The recipe page rendered and edited the value it was opened with, so a saved edit did not show and a second edit overwrote the first. It now reads RecipeStore.currentVersion(of:). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RECIPES_LOGIC-11. Rows were derived from the joined text with empty lines dropped and identified by position, so emptying a row moved focus into the next line. Rows now carry their own ids and are not trimmed while editing; blank lines are still dropped on save. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PLANNING-8. Saving an AI 重新设计菜单 draft replaced the whole menu, dropping cooked dishes (and their receipt link) and library-added dishes without a word. Cooked dishes now stay with their ids, and saving over uncooked dishes first lists what will be replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SHOPPING_LOGIC-4. Ticked-but-not-stocked rows counted as neither stock nor list, so generators asked to buy them again. They now count as listed (已买「X」,待入库) with the same .inform/.subtract handling as pending rows, and restock treats them as already on the list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SHOPPING_LOGIC-5, RECIPES_LOGIC-6. "鸡蛋 2-3 个" became a food named "鸡蛋 2-" and "蒜 3 瓣" kept the whole line as its name. A range between digits is one quantity (its upper end, for buying), the common measure words are units, and scaling a range scales both ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SHOPPING_LOGIC-7. The weekly-menu page added the AI's list directly: foods with any stock were dropped, "1,500" became 1 and repeated taps stacked. The button now opens the same generator sheet as ⋯ → 生成购物清单. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PLANNING-5. 重新生成 kept a stale or already-added menu's start date, and 复制到 7 天后 copied the stored menu with no clamp. Both now follow the batch-1 "not before today" rule; the copy is of the menu on screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RECIPES_LOGIC-12. Built-in recipes state no difficulty or time, so either filter removed all of them. Unlabelled recipes are now kept, listed after the matches, and the filter chip says 含未标注. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions AI_LOGIC-1. The server advertises plannedServings on propose_add_recipe_to_tonight and propose_replace_planned_meal, but the interpreter refused any value, so "今晚做红烧肉,4 个人吃" always failed. A whole number 1-12 is now carried and applied; null is "not stated". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AI_LOGIC-7. Today and Planner share one controller; opening one page swapped the other's conversation, cancelled its reply and dropped its pending change. A page now reopens its own conversation on every appearance, but never while a reply is generating or a change awaits 应用修改. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AI_LOGIC-4. The model was never told today's date, and 确认计划变更 rows did not say which day they change. The system text now starts with today's local date and planner preview rows start with the meal's day. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RECIPES_LOGIC-10, PERSISTENCE_LIFECYCLE-5. A shared link that failed or was already imported came back and re-imported on every launch, with no way to remove it. The share sheet gains 不再导入, and a share already shown and closed waits for 开始识别 instead of auto-starting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PERSISTENCE_LIFECYCLE-7. Restock reminders fired one second after an in-app change, while the app was in front, where iOS does not show them; and the toggles stayed on after notifications were denied in iOS Settings. Reminders now go out at the next 9:00 and the toggles read the system permission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Empty commit: the [ui-all] marker makes ios-tests.yml run every UI test class in four shards alongside the default unit, focused UI and screenshot-tour job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…one [ui-all] testARecognisableNameShowsNoHint checked .exists right after typing 卤鸡腿. The partial names typed on the way (卤, 卤鸡) may show the hint for a moment, so on the slower CI simulator the check caught it before the final name updated. Wait for it to disappear instead. The [ui-all] marker reruns the full UI suite on the new head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two focused UI tests failed once on CI with code that had passed the same tests earlier: - ShoppingExperienceUITests.testEmptyStateUsesTheExistingAddShoppingSheet reopened the bulk menu while 75e4f3b's new 撤销 toast was expiring, and the 清除已购买 alert never appeared. Wait for the toast to appear and run out, and for the menu item, before tapping. - HomeDashboardUITests.testHomePolishVisualStates read the 换一批 card's frame before the lazy shelf had built it. Keep swiping while it is missing and assert it exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…all] PlannerMealDeleteUITests.testContextMenuAlsoOffersRemove and PlannerQuickCompleteUITests.testAXXXLLeadingEdgeKeepsBothActionsReachable failed once on CI with app code that passed them in the previous run. The row() helpers swipe the list until the row exists and return at once, so the long press or swipe could land while the list was still decelerating and only stop the scroll. Wait until the row is hittable and its frame has stopped moving. The [ui-all] marker reruns the full UI suite on the new head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UITEST_MERGE_LOADING slept 2 s and then fell through to a transport error, so on the slower CI simulator the two loading-state tests in GuestMergePreviewUI5B2BAUITests first queried after it had already turned into the offline error. Hold the loading state for 600 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The system List minimum row height (52pt on iOS 26/27) beat the empty day's 44pt whole-row target, so an unplanned day was exactly as tall as a planned meal row and PlannerMealCreateUITests. testUnplannedDaysWeighLessThanPlannedContent failed on every OS. Set the Planner week List's defaultMinListRowHeight to the 44pt hit target. Side effect: the week-range and 菜谱库 rows also go from 52pt to 44pt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PlannerMealEditUITests.testACompletedMealLocksServingsAndExplainsWhy fails only on iOS 26.5 (CI): the servings Stepper's + reads enabled. Report the element in the failure and check that tapping + leaves 2 人份 unchanged, to tell an accessibility-trait issue from a live Stepper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
testEmptyPlanGeneratesADraftMenu looked for the loading state after the 1.5 s stub had already finished on CI. Add an opt-in UITEST_SPECIAL_PLAN_AI_SLOW (6 s) used only by this test; other tests keep 1.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
testReplacingAnOffScreenDishIsObservedByItsOwnRow ignored the floating tab bar, so its reveal drag started on the tab bar and left the plan detail; record() then read a missing cell. End the viewport at the tab bar and report an absent row instead of failing on its frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
testProductionDarkAccessibilityMatrix's scroll helper began its drag inside the 单位 field just above the keyboard, which on CI moved nothing. Start the drag left of the field column, centred in the viewport. The [ui-all] marker reruns the full UI suite with the six pre-existing red fixes (98c9fea..29bc739, cherry-picked) on the PR head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…epper On iOS 26.5 (CI) the disabled Stepper's + still read as enabled, so PlannerMealEditUITests.testACompletedMealLocksServingsAndExplainsWhy failed and VoiceOver would offer a control that refuses the tap; the probe in 49c79f5 showed tapping + left 2 人份 unchanged, so only the trait was wrong. Render the fixed count as plain text, as the form already does for the recipe row, and assert there is no +/− control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ui-all] testCookingTimerCanStartAndCancelWithoutDebugUI tapped the timer as the full-screen cooking cover was still sliding in, so on CI the menu never opened and 1 分钟 was not found. Wait until the timer control is hittable before tapping it. The [ui-all] marker reruns the full UI suite on the new head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
…tatus staples - A weekly menu whose first day has passed now asks before it is added, then moves the whole draft to start today with its dishes and order kept. Cancelling writes nothing, the collision check still runs on the moved days, a pending or finished receipt is never moved, and if saving the moved draft fails no meal is written. The prompt names the passed start date and the new days, with years when they span two years. - Status-tracked staples (有货/快没了/缺货) are never deducted by cooking: their quantity is a placeholder. The consumption sheet shows them as present and says why; mixed stock only deducts the counted batches. RecipeStockMatch and the D-050 undo contract are unchanged. - DEBUG fixtures: injectable "now" for planner UI tests; stuck-share-link and consumption-review seeds (the share seed stops instead of falling back to the App Group queue or standard defaults); a deletion-service stand-in so the account fixture never reaches the backend. - Tests: weekly stale-start unit and UI tests, StatusStapleConsumptionTests, and PR31VisualAcceptanceUITests (Light/Dark x Normal/AXXXL). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n PR31 visual tests CI (iOS 26.5) failed 3 of the 8 PR31VisualAcceptanceUITests, and all three were test faults: - Dark runs rendered light: the simulator appearance alone does not reach the app before its first render. Pass UITEST_FORCE_DARK/LIGHT_APPEARANCE, as the other screenshot suites do. - A SwiftUI Label's identifier landed on its icon, which is never hittable. Judge reachability by the label's text and only check the identifier still exists. - The 1.8s removal toast was gone before the first check after the tap's idle wait. A DEBUG-only UITEST_LONG_FEEDBACK_TOAST holds Home's toast for 20s, as UndoToastTiming does for 撤销; release and argument-less debug builds keep 1.8s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e in PR31 visual tests CI (iOS 26.5) still failed testConsumptionSheetExplainsUnitsAndStatusStaples at Light-AXXXL, for two test faults: - The identifier was checked before scrolling, and an off-screen list row is not in the accessibility tree yet. revealLabel now scrolls to the label's text first, then checks the identifier; no assertion is dropped. - The CI simulator runs in English, so localizedCompare sorted the rows 番茄, 葱, 鸡蛋 and the test, scrolling down to 葱, left 番茄 above the screen. The visual tests now launch the app in its own zh-Hans / zh_CN, the order a member sees. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1395490241lhj-code
added a commit
that referenced
this pull request
Oct 22, 2026
Brings PR #31 (iOS review fixes) and PR #34 (Kitchen AI failure diagnostics) under the Phase 1a work. - test/ai-conversation-stream.test.mjs: both sides appended tests. Keep main's file whole (all 43 PR #34 tests, S1/S2 diagnostics included) and append this branch's servings test, rewritten for the protocol below. - src/server/services/ai-conversation.js: keep plannedServings on propose_add_recipe_to_tonight and propose_replace_planned_meal. This branch had removed it because the old client refused it; PR #31's interpreter now accepts 1-12 and refuses anything else, so the schema offers the optional field with that range in its description. The low-risk wording for add-to-tonight is kept: the client executes it after validation without a confirmation step. - The other shared iOS files merged without conflict. Co-Authored-By: Claude Opus 5.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.
Summary
Fixes from two read-only reviews of the native iOS app (a new-user UX review and a functional-logic review, 2026-10-19). Every finding was re-checked against the code by an independent verifier before it was fixed. The review fixes are one commit per item, so any single fix can be reverted on its own. Later commits stabilise UI tests on CI and add the pre-merge fixes below. 60 commits in total.
No SwiftData schema change. Legacy data migration now runs only once (
de14ffd), so emptied lists stay empty. No sync flag, Keychain, entitlement, backup-format, login, timer or background-behaviour change.Batch 1: dead ends and data safety (
5ff9eac..46821a2, 8 commits)Batch 2: inventory deduction, reminders, data safety (
829fdc2..cc1dd5a, 15 commits)df25377.Test and docs (
723ebeb,aeafe7c)PlannerUITests.testCreateSpecialPlanFlowIsOneRequestPlusOneSwitchnow accepts the draft-discard alert added in46821a2.AGENTS.md/CLAUDE.md: shared Mac resource rules (owner's edit).Batch 3: cooking, recipe editing, planning, AI logic (
45a0e62..2a57c56, 20 commits)CI follow-ups (
c9f3998..e23e6a2, 12 commits)98cd920), and a completed meal shows its servings as text (fb2e567).Pre-merge fixes (
dd9ab14)RecipeStockMatchand the D-050 undo contract are unchanged.AccountLifecycleFixtureDeletionService, so the account UI-test fixture never reaches the backend. Its preview is canned and every later step refuses.StatusStapleConsumptionTests;PR31VisualAcceptanceUITests, a reusable visual regression class over Light/Dark × Normal/AXXXL.CI visual-test fixes (
8a6e66e)On CI (iOS 26.5), 3 of the 8
PR31VisualAcceptanceUITestsfailed in dispatch run 39611008239. The xcresult, activity timeline and screen recordings showed all three were faults in the tests, not in the app:UITEST_FORCE_DARK_APPEARANCE/UITEST_FORCE_LIGHT_APPEARANCE, like the other screenshot suites. The Dark screenshots from run 39611008239 are therefore not valid evidence.Label's identifier lands on its icon, which is never hittable. The recordings show the text fully on screen. Reachability is now judged on the label's text, and the identifier is only checked to still exist.UITEST_LONG_FEEDBACK_TOASTnow holds Home's toast for 20s, asUndoToastTimingdoes for 撤销. Release builds have noDEBUGcondition, and debug builds without the argument, keep 1.8s.CI visual-test fixes, part 2 (
7514f3e)Dispatch run 39637015717 on
8a6e66epassed 7 of 8. Its Dark screenshots are genuinely dark: mean luma 27–39, against 191+ for Light.testConsumptionSheetExplainsUnitsAndStatusStaplesstill failed at Light-AXXXL, for two more test faults:revealLabelnow scrolls to the label's text first, then checks the identifier. The reachability, identifier and full-text assertions are all kept.localizedComparesorted the rows 番茄, 葱, 鸡蛋. Scrolling down to 葱 left 番茄 above the screen. The visual tests now launch the app in its ownzh-Hans/zh_CN, the order a member sees. Swiping back down was not used, because the sheet could be dismissed by it.-testLanguage en -testRegion US, to reproduce CI: 8/8 passed, with rows in 葱, 番茄, 鸡蛋 order.Validation for
dd9ab14Local runs used the reserved simulator (iPhone 18 Pro / iOS 27.2) through
dev-sim-slotwith thexcodebuildfallback, because Xcode MCP was held by another worktree.WeeklyMenuMaterializationTests51/51 andSharedImportQueueTests15/15;WeeklyMenuMaterializationUITests16/16 andPlannerWeeklyHostUITests4/4;PlannerUITests,RecipeCookingModeUITestsandSpecialPlanMenuUITests: the affected cases passed.PR31VisualAcceptanceUITestscovers 8 scenarios × 4 variants. All 78 screenshots were reviewed. Every new dialog is reachable with full text, and destructive actions are red.e23e6a2(run 39540334113):GuestMergeSummaryUI5B2BB2AUITests21/21. It shows the earlierui-full (2)failure was a CI flake. It is not evidence fordd9ab14.dd9ab14:ConsumptionPersistenceTests20/20 andKitchenStoreTests49/49 (D-050),RecipePersistenceTests13/13 andSwiftDataConsistencyTests6/6 (de14ffd),StatusStapleConsumptionTests7/7 andWeeklyMenuMaterializationTests51/51.PR31VisualAcceptanceUITests(dispatch run 39611008239): 3 of 8 failed. These were test faults, fixed in8a6e66e(see above). Unit target 2,621 run, 0 failures.8a6e66e:7514f3e.7514f3e(final head):ConsumptionPersistenceTests20/20 andKitchenStoreTests49/49, andde14ffdRecipePersistenceTests13/13 andSwiftDataConsistencyTests6/6. Default UI set: 10 classes, 116 tests, 0 failures.PR31VisualAcceptanceUITests, dispatch run 39656183440 (iPhone 17 Pro, iOS 26.5): 8/8 passed. Unit target 2,621 run, 0 failures.Earlier validation (before the first push, older tree)
SpecialPlanMenuUITests.testReplacingAnOffScreenDishIsObservedByItsOwnRowfails the same way on the clean baseline46821a2.Not verified / known visual notes
main.Known follow-ups (not in this PR)
8f94284) acceptsplannedServingsfrom Kitchen AI, while PR Kitchen AI Phase 1a: tonight recipe recommendations with deterministic kitchen facts #32 removes it from the server schema. Resolve when Kitchen AI Phase 1a: tonight recipe recommendations with deterministic kitchen facts #32 is integrated.be89345ignores the servings stepper;1afdac6takes the upper end of a quantity range;6a56646saves silently;4fceba8may reclassify some seasonings.🤖 Generated with Claude Code