Noon · 2025
Assortment Rationalisation Framework for Dark Stores
Balancing efficiency, profitability, and customer choice
Analytics & Experimentation | Platform & Operations
Every SKU in every store ends up as keep, review or delist
- Role
- Product Manager
- Timeline
- ~8 weeks
- Worked with
- Category, Merchandising, Supply Chain, Pricing, Store Ops
- Tools
- SQL, BI dashboards, pricing inputs, sales and inventory data
12,400+
SKUs evaluated
90% → 11%
stores above storage capacity
10%
less perishable disposal loss
<1%
conversion drop, add-to-cart to checkout
The problem
A growing long tail of weak SKUs was eating shelf space in dark stores, but low sales alone couldn't tell us whether a SKU was truly weak or just held back.
What I did
Defined an explainable 9-step funnel that separates weak demand from suppressed demand, with guardrails and a disposal override, and recommends an action for every SKU.
The result
12,400+ SKUs evaluated, stores above storage capacity down from 90% to 11%, and 10% less perishable disposal loss, with under 1% drop in conversion.
The ask
As dark store assortments grew, a long tail of low performers started taking up limited shelf space, adding replenishment and picking work, and in some cases driving disposal losses. The business needed a scalable way to decide which SKUs stay, which need help, and which can go.
- 01
Assortment grows
More SKUs added every month
- 02
Long tail expands
Low-velocity SKUs pile up
- 03
Waste increases
Disposal and inventory costs
Low sales is not the same as weak
Removing low sellers looks easy from the outside, but it's easy to remove the wrong SKU. A SKU can sell little for reasons that have nothing to do with demand:
New launch
Not enough data to judge yet.
Low availability
Supply held demand back.
Low discoverability
Customers couldn't find it.
Poor pricing
Priced above competitors.
Niche subtype
Needed to keep the category complete.
Repeat-led demand
Small but loyal audience.
The real question was whether low performance was structural or fixable. Short shelf life adds a third case: SKUs whose disposal risk outweighs what they sell.
Goal and non-goals
Goal
An explainable framework that finds structurally weak SKUs, protects healthy ones early, doesn't penalise suppressed demand, and recommends the right action instead of a binary keep-or-remove.
Non-goals
Not a black-box ML score.
Not a replacement for category judgement on special cases.
Not a full assortment redesign or optimisation engine in V1.
Principles
I designed it as an explainable funnel rather than one composite score, which made it easier to reason about, validate, and trust.
- 01
Protect clearly healthy SKUs early
If a SKU contributes meaningfully to sales or units, it exits the funnel immediately.
- 02
Distinguish weak from suppressed demand
Before concluding demand is low, check whether availability, discoverability or pricing is holding it back.
- 03
Explainability over black-box scoring
Every recommendation traces back to a specific, auditable reason.
- 04
Recommend actions, not just labels
Output 'increase availability' or 'reduce price', not just 'watchlist'. Actionable outputs drive adoption.
- 05
Preserve subtype and assortment integrity
Never delist every SKU in a subtype. Keep at least one so the category has no gaps.
The signals
The key design decision was keeping suppression signals separate from demand signals. A SKU with low sales and poor availability isn't weak, it's constrained. For example, availability below 60% counted as suppression, not performance.
- Demand
How much it sells
GMV contribution, units contribution, dark store penetration, subtype penetration.
- Suppression
What holds it back
New SKU check, availability (% days in stock), discoverability (impressions, conversion, visibility).
- Commercial
Price and loyalty
Price competitiveness vs the lowest competitor price, and repeat purchase index (repeat buyers / unique buyers, 90 days).
The 9-step funnel
Every SKU enters at the top and is checked in order. At each step it either exits with a clear recommendation or moves on. Only SKUs that fail all nine checks are recommended for delisting.
Phase 1: remove clear winners
- 01
Sales contributionActive if top 80% GMV
- 02
Units soldActive if top 80% units
Phase 2: check for fixable constraints
- 01
Dark store penetrationActive if high store spread
- 02
New SKU checkWatchlist if recently launched
- 03
AvailabilityWatchlist if below 60%
- 04
DiscoverabilityWatchlist if low impressions, high conversion
Phase 3: evaluate structural strength
- 01
Subtype penetrationActive if high subtype share
- 02
Pricing (price competitiveness score)Watchlist if overpriced vs market
- 03
Repeat purchaseWatchlist if high repeat index
Disposal override
Perishable and short shelf-life SKUs needed separate treatment. Some weren't just weak, they actively lost money because expected sell-through didn't justify the disposal risk. A SKU can convert decently and still lose money if its shelf life doesn't match how fast it sells.
Guardrails
New launch protection
Recently launched SKUs are excluded until there's enough data to judge them.
Availability distortion
SKUs with under 50 to 80% availability go to the watchlist, since low sales may be supply-driven.
Subtype wipeout prevention
If every SKU in a subtype is flagged, the best seller stays as a fallback.
Premium niche protection
Low volume doesn't mean low value. High-margin niche SKUs go to manual review.
Loyalty-driven SKUs
SKUs with a high repeat purchase index stay even at low volume, because they serve loyal customers.
Price correction path
Overpriced SKUs go to price correction instead of delisting. The problem is commercial, not structural.
Three outcomes
- Active
Structurally healthy
Keep in the assortment.
- Watchlist
Could recover with help
Fix the underlying issue: new SKU, availability, discoverability, price, forecasting, repeat buyers, or subtype protection.
- Delist
Still weak after every check
Remove from the assortment.
In most watchlist cases, one fixable constraint was the difference between recovery and removal. Three example walkthroughs (SKU names are illustrative; signals and outcomes are from real framework outputs):
What it found
- 01
12,400+
SKUs evaluated
- 02
62%
recommended active
- 03
23%
moved to watchlist
- 04
15%
recommended delist
Freed shelf space went to new SKU trials, and some of them became high performers within the review period.
How it ran
The framework ran monthly on the 28th. Each category manager got an email with their category's watchlist and delist recommendations, and the reasoning behind each flag.
- 01
Historical backtesting
Run against the past 90 days and compare with actual delist outcomes.
- 02
False positive analysis
Audit delist recommendations with high cart inclusion or high margin.
- 03
Monthly category emailer
Flagged SKUs and reasoning sent to category managers each cycle.
- 04
30/60/90-day monitoring
Track disposal rate, availability and space utilisation after delisting.
- 05
Space reallocation simulation
Model the impact of freed space on category revenue.
- 06
Auto-delist on the 5th
SKUs with no category manager action or comment by the 5th were delisted automatically.
What I'd build next
V1 was kept explainable and rule-based on purpose, so category managers could trust it and override it. Later versions move from flagging weak SKUs to optimising what replaces them.
- V1 · Current
Explainable funnel
Rules-based, 9-step sequential evaluation, with disposal override logic.
- V2 · Near term
Sharper economics
Profitability per cubic volume, cart breaker score, customer returns analysis, better price sensitivity logic.
- V3 · Future
Optimised assortment
Optimisation-based planning, storage-type-aware decisions, and allocation constrained by demand, margin and volume.
Built at Noon · 2025