@openlup/platform 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/CHANGELOG.md +210 -47
  2. package/README.md +27 -4
  3. package/dist/composition/composeBundle.d.ts +7 -0
  4. package/dist/composition/composeBundle.js +2 -0
  5. package/dist/composition/fulfillmentContribution.d.ts +21 -0
  6. package/dist/composition/fulfillmentContribution.js +19 -0
  7. package/dist/composition/index.d.ts +1 -0
  8. package/dist/composition/index.js +1 -0
  9. package/dist/fulfillment/adapterConformance.d.ts +3 -0
  10. package/dist/fulfillment/adapterConformance.js +223 -0
  11. package/dist/fulfillment/bindings.d.ts +3 -0
  12. package/dist/fulfillment/bindings.js +29 -0
  13. package/dist/fulfillment/commerceFulfillmentHandlers.d.ts +29 -0
  14. package/dist/fulfillment/commerceFulfillmentHandlers.js +184 -0
  15. package/dist/fulfillment/commerceFulfillmentReadModel.d.ts +86 -0
  16. package/dist/fulfillment/commerceFulfillmentReadModel.js +131 -0
  17. package/dist/fulfillment/contracts/alignment.d.ts +25 -0
  18. package/dist/fulfillment/contracts/alignment.js +1 -0
  19. package/dist/fulfillment/contracts/bindings.d.ts +51 -0
  20. package/dist/fulfillment/contracts/bindings.js +1 -0
  21. package/dist/fulfillment/contracts/capabilities.d.ts +29 -0
  22. package/dist/fulfillment/contracts/capabilities.js +1 -0
  23. package/dist/fulfillment/contracts/conformance.d.ts +93 -0
  24. package/dist/fulfillment/contracts/conformance.js +1 -0
  25. package/dist/fulfillment/contracts/customerAlignment.d.ts +6 -0
  26. package/dist/fulfillment/contracts/customerAlignment.js +1 -0
  27. package/dist/fulfillment/contracts/dispatch.d.ts +105 -0
  28. package/dist/fulfillment/contracts/dispatch.js +1 -0
  29. package/dist/fulfillment/contracts/index.d.ts +18 -0
  30. package/dist/fulfillment/contracts/index.js +1 -0
  31. package/dist/fulfillment/contracts/label.d.ts +35 -0
  32. package/dist/fulfillment/contracts/label.js +1 -0
  33. package/dist/fulfillment/contracts/nativeUnsupported.d.ts +6 -0
  34. package/dist/fulfillment/contracts/nativeUnsupported.js +1 -0
  35. package/dist/fulfillment/contracts/observation.d.ts +52 -0
  36. package/dist/fulfillment/contracts/observation.js +1 -0
  37. package/dist/fulfillment/contracts/operator.d.ts +64 -0
  38. package/dist/fulfillment/contracts/operator.js +1 -0
  39. package/dist/fulfillment/contracts/read.d.ts +110 -0
  40. package/dist/fulfillment/contracts/read.js +1 -0
  41. package/dist/fulfillment/contracts/readback.d.ts +38 -0
  42. package/dist/fulfillment/contracts/readback.js +1 -0
  43. package/dist/fulfillment/contracts/replacement.d.ts +34 -0
  44. package/dist/fulfillment/contracts/replacement.js +1 -0
  45. package/dist/fulfillment/contracts/store.d.ts +86 -0
  46. package/dist/fulfillment/contracts/store.js +1 -0
  47. package/dist/fulfillment/contracts/sync.d.ts +170 -0
  48. package/dist/fulfillment/contracts/sync.js +1 -0
  49. package/dist/fulfillment/currentFulfillmentParcel.d.ts +2 -0
  50. package/dist/fulfillment/currentFulfillmentParcel.js +1 -0
  51. package/dist/fulfillment/delayReadModel.d.ts +11 -0
  52. package/dist/fulfillment/delayReadModel.js +45 -0
  53. package/dist/fulfillment/deliveryAlignmentReadModel.d.ts +4 -0
  54. package/dist/fulfillment/deliveryAlignmentReadModel.js +12 -0
  55. package/dist/fulfillment/dispatchProjection.d.ts +7 -0
  56. package/dist/fulfillment/dispatchProjection.js +18 -0
  57. package/dist/fulfillment/fulfillmentObservationEffects.d.ts +66 -0
  58. package/dist/fulfillment/fulfillmentObservationEffects.js +36 -0
  59. package/dist/fulfillment/handlerSchemas.d.ts +647 -0
  60. package/dist/fulfillment/handlerSchemas.js +213 -0
  61. package/dist/fulfillment/handlerSupport.d.ts +33 -0
  62. package/dist/fulfillment/handlerSupport.js +25 -0
  63. package/dist/fulfillment/index.d.ts +37 -0
  64. package/dist/fulfillment/index.js +37 -0
  65. package/dist/fulfillment/labelLifecycle.d.ts +24 -0
  66. package/dist/fulfillment/labelLifecycle.js +9 -0
  67. package/dist/fulfillment/lowStockEvidenceHandler.d.ts +36 -0
  68. package/dist/fulfillment/lowStockEvidenceHandler.js +46 -0
  69. package/dist/fulfillment/migrations.d.ts +27 -0
  70. package/dist/fulfillment/migrations.js +8 -0
  71. package/dist/fulfillment/nativeUnsupported.d.ts +10 -0
  72. package/dist/fulfillment/nativeUnsupported.js +18 -0
  73. package/dist/fulfillment/normalizedFulfillmentFacts.d.ts +2 -0
  74. package/dist/fulfillment/normalizedFulfillmentFacts.js +1 -0
  75. package/dist/fulfillment/observationProjection.d.ts +11 -0
  76. package/dist/fulfillment/observationProjection.js +37 -0
  77. package/dist/fulfillment/omnipack/capabilities.d.ts +3 -0
  78. package/dist/fulfillment/omnipack/capabilities.js +16 -0
  79. package/dist/fulfillment/omnipack/client.d.ts +37 -0
  80. package/dist/fulfillment/omnipack/client.js +162 -0
  81. package/dist/fulfillment/omnipack/index.d.ts +52 -0
  82. package/dist/fulfillment/omnipack/index.js +349 -0
  83. package/dist/fulfillment/omnipack/mappers.d.ts +73 -0
  84. package/dist/fulfillment/omnipack/mappers.js +177 -0
  85. package/dist/fulfillment/omnipack/observation.d.ts +21 -0
  86. package/dist/fulfillment/omnipack/observation.js +57 -0
  87. package/dist/fulfillment/omnipack/omnipackDispatchPayload.d.ts +36 -0
  88. package/dist/fulfillment/omnipack/omnipackDispatchPayload.js +63 -0
  89. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.d.ts +83 -0
  90. package/dist/fulfillment/omnipack/omnipackOutboundOrderPayload.js +113 -0
  91. package/dist/fulfillment/omnipack/omnipackProductPackPayload.d.ts +11 -0
  92. package/dist/fulfillment/omnipack/omnipackProductPackPayload.js +38 -0
  93. package/dist/fulfillment/omnipack/omnipackProductPayload.d.ts +18 -0
  94. package/dist/fulfillment/omnipack/omnipackProductPayload.js +51 -0
  95. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.d.ts +1 -0
  96. package/dist/fulfillment/omnipack/omnipackReconciliationPayload.js +3 -0
  97. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.d.ts +4 -0
  98. package/dist/fulfillment/omnipack/omnipackStatusVocabulary.js +87 -0
  99. package/dist/fulfillment/omnipack/omnipackWebhookPayload.d.ts +9 -0
  100. package/dist/fulfillment/omnipack/omnipackWebhookPayload.js +76 -0
  101. package/dist/fulfillment/omnipack/productSyncMappers.d.ts +18 -0
  102. package/dist/fulfillment/omnipack/productSyncMappers.js +43 -0
  103. package/dist/fulfillment/omnipack/providerError.d.ts +25 -0
  104. package/dist/fulfillment/omnipack/providerError.js +47 -0
  105. package/dist/fulfillment/omnipack/trackingReferences.d.ts +16 -0
  106. package/dist/fulfillment/omnipack/trackingReferences.js +52 -0
  107. package/dist/fulfillment/paidFulfillmentRecovery.d.ts +67 -0
  108. package/dist/fulfillment/paidFulfillmentRecovery.js +154 -0
  109. package/dist/fulfillment/paidHandoff.d.ts +27 -0
  110. package/dist/fulfillment/paidHandoff.js +86 -0
  111. package/dist/fulfillment/paidHandoffPorts.d.ts +24 -0
  112. package/dist/fulfillment/paidHandoffPorts.js +3 -0
  113. package/dist/fulfillment/postgresDeliveryAlignment.d.ts +4 -0
  114. package/dist/fulfillment/postgresDeliveryAlignment.js +12 -0
  115. package/dist/fulfillment/postgresDispatchStore.d.ts +16 -0
  116. package/dist/fulfillment/postgresDispatchStore.js +44 -0
  117. package/dist/fulfillment/postgresEvidenceReadPort.d.ts +25 -0
  118. package/dist/fulfillment/postgresEvidenceReadPort.js +45 -0
  119. package/dist/fulfillment/postgresPaidFulfillmentRecovery.d.ts +25 -0
  120. package/dist/fulfillment/postgresPaidFulfillmentRecovery.js +26 -0
  121. package/dist/fulfillment/postgresPaidHandoffStore.d.ts +4 -0
  122. package/dist/fulfillment/postgresPaidHandoffStore.js +10 -0
  123. package/dist/fulfillment/postgresShipmentSpine.d.ts +63 -0
  124. package/dist/fulfillment/postgresShipmentSpine.js +232 -0
  125. package/dist/fulfillment/postgresStockSyncPort.d.ts +8 -0
  126. package/dist/fulfillment/postgresStockSyncPort.js +63 -0
  127. package/dist/fulfillment/productReconciliationEvidenceHandler.d.ts +36 -0
  128. package/dist/fulfillment/productReconciliationEvidenceHandler.js +50 -0
  129. package/dist/fulfillment/providerCapabilities.d.ts +9 -0
  130. package/dist/fulfillment/providerCapabilities.js +17 -0
  131. package/dist/fulfillment/providerCommandLedger.d.ts +143 -0
  132. package/dist/fulfillment/providerCommandLedger.js +14 -0
  133. package/dist/fulfillment/providerDispatchAcceptance.d.ts +26 -0
  134. package/dist/fulfillment/providerDispatchAcceptance.js +23 -0
  135. package/dist/fulfillment/providerDispatchError.d.ts +6 -0
  136. package/dist/fulfillment/providerDispatchError.js +5 -0
  137. package/dist/fulfillment/providerDispatchWorker.d.ts +31 -0
  138. package/dist/fulfillment/providerDispatchWorker.js +172 -0
  139. package/dist/fulfillment/providerProductSyncWorker.d.ts +28 -0
  140. package/dist/fulfillment/providerProductSyncWorker.js +122 -0
  141. package/dist/fulfillment/providerReconciliationError.d.ts +9 -0
  142. package/dist/fulfillment/providerReconciliationError.js +17 -0
  143. package/dist/fulfillment/providerReconciliationTerminalSkip.d.ts +2 -0
  144. package/dist/fulfillment/providerReconciliationTerminalSkip.js +6 -0
  145. package/dist/fulfillment/providerReconciliationTimestamp.d.ts +1 -0
  146. package/dist/fulfillment/providerReconciliationTimestamp.js +27 -0
  147. package/dist/fulfillment/providerReconciliationWorker.d.ts +82 -0
  148. package/dist/fulfillment/providerReconciliationWorker.js +151 -0
  149. package/dist/fulfillment/providerStockAvailability.d.ts +13 -0
  150. package/dist/fulfillment/providerStockAvailability.js +51 -0
  151. package/dist/fulfillment/providerStockSyncWorker.d.ts +37 -0
  152. package/dist/fulfillment/providerStockSyncWorker.js +186 -0
  153. package/dist/fulfillment/providerTrackingReferences.d.ts +15 -0
  154. package/dist/fulfillment/providerTrackingReferences.js +23 -0
  155. package/dist/fulfillment/replacementRefusals.d.ts +5 -0
  156. package/dist/fulfillment/replacementRefusals.js +38 -0
  157. package/dist/fulfillment/replacementShipmentHandler.d.ts +5 -0
  158. package/dist/fulfillment/replacementShipmentHandler.js +46 -0
  159. package/dist/fulfillment/schemaCapabilities.d.ts +13 -0
  160. package/dist/fulfillment/schemaCapabilities.js +7 -0
  161. package/dist/fulfillment/shipmentsOverviewHandler.d.ts +16 -0
  162. package/dist/fulfillment/shipmentsOverviewHandler.js +54 -0
  163. package/dist/fulfillment/statusMap.d.ts +2 -0
  164. package/dist/fulfillment/statusMap.js +1 -0
  165. package/dist/fulfillment/trackingProgress.d.ts +1 -0
  166. package/dist/fulfillment/trackingProgress.js +1 -0
  167. package/dist/fulfillment/verifiedIngress.d.ts +52 -0
  168. package/dist/fulfillment/verifiedIngress.js +66 -0
  169. package/dist/payments/stripe/index.d.ts +25 -0
  170. package/dist/payments/stripe/index.js +25 -0
  171. package/dist/payments/tpay/index.d.ts +30 -0
  172. package/dist/payments/tpay/index.js +30 -0
  173. package/package.json +17 -2
  174. package/release-gates.json +44 -3
  175. package/sql/20260808210000_fulfillment_shipment_rail.sql +810 -0
  176. package/sql/20260819150000_fulfillment_shipment_sequence.sql +98 -0
  177. package/sql/20261022080000_fulfillment_command_ledger.sql +786 -0
  178. package/sql/20261022090000_fulfillment_delivery_alignment.sql +1106 -0
  179. package/src/composition/composeBundle.ts +4 -0
  180. package/src/composition/fulfillmentContribution.ts +28 -0
  181. package/src/composition/index.ts +1 -0
  182. package/src/fulfillment/adapterConformance.ts +195 -0
  183. package/src/fulfillment/bindings.ts +26 -0
  184. package/src/fulfillment/commerceFulfillmentHandlers.ts +263 -0
  185. package/src/fulfillment/commerceFulfillmentReadModel.ts +257 -0
  186. package/src/fulfillment/contracts/alignment.ts +13 -0
  187. package/src/fulfillment/contracts/bindings.ts +30 -0
  188. package/src/fulfillment/contracts/capabilities.ts +15 -0
  189. package/src/fulfillment/contracts/conformance.ts +61 -0
  190. package/src/fulfillment/contracts/customerAlignment.ts +4 -0
  191. package/src/fulfillment/contracts/dispatch.ts +58 -0
  192. package/src/fulfillment/contracts/index.ts +18 -0
  193. package/src/fulfillment/contracts/label.ts +9 -0
  194. package/src/fulfillment/contracts/nativeUnsupported.ts +6 -0
  195. package/src/fulfillment/contracts/observation.ts +18 -0
  196. package/src/fulfillment/contracts/operator.ts +31 -0
  197. package/src/fulfillment/contracts/read.ts +42 -0
  198. package/src/fulfillment/contracts/readback.ts +11 -0
  199. package/src/fulfillment/contracts/replacement.ts +15 -0
  200. package/src/fulfillment/contracts/store.ts +26 -0
  201. package/src/fulfillment/contracts/sync.ts +61 -0
  202. package/src/fulfillment/currentFulfillmentParcel.ts +2 -0
  203. package/src/fulfillment/delayReadModel.ts +60 -0
  204. package/src/fulfillment/deliveryAlignmentReadModel.ts +15 -0
  205. package/src/fulfillment/dispatchProjection.ts +20 -0
  206. package/src/fulfillment/fulfillmentObservationEffects.ts +86 -0
  207. package/src/fulfillment/handlerSchemas.ts +255 -0
  208. package/src/fulfillment/handlerSupport.ts +25 -0
  209. package/src/fulfillment/index.ts +38 -0
  210. package/src/fulfillment/labelLifecycle.ts +11 -0
  211. package/src/fulfillment/lowStockEvidenceHandler.ts +60 -0
  212. package/src/fulfillment/migrations.ts +8 -0
  213. package/src/fulfillment/nativeUnsupported.ts +23 -0
  214. package/src/fulfillment/normalizedFulfillmentFacts.ts +2 -0
  215. package/src/fulfillment/observationProjection.ts +41 -0
  216. package/src/fulfillment/omnipack/capabilities.ts +18 -0
  217. package/src/fulfillment/omnipack/client.ts +258 -0
  218. package/src/fulfillment/omnipack/index.ts +312 -0
  219. package/src/fulfillment/omnipack/mappers.ts +261 -0
  220. package/src/fulfillment/omnipack/observation.ts +61 -0
  221. package/src/fulfillment/omnipack/omnipackDispatchPayload.ts +93 -0
  222. package/src/fulfillment/omnipack/omnipackOutboundOrderPayload.ts +194 -0
  223. package/src/fulfillment/omnipack/omnipackProductPackPayload.ts +47 -0
  224. package/src/fulfillment/omnipack/omnipackProductPayload.ts +67 -0
  225. package/src/fulfillment/omnipack/omnipackReconciliationPayload.ts +7 -0
  226. package/src/fulfillment/omnipack/omnipackStatusVocabulary.ts +103 -0
  227. package/src/fulfillment/omnipack/omnipackWebhookPayload.ts +73 -0
  228. package/src/fulfillment/omnipack/productSyncMappers.ts +74 -0
  229. package/src/fulfillment/omnipack/providerError.ts +64 -0
  230. package/src/fulfillment/omnipack/trackingReferences.ts +77 -0
  231. package/src/fulfillment/paidFulfillmentRecovery.ts +252 -0
  232. package/src/fulfillment/paidHandoff.ts +122 -0
  233. package/src/fulfillment/paidHandoffPorts.ts +21 -0
  234. package/src/fulfillment/postgresDeliveryAlignment.ts +14 -0
  235. package/src/fulfillment/postgresDispatchStore.ts +55 -0
  236. package/src/fulfillment/postgresEvidenceReadPort.ts +59 -0
  237. package/src/fulfillment/postgresPaidFulfillmentRecovery.ts +29 -0
  238. package/src/fulfillment/postgresPaidHandoffStore.ts +11 -0
  239. package/src/fulfillment/postgresShipmentSpine.ts +321 -0
  240. package/src/fulfillment/postgresStockSyncPort.ts +65 -0
  241. package/src/fulfillment/productReconciliationEvidenceHandler.ts +64 -0
  242. package/src/fulfillment/providerCapabilities.ts +18 -0
  243. package/src/fulfillment/providerCommandLedger.ts +53 -0
  244. package/src/fulfillment/providerDispatchAcceptance.ts +31 -0
  245. package/src/fulfillment/providerDispatchError.ts +7 -0
  246. package/src/fulfillment/providerDispatchWorker.ts +131 -0
  247. package/src/fulfillment/providerProductSyncWorker.ts +154 -0
  248. package/src/fulfillment/providerReconciliationError.ts +20 -0
  249. package/src/fulfillment/providerReconciliationTerminalSkip.ts +8 -0
  250. package/src/fulfillment/providerReconciliationTimestamp.ts +34 -0
  251. package/src/fulfillment/providerReconciliationWorker.ts +150 -0
  252. package/src/fulfillment/providerStockAvailability.ts +60 -0
  253. package/src/fulfillment/providerStockSyncWorker.ts +222 -0
  254. package/src/fulfillment/providerTrackingReferences.ts +31 -0
  255. package/src/fulfillment/replacementRefusals.ts +43 -0
  256. package/src/fulfillment/replacementShipmentHandler.ts +47 -0
  257. package/src/fulfillment/schemaCapabilities.ts +7 -0
  258. package/src/fulfillment/shipmentsOverviewHandler.ts +73 -0
  259. package/src/fulfillment/statusMap.ts +2 -0
  260. package/src/fulfillment/trackingProgress.ts +1 -0
  261. package/src/fulfillment/verifiedIngress.ts +80 -0
  262. package/src/payments/stripe/index.ts +30 -0
  263. package/src/payments/tpay/index.ts +36 -0
