Skip to content

fix(cook-mode): reserve swap consumption splits and re-arm timer alerts on resume or adjust - #190

Merged
SamGu-NRX merged 5 commits into
alphafrom
obv/burst10-fridgeluck-p1-fixes
Oct 16, 2026
Merged

SamGu-NRX merged 5 commits into
alphafrom
obv/burst10-fridgeluck-p1-fixes

Conversation

@obvious-autobuild

@obvious-autobuild obvious-autobuild Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Why

Greptile review 5542992530 on PR #181 posted six P1 findings. This PR fixes two of them — finding 3 (timer alerts stop matching after pause/resume/adjust) and finding 5 (saved swaps reserve the wrong stock) — on minimal branches so they can merge independently of PR #188.

What

Finding 5 — saved swaps reserve wrong stock (fixed, 368c0a1). A swap-covered plan line consumes grams from two ingredients: the original's covered share and the substitute's shortfall cover. Save persisted only the full requirement against the original, and loadReservedGrams ignored the stored swap entirely, so the substitute's consumed grams stayed double-bookable by the next plan (reserving the full 300 g requirement against the original that actually supplied 200 g, and reserving nothing of the substitute's 100 g).

PlanSwap now records the consumed split (originalGrams, substituteGrams, optional); the allocator populates it when it applies a swap; loadReservedGrams reserves each side against its own ingredient. Rows saved before the split decode as nil and fall back to the legacy full-requirement math, so old saved plans keep loading and reserving as before.

Finding 3 — timer alerts stop matching (fixed, 81ef8d6). resumeTimer and adjustTimer passed label: nil into the effect run, and the scheduling effect drops updates without a label: a paused-then-resumed timer had no alert at all, and an adjusted timer kept its stale deadline. All three timer mutations now pass the timer's own stored label; cancel effects ignore it.

Scope note: findings 1, the journal half of 2, 4, and 6 ride PR #188 (commit 770ab5e); the inventory-deduction half of finding 2 is a documented feature-sized follow-up, intentionally not attempted here.

