Part 1 of 2
Cart Assignment — Level 1
Which cart does each order go on? This is the first problem to solve — and the most critical. Everything in Part 2 depends on getting this right.
Part 1 — Section 02

Cart Types & Capacities

LifeSeasons uses seven cart types. All capacities, bin counts, and physical cart quantities are now confirmed. Dynamic and Distributor are identified but sit outside the main batching algorithm.

Green Cart (5×9)
45 bins
Small multi-product orders through the auto-bagger. 9 carts in warehouse. (confirmed)
Per bin: 3 bottles
3 bottles per bin due to current bag size — confirmed. Cannot include restricted SKUs (272, 284, 503, 307, 317, 369) — these are too large for the auto-bagger. Classification proxy: ≤3 unique shelf locations AND ≤3 total bottles. SKU 505 is NOT on the exclusion list (confirmed by Sherry).
Red Cart (2×5)
10 bins
Large orders, 29–80 bottles. 10 carts in warehouse. (confirmed)
Per bin: max 80 bottles
Sherry stated explicitly: “80 bottles is our limit to how many bottles can fit in one red bin.” Orders with >80 bottles fall back to the mailer cart. 10 physical carts in the warehouse.
Mailer Cart
80 bins regular
NQ-prefix & mailer SKUs, or bulk fallback (>80 bottles). 12 carts in warehouse. (confirmed)
Per bin: infinite
Regular mailer: 80 bins, 12 carts. No physical bottle limit per bin. Triggers: orders containing the mailer insert SKUs (9085, 9136, 9137, 9138). NQ-prefix orders only go on mailer if the mailer + insert SKU is in the order — otherwise they route by size (bag or basic box). Also the overflow fallback for any order >80 bottles. SKU 505 routes to mailer (yellow cart removed).
NQ Pre-Kit Cart
120 bins
Pre-kitted NeuroQ orders. 12 carts in warehouse. (confirmed)
Per bin: infinite
Larger pre-kit variant of the mailer cart: 120 bins per cart, 12 carts. No physical bottle limit per bin. Used for pre-kitted NeuroQ orders specifically.
Pack-One Cart
200 bins
Single-product orders, 1 line, 1–3 bottles. 6 carts in warehouse. (confirmed)
Per bin: 1–3 bottles
Fastest pick type — every bottle is the same product so the picker grabs a pre-prepped box. 1 line item, 1–3 bottles per bin, 200 bins per cart, 6 carts. Our proxy: exactly 1 unique shelf location AND ≤3 total bottles.
Blue Cart (4×7)
28 bins
Standard multi-product orders up to 28 bottles. 6 carts in warehouse. (confirmed)
Per bin: ≤28 by rule
Standard: Orders with ≤28 bottles. Max 28 per bin by rule. 6 physical carts in warehouse.

Vertical config: SKUs 272 and 284 (large boxes, can’t go in auto-bagger) use all 7 bins in a single column for one order.
Dynamic Cart
1 bin
Exception / hold cart for orders outside the standard batching flow. 4 carts in warehouse. (confirmed)
Per bin: infinite
1 bin per cart, no bottle limit per bin, 4 carts in warehouse. Used as a manual hold — orders are assigned here when they need extra attention, isolation, or a holding pattern. This is always a human decision; it cannot be automated. Not included in the batching algorithm.
Distributor Cart
100 bins
Wholesale distributor orders. Detected via CustomField2. 3 carts in warehouse. (confirmed)
Per bin: infinite
100 bins per cart, no bottle limit per bin, 3 carts in warehouse. Identified by CustomField2 = “Distributor Order” or “Distributor Health Concerns” in the WMS export. Classified first in the hierarchy (step 1). Wholesale only — not DTC. Assigned to specific people by Sherry.

Auto-Bagger Exclusions — Confirmed List

These SKUs cannot go through the auto-bagger (too large or boxed). They must be routed to blue or red carts instead of green. Confirmed by Ben and Sherry (SKU 505 is not on this list — confirmed by Sherry):

SKU 272 SKU 284 SKU 503 SKU 307 SKU 317 SKU 369
Part 1 — Section 03

Sherry's Current Assignment Process

Part 1 — Section 04

Brand & Priority Breakdown

From the 930 usable orders in the ~10-day sample. Brand is detected from item number prefixes. Orders from different brands are never grouped into the same batch.

Brand Breakdown

Detected from item number prefixes. Orders from different brands are never grouped into the same batch.