@@ -0,0 +1,98 @@
1
+ -- Public platform shipment rail: an order may hold more than one shipment.
2
+ -- Three columns, two rules, one constraint swap, one index, no behaviour.
3
+ --
4
+ -- WHAT THIS FORWARD SHIPS. `fulfillment_shipments` carried `UNIQUE (order_id)`, which said that an
5
+ -- order is fulfilled once and only once. That is true of the ordinary case and false of the case
6
+ -- every shop eventually meets: the parcel was lost, arrived damaged, or came back undelivered, and
7
+ -- the operator has to send another one. This forward replaces the single-column key with
8
+ -- `UNIQUE (order_id, sequence_no)` and gives a second shipment the three facts it needs to be more
9
+ -- than an accidental duplicate -- its ordinal within the order, the shipment it stands in for, and
10
+ -- why it was sent.
11
+ --
12
+ -- WHY IT IS A SECOND SHIPMENT AND NOT A SECOND ORDER. The buyer bought once. Making the replacement
13
+ -- a new order would produce a second document trail, a second settlement and a second identifier
14
+ -- the buyer never agreed to; every one of those is a defect a support desk then has to undo. The
15
+ -- order stays the commercial fact and the shipment becomes the repeatable one, which is the same
16
+ -- direction the lifecycle already points: shipments already carry their own state machine, their own
17
+ -- external references and their own operation ledger, all keyed on the shipment rather than on the
18
+ -- order.
19
+ --
20
+ -- WHY THE ORDINAL RATHER THAN A FLAG. A boolean `is_replacement` cannot answer the third question --
21
+ -- the second replacement -- and a timestamp cannot be made unique without also making it a key.
22
+ -- `sequence_no` is derivable, orderable and stable, so a caller can compute the external identifier
23
+ -- for a shipment without inventing one, and the unique key above refuses the same ordinal twice.
24
+ --
25
+ -- WHY THE SHAPE RULE IS NOT OPTIONAL. Dropping a unique constraint gives up a real defence: today a
26
+ -- stray second insert for one order is refused by the database. The shape rule is what is put in its
27
+ -- place. An ordinal of 0 is the original and must carry neither a predecessor nor a reason; an
28
+ -- ordinal above 0 must carry both. A stray insert that simply omits the ordinal therefore still
29
+ -- takes 0 and still collides, exactly as it did before this forward, and writing a second shipment
30
+ -- on purpose now means filling three columns consistently.
31
+ --
32
+ -- WHY IT CHANGES NOTHING TODAY. `sequence_no` takes 0 by column default, so the new key is
33
+ -- constraint-for-constraint as strict as the one it replaces for every row that exists. No function
34
+ -- in this catalogue writes an ordinal, and none needs a repair to read one: every lifecycle function
35
+ -- is keyed on the shipment identifier, the notification suppressor is an `EXISTS`, and the retention
36
+ -- reads that join a shipment to its order either sit inside `SELECT EXISTS (...)` or collapse under
37
+ -- an order-scoped idempotency key. This forward is therefore the transition and only the transition.
38
+ --
39
+ -- NOT VALID on both rules follows this catalogue's convention for a constraint added to a table that
40
+ -- may already carry rows: every write from this statement on is checked, no blocking scan is taken,
41
+ -- and every pre-existing row satisfies the rule trivially because its ordinal is 0 and both new
42
+ -- columns are NULL.
43
+ --
44
+ -- WHAT THIS FORWARD DELIBERATELY DOES NOT SHIP:
45
+ -- * no way to create the second shipment. `fulfillment_create_shipment` replays through the
46
+ -- operation ledger and opens exactly one shipment per idempotency key; it is untouched, and
47
+ -- until an operator command is authored nothing can reach an ordinal above 0;
48
+ -- * no external identifier scheme. What a deployment calls the replacement at its integration is
49
+ -- derivable from the ordinal, and deriving it is the host application's business;
50
+ -- * no refund, return or restock consequence. Sending a replacement says nothing about the money;
51
+ -- * no reader. Nothing in this catalogue selects the three columns, and the resolution order the
52
+ -- index carries is a hint for a future reader, not a policy this forward enforces.
53
+
54
+ ALTER TABLE public.fulfillment_shipments
55
+ ADD COLUMN sequence_no smallint NOT NULL DEFAULT 0,
56
+ ADD COLUMN replaces_shipment_id uuid,
57
+ ADD COLUMN replacement_reason text;
58
+
59
+ -- SET NULL rather than CASCADE: erasing a superseded shipment must not erase the record that its
60
+ -- successor was sent, and the ordinal keeps the successor legible on its own.
61
+ ALTER TABLE public.fulfillment_shipments
62
+ ADD CONSTRAINT fulfillment_shipments_replaces_shipment_id_fkey
63
+ FOREIGN KEY (replaces_shipment_id) REFERENCES public.fulfillment_shipments(id)
64
+ ON DELETE SET NULL NOT VALID;
65
+
66
+ ALTER TABLE public.fulfillment_shipments
67
+ ADD CONSTRAINT fulfillment_shipments_replacement_reason_check CHECK (
68
+ replacement_reason IS NULL
69
+ OR replacement_reason IN ('damaged', 'lost', 'returned_undelivered', 'other')
70
+ ) NOT VALID;
71
+
72
+ -- The rule that replaces the guarantee the dropped key was giving.
73
+ ALTER TABLE public.fulfillment_shipments
74
+ ADD CONSTRAINT fulfillment_shipments_replacement_shape_check CHECK (
75
+ (sequence_no = 0 AND replaces_shipment_id IS NULL AND replacement_reason IS NULL)
76
+ OR (sequence_no > 0 AND replaces_shipment_id IS NOT NULL AND replacement_reason IS NOT NULL)
77
+ ) NOT VALID;
78
+
79
+ ALTER TABLE public.fulfillment_shipments
80
+ DROP CONSTRAINT fulfillment_shipments_order_id_key;
81
+
82
+ -- The unique key swap is this migration's whole point and cannot be expressed without
83
+ -- building a unique index. It is spelled as a unique INDEX rather than a UNIQUE CONSTRAINT
84
+ -- because that is this repository's established shape for in-transaction uniqueness -- it
85
+ -- enforces identically and needs only the one accepted ignore. CONCURRENTLY is unavailable:
86
+ -- the migration runner wraps each file in a transaction, which is what the squawk gate assumes.
87
+ -- The build cannot find a duplicate: `sequence_no` is NOT NULL DEFAULT 0, so every
88
+ -- pre-existing row backfills to the same ordinal and the new key is exactly as strict as the
89
+ -- one it replaces.
90
+ -- squawk-ignore require-concurrent-index-creation
91
+ CREATE UNIQUE INDEX IF NOT EXISTS fulfillment_shipments_order_id_sequence_no_key
92
+ ON public.fulfillment_shipments (order_id, sequence_no);
93
+ COMMENT ON COLUMN public.fulfillment_shipments.sequence_no IS
94
+ 'Ordinal of this shipment within its order. 0 is the original; a replacement takes the next free ordinal. Externally derivable and stable; the buyer never sees it.';
95
+ COMMENT ON COLUMN public.fulfillment_shipments.replaces_shipment_id IS
96
+ 'The shipment this one stands in for. This is the linkage truth; never recover it by parsing an external identifier.';
97
+ COMMENT ON COLUMN public.fulfillment_shipments.replacement_reason IS
98
+ 'Why the replacement was sent: damaged, lost, returned_undelivered, other. NULL on the original.';