How to Review

  • LeChefPlanModels.swift — PlanSwap split fields, legacy init delegates to the new designated init so every existing call site compiles unchanged.
  • PlanAllocating.swift — one-line change: the swap arm passes allocated (the original's consumed grams) and substituteGrams into the swap it emits.
  • PlanDataAdapter.swift — loadReservedGrams selects l.swap, decodes it, and adds the split per side; the fallback path preserves pre-split behavior exactly.
  • CookModeViewModel.swift — storedTimerLabel(id:) lookup, passed into perform from pause/resume/adjust; removeTimer deliberately stays nil (its only effects are cancels).
  • Intentionally not reformatted: the touched files carry pre-existing swift-format drift on alpha (verified by linting the parent 485ae82e blobs — e.g. 31 pre-existing findings in CookModeViewModel.swift); this diff introduces zero new findings, and reformatting whole files would collide with PR feat(release): the release-candidate build with every late fix, the goal path and the safety sweep green #188.

Test Evidence

Portable Linux harness (Swift 6.4, GRDB 7.10.0, scratch package mirroring the plan sources and suites, outside the repo):

  • Fails first — before the fix, testSavedSwapReservesEachIngredientItsOwnConsumedShare failed exactly as the bug predicted: original available 200.0 vs expected 300.0, substitute available 400.0 vs expected 300.0 (2 failures, 1 test executed).
  • After the fix: LeChefPlanAllocatorTests 21/21 passed (including new assertions that the allocator's emitted swap records 200 g original / 100 g substitute for the 300-demand 200-stock case) and LeChefPlanPersistenceTests 12/12 passed (including the new saved-swap reservation test).
  • swiftc -parse clean on all seven touched files; swift format lint --strict introduces zero new findings.

macOS-CI-only: CookModeViewModelTimerAlertTests (new, resumes and adjusts a timer against a recording scheduler and asserts the re-armed schedule keeps the stored label and fresh deadline) cannot run in the portable Linux harness because the view model imports UserNotifications. Its pass/fail is verified by the repository's hosted macOS CI on this branch's head, and by nothing else.

Human author: Sam Gu (sgu07966@gmail.com)

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact

CI History

  • Run 38852734023 (81ef8d6): build-and-test FAILED — the commit carried the storedTimerLabel call sites but lost the helper definition (sandbox working-tree revert between edit and commit). dead-code-advisory skipped.
  • Run 38853188080 (b0975bd): build-and-test FAILED — helper restored, but the call sites passed no argument (storedTimerLabel(id:)).
  • Run 38853597762 (44f7e48): build-and-test FAILED — sed produced storedTimerLabel(id:), which Swift parses as an unapplied function reference, not a call.
  • Run 38854106728 (a7a2ce0, this head): GREEN — build-and-test ✅, dead-code-advisory ✅. macOS CI compiled and ran CookModeViewModelTimerAlertTests, covering the finding-3 validation the portable Linux harness cannot perform.

Each failure was a view-model compile error on macOS only (swiftc -parse cannot catch name resolution) — no behavior change beyond the fixes described above.

ObviousApp and others added 2 commits October 16, 2026 04:50
A swap-covered line consumes grams from two ingredients — the original's
covered share and the substitute's shortfall cover — but save persisted
only the full requirement against the original and loadReservedGrams
ignored the swap entirely: the substitute's consumed grams stayed
double-bookable by the next plan.

PlanSwap now records the consumed split (originalGrams, substituteGrams);
the allocator populates it when it applies a swap, and loadReservedGrams
reserves each side against its own ingredient, falling back to the
legacy full-requirement math for rows saved before the split existed.

Fails-first evidence (portable Linux harness, Swift 6.4 / GRDB 7.10):
- RED: testSavedSwapReservesEachIngredientItsOwnConsumedShare failed with
  exactly the bug — original available 200 (full 300 reserved) vs 300
  expected, substitute available 400 (nothing reserved) vs 300 expected.
- GREEN after the fix: LeChefPlanAllocatorTests 21/21,
  LeChefPlanPersistenceTests 12/12.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
…nd adjust

Resume and adjust passed label: nil into the effect run, and the
scheduling effect drops updates without a label: a paused-then-resumed
timer had no alert at all and an adjusted timer kept its stale deadline.
All three timer mutations now pass the timer's own stored label; cancel
effects ignore it.

Validation is macOS-CI-only: the view model imports UserNotifications,
so the new CookModeViewModelTimerAlertTests cannot run in the portable
Linux harness.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b321e965-4862-452b-a9d5-9dc620abe535

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

ObviousApp and others added 3 commits October 16, 2026 04:56
The previous commit carried the three storedTimerLabel call sites but lost
the helper definition — the macOS build failed with "cannot find
'storedTimerLabel' in scope". Re-add private func storedTimerLabel(id:)
after perform.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
The call sites invoked storedTimerLabel(id) without the argument label;
the Linux parse pass cannot catch name-resolution, and macOS CI flagged
the three sites.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
storedTimerLabel(id:) parsed as an unapplied function reference; the call
needs the argument value — storedTimerLabel(id: id). Comment order around
the call sites restored.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
@SamGu-NRX
SamGu-NRX marked this pull request as ready for review October 16, 2026 05:29
@codemetrics-ai

Copy link
Copy Markdown

Note

Review skipped

Codemetrics is installed on this repository, but it hasn't been added to your team yet.

To enable AI code reviews for this repo, go to your dashboard and add FridgeLuck to your team's repositories.

@SamGu-NRX
SamGu-NRX merged commit 4973b8f into alpha Oct 16, 2026
3 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T05:31:01.930415Z a7a2ce0 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codemetrics-ai

Copy link
Copy Markdown

Note

Review skipped

Codemetrics is installed on this repository, but it hasn't been added to your team yet.

To enable AI code reviews for this repo, go to your dashboard and add FridgeLuck to your team's repositories.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants