Decision 0019 — Outbound Allocation Authority¶
- Status:
ACCEPTED - Task:
NS2-021 - Date:
2026-08-26
Context¶
Phase 2 needs one tenant-neutral Sale -> Outbound Fulfillment -> Inventory Demand -> Allocation flow.
Current source already separates Sale/fulfillment persistence from explicit Inventory allocation:
projectAllocationPreview is read-only, applyAllocation owns the transaction and
reverseAllocation owns release. The remaining implementation must complete this contract rather
than introduce another workflow owner.
Decision¶
- Commercial Sale owns commercial intent. Fulfillment owns the 1:1 execution order and 1:N demand lines. Saving either never allocates inventory.
- Inventory owns read-only preview and explicit apply/reverse commands. One demand line may receive many allocations and one lot may serve many demands; each allocation relates exactly one lot to one demand line.
- Partial and multi-lot allocation are allowed. Quantity and weight must not exceed either the locked lot balance or cumulative demand. Zero requested weight means quantity is authoritative; otherwise both dimensions conserve.
- db-mysql remains the single transaction owner. Apply locks/resolves tenant-scoped UUID relations,
claims the demand
ALLOCATION_VERSION, conditionally decrements the lot, inserts the UUID allocation and appends the signed immutable ledger before commit. A lost version or balance race is a conflict. - Allocation UUID is the idempotency key. Identical retry returns authoritative lot readback; different payload conflicts. Unknown result is resolved only by rereading that UUID and exact relation/quantity/weight facts.
- Reallocation is explicit reverse then apply with a new UUID. Reverse soft-deletes the relation, restores lot quantity/weight, appends a compensating ledger row and recomputes demand state.
- Reverse is allowed only while the demand is
OPEN,PARTIALorALLOCATED. Any execution state after allocation (picked/loaded/shipped/completed or an active progressed equipment/transport bridge) blocks release. NS2-022 must bind current persisted bridge facts to this guard. - Booking, equipment and carrier remain optional context owners. They may consume a ready outbound order but never own allocation or infer it from a Sale save.
- Routes retain tenant UUID resolution and explicit
inventory.allocation.apply/.reversecapabilities. Menus are navigation, not business authorization.
Conservation¶
For each lot: inbound - reversed receipts - active allocations = remain.
For each demand line: requested - active allocations = unallocated, with active allocations never
exceeding requested quantity or positive requested weight. Apply ledger deltas are negative; reversal
deltas are equal positive compensation.
Alternatives¶
Alternative 1 — Automatic Sale Allocation¶
Rejected: hides side effects, cannot choose lots and makes retry/correction ambiguous.
Alternative 2 — New Allocation Service¶
Rejected: current Inventory plus db-mysql owners already provide the admitted command, lock and ledger boundary; another owner duplicates them.
Alternative 3 — Booking-Owned Reservation¶
Rejected: optional transportation context cannot become the inventory writer and would exclude non-Booking outbound flows.
Alternative 4 — Existing Inventory Owner¶
Accepted: harden the existing Inventory command and db-mysql transaction owner with the smallest missing progressed-state and multi-lot proofs.
Consequences¶
- Allocation remains explicit, tenant-scoped and independently retryable.
- Multi-lot work composes existing one-lot commands; no orchestration framework is added.
- Transportation progress is a reversal guard, never an inventory writer.
- NS2-022 must prove the remaining bridge-state and concurrent runtime cases.
Revisit¶
Revisit only if an admitted shipment owner introduces a persisted state that cannot be projected into the existing progressed-state guard, or measured throughput proves the current transaction boundary insufficient. Neither condition is currently present.
NS2-022 Boundary¶
Reuse existing packages/routes/UI. Add no package, service, queue, event bus or customer branch. Implement only gaps required to prove multi-lot partial allocation, concurrent conflict, safe retry, reallocation/reversal, progressed-state guard, tenant/capability denial and authoritative readback.
---¶
Source:
new-system/docs/decisions/0019-outbound-allocation-authority.md— ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.