0029: rescope uq_expense_source_order for per-shipment bridge rows
ci / lint-test (push) Successful in 1m1s

Split-shipment orders are charged per shipment; the spine bridge now
writes one row per shipment sharing (source, order_reference). Meal-lane
idempotency semantics unchanged (index scope excludes only
source='order-bridge'); bridge rows get their own unique index on
(source, source_message_id). Applied 2026-08-10.
This commit is contained in:
2026-08-10 17:42:45 +10:00
parent 7819a88af2
commit 502e3f563c
@@ -0,0 +1,25 @@
-- 0029: let the spine bridge write one row PER SHIPMENT of a split order.
--
-- An Amazon order that ships in two boxes is charged per shipment, so its
-- order_total matches no statement line — the bridge (ingestion-engine
-- jobs/order_transaction_bridge.py) matches each shipment's own amount and
-- items instead. Those rows share (source='order-bridge', order_reference),
-- which uq_expense_source_order forbade.
--
-- The index exists as the MEAL lane's idempotency key (0018 I7), and that
-- lane's semantics are untouched: the scope simply excludes bridge rows,
-- whose idempotency key is source_message_id (<entity_key> for whole-order
-- rows, <entity_key>#f<fact_id> per shipment) — now enforced with its own
-- unique index instead of by convention. No app code does ON CONFLICT
-- against either index; ingest idempotency is SELECT-based
-- (lib/order-ingestion.ts).
DROP INDEX IF EXISTS uq_expense_source_order;
CREATE UNIQUE INDEX uq_expense_source_order
ON expense_metadata (source, order_reference)
WHERE order_reference IS NOT NULL AND source <> 'order-bridge';
CREATE UNIQUE INDEX uq_expense_bridge_message
ON expense_metadata (source, source_message_id)
WHERE source = 'order-bridge';