Repository navigation
Commit d0f2b38
Stock/concurrency invariants — explicit transfer guard + verification (audit-M-stock) (#206)
* fix(stock): make transfer reserved-stock guard explicit; document stock invariants (closes audit-M-stock)
Stock/concurrency cluster (bkhk). Most findings were already resolved by prior
work; this makes the remaining guard explicit + tested and documents the rest:
1. Transfer-of-allocated-stock: dispatch availability already nets the source
warehouse's per-(product,warehouse) reservedQty (kept in sync with order
allocations), so a transfer can't strand an order. Extracted that rule into a
pure availableForTransfer/canDispatchTransferQty helper (used by dispatch) so
it's explicit and regression-tested.
2. Manual receipt + WMS booked-in double-layer: VERIFIED resolved —
reconcileBookedInQuantities nets localReceivedQty (read under the PO FOR UPDATE
lock); already covered by mintsoft-phase6-booked-in tests.
3. Opening-stock race: VERIFIED resolved — applyOpeningStock takes a FOR UPDATE
lock on the stock level before the existing-opening-layer check, serialising
concurrent calls.
4. Transfer FIFO ordering at destination: documented + accepted (cosmetic; per
layer cost basis preserved).
5. stock_levels CHECK >= 0: VERIFIED present (migration 20260512100000:
quantity>=0, reservedQty>=0, reservedQty<=quantity).
Documented all five in docs/workflows.md under Stock / concurrency invariants.
Tests: 5 transfer-availability cases; type-check + lint clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(stock): preserve over-reservation diagnostic + precise docs (adversarial review)
Codex adversarial pass on PR #206 (verified all three 'already-resolved' claims
are substantively correct; no refuted claims):
MEDIUM — the extracted helper clamped a negative (over-reserved) available to 0,
so the dispatch error message showed '0 available' instead of the real negative
delta, hiding a data-integrity signal. The error now reports the raw (unclamped)
delta while the clamped value still gates dispatch.
MEDIUM — docs overstated the reservedQty<=quantity constraint: it's NOT VALID
(new-writes-only, never validated against historical rows), unlike the fully
VALIDATEd quantity>=0 / reservedQty>=0. Docs corrected, and note the transfer
guard (not just the constraint) is what protects allocations.
LOW — docs now mention both the PO and stock-transfer FOR UPDATE locks for the
WMS reconcile; JSDoc warns availableForTransfer's clamp must not be reused for
data-integrity checks; added an over-reserved canDispatchTransferQty test.
6/6 helper tests; type-check + lint clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent 0f976be commit d0f2b38
4 files changed
Lines changed: 103 additions & 3 deletions
File tree
- app/actions
- docs
- lib/domain/inventory
- tests/domain/inventory
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
388 | 389 | | |
389 | 390 | | |
390 | 391 | | |
391 | | - | |
392 | | - | |
393 | | - | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
394 | 399 | | |
395 | 400 | | |
396 | 401 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
0 commit comments