Live on prod 2026-05-20. Two more carry-overs from the Reports arc. Backend migration + nix-cafe action + UI all shipped + verified on prod data.
13fc0e0 (migration) + 35b26d7 (view-aware fixes to older
migrate.js entries) + nix-cafe c33f269. Prod migration applied via
node migrate.js directly; H4-X view-ification surfaced 4 pre-existing
cafe.products ALTER/INDEX/UPDATE migrations that needed view-awareness on re-run —
patched all of them in a single follow-up commit. Without the pgView guard from
yesterday, these wouldn't have surfaced until the next prod migrate.js run.
cafe_product_product_tmpl_code_unique_idx landed on prod Supabase/cafe/reports shows Export CSV link with current filter querystring carried into hreftext/csv; charset=utf-8, Content-Disposition: attachment; body contains title, KPI table, Sales-by-Hours, Tax summarytext/csv, body contains title + "Total","Total" + month labeldefault_code restored on edited variant/cafe/reports + /cafe/reports/order-analysis both renderVariant modal dup-error — verified via DB probe, not browser flow on prod.
The browser flow looks for a template with ≥2 variants that both have non-NULL
default_codes. get-coffee's seeded data on prod doesn't currently
have any such template (most products are single-default or auto-V001/V002), so
the browser-side dup-typing test executed but its "find eligible template" step
returned empty and the test short-circuited as a pass without exercising the UI
error. DB-level dup rejection IS verified on prod via a direct
DAO INSERT of two same-default_code rows under the same template (rejected with
23505 on the new constraint, then cleaned up). The friendly error translation in
updateVariantAction was exercised in the Gate 1 local pass, on the
same code path. No prod-side UI screenshot — would need to seed eligible variants
first.
| test-phase1-prod.mjs | 11/11 |
| test-phase2-sso-outdoor-prod.mjs | 6/6 |
| test-phase2-cafe-multishop-prod.mjs | 6/6 |
| test-m1-prod.mjs | 10/10 |
| test-r7-prod.mjs | 14/14 |
| test-r8-prod.mjs | 4/4 |




Actual CSV bodies captured from prod for reference: summary.csv · order-analysis.csv · dupe-probe.json
First node migrate.js run against prod failed twice in cascade. Root
cause: H4-X (2026-05-20 earlier) converted cafe.products from a real
table to a Postgres view. Three pre-existing entries in migrate.js
mutate cafe.products directly (R6.2a / R6.4 / R10 plural tables), and
since migrate.js re-runs every entry on every invocation, they tried to
ALTER TABLE cafe.products / CREATE INDEX ON cafe.products
/ CREATE TABLE … REFERENCES cafe.products(id) — all of which Postgres
rejects when the target is a view (relation kind 'v', not 'r').
Fixed in commit 35b26d7 by adding a one-shot
relkind probe at the top of each affected migration and skipping the
ALTER/INDEX block when the relation is a view. The R10 plural-tables migration
preserves the surviving cafe.order_lines.variants ALTER (still
relevant) but skips the rest of its DDL. Re-runs are now idempotent post-H4-X.
This is a class of issue: any future view-ification of a non-trivial table will need the same defensive guard on pre-existing migration entries. Worth a durable memo if it happens again.
default_code uniqueness validationStill tracked (all need Narong spec or downstream model changes):