Skip to content

Commit df423c5

Browse files
privatejoelclaude
andauthored
feat: model structural overhang vs bleed-off; fix net-benefit triviality (#2)
Addresses the core critique that "above-target" is not the same as "liquidate" — under steady demand you pause replenishment and let stock bleed off; you only clear inventory that won't self-resolve. Model: - New `clearWindowMonths` patience window. Above-target stock that sells through within it is "Bleeding Off" (no clearance); only the remainder is a "Structural Overhang" and the actionable base for carry/clear. - Carry-vs-clear and recapture now compute on the overhang, not gross excess, so the rule stops trivially firing on everything. - Recalibrated demand so the slow segments (EV, luxury) carry genuinely soft run-rates → a real months-long overhang, telling the EV-glut / slow-luxury story for the right reason. Fast pools (Tucson) read "Bleeding Off". Every documented figure reproduces from the data. - New statuses Overhang / Bleeding Off; dashboard gains a bleed-off window slider, a months-to-clear reality check, and per-row gating. Docs (METHODOLOGY.md): - §3/§5 rewritten for the two-step rule; §7 baseline refreshed. - New §11 (OEM-owned vs dealer-floorplanned capital) and §12 (the liquidation channel ladder: incentive / fleet / auction + residual hit). Baseline now: $2.80B deployed, $603M above target, of which only $320M is structural overhang; $58M/yr carry, $19M clearance, $301M recaptured, $38M net, $216M stockout gap fully covered. Verified: tsc --noEmit clean; vite build; data reproduces docs exactly. Co-authored-by: privatejoel <privatejoel@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f62d3df commit df423c5

3 files changed

Lines changed: 256 additions & 113 deletions

File tree

METHODOLOGY.md

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,35 @@ the narrative is coherent, not pulled from Hyundai's actuals.
2222

2323
## 3. Core formulas
2424

25+
The central correction over a naive DSI model: **above-target stock is not automatically a
26+
liquidation candidate.** Stock that will sell through within a patience window at current
27+
demand should simply have its replenishment paused — it *bleeds off* at no clearance cost.
28+
Only the residual still sitting after the window is a **structural overhang** worth a
29+
clearance haircut. This is what stops the model from recommending you discount demand you
30+
already have.
31+
2532
```
2633
dailySales = avgMonthlySales × (1 + demandShift) / 30
2734
DSI = stock / dailySales # days of inventory on hand
2835
targetStock = targetDSI[category] × dailySales
29-
excessUnits = max(0, stock − targetStock)
30-
excessCapital = excessUnits × unitCost
31-
carryingOnExcess= excessCapital × carryingRate # annual $ bled on the excess
32-
liquidationLoss = excessCapital × liquidationDiscount # one-time clearance haircut
33-
recaptured = excessCapital × (1 − liquidationDiscount)
34-
netFirstYear = carryingOnExcess − liquidationLoss
36+
excessUnits = max(0, stock − targetStock) # gross above target
37+
windowUnits = dailySales × 30 × clearWindowMonths # what sells within the patience window
38+
bleedUnits = min(excessUnits, windowUnits) # clears organically — no action
39+
overhangUnits = max(0, excessUnits − bleedUnits) # structural overhang — the actionable base
40+
overhangCapital = overhangUnits × unitCost
41+
monthsToClear = excessUnits / (dailySales × 30) # organic sell-through of the excess
42+
43+
carryOnOverhang = overhangCapital × carryingRate # annual $ bled on the overhang
44+
liquidationLoss = overhangCapital × liquidationDiscount # one-time clearance haircut
45+
recaptured = overhangCapital × (1 − liquidationDiscount)
46+
netBenefit = carryOnOverhang − liquidationLoss
3547
portfolioDSI = Σ stock / Σ dailySales # volume-weighted, not a simple average
3648
```
3749

3850
**Status rule (segment-specific, not one universal cutoff):**
3951

40-
- `At Risk``DSI > targetDSI` (over-stocked relative to the segment's velocity)
52+
- `Overhang``overhangUnits > 0` (above target *and* won't clear within the window → clearance candidate)
53+
- `Bleeding Off` — above target but `overhangUnits = 0` (self-resolves once replenishment pauses → no clearance)
4154
- `Stockout Risk``DSI < 0.5 × targetDSI` (too lean; turning away serviceable demand)
4255
- `Healthy` — otherwise
4356

@@ -53,45 +66,63 @@ segments do not. A uniform threshold would contradict the thesis.
5366
| SUV | 60 | Mainstream mid-velocity |
5467
| Volume | 45 | High turnover; lean target protects ROIC |
5568

56-
## 5. Decision rule
69+
## 5. Decision rule (two steps)
70+
71+
1. **Pause, don't dump.** For every above-target pool, first stop replenishment and let it
72+
bleed off. Anything that clears within `clearWindowMonths` never warrants a clearance
73+
haircut — liquidating demand you already have is value-destructive.
74+
2. **Clear the overhang on net benefit.** For the structural overhang that remains, act
75+
**only when `netBenefit > 0`** — the annual carrying cost avoided exceeds the one-time
76+
clearance loss. Because the overhang sits *beyond* the window by construction, annual
77+
carry is the right horizon to weigh against the one-time haircut.
5778

58-
For each above-target pool, act **only when `netFirstYear > 0`** — i.e. the annual
59-
carrying cost avoided exceeds the one-time clearance loss. Recaptured capital is then
60-
redeployed against `Stockout Risk` pools first (relieving lost-sale demand), with the
61-
remainder funding strategic EV / growth priorities. This resolves the
62-
redirect-vs-liquidate distinction: transfer where a constrained pool can absorb units,
63-
clear only where none can.
79+
Recaptured capital is then redeployed against `Stockout Risk` pools first (relieving
80+
lost-sale demand), with the remainder funding strategic EV / growth priorities. This is why
81+
the model clears the IONIQ 5 (soft demand → a months-long overhang) but *not* the Tucson
82+
(above target, yet sells through in days). It also resolves the redirect-vs-liquidate
83+
distinction: transfer where a constrained pool can absorb units, clear only where none can.
6484

6585
## 6. Scenario parameters (defaults & ranges)
6686

6787
| Parameter | Default | Range | Source logic |
6888
|---|---|---|---|
6989
| `carryingRate` | 18%/yr | 8–28% | Floorplan interest (~8%) + depreciation (~7%) + storage/insurance (~3%) |
70-
| `liquidationDiscount` | 6% | 2–15% | Wholesale/auction haircut to clear excess units |
90+
| `liquidationDiscount` | 6% | 2–15% | Wholesale/auction haircut to clear excess units (see §12 for the channel ladder) |
91+
| `clearWindowMonths` | 2 mo | 1–6 mo | Patience window: above-target stock that sells through within it bleeds off rather than being cleared |
7192
| `demandShift` | 0% | −20% to +20% | Demand stress test |
7293

7394
## 7. Baseline results (default assumptions)
7495

7596
| Metric | Value |
7697
|---|---|
77-
| Capital deployed | $2.87B |
78-
| Capital above target | $412M (14% of deployed) |
79-
| Annualized carrying cost on excess | $74M/yr |
80-
| Capital recaptured (net of discount) | $387M |
81-
| One-time clearance loss | $25M |
82-
| First-year net benefit | $49M |
98+
| Capital deployed | $2.80B |
99+
| Capital above target (gross) | $603M (22% of deployed) |
100+
| Structural overhang (actionable) | $320M (11% of deployed) |
101+
| Annualized carrying cost on overhang | $58M/yr |
102+
| Capital recaptured (net of discount) | $301M |
103+
| One-time clearance loss | $19M |
104+
| Net benefit | $38M |
83105
| Stockout-risk funding gap | $216M (fully covered by recaptured capital) |
84-
| Portfolio DSI (volume-weighted) | 50 days |
106+
| Portfolio DSI (volume-weighted) | 52 days |
107+
| Overhang pools / bleeding-off pools | 3 / 1 |
108+
109+
Note the gap between **$603M above target** and the **$320M actually cleared**: ~$283M of
110+
above-target stock bleeds off on its own once replenishment pauses, and is never liquidated.
85111

86112
## 8. Sensitivity (illustrative)
87113

88-
- **Carrying rate is the swing factor.** At 8% the annual bleed falls to ~$33M and several
89-
pools no longer clear the net-benefit hurdle; at 28% it rises past ~$115M and clearance is
90-
obviously worth it. This is why the rate assumption must be owned by Finance, not assumed.
91-
- **Clearance discount** mostly affects *how much* is recaptured, not *whether* to act,
92-
until it approaches the carrying rate.
93-
- **Demand shift** moves pools across thresholds — a −10% shock pushes additional volume/SUV
94-
pools above target; +10% relieves them. The status logic recomputes live.
114+
- **The bleed-off window decides how much is even actionable.** This is the parameter that
115+
encodes "don't liquidate demand you still have." At a 1-month window more above-target stock
116+
counts as overhang; widen it toward 6 months and most pools are judged self-resolving, so the
117+
overhang — and the recommended clearance — shrinks toward zero. At the 2-month default, $320M
118+
of the $603M above-target is overhang.
119+
- **Carrying rate** scales the annual bleed on the overhang (≈$26M at 8%, ≈$90M at 28% on the
120+
baseline overhang) and, with the discount, sets whether clearing clears the net-benefit hurdle.
121+
It must be owned by Finance, not assumed.
122+
- **Clearance discount** mostly affects *how much* is recaptured, not *whether* to act, until it
123+
approaches the carrying rate.
124+
- **Demand shift** moves pools across thresholds and resizes the overhang — a −10% shock lengthens
125+
sell-through (more overhang); +10% lets more stock bleed off. The status logic recomputes live.
95126

96127
## 9. Known limitations (and the honest next steps)
97128

@@ -100,8 +131,9 @@ clear only where none can.
100131
- **Contribution margin not modeled**, so redeployment upside is stated as the funded demand gap,
101132
not an incremental-profit figure. *Next step: per-segment margin to value recaptured capital.*
102133
- **Steady-state demand** — no seasonality, model-year transitions, or incentive elasticity.
103-
- **Single-period view**`netFirstYear` mixes a recurring annual saving with a one-time loss;
104-
a full NPV would discount multi-year carrying savings. *Next step: multi-period NPV.*
134+
- **Single-period view**`netBenefit` weighs one year of carry on the overhang against a one-time
135+
loss. The bleed-off window removes the cruder "annual-vs-one-time always clears" bias, but a true
136+
model would integrate carry over each pool's expected hold path. *Next step: multi-period NPV.*
105137
- Figures are illustrative and not Hyundai actuals.
106138

107139
## 10. Retail & DMS layer
@@ -147,3 +179,39 @@ from the OEM layer, now visible as floorplan cost.
147179
yet modeled (would quantify the *margin* cost of aging, not just floorplan); dealer-trade
148180
logistics cost is assumed negligible; and a live DMS integration (vs. illustrative aging
149181
vectors) is the obvious productionization step.
182+
183+
## 11. Whose capital is it — OEM vs. dealer floorplan
184+
185+
A deliberate simplification worth stating plainly: the OEM layer values the **entire** national
186+
pipeline at OEM wholesale cost and frames clearing it as recovering OEM capital. In reality,
187+
once a unit is wholesaled to a franchised dealer it sits on the **dealer's floorplan**, not the
188+
OEM's balance sheet — which is exactly what the Retail & DMS layer (§10) measures. The two
189+
layers describe the same metal from two balance sheets:
190+
191+
| Stage | Who owns it | Where the carry lands |
192+
|---|---|---|
193+
| In production / in-transit / port / unallocated | **OEM** | OEM working capital |
194+
| Allocated & wholesaled to a dealer (on the lot) | **Dealer** | Dealer floorplan interest (Retail layer) |
195+
196+
The OEM's *direct* capital-at-risk is therefore the un-wholesaled slice plus its exposure to
197+
incentives and residual support; the on-lot overhang is borne by dealers and influenced by the
198+
OEM through **allocation and incentive policy**, not by repossessing units. Figures are stated on
199+
a single OEM-wholesale-cost basis for clarity, with the dealer view reconciled in §10. *Next step:
200+
split the pipeline into OEM-owned vs. dealer-floorplanned and carry each at its own rate.*
201+
202+
## 12. How the overhang actually clears (the "6%" unpacked)
203+
204+
`liquidationDiscount` is a single blended haircut; in practice clearance runs down a ladder of
205+
channels, each with a different cost and side effect — there is no single anonymous buyer:
206+
207+
| Channel | Buyer | Typical haircut | Side effect |
208+
|---|---|---|---|
209+
| Retail incentive | Ordinary retail customer | ~2–8% (subvented APR/lease, cash) | Pulls demand forward; brand-equity drag on luxury |
210+
| Fleet / commercial | Rental & commercial fleets | ~8–15% | Floods the used market later → **depresses residuals** |
211+
| Dealer trade / wholesale | Other dealers | ~10–20% | Logistics cost; limited absorbing capacity |
212+
| Auction / remarketing | Dealers & exporters | ~15–30% | Last resort for 90+ day units (see §10 curtailment) |
213+
214+
The default 6% corresponds to a **modest retail-incentive bump** — the cheapest rung. The model
215+
does not yet price the residual-value contamination from the fleet/auction rungs, which would feed
216+
back into a higher effective EV carrying rate. *Next step: a channel-mix input that blends the
217+
haircut and routes the residual hit back into `carryingRate`.*

README.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,27 @@ one place while demand goes unserved in another.
1818
## The approach
1919

2020
Measure each model's **Days Sales of Inventory (DSI)** against a **segment-specific target**,
21-
then apply a **net-benefit decision rule**: clear above-target inventory *only when the annual
22-
carrying cost avoided exceeds the one-time clearance loss*, and redeploy the recaptured capital
23-
to relieve stockout-risk segments first.
21+
separate stock that will **bleed off on its own** (just pause replenishment) from a genuine
22+
**structural overhang**, then clear only that overhang *when the annual carrying cost avoided
23+
exceeds the one-time clearance loss* — redeploying the recaptured capital to relieve
24+
stockout-risk segments first. The point of the bleed-off step: never discount demand you
25+
already have.
2426

2527
## Key results (illustrative baseline)
2628

2729
| Metric | Value |
2830
|---|---|
29-
| Capital deployed | **$2.87B** |
30-
| Capital above segment target | **$412M** (14%) |
31-
| Annualized carrying cost bled | **$74M/yr** |
32-
| Capital recaptured | **$387M** |
33-
| First-year net benefit | **$49M** |
31+
| Capital deployed | **$2.80B** |
32+
| Capital above segment target (gross) | **$603M** (22%) |
33+
| Structural overhang (won't bleed off) | **$320M** (11%) |
34+
| Annualized carrying cost on overhang | **$58M/yr** |
35+
| Capital recaptured | **$301M** |
36+
| Net benefit | **$38M** |
3437
| Demand-constrained gap funded | **$216M**, fully covered |
3538

36-
The recaptured capital more than covers the volume shortfall — the EV-glut and slow-luxury pools
37-
fund the lean volume line, with ~$171M left for strategic priorities. Full derivation in
39+
Most above-target stock isn't cleared — it *bleeds off* once replenishment pauses; only the **$320M
40+
structural overhang** (EV-glut + slow-luxury) is liquidated. The recaptured capital more than covers
41+
the volume shortfall, with **~$85M** left for strategic priorities. Full derivation in
3842
[METHODOLOGY.md](./METHODOLOGY.md).
3943

4044
## How it's structured
@@ -43,9 +47,10 @@ The app is organized as four role-targeted views:
4347

4448
1. **Strategy Brief** — answer-first recommendation with quantified impact, then a
4549
Situation / Complication / Resolution case. *(Consulting framing.)*
46-
2. **Decision Dashboard** — segment-targeted DSI table, corrected and accurately-labeled KPIs,
47-
a ranked net-benefit recommendation engine, and **live scenario sliders** (carrying rate,
48-
clearance discount, demand shift) so every figure can be stress-tested. *(Planning / analytics.)*
50+
2. **Decision Dashboard** — segment-targeted DSI table that separates a **structural overhang**
51+
from above-target stock that simply **bleeds off**, accurately-labeled KPIs, a ranked
52+
net-benefit recommendation engine, and **live scenario sliders** (carrying rate, clearance
53+
discount, bleed-off window, demand shift) so every figure can be stress-tested. *(Planning / analytics.)*
4954
3. **Execution Plan** — phased rollout, RACI decision rights, governance KPIs, and a
5055
risk/mitigation register. *(Program management.)*
5156
4. **Retail & DMS** — drills the OEM thesis down to the dealer P&L: DMS-sourced aging buckets,
@@ -62,6 +67,8 @@ This was deliberately built to survive a probing interview:
6267
and a volume-weighted "Portfolio DSI," not a count ratio mislabeled as a financial return.
6368
- **The headline tradeoff is actually computed** — carrying cost avoided vs. clearance loss, per
6469
pool, with an explicit act/hold rule — not asserted in prose.
70+
- **Above-target ≠ liquidate** — the model strips out inventory that sells through on its own and
71+
only clears the structural overhang, so it never recommends discounting demand you already have.
6572
- **Targets are segment-specific**, consistent with the core thesis.
6673
- **Assumptions are owned and sourced**, with sensitivity and limitations documented openly.
6774

0 commit comments

Comments
 (0)