A transfer read the sending branch's stock and then wrote its movements
as two separate steps. Requests arriving together all saw the same
balance and all passed the check: five simultaneous transfers of 4 from
a stock of 10 all succeeded, sending 20.
The check and the write now run under withStockLock: a short lease on
one product's stock at one branch, taken with a single atomic upsert
(it only succeeds when no unexpired lease exists) and released when the
request finishes. A second request waits briefly, then sees the updated
balance; after 5 seconds it gets 409 "try again". A lease expires after
10 seconds, so a crashed request cannot block the stock for good.
Physical counts take the same lock, so a count is never computed from a
balance a transfer is changing. A double-tapped transfer that races
itself still moves stock once. Sales do not take the lock: they are
recorded even when stock runs out, by design.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>