Why our inventory is an append-only ledger
On-hand is a sum, not a field. What that buys a two-person company selling the same stock on two marketplaces.
Most small shops keep inventory as a number in a cell. You sell one, you subtract one. You count the shelf, you overwrite the cell. It works until it doesn’t, and when it doesn’t, nobody can say why.
We keep it as a ledger instead. Every movement of stock is one row: which SKU, which location, a signed quantity, a reason, who did it, and a reference to the order or count that caused it. Rows are only ever added. On-hand for a SKU is the sum of its rows.
on_hand(sku) = Σ delta over every row for that sku
What it changes
Corrections are rows. If a count finds eleven boxes where the ledger says twelve, we do not edit anything. A count row with delta −1 and reason count goes in, and the history keeps both the mistake and the fix.
Every channel derives from one number. TikTok Shop and eBay each show a listed quantity. Both are pushed from the same on-hand, minus what is reserved for orders not yet shipped. A sale on one channel pulls the other down within minutes, and no platform can ever show more than what is physically on the shelf.
A SKU that has never been counted is never pushed. Seeding the system from marketplace listings gives you their numbers, not reality. Until someone has physically counted a SKU, the worker refuses to push a quantity for it, and an alert lists what is waiting to be counted.
People and agents leave the same trace. A stock movement made by Claude through MCP is a row with a user id, exactly like one made in the browser. There is no second, looser path for automation.
What it costs
A little discipline, and a query that sums instead of reads. For a company of two people and some agents, that is a good trade. The ledger is the one place where “what do we actually have” is answered, and nobody has to remember to update it.