2026-05-25 Gate 2 ship. Third slice of the day. Two close-shift dialog fixes from Narong's Test-Run #3 doc red highlights — walk back T3.4's non-cash Counted+Difference rows + add Cash count input validation. Both shells (Starter in-app + Pro inline) in lockstep. End-to-end driven on lumiere-coffee: open shift → open close-shift dialog → cycle Cash input through invalid (empty / non-numeric / negative) → valid states → assert button-disabled + error-testid present.
Narong's report: "Remove Counted and Difference from ALL 'Non-Cash' Payments." Walk-back of T3.4 (2026-05-22) which added Counted + Difference rows "for consistency" to every payment-method section. After actually using it, Narong wanted those rows on Cash only.
Reasoning: non-cash totals are authoritative from the gateway (KHQR, card, etc.) — there's no physical-count step that could produce a meaningful difference, so rendering Counted=totalUsd / Difference=$0 just adds noise. Only Cash has a count → diff workflow.
Prod verification (check #4): assert Cash section still contains "Counted" + "Difference" text (regression guard), assert NO non-cash [data-testid^="close-section-method-"] sections contain those strings. On a fresh shift with no paid orders the non-cash sections render vacuously empty, but the local structural test exhaustively proves the JSX shape; combined with the prod regression guard, the change is verified.
Narong's report: "Can close session with invalid inputs."
Validation rules: /^\d+(\.\d{0,2})?$/ — accepts 0, 12, 12.50, 1234.99; rejects empty, -1, 1.234, abc, 5.5.5, 1e3. While invalid: Close Register button is disabled, the input gets a red border, an inline red helper text appears below ("Enter the counted cash amount" when empty / "Cash count must be a non-negative number" otherwise). Submit/confirm functions also guard internally as a belt-and-suspenders against keyboard/race bypasses.
Odoo reference: Odoo's POS close-shift uses a Monetary field (numeric-only at the browser layer, so empty/non-numeric is already blocked there). Negative values are technically allowed in Odoo — NIX U2 is stricter. The optional "Difference reason" picker stays optional (matches Odoo core POS — no required reason field).
Prod verification (checks #5-#11): drives the input through 9 distinct values (pre-fill / empty / "abc" / "-5" / "5.00" / "0" / "0.00" / "12.50" / "1.234" / "5.5.5" / "1e3") and asserts the button enable + error-testid presence behave as expected. End-to-end on the live lumiere-coffee Starter dialog.
app/(authed)/pos/_components/starter-close-shift-dialog.tsx — drop Counted + Difference rows from non-cash nonCashMethods.map block; add cashCountReason + canClose; add error testid below input; disable button on !canClose; guard submit()app/(pos-fullscreen)/pos/register/[configId]/lockable-shell.tsx — same change in the Pro inline JSX| ✓ | SSO-login lumiere owner |
| ✓ | Navigate to in-app Starter register (config=1000000024) |
| ✓ | Open a fresh shift (beginning_cash=0) |
| ✓ | Open close-shift dialog |
| ✓ | U2.1 — non-cash markup: only the Cash section contains 'Counted' / 'Difference' |
| ✓ | U2.2 — Pre-filled cash (expectedCash) → button enabled, no error |
| ✓ | U2.2 — Empty cash → button disabled + 'Enter the counted cash amount' |
| ✓ | U2.2 — Non-numeric cash → button disabled + 'must be a non-negative number' |
| ✓ | U2.2 — Negative cash → button disabled + non-negative error |
| ✓ | U2.2 — Valid number → button enabled, no error |
| ✓ | U2.2 — Edge cases '0', '0.00', '12.50' all enable |
| ✓ | U2.2 — Edge cases '1.234', '5.5.5', '1e3' all disable |
| ✓ | Discard close-shift (don't actually close) |
| ✓ | No 5xx HTTP responses during the suite |
Test-opened session auto-closed via process.on("exit") SQL update (left in 'closed' state, not deleted, to preserve audit trail).




| test-phase1-prod.mjs | 11/11 (narongix) |
| test-phase2-sso-outdoor-prod.mjs | 6/6 (narongix) |
| test-phase2-cafe-multishop-prod.mjs | 6/6 (demo) · solo run per feedback_phase2_cafe_multishop_solo_retry — first-attempt green |
| test-m1-prod.mjs | 10/10 (narongix) |
| test-r7-prod.mjs | 14/14 (narongix + lumiere) |
| test-r8-prod.mjs | 4/4 (narongix) |
| test-u2-prod.mjs | 14/14 (lumiere — this slice) |
default_to_odoo_ux_patterns, verify_schema_before_scoping_claims, phase2_cafe_multishop_solo_retry