A worked demonstration on a constructed dataset. Crestline Supply Co. is not a client. It is a $36M industrial distributor built from scratch so the method below can be shown end to end, with the data and the scripts published alongside it. Every number on this page is computed from that dataset, not asserted. Anyone can re-run it and get the same figures. Where the method has limits, they are stated at the bottom rather than left out.
The situation
Crestline Supply Co. distributes fasteners, hydraulic fittings, hose assemblies and MRO consumables from three warehouses. Trailing twelve month revenue is $35.97M, down 7.2% from $38.76M the year before. Gross margin has held at 28.6%. The business is profitable.
Over the same 24 months, inventory went from $6.13M to $8.24M. Up 34.6% while sales fell 7.2%. Days inventory outstanding is 117. Turns are 3.1x.
The CFO knows all of that. It is on the balance sheet. What the CFO cannot answer is the question the bank asked: which decisions put the extra $2.1M there, and will the same decisions put another $2.1M there next year.
That is the gap this diagnostic closes.
What the existing reports already said
Crestline runs a cloud inventory management system. Before any of this started, the system and a spreadsheet could already produce, in minutes:
- Stock on hand by SKU and location, with value (the stock on hand report)
- How long stock has been sitting, in age buckets (the inventory ageing report)
- Purchase history by supplier and by category (the purchase order detail report)
- ABC analysis on trailing twelve month cost of goods sold, built in a spreadsheet from the sales report. The system has no ABC report of its own and does not build custom reports
Those reports are not wrong and they are not missing. They were run. They said:
- $1.72M sits in 1,003 SKUs with no sale in 180 days
- $0.96M sits in 578 SKUs with no sale in a full year
- C class items hold 74.2% of the excess while producing 5% of COGS
All true. All useless for the bank's question. Every one of those reports groups by a field that already exists: supplier, category, location, date. None of them groups by why the item was bought, because the system has no field for that, and neither does any other.
So the analysis always stops at which SKU is stuck. It never reaches which decision process produces stuck SKUs. Those are different questions and only the second one changes next year.
The question nobody could answer
Purchases at Crestline arrive through four different decisions, and they are not equally risky:
| Channel | What it means |
|---|---|
| Replenishment | Reorder point triggered it. The system suggested it. |
| Customer-driven | A customer ordered it, so it was bought. |
| Vendor program | A supplier deal, rebate tier or price increase triggered it. |
| Buyer judgment | A buyer decided it would sell. New line, house brand, line extension. |
Nobody at Crestline tags this. Nobody at any distributor this size tags this. It is not negligence. There is no seat in a $36M company that owns the connection between SKU level buying decisions and the cash those decisions consume. The CFO owns the balance sheet number. The buyer owns the SKU decisions and is measured on fill rate and vendor terms, never on cash. Neither one is wrong.
Why this was not solvable before
The analysis was always possible. The column it needed never existed.
To build that column by hand, someone would have to read 3,246 purchase orders, cross reference each one against customer order dates, recognise that a 21 line order from one supplier landing two weeks before quarter end is a program buy while a 3 line order placed four days after a customer order is not, and make a judgment call on each. Then do it again next year.
Call it two weeks of a capable analyst's time, on work that is beneath them, that has to be redone annually. The math never worked. So it never got done, and the report that explains the trapped cash was never built.
What changed is the cost of that judgment, not the cost of the analysis. Reading messy evidence and applying consistent classification across thousands of rows went from two weeks to an afternoon. Same ABC. Same aging. Same FIFO. The missing column can finally be filled in.
That is the whole claim. This is clerical judgment at scale, not demand prediction.
What was actually done
Inputs. One product export and three standard reports from the inventory system, exported to Excel. Nothing custom.
| Export | Volume |
|---|---|
| Product list (Inventory, Products, Export) | 4,100 SKUs |
| Purchase order detail report | 3,246 orders, 38,959 lines, $57.1M |
| Sales order detail report | 18,167 orders, 81,033 lines |
| Stock on hand report | 3,795 SKUs holding stock, $8.24M |
One limit to know. The standard purchase order detail report carries the line comment, not the order note or the person who raised the order. Those two come from the purchase list or the API. Without them the classification still runs on structure alone, which is why the accuracy below is reported both ways.
Step 1. Reconstruct the missing field. Each purchase order was classified into one of the four channels using evidence already in the data:
- how many lines the order carried, and whether they came from one supplier
- whether a customer order for that SKU predated the purchase order, and whether the quantities matched
- how many weeks of cover the quantity represented against trailing demand
- what share of the lines were SKUs with no sale in the prior twelve months
- how close the order date sat to quarter end
- the free text Note and Reference fields on the order
Step 2. Attribute the closing inventory back to the decision that bought it. Receipts and sales were replayed per SKU under FIFO, so what remains on the shelf is matched to the specific purchase orders that are still sitting there. Every dollar of the $8.24M carries the channel that bought it.
Step 3. Define trapped, conservatively. An item with no sale in 180 days is fully trapped. An item that still sells is trapped only on the quantity above twelve months of cover. Twelve months is a deliberately generous cap for a business running 3.1 turns. A tighter cap makes the number larger.
Step 4. Cross it with ABC on trailing twelve month COGS, and price the decision list.
What it found
Closing inventory of $8,244,494. Trapped: $1,950,584, or 23.7%.
Here is the table Crestline had never seen, because the column it needs does not exist in any system they own:
| Sourcing channel | Purchase dollars | Share | Inventory held | Trapped | Share of trapped | Trapped rate |
|---|---|---|---|---|---|---|
| Replenishment | $45,489,829 | 79.7% | $5,607,739 | $1,019,272 | 52.3% | 18.2% |
| Vendor program | $8,736,456 | 15.3% | $1,906,647 | $762,789 | 39.1% | 40.0% |
| Buyer judgment | $1,927,496 | 3.4% | $528,191 | $129,281 | 6.6% | 24.5% |
| Customer-driven | $952,627 | 1.7% | $200,089 | $37,416 | 1.9% | 18.7% |
Read the last column first. A dollar bought on a vendor program is 2.2 times more likely to end up trapped than a dollar bought on replenishment. A dollar bought on buyer judgment is 1.3 times more likely.
Read the middle columns second. Vendor programs and buyer judgment together are 18.7% of purchase dollars and 45.7% of the trapped cash. Roughly a fifth of the buying produced nearly half of the problem.
Two supporting facts that make the mechanism concrete:
- 47.4% of vendor program dollars are committed in the last 21 days of a quarter, against 28.6% for purchasing as a whole. The buying is driven by the supplier's calendar, not Crestline's demand.
- Program orders routinely include SKUs with no sale in the prior twelve months. Replenishment, by construction, never does. That single contrast is the strongest signal in the entire dataset.
And the concentration by class:
| ABC class | Inventory | Trapped | Share of trapped |
|---|---|---|---|
| A | $4,810,119 | $271,817 | 13.9% |
| B | $1,424,194 | $232,219 | 11.9% |
| C | $2,010,181 | $1,446,548 | 74.2% |
The largest single block in the whole analysis is C class inventory bought on vendor programs and replenishment: $625,476 and $673,962 respectively. Slow items, bought in quarter end bulk, against a rebate tier.
The decision list
Not a plan. Four decisions, each attached to a number.
| # | Decision | Value |
|---|---|---|
| 1 | Exercise unused return rights on program stock still inside supplier terms | $243,999 |
| 2 | Stop buy list: 1,003 SKUs with no sale in 180 days, suppressed from all program orders | $217,795 |
| 3 | Run down buyer judgment bets that never established demand | $19,328 |
| 4 | Clear special order residue left after customer orders shipped | $6,807 |
| Recoverable within two quarters | $488,386 |
The recovery assumptions are explicit and conservative: 45% of aged program stock, 30% of buyer judgment stock, 22% of replenishment excess, 20% of customer-driven residue, applied only to stock already older than 180 days. They are assumptions, and they are the first thing to test against Crestline's actual supplier agreements.
$488,386 against a $8.24M inventory position. It does not fix the business. It funds the thing that does, which is the next section.
Making it permanent, in the system they already own
The diagnostic reconstructs the field backwards. Keeping it requires capturing it forwards, and that takes two seconds per purchase order.
In the inventory system this is one custom field on the purchase order: a dropdown with four values. It shows on every purchase order. The system does not force it to be filled in, so making it a habit is a rule for the buyers, not a system setting. Crestline already uses custom fields on products. The same mechanism applies to purchase orders. No customisation, no third party tool, no change to how orders are raised.
Once that field is populated it appears as a column on the purchase order detail report. The system does not build custom reports, so stock on hand by channel and the trapped cash table are still produced outside the system, from the same exports, each month. The difference is that nothing has to be reconstructed first, so it becomes a standing monthly report instead of a project.
The sequencing matters more than the mechanics. Nobody adds a required field because a consultant recommended it. They add it after they have seen $488,386 sitting in one of the four buckets. Then it is obvious, and the buyers stop arguing about it.
Diagnostic proves the number. The number justifies the field. The field needs a system that can hold it and report on it. Every step is something the business asked for.
Where the AI actually sits
Not in forecasting. Not in optimisation. In one place only: reading the evidence.
The method was scored twice against the held out truth, and the gap between the two runs is the entire AI argument:
| Pass | Evidence used | Orders correct | Purchase dollars correct |
|---|---|---|---|
| A | Structured fields only | 80.9% | 88.9% |
| B | Structured fields plus the free text Note | 90.8% | 93.6% |
43.3% of purchase orders carry no note at all. Of the ones that do, the text is written by three different people with no convention and no template:
BUY-IN, 3% OFF INVOICE·pre-buy ahead of Jan increase·stock up before price increase Dec1qtr end program buy·release for Tulare Dairy Systems blanket·backorder Valley Ag Equipmentstocking order - new item·house brand intro·trying this vs Valmount·min/max
No regular expression covers that. No dropdown was ever going to be filled in retrospectively. But a language model reads it the way a buyer reads it, and it moves order level accuracy by ten points and dollar level accuracy by five.
Results are returned at three confidence levels. The high confidence set, where the note and the structural evidence agree, was 100% correct and covers $21.3M of purchase value. The uncertain orders are flagged for the buyer to confirm rather than guessed at. You do not need perfect classification. You need enough to show the pattern holds, and a clear list of what to check.
What changed for the CFO
Before, the answer to the bank was that inventory went up $2.1M and management was looking at it.
After, the answer is that 18.7% of purchase dollars flow through two discretionary channels, those channels hold 45.7% of the trapped cash, $488,386 is recoverable within two quarters, and every purchase order from this month forward carries the field that tracks it.
That is the difference between a number you carry into the room and a number you can defend in it.
How to read this, and what it does not prove
- Crestline is constructed. The dataset was generated, then analysed as if it had arrived from a client. The generator and the analysis are separate scripts and the analysis never reads the answer key until the scoring step.
- Accuracy figures are measured against constructed ground truth, which is a fair test of the method's logic and not a promise of the same percentage on live data. On a real engagement, accuracy is established by having the buyer confirm a labelled sample in the first working session, which is also how the thresholds get calibrated.
- The classification thresholds were calibrated on this dataset. That is the method, not a shortcut. They would be recalibrated for any real business.
- The recovery rates in the decision list are assumptions, stated above, and would be replaced by the actual supplier terms.
- The $488,386 is a working capital release, not profit. It converts stock into cash. Margin effects depend entirely on the terms each item comes back under.
- Reproduce it:
python scripts/generate_data.pythenpython scripts/analyze.py.
If this sounds like your balance sheet
The pattern shows up wherever purchasing runs through more than one decision process and only one of them is visible in the reporting. If your inventory has grown faster than your revenue and nobody can tell you which decisions did it, that is the same gap.
I work with CFOs and owners of industrial distributors and manufacturers to find where inventory decisions are quietly draining cash, through advisory diagnostics, workshops, speaking and coaching.