Health Concerns
44 orders
Items start with HC. In our sample all are wholesale (UPS Ground). Ben listed HC as a D2C channel — needs clarification (see Q3 below).
NGVC / Private Label
54 orders
Items start with PL-NGVC. Natural Grocers Vitamin Cottage. Stored on Speed Cell 3. Never mixed with HC.
LifeSeasons / Other
832 orders
All other brands (Femitry, Inner Eco, standard LS). Can share batches with HC or NGVC per Ben, but HC and NGVC never share a batch.

Priority Breakdown

Wave 1 — Urgent (DTC)
570 orders
Hyphenated order numbers (e.g. 4046858-3990825). All carry OrderLogix in CustomField4 in current data. Need updated export with Shopify store names.
Wave 2 — Standard
360 orders
Plain numeric order numbers. Wholesale (Sage) or blank CustomField4. UPS Ground shipping.
Part 1 — Section 05

Open Questions for LifeSeasons

Four gaps need clarification before the system can go live. Everything else has been confirmed.

Part 1 — Section 06

Cart Assignment — How the System Runs

This is the full pipeline from raw WMS export files to each order being assigned a cart type. Every decision is made in the sequence shown below — top to bottom, left to right.

📥
Input — WMS Export Files
Two text files exported from the LifeSeasons WMS every morning.
Inventories file
Every shelf location in the warehouse + its pick sequence number (1,563 locations in sample)
History Logs file
Every pick event — order number, item number, shelf location, quantity, batch ID
📄
Parse & Load — real_data_parser.py
Raw text files are read line by line and turned into usable data structures.
load_inventory()
Outputs a location map: shelf name → pick sequence number. Used to order the warehouse route.
load_history()
Filters to PickComplete rows. Outputs a table of order rows with order number, item, location, qty, priority.
📦
Build Orders — build_orders()
Groups all pick rows by order number. For each order, computes: total bottle quantity, unique shelf locations, brand (HC / NGVC / LS), priority (urgent D2C or standard wholesale), and which SKUs it contains.
930 orders extracted 570 urgent (DTC) 360 standard (wholesale)
🛒
Cart Classifier — 8-Step Hierarchy
Each order passes through these checks top to bottom. The first match wins. Remaining orders fall to the next step.
1
Mailer cart — NQ order prefix or SKU 9085 (Symmetry). Cap 80. mailer
2
Yellow cart — SKU 505 (My Best Heart, crushable). Cap 40 (5×8). Falls to blue if volume low. yellow
3
Blue-forced — SKUs 272 or 284 (large boxes). Must go on vertical blue cart (4×7). Cannot go in auto-bagger or any smaller cart. blue (forced)
4
Pack-one cart — Real rule: every bottle is the same product, 1–12 bottles. Proxy we use: exactly 1 shelf location AND ≤12 bottles (we can't see product identity in the data). Cap ~44 (derived from data, unconfirmed). pack_one
5
Green cart — Real rule: 2–3 distinct products, fits small bag. Proxy we use: ≤3 unique shelf locations AND no auto-bagger-excluded SKUs (272, 284, 503, 307, 317, 369, 505). Uses auto-bagger. Cap 45 (5×9). green
6
Blue cart — Total bottles ≤28. Standard upright bins. Cap 28 (4×7). blue
7
Red cart — Total bottles 29–80. Large bins, up to 80 bottles per bin. Cap 10 bins (2×5). red
8
Mailer fallback — Total bottles >80. Bulk orders too large for any cart. mailer
Yellow Fallback Check — apply_yellow_fallback()
After classification, count all yellow-cart orders. If fewer than 5 MBH orders exist today, reclassify them to blue — not enough volume to pull a dedicated yellow cart. Threshold (5) is unconfirmed; need to ask Sherry.
🔄
Brand & Priority Split
Each order now has: cart_type + brand (HC / NGVC / LS) + priority (1=urgent, 2=standard). These three together define which batching pool the order belongs to. HC and NGVC orders are never placed in the same batch. Priority 1 (DTC) is processed before priority 2 (wholesale).
HC
44
orders
NGVC
54
orders
LS / Other
832
orders
Output — Orders Assigned to Cart Types
Every order now has a confirmed cart type, brand label, and priority. This is the input to the batch optimization algorithms in Part 2.
483 pack_one
329 green
102 blue
13 red
3 mailer
0 yellow
Part 2 of 2
Batch Optimization — Level 2
Within each cart type, which orders get grouped together? Nobody does this today. Our algorithms tackle it — and the results are significant.
Part 2 — Section 01

What Is Batch Optimization?

Once orders are assigned to a cart type (Part 1), there is a second decision: within that cart type, which specific orders get grouped into one batch? For example, if you have 100 blue cart orders, you need roughly 4 batches of 28. Which 28 go together in each batch?

Sherry does not currently optimize this. She assigns orders to batches based on what fits — not on which orders are physically closest on the shelves. This is the gap our algorithms fill. Grouping orders that pick from nearby shelf locations means the worker walks a shorter total distance per batch.

930
Orders tested
~10 days of real LifeSeasons data
1,563
Shelf locations
Mapped with pick sequence numbers
4
Algorithms tested
vs. WMS and random baseline
Part 2 — Section 02

Route Cost Model

We do not have the physical warehouse floor plan yet. As a proxy, route cost is:

Route Cost = 2 × max pick sequence in batch Walk from depot (seq = 0) to the farthest shelf location and back. Applied identically to all methods including WMS.

Known limitation: Pick sequence numbers do not capture cross-aisle travel or real warehouse geometry. The relative ranking of algorithms is reliable. The absolute improvement percentages will change once we have real walking distances from the floor plan.

Part 2 — Section 03

The 4 Algorithms We Tested

Each algorithm runs independently on orders of the same cart type, brand, and priority. Green cart orders are never mixed with blue cart orders. HC orders are never mixed with NGVC orders.

Baseline

Jaccard Greedy

  • Seed batch with farthest-location order
  • Fill by shared location overlap score
  • Fast, simple, good comparison baseline
Enhanced

RAG — Routing-Aware Greedy

  • Same seed as Jaccard
  • Screen top-15 by Jaccard similarity
  • Pick the one that adds the least route cost
Winner

Clarke-Wright Savings (CW)

  • Calculate savings from merging every pair of orders
  • Merge highest-savings pairs first
  • Industry-standard vehicle routing algorithm
  • Best performance across all metrics
Variant

CW + Consolidation

  • Run CW, then merge small batches to fill carts
  • Slightly worse than CW alone with smaller cart sizes
  • Not recommended for current capacity profile
Part 2 — Section 04

Results

All numbers use real LifeSeasons data (930 orders, ~10 days). Per-cart-type capacities applied. Brand and priority grouping enforced. Lower average route cost = less walking = better.

Average Route Cost Comparison
Lower bar = less walking = better. Scaled to Random baseline (59,118).
Random (no system)59,118
Baseline
no optimization — random grouping within cart types
WMS (current system)51,901
+12.2% vs Random
current production — modest improvement over random grouping
Jaccard Greedy49,944
+15.5% vs Random  |  +3.8% vs WMS
location-overlap grouping
RAG (Routing-Aware Greedy)49,944
+15.5% vs Random  |  +3.8% vs WMS
marginal cost minimization
Clarke-Wright Savings  Best43,439
+26.5% vs Random  |  +16.3% vs WMS
pairwise savings merging — clear winner
CW + Consolidation46,467
+21.4% vs Random  |  +10.5% vs WMS
slightly worse than CW alone — consolidation merges orders from different shelf areas
MethodAvg Route Costvs Randomvs WMSStatus
Random (no system) 59,118 baseline No optimization
WMS (current) 51,901 +12.2% better baseline In production
Jaccard Greedy 49,944 +15.5% better +3.8% better Tested
RAG (Routing-Aware Greedy) 49,944 +15.5% better +3.8% better Tested
Clarke-Wright Savings 43,439 +26.5% better +16.3% better Top Performer
CW + Consolidation 46,467 +21.4% better +10.5% better Tested

Clarke-Wright is the clear winner — 16.3% better than the current WMS on average route cost. Note that the WMS was free to mix priority 1 and priority 2 orders in the same batch, while our algorithms are constrained to never mix priorities. Despite this handicap, CW still wins by 16.3%, making the result stronger than it appears.

Part 2 — Section 05

Limitations & What's Next

The Distance Problem

Route cost is currently 2 × max pick sequence. This assumes location 10,000 is exactly double the distance of location 5,000 — not true in a real warehouse with aisles, cross-aisle travel, and physical geometry.

Fix: replace pick sequence with real Manhattan distances from the actual warehouse floor plan. All four algorithms immediately improve, and numbers become exact rather than approximate.

What We Need for Part 2 to Be Exact

Current State vs After Answering Open Questions
Right Now
Pick-sequence proxy for distance
~10 days of historical data
Pack-one / green / mailer capacity estimated
Cart assignment rules partially confirmed
CW already 16.3% better than WMS
After Open Questions Answered
Confirmed cart classification for all order types
Exact capacities for every cart type
Accurate D2C / SLA detection with order creation time
Real warehouse geometry for exact distances
Confirmed dollar figure on labor savings per day