ADR-011: The inventory ledger is the only stock writer
Status: accepted 13 September 2026 (BRV-05).
Context
Section titled “Context”The baseline found ten places that changed stock, two stock figures with no link between them, and no record of why a quantity changed. Reservations, consumption, corrections and write-offs all need one trustworthy history.
Decision
Section titled “Decision”InventoryLedgeris the single writer. It locks the flower row, then the batch row, writes aninventory_movementsrow identified by an action key, and updates the projections (supply_items.quantity_remaining,supply_items.quantity_reserved,flowers.stock_quantity) in the same transaction. A repeated action key returns the existing movement instead of applying twice.- Invariants after every action: on-hand ≥ 0, reserved ≥ 0, reserved ≤ on-hand. An action that would break one is refused with a message an operator can read.
- Movements are append-only. History is corrected with a compensating movement, never by editing a movement.
- Batches carry history, so they are never hard-deleted. Removing a batch reverses its receipt and soft-deletes the row; it is refused once stems are reserved or consumed. A batch cannot be moved to another flower.
- Pending orders reserve nothing (rule B01). The old create/cancel/delete decrements are gone; reservation arrives with confirmation (BRV-06) and consumption with assembly (BRV-07).
- The flower form no longer sets stock. Stock enters through supplies and changes through corrections, write-offs and orders.
Cutover
Section titled “Cutover”At introduction every existing batch received an opening-balance movement documenting its remainder, without inventing pre-cutover receipts or consumption. Flower stock that no batch accounted for was preserved as a legacy batch with unknown cost and expiry in status review, kept on hand and visible but excluded from automatic allocation (rules B06, B13). php artisan inventory:reconcile is read-only and exits non-zero on any disagreement between movements and projections.
Consequences
Section titled “Consequences”- A reviewer can explain every change in a batch from recorded actions.
- Between BRV-05 and BRV-07, confirmed orders do not yet reserve; the branch is not for a real shop until BRV-07 lands.
- Legacy
reviewbatches need an operator to set an expiry (and cost) before they can be sold.