2026-05-25 Gate 2 ship. Wires the previously-cosmetic /cafe/settings page end-to-end (Store Information + Currency + NIX Cash cards all persist via saveStoreSettingsAction). Adds a canonical company logo (unified — same column drives the receipt header AND the Customer Display idle screen, Odoo's res.company.logo pattern). Closes Narong's Telegram ask about where to set the receipt logo + ships full Configuration → Store, editable timezone, and a "show both currencies on receipts" toggle.
store-settings-error. Success surfaces inline with store-settings-saved.cafe.tenant_config.display_logo_url → store_logo_url. The CDS keeps consuming the value through the renamed column; the receipt now reads the same column too. One canonical company logo, surfaced at Settings > Store.khmer-receipt.tsx) renders <img src={storeLogoUrl} /> centered above the store name. Skipped when unset → falls back to text-only header (back-compat with historical reprints).
display-logo-url 0 matches) + the new read-only pointer card (display-logo-pointer) links back to Settings > Store
/cafe/display/[sessionId]?secret=… renders 200 with the renamed column read working server-side (closed-session screen shown — most recent lumiere session was closed, so the visible-logo assertion was gracefully skipped; the 200 + DAO probe combined prove the rename works at every consumer)| ✓ | Prod: store_logo_url + show_both_currencies_on_receipts present, display_logo_url gone |
| ✓ | DAO probe: getStoreSettings → saveStoreSettings → re-read round-trips all 15 fields on prod Supabase |
| ✓ | Login to lumiere-coffee |
| ✓ | /cafe/settings renders Store Settings client (all expected testids: store-settings-root, store-logo-preview, store-logo-url, store-name, timezone, currency-primary, exchange-rate, show-both-currencies, enforce-nix-cash, store-settings-save) |
| ✓ | Settings UI: fill multiple fields (name, logo, address, phone, email, timezone, exchange rate, show-both toggle) + save |
| ✓ | Reload → all UI-saved fields persist via prod Supabase |
| ✓ | DB confirms timezone landed on public.tenants (not cafe.tenant_config) — 2-table transaction works on prod |
| ✓ | Settings > Customer Display: Logo URL field removed + pointer card shown |
| ✓ | CDS route renders 200 with renamed store_logo_url column (route-level rename verified — drizzle would have 500'd if the column read broke) |
| ✓ | Restore original store settings (via DAO + at-exit safety net) |
| ✓ | No 5xx HTTP responses during the suite |
| test-u5-store-settings-prod.mjs | 11/11 |
| test-phase1-prod.mjs | 11/11 |
| test-phase2-sso-outdoor-prod.mjs | 6/6 |
| test-phase2-cafe-multishop-prod.mjs | 6/6 (solo, first-attempt green — rule validated 6× now) |
| test-m1-prod.mjs | 10/10 |
| test-r7-prod.mjs | 14/14 |
| test-r8-prod.mjs | 4/4 |
First push at 14:36 UTC didn't trigger a CF Workers Build. Last deploy was U4's 11:25 UTC. After 8 min with no new version on wrangler versions list, pushed an empty commit at 14:46 UTC per feedback_verify_cf_worker_deploy_landed. The retrigger landed at 14:51 UTC (5 min after the empty commit). No status.cloudflare.com incident. Rule re-validated: when in doubt, empty-commit retrigger before manual deploy. Lost ~12 min — exactly the failure mode the rule was saved for during the T4 burn 2 days ago.
First attempt asserted display-idle / display-idle-logo testid on the CDS public route. lumiere's most recent session is closed → CDS renders the "Session closed" screen, which has no idle testids. Patched the check to: (a) assert status 200 always (proves the column rename works server-side — drizzle 500s on missing physical column), (b) only assert the visible logo when the session state is open or opening_control. Combined with the DAO probe + Settings > Customer Display logo-pointer test, every consumer of the renamed column is verified.
display_promo_image_url field still lives under Settings > Customer Display — only the LOGO got unified. The two promo image paths (landscape + U3 portrait) remain CDS-only.display_branding.update (with logoSet) to store_settings.update (with logoSet). Saving the logo now writes a store_settings.update row.<img> on the printed receipt: Gate 2 verified the source path + DAO round-trip + Settings UI persistence + the CDS consumer of the same column. The actual print iframe HTML wasn't probed because receipts render client-side via React (not a server route); the source assertion in Gate 1 confirmed the receipt component renders <img data-testid="receipt-store-logo"> when data.storeLogoUrl is set. Narong can verify visually by printing a paid order receipt.