Bundle of three Notion Needs-Rework tickets (NIX-OS-78/79/80) plus two net-new asks captured during Narong's 2026-05-07 call. Five sub-tasks, one Gate 1 / Gate 2 cycle, no DB migration.
"". Cashier must type the actual amount tendered. Validate stays disabled with "Cash short — add more" until cash ≥ amount. Touched pay-dialog.tsx: initial split, updateSplit, total-resync effect, addSplit.createDiffReasonForCloseShiftAction (gated on nix_cafe.pos.session_close, not settings.edit) which creates a permanent active reason and uses the returned id. Both Pro CloseShiftDialog and Starter StarterCloseShiftDialog get the picker (Starter gained the picker for the first time).sumCashPaymentsForSession, threaded through page → LockableShell as cashSalesTotal). Same fix applied to the CashMovementDialog "Drawer so far" card and the Telegram session-closed message. endingBank dropped from closeShiftAction param shape.SuccessModal Pro uses, then the modal gained a summary card: items count + total + paid + change due, all above the Print button.<select> in product-grid.tsx replaced with a popover combobox: trigger button → search input + filterable list. Esc / outside-click closes; Enter picks first match. "All categories" stays pinned.nix-cafe (no backend touched, no migrations): app/(authed)/pos/_components/pay-dialog.tsx — NIX-OS-78 app/(authed)/pos/_components/success-modal.tsx — summary block app/(authed)/pos/_components/starter-register-mount.tsx — successUx → "modal" app/(authed)/pos/_components/starter-close-shift-dialog.tsx — NIX-OS-79 (parity) app/(authed)/pos/_components/starter-lockable-shell.tsx — diffReasons pass-through app/(authed)/pos/_components/product-grid.tsx — CategoryPicker app/(pos-fullscreen)/pos/register/[configId]/page.tsx — load cashSalesTotal + diffReasons app/(pos-fullscreen)/pos/register/[configId]/lockable-shell.tsx — NIX-OS-79 + 80 lib/actions/payment_diff_reasons.ts — new cashier-callable action lib/actions/register.ts — drop endingBank, fix Telegram cash math
1. Single nix-cafe commit (one -m line). No backend changes, no DB migration. 2. Push origin karouna-dev → CF Pages auto-redeploys cafe Worker (~90s). 3. Run new test-phase4-prod.mjs: - Pro (get-coffee) + Starter (Lumière) both ring orders end-to-end - Assert Cash Received empty on Pay dialog open - Assert Validate disabled until cash typed - Assert SuccessModal shows summary block + change row - Assert close dialog: no Bank Count, Expected = cash-only, Other reason creates row - Assert category dropdown is the new popover combobox 4. Regression sweep: phase1 + phase2-sso-outdoor + phase2-cafe-multishop + m1 + nix-os-88 5. Publish phase4-prod gallery with regression table.
This bundle is mostly UI polish. The 17 local checks are file-content asserts (deterministic, fast) plus 4 route smoke probes. Real end-to-end browser walkthroughs (rings + close-shift) are deferred to Gate 2 prod where Odoo + real cafe.orders are reachable. Local DB has no in-flight session to drive the close dialog without seeding.