A retail group whose stock figure depended on who you asked
Thirty-eight branches, one stock ledger, and an end to the nightly reconciliation
The website and the branches held different stock figures, and both were defended. Every night a job reconciled them, which hid the disagreement rather than resolving it, so an oversell was discovered by the customer rather than by the business. We replaced the reconciliation with a single movement ledger where every adjustment carries a person and a reason, and the disagreement had nowhere left to live.
The Client
A retail group whose stock figure depended on who you asked
Anonymised · NDA- Retail · 38 branches
- Saudi Arabia · Egypt
Branches counted stock on a schedule, the warehouse counted on receipt, and the storefront decremented on order. Three honest systems producing three different numbers, reconciled by a nightly job whose output nobody read until something went wrong, by which point the customer already knew.
Diagnosis
What was broken
- [01]
Three systems decremented stock on three different events, and none deferred to another.
- [02]
The nightly job overwrote differences silently, so the size of the drift was never visible.
- [03]
An adjustment had no author and no reason, so a wrong one could not be traced or reversed.
- [04]
Transfers between branches were recorded twice, as a despatch and an unrelated receipt.
- [05]
Oversells were refunded at the counter and never classified, so the rate stayed anecdotal.
- [06]
Buyers planned from the previous night, so a fast-moving line was ordered a day late.
Business Impact
Two people spent the first ninety minutes of every day reading a reconciliation report that told them a number had changed but not why. The larger cost was the buying decisions made on that number: a line that had actually sold out looked healthy until the next night.
Why previous attempts failed
Each previous attempt made one of the three systems authoritative. That works until the other two keep writing, which they did, because each owned an event the authoritative one could not observe.
Our Approach
How we solved it
Phase 01 of 04 · Measure the drift honestly
01
Measure the drift honestly
We stopped the nightly overwrite for two weeks and logged the differences instead of erasing them. That gave the first honest picture of how far apart the three systems ran, and which SKUs drifted — it was concentrated in about six per cent of lines, not spread evenly as everyone assumed.
Deliverables
- Two-week drift log, nothing overwritten
- The 6% of lines that produced the drift
- Oversell rate, classified for the first time
02
One ledger, append only
Stock stopped being a number and became the sum of its movements. Receipts, sales, transfers, shrinkage and corrections are all rows; nothing is edited and nothing is overwritten. The current figure is derived, so it cannot disagree with its own history the way a stored number can.
Deliverables
- Append-only movement ledger per SKU
- Author and reason required on every row
- Transfers as one paired, balanced movement
03
Cut the branches over in waves
Six branches went first, chosen because between them they covered all three stock-handling patterns in the estate. They ran against the new ledger while the old reconciliation continued in shadow, and the two were compared every morning until the comparison stopped being interesting.
Deliverables
- Six pilot branches covering all patterns
- Shadow reconciliation during the overlap
- Counter staff trained in Arabic and English
04
Retire the nightly job
The reconciliation was switched off rather than left running quietly, which is the part that makes this permanent. The storefront now reads the ledger directly, buyers plan from the current figure, and the ninety minutes that two people spent reading a report each morning went back to them.
Deliverables
- Nightly reconciliation decommissioned
- Storefront reading the ledger directly
- Runbooks and alerting the group owns
End of approach
Scroll on for the results →
Scroll · 4 phases · pinned
Tech Stack
Tools & technologies
PostgreSQL · Drizzle
Data
TypeScript · Node
Language
Next.js App Router
Interface
Terraform · Actions
Infrastructure
Results
Quantified outcomes
−94%
Nightly reconciliation
Ninety minutes a morning for two people, returned to them entirely
38
Branches on one ledger
Cut over in waves of six, each shadowed against the old job
100%
Adjustments attributed
Author and reason are required columns, not an optional comment
Live
Figure buyers plan from
Derived from the movements rather than stored and corrected
Key Takeaways
What we learned
01
Reconciliation is a symptom, not a feature
A nightly job that makes two numbers agree is evidence that two systems both believe they own the number. Fixing the ownership removes the job; improving the job makes the disagreement cheaper to tolerate, which is why it survives for years.
Useful when: Any estate where a scheduled job exists to make two systems agree.
02
Stop erasing the evidence before you fix it
Two weeks of logging the differences instead of overwriting them cost nothing and changed the plan. The drift turned out to be concentrated in six per cent of lines, so the first release targeted those rather than attempting the whole catalogue.
Useful when: Before replacing any process whose output is routinely discarded.
03
Derive the number, do not store it
A stored quantity can disagree with the events that produced it. A quantity summed from an append-only ledger cannot, which means a wrong figure is always a wrong movement — findable, attributable and reversible rather than a mystery to be corrected.
Useful when: Inventory, ledgers, balances — anything that must survive an audit.
04
Switch the old thing off, or it never ends
Leaving the reconciliation running quietly would have been the comfortable choice and would have guaranteed a second source of truth within a year. Decommissioning it was a scheduled, named step with an owner, not something left to happen later.
Useful when: Every replacement project, at the point the new system goes live.
FAQ
Frequently asked
01Does an append-only ledger not grow without limit?
02What happens when a physical count disagrees with the ledger?
03Why did the first wave contain only six of the branches?
04Was the nightly reconciliation really switched off?
05Why is this case study anonymised rather than named?
The closing thought
Ready to write yours?
Every project on this site started as an operational problem somebody had stopped expecting to fix. If one of yours sounds like this, that is the conversation to have.
Let's write yours.
Book a call- −94% Nightly reconciliation time
- 38 Branches on one stock ledger
- SiaSol · siasol.ai
Software products built in Egypt, Saudi Arabia and the UAE.

