Retail · 2025

A retail group whose stock figure depended on who you asked

6 min read
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

  1. [01]

    Three systems decremented stock on three different events, and none deferred to another.

  2. [02]

    The nightly job overwrote differences silently, so the size of the drift was never visible.

  3. [03]

    An adjustment had no author and no reason, so a wrong one could not be traced or reversed.

  4. [04]

    Transfers between branches were recorded twice, as a despatch and an unrelated receipt.

  5. [05]

    Oversells were refunded at the counter and never classified, so the rate stayed anecdotal.

  6. [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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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

  1. 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.

  2. 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.

  3. 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.

  4. 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?

It grows, but at retail movement volumes that is a few hundred million rows a year, which Postgres handles without difficulty when the table is partitioned by period. Current quantities are materialised per SKU and refreshed on write, so a shelf-edge query never sums the whole history.

02What happens when a physical count disagrees with the ledger?

The count becomes a movement like any other, with the counter as its author and shrinkage or correction as its reason. The ledger is never edited to match reality; reality is recorded as an event. That is what makes the difference between the two measurable rather than invisible.

03Why did the first wave contain only six of the branches?

Because six was the smallest set that covered all three stock-handling patterns in the estate — a warehouse-fed branch, a branch that receives direct from suppliers, and one that does both. Coverage of patterns mattered more than coverage of volume, since a pattern we had not seen was the risk.

04Was the nightly reconciliation really switched off?

Yes, and that was a named step with a date and an owner rather than something left to happen. Leaving it running would have been comfortable and would have recreated a second source of truth within a year, which is precisely the problem the project existed to remove.

05Why is this case study anonymised rather than named?

Branch counts, margins and oversell rates are commercially sensitive, and the engagement was covered by a mutual confidentiality agreement. The architecture, the sequencing and the numbers are reported exactly; the name is not.

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.

Edition № 002Case Study · Retail · 2025

Let's write yours.

Book a call
  • −94% Nightly reconciliation time
  • 38 Branches on one stock ledger
  • SiaSol · siasol.ai
View all

Software products built in Egypt, Saudi Arabia and the UAE.