SKILL: Northwind Components ERP — Inventory / Order-Fulfillment Operations
Transferable, executable playbook for the Northwind Components ERP benchmark
(inventory status, order release, allocation/transfer, replenishment, supplier
incident scorecards, quality-hold control). Built from working the live API.
0. REMOTE API — how to use it
Base URL (ALWAYS use this; ignore any "127.0.0.1:8007" or local-env mention in
task prompts — those are stale):
<remote-env-url>
GET endpoints (all JSON):
/health — manifest, record counts, seed.
/products /products/<sku> — product master.
/customers /customers/<customer_id> — account/risk master.
/suppliers — supplier master (incl. quality_status).
/warehouses — 3 warehouses: WH_NORTH (07102), WH_CENTRAL (60607), WH_WEST (89502).
/inventory?warehouse_id=&sku= — stock rows.
/purchase_orders?supplier_id=&sku=&status= — POs. status ∈ open|confirmed|received|cancelled.
/orders?wave=&required_date=&customer_id= /orders/<order_id> — sales orders.
/shipping/quote?warehouse_id=&destination_zip=&weight_lb=&speed= — speed ∈ ground|two_day|overnight.
/incidents?start=&end=&supplier_id=&sku=&incident_type=&status= — quality incidents.
/boms /boms/<bom_id> — kit bills of material.
All listed query params work as filters and compose (AND). Always pull a wave with
/orders?wave=WAVE_ID and fetch /orders/<id> only if you need a single record.
Key record fields
- product:
sku, name, category, active(bool), safety_stock(int), overstock_threshold(int), unit_cost, weight_lb, supplier_id
- customer:
customer_id, name, account_status(active|review_required|blocked), risk_flag(none|credit_watch|fraud_watch), tier(strategic|standard|economy), margin_band
- inventory:
warehouse_id, sku, on_hand, reserved, quarantined, last_count_date
- purchase_order:
po_id, supplier_id, sku, warehouse_id, quantity, status, eta
- order:
order_id, customer_id, warehouse_id, destination_zip, shipping_speed, required_date, priority, wave, lines[{line_id, sku, quantity, unit_price}]
- incident:
incident_id, supplier_id, sku, warehouse_id, incident_type(RMA|WORK_ORDER), severity(low|medium|high|critical), status(open|closed), open_date, close_date(nullable), resolution_cost, root_cause
- bom:
bom_id, name, warehouse_id, target_date, components[{sku, quantity_per_kit}]
1. CORE FORMULAS (memorize — used everywhere)
Effective available (the only "freely usable" quantity; reserved + quarantined
are protected and NOT available):
effective_available = on_hand - reserved - quarantined
If no inventory row exists for (warehouse, sku), treat effective_available = 0.
Effective available can be negative; clamp ship quantities at 0 (never ship < 0).
Transferable surplus from a source warehouse (do not dip into safety stock):
transfer_surplus(src, sku) = effective_available(src, sku) - safety_stock(sku)
Only positive surplus is movable. Safety stock and quarantine/reserved are protected.
Shipping quote — call the API; it returns the answer directly. Do NOT recompute.
The endpoint internally uses
base_rate = 8.75 + 3.40*zone_distance + 1.18*weight_lb, then
total_cost = base_rate * speed_mult * (1 + fuel_surcharge_rate) with
speed_mult ground=1.0, two_day=1.75, overnight=2.65 and fuel_surcharge_rate≈0.0925.
You only need to: compute the order's total weight, hit the endpoint, and copy
zone_distance(int), service_days(int), total_cost(→total_cost_usd, 2 dp).
order_weight_lb = sum(product.weight_lb * line.quantity) over ALL order lines
Quote per order using the order's own warehouse_id, destination_zip, total
weight, and the order's shipping_speed (unless a memo names a specific speed).
2. INVENTORY STATUS CLASSIFICATION (per order, rolled up from lines)
Classify each line, then roll the order up by the precedence below.
Per line at the order's requested warehouse:
- shortage if line is active but
effective_available < quantity.
- inactive if
product.active == false (a product-master problem).
- low_stock if active and ships fully (
effective_available >= quantity) but
effective_available < safety_stock (stock already below safety buffer).
- otherwise ready.
A single line can be BOTH inactive and short (inactive product whose eff_avail <
quantity) → it goes in both lists.
Order-level inventory_status enum precedence (highest first):
inactive_and_shortage — any inactive SKU AND any shortage SKU present.
inactive_sku — any inactive SKU (no shortage).
shortage — any shortage SKU.
low_stock — any low-stock SKU.
ready — none of the above.
Per-order SKU lists (each sorted ascending):
shortage_skus = active SKUs with eff_avail < qty (plus inactive-and-short SKUs).
inactive_skus = SKUs whose product.active is false.
low_stock_skus = active, fully-shippable SKUs with eff_avail < safety_stock.
3. CUSTOMER EXCEPTION CLASSIFICATION
From the customer master. customer_exception enum, precedence (highest first):
account_blocked — account_status == blocked (HARD stop, beats any risk flag).
fraud_watch — risk_flag == fraud_watch.
credit_watch — risk_flag == credit_watch.
review_required — account_status == review_required.
none — active account, risk none.
A blocked account that is also credit_watch resolves to account_blocked.
4. ORDER-RELEASE DECISION MATRIX (expedite/dispatch tasks)
Decide final_decision + next_action by precedence — customer/account issues
outrank product and stock issues:
| condition (first match wins) |
final_decision |
next_action |
| account_blocked |
reject_hold |
hold_credit_or_fraud |
| fraud_watch OR credit_watch |
reject_hold |
hold_credit_or_fraud |
| review_required |
manual_review |
send_account_review |
| inactive_sku / inactive_and_shortage |
manual_review |
escalate_product_master |
| shortage |
backorder |
create_backorder |
| low_stock |
delayed_release |
delay_and_monitor |
| ready |
ship_now |
release_to_pick |
Notes:
- A same-week/expedite "exception" request from the customer does NOT override an
account block or risk flag — still reject_hold.
- Always produce the shipping quote even when the decision is not "ship" (a quote
may be explicitly requested regardless of release).
Summary block (expedite task)
order_count = number of orders.
decision_counts = object with integer counts for EACH of the 5 final_decision
enums (include zeros).
total_shipping_cost_usd = sum of every order's quote total_cost (2 dp).
blocked_order_ids = orders with final_decision reject_hold (account/risk holds).
manual_review_order_ids, backorder_order_ids = by final_decision.
inactive_sku_order_ids = orders containing any inactive SKU.
- Records sorted by
order_id; every SKU list sorted ascending; all order-id lists sorted.
5. MIXED-WAREHOUSE ALLOCATION (line-level transfer/backorder tasks)
For every line in the wave, choose ONE action ∈ ship | transfer | backorder |
manual_review and a primary_reason ∈ none | account_blocked |
account_review_required | fraud_watch | inactive_product | insufficient_effective_stock.
Per-line precedence:
- Account/customer-risk stop → manual_review (and the WHOLE order's lines all
become manual_review). Reason mapping:
- account_status blocked →
account_blocked
- risk_flag fraud_watch →
fraud_watch
- account_status review_required →
account_review_required
- Inactive product → manual_review, reason
inactive_product (line-only; does
NOT block the rest of the order).
- Enough at requested WH (
requested_effective_available >= quantity) →
ship, ship_quantity = quantity, reason none.
- Partial + transfer: ship the usable requested-WH quantity
(
ship_quantity = max(0, requested_effective_available)), then cover the
remainder need = quantity - ship_quantity from ONE source warehouse whose
transfer_surplus(src) >= need (surplus above that warehouse's safety stock).
→ transfer, transfer_from = that source, transfer_quantity = need,
reason insufficient_effective_stock. Emit a row in transfer_requests.
- Otherwise → backorder: ship the usable part, backorder_quantity = remainder,
reason
insufficient_effective_stock.
requested_effective_available reported on each line = effective_available at the
order's own warehouse (may be negative — report as computed).
Roll-ups & summary
blocked_orders (top-level list AND summary count) = orders stopped at the
account/customer-risk level (account_blocked, fraud_watch, account_review_required).
NOT line-only product (inactive) reviews.
order_rollup.outcome per order ∈ ready_to_ship | needs_transfer | has_backorder
| manual_review | mixed_actions. If an order's lines have a single action class
use that; if it mixes (e.g. one inactive manual_review line + one backorder line),
use mixed_actions.
- summary integers: total_orders, total_lines, ship_lines, transfer_lines,
backorder_lines, manual_review_lines, blocked_orders, transfer_units (sum of
transfer_quantity), backorder_units (sum of backorder_quantity).
- Sort line_actions and transfer_requests by order_id then line_id; rollup by order_id.
6. KIT REPLENISHMENT PLANNING (BOM build run)
Goal: for each component SKU needed by a kit run at a planning warehouse, decide
no-action / transfer / purchase, honoring existing PO coverage and overstock.
Steps:
- Pull each BOM in the memo.
total_required(sku) = Σ over builds of
quantity_per_kit * build_quantity (aggregate a shared SKU across BOMs).
needed_by(sku) = the earliest build_date among builds that consume the SKU.
target_effective_available(sku) = effective_available at the PLANNING warehouse.
gap = total_required - target_effective_available.
- Timely PO coverage:
timely_po_qty = Σ quantity of POs that are
same planning warehouse, status open OR confirmed (NOT received — received
stock is already in on_hand; NOT cancelled), AND eta <= needed_by. Collect
their coverage_po_ids (sorted).
- Decision waterfall (sets
final_action + exclusion_reason):
gap <= 0 and target_effective_available >= overstock_threshold →
overstock_excluded / reason target_overstock (already over-stocked; add nothing).
gap <= 0 (stocked, not overstocked) → no_action_stocked / reason stocked_no_gap.
timely_po_qty >= gap → timely_po_covered / reason timely_po_covers_gap.
- else remaining =
gap - timely_po_qty; cover as much as possible with
transfers (surplus above safety from other warehouses), set transfer_qty;
purchase_requisition_qty = max(0, remaining - transfer_qty).
- if purchase_requisition_qty == 0 →
transfer_only / reason none.
- else →
purchase_required / reason none.
transfer_requests: one row per source per SKU (sku, from_warehouse_id,
to_warehouse_id=planning WH, quantity, needed_by). Sort by sku asc, then
quantity desc, then from_warehouse_id asc.
purchase_requisitions: sku, supplier_id (= product.supplier_id), warehouse_id
(planning WH), quantity = purchase_requisition_qty, needed_by, unit_cost
(= product.unit_cost, 2 dp), extended_cost = round(quantity*unit_cost, 2). Sort by sku.
excluded_components: components whose final_action is overstock_excluded /
timely_po_covered / no_action_stocked, with reason ∈ target_overstock |
timely_po_covers_gap | stocked_no_gap and supporting_po_ids (the covering POs,
sorted; empty for overstock/stocked).
kit_targets: one row per BOM (bom_id, kit_name=BOM name, warehouse_id,
build_quantity, build_date), sorted by bom_id.
- summary: component_count (rows in component_plan), total_purchase_units,
total_purchase_cost (2 dp), total_transfer_units, timely_po_covered_units
(Σ timely_po_qty actually used to close a gap).
component_plan sorted by sku; task_id/plan_date per template.
7. SUPPLIER INCIDENT SCORECARD (period quality review)
- Filter incident population with the API date window:
/incidents?start=<start>&end=<end> — the window applies to open_date and is
inclusive on both ends. (Q1 example: start=2026-01-01&end=2026-03-31.)
- Group by supplier_id. A supplier is "in scope" only if it has >=1 filtered incident.
- Per supplier compute:
incident_count, incident_percentage = count / total_filtered_population * 100,
rounded to 1 decimal.
total_resolution_cost = Σ resolution_cost (2 dp).
avg_duration_days (2 dp). Duration per incident = calendar days:
closed → open_date→close_date; open → open_date→analysis_date.
rma_count (incident_type RMA), work_order_count (WORK_ORDER).
open_incident_count (status open).
severe_incident_count = severity in {high, critical}.
recommendation_code by precedence (first match):
- ESCALATE_SUPPLIER: supplier
quality_status == quality_hold with >=3 filtered
incidents; OR any critical RMA; OR (rma_count >= 3 AND total cost >= 15000.00).
- PROCESS_REVIEW: work_order_count >= 3 AND work_order_count > rma_count.
- WATCHLIST: quality_status in {watch, quality_hold}; OR incident_count >= 4;
OR total cost >= 12000.00; OR severe_incident_count >= 2.
- MONITOR: none of the above.
supplier_scorecard sorted by supplier_id ascending.
top_escalation_suppliers = supplier_ids with code ESCALATE_SUPPLIER, sorted by
incident_count desc, then total_resolution_cost desc, then supplier_id asc.
highest_cost_supplier_id = supplier with max total_resolution_cost.
highest_share_supplier_id = supplier with max incident_count (i.e. highest share).
- summary: filtered_incident_count, supplier_count, total_resolution_cost (2 dp),
overall_rma_count, overall_work_order_count.
8. QUALITY-HOLD REPLENISHMENT CONTROL (per named supplier)
- Window from the request (
start,end); filter incidents per supplier with
/incidents?start=&end=&supplier_id=.
- Per supplier compute: recent_incident_count, recent_rma_count,
severe_or_critical_count (severity high|critical), open_incident_count,
affected_skus (sorted unique), sample_incident_ids (sorted, max 5),
quality_status (from /suppliers).
held_po_ids per supplier = that supplier's POs with status open OR confirmed
(/purchase_orders?supplier_id=&status=...), sorted.
decision precedence:
freeze_new_replenishment: quality_status == quality_hold (hard stop).
buyer_review_required: quality_status == watch (or, if approved, elevated
recent risk: recent_rma_count >= 2 OR severe_or_critical_count >= 2 OR
open_incident_count >= 2).
monitor_only: approved supplier with no/low recent risk.
- A supplier's
held_po_ids are reported for frozen suppliers (and any whose
replenishment is being stopped). monitor_only suppliers release their POs.
- Top-level:
held_po_ids = sorted unique union of all held PO ids;
release_supplier_ids = suppliers whose decision is monitor_only (sorted).
- summary: suppliers_reviewed, freeze_count, buyer_review_count, monitor_count,
held_po_count (size of unique held set), total_recent_incidents.
- supplier_decisions sorted by supplier_id ascending.
9. OUTPUT CONVENTIONS (apply to every task)
- Return only the JSON object matching the task's
answer_template.json — no
prose, no markdown fences around it.
- Include EXACTLY the required top-level keys and every required item key; use the
exact enum spellings from the template.
- Currency (
*_cost*, *_usd, unit_cost, extended_cost, total_resolution_cost):
round to 2 decimals.
- Percentages: round to 1 decimal (scorecard) unless template says otherwise.
- Durations: 2 decimals. Quantities / counts / zone_distance / service_days /
line_id: integers.
- Sorting: obey the template's stated order exactly. Defaults: records by
order_id; line lists by order_id then line_id; SKU lists ascending; supplier lists
by supplier_id ascending; id lists ascending. Apply secondary/tertiary keys when
specified (e.g. transfer_requests: sku asc, qty desc, from_warehouse asc).
- Emit zero-valued entries for required enum count maps (don't omit a decision class).
- Use the wave_id / task_id
required_value from the template verbatim.
10. COMMON MISJUDGMENTS — explicit exclusion rules
- Do not count reserved or quarantined as available. Available = on_hand −
reserved − quarantined.
- Do not transfer below a source warehouse's safety stock. Only surplus moves.
- Inactive SKUs (
product.active == false) never auto-ship — they go to
manual_review / escalate_product_master, even if stock is plentiful.
- Account block / fraud_watch / credit_watch / review_required outrank stock and
product status. A blocked or risk-flagged customer's order is held even with full
stock; in allocation, ALL lines of that order become manual_review.
- Overstock exclusion: if a planning-WH SKU's effective_available already meets/
exceeds its
overstock_threshold, exclude it from replenishment (target_overstock)
— never add stock to an overstocked item.
- Timely-PO coverage counts only same-warehouse, open/confirmed POs with
eta <= needed_by. received POs are already in on_hand (don't double-count);
cancelled never counts; a PO arriving after the build is not timely.
- Critical RMA alone forces ESCALATE_SUPPLIER regardless of count/cost.
- Incident date window filters
open_date and is inclusive on both endpoints —
use the API's start/end rather than client-side filtering when possible.
- Open incidents have
close_date == null; their duration runs to the analysis
date, and they count toward open_incident_count.
- Shipping weight is the whole order's summed line weight, not a single line; and
quote from the order's own warehouse/zip/speed. Trust the API's returned total_cost.
- Watch out for missing inventory rows → effective_available = 0 (treat as shortage,
not error).
1---2name: self-attempt-02-283description: SKILL: Northwind Components ERP — Inventory / Order-Fulfillment Operations4---5# SKILL: Northwind Components ERP — Inventory / Order-Fulfillment Operations67Transferable, executable playbook for the Northwind Components ERP benchmark8(inventory status, order release, allocation/transfer, replenishment, supplier9incident scorecards, quality-hold control). Built from working the live API.1011---1213## 0. REMOTE API — how to use it1415Base URL (ALWAYS use this; ignore any "127.0.0.1:8007" or local-env mention in16task prompts — those are stale):1718 <remote-env-url>1920GET endpoints (all JSON):21- `/health` — manifest, record counts, seed.22- `/products` `/products/<sku>` — product master.23- `/customers` `/customers/<customer_id>` — account/risk master.24- `/suppliers` — supplier master (incl. `quality_status`).25- `/warehouses` — 3 warehouses: WH_NORTH (07102), WH_CENTRAL (60607), WH_WEST (89502).26- `/inventory?warehouse_id=&sku=` — stock rows.27- `/purchase_orders?supplier_id=&sku=&status=` — POs. status ∈ open|confirmed|received|cancelled.28- `/orders?wave=&required_date=&customer_id=` `/orders/<order_id>` — sales orders.29- `/shipping/quote?warehouse_id=&destination_zip=&weight_lb=&speed=` — speed ∈ ground|two_day|overnight.30- `/incidents?start=&end=&supplier_id=&sku=&incident_type=&status=` — quality incidents.31- `/boms` `/boms/<bom_id>` — kit bills of material.3233All listed query params work as filters and compose (AND). Always pull a wave with34`/orders?wave=WAVE_ID` and fetch `/orders/<id>` only if you need a single record.3536### Key record fields37- **product**: `sku, name, category, active(bool), safety_stock(int), overstock_threshold(int), unit_cost, weight_lb, supplier_id`38- **customer**: `customer_id, name, account_status(active|review_required|blocked), risk_flag(none|credit_watch|fraud_watch), tier(strategic|standard|economy), margin_band`39- **inventory**: `warehouse_id, sku, on_hand, reserved, quarantined, last_count_date`40- **purchase_order**: `po_id, supplier_id, sku, warehouse_id, quantity, status, eta`41- **order**: `order_id, customer_id, warehouse_id, destination_zip, shipping_speed, required_date, priority, wave, lines[{line_id, sku, quantity, unit_price}]`42- **incident**: `incident_id, supplier_id, sku, warehouse_id, incident_type(RMA|WORK_ORDER), severity(low|medium|high|critical), status(open|closed), open_date, close_date(nullable), resolution_cost, root_cause`43- **bom**: `bom_id, name, warehouse_id, target_date, components[{sku, quantity_per_kit}]`4445---4647## 1. CORE FORMULAS (memorize — used everywhere)4849**Effective available** (the only "freely usable" quantity; reserved + quarantined50are protected and NOT available):5152 effective_available = on_hand - reserved - quarantined5354If no inventory row exists for (warehouse, sku), treat effective_available = 0.55Effective available can be negative; clamp ship quantities at 0 (never ship < 0).5657**Transferable surplus** from a *source* warehouse (do not dip into safety stock):5859 transfer_surplus(src, sku) = effective_available(src, sku) - safety_stock(sku)6061Only positive surplus is movable. Safety stock and quarantine/reserved are protected.6263**Shipping quote** — call the API; it returns the answer directly. Do NOT recompute.64The endpoint internally uses65`base_rate = 8.75 + 3.40*zone_distance + 1.18*weight_lb`, then66`total_cost = base_rate * speed_mult * (1 + fuel_surcharge_rate)` with67speed_mult ground=1.0, two_day=1.75, overnight=2.65 and fuel_surcharge_rate≈0.0925.68You only need to: compute the order's total weight, hit the endpoint, and copy69`zone_distance`(int), `service_days`(int), `total_cost`(→`total_cost_usd`, 2 dp).7071 order_weight_lb = sum(product.weight_lb * line.quantity) over ALL order lines7273Quote per order using the order's own `warehouse_id`, `destination_zip`, total74weight, and the order's `shipping_speed` (unless a memo names a specific speed).7576---7778## 2. INVENTORY STATUS CLASSIFICATION (per order, rolled up from lines)7980Classify each line, then roll the order up by the precedence below.8182Per line at the order's requested warehouse:83- **shortage** if line is active but `effective_available < quantity`.84- **inactive** if `product.active == false` (a product-master problem).85- **low_stock** if active and ships fully (`effective_available >= quantity`) but86 `effective_available < safety_stock` (stock already below safety buffer).87- otherwise **ready**.8889A single line can be BOTH inactive and short (inactive product whose eff_avail <90quantity) → it goes in both lists.9192Order-level `inventory_status` enum precedence (highest first):931. `inactive_and_shortage` — any inactive SKU AND any shortage SKU present.942. `inactive_sku` — any inactive SKU (no shortage).953. `shortage` — any shortage SKU.964. `low_stock` — any low-stock SKU.975. `ready` — none of the above.9899Per-order SKU lists (each sorted ascending):100- `shortage_skus` = active SKUs with eff_avail < qty (plus inactive-and-short SKUs).101- `inactive_skus` = SKUs whose product.active is false.102- `low_stock_skus` = active, fully-shippable SKUs with eff_avail < safety_stock.103104---105106## 3. CUSTOMER EXCEPTION CLASSIFICATION107108From the customer master. `customer_exception` enum, precedence (highest first):1091. `account_blocked` — `account_status == blocked` (HARD stop, beats any risk flag).1102. `fraud_watch` — `risk_flag == fraud_watch`.1113. `credit_watch` — `risk_flag == credit_watch`.1124. `review_required` — `account_status == review_required`.1135. `none` — active account, risk none.114115A blocked account that is also credit_watch resolves to `account_blocked`.116117---118119## 4. ORDER-RELEASE DECISION MATRIX (expedite/dispatch tasks)120121Decide `final_decision` + `next_action` by precedence — **customer/account issues122outrank product and stock issues**:123124| condition (first match wins) | final_decision | next_action |125|-----------------------------------------|------------------|------------------------|126| account_blocked | reject_hold | hold_credit_or_fraud |127| fraud_watch OR credit_watch | reject_hold | hold_credit_or_fraud |128| review_required | manual_review | send_account_review |129| inactive_sku / inactive_and_shortage | manual_review | escalate_product_master|130| shortage | backorder | create_backorder |131| low_stock | delayed_release | delay_and_monitor |132| ready | ship_now | release_to_pick |133134Notes:135- A same-week/expedite "exception" request from the customer does NOT override an136 account block or risk flag — still reject_hold.137- Always produce the shipping quote even when the decision is not "ship" (a quote138 may be explicitly requested regardless of release).139140### Summary block (expedite task)141- `order_count` = number of orders.142- `decision_counts` = object with integer counts for EACH of the 5 final_decision143 enums (include zeros).144- `total_shipping_cost_usd` = sum of every order's quote total_cost (2 dp).145- `blocked_order_ids` = orders with final_decision reject_hold (account/risk holds).146- `manual_review_order_ids`, `backorder_order_ids` = by final_decision.147- `inactive_sku_order_ids` = orders containing any inactive SKU.148- Records sorted by `order_id`; every SKU list sorted ascending; all order-id lists sorted.149150---151152## 5. MIXED-WAREHOUSE ALLOCATION (line-level transfer/backorder tasks)153154For every line in the wave, choose ONE `action` ∈ ship | transfer | backorder |155manual_review and a `primary_reason` ∈ none | account_blocked |156account_review_required | fraud_watch | inactive_product | insufficient_effective_stock.157158Per-line precedence:1591. **Account/customer-risk stop → manual_review** (and the WHOLE order's lines all160 become manual_review). Reason mapping:161 - account_status blocked → `account_blocked`162 - risk_flag fraud_watch → `fraud_watch`163 - account_status review_required → `account_review_required`1642. **Inactive product → manual_review**, reason `inactive_product` (line-only; does165 NOT block the rest of the order).1663. **Enough at requested WH** (`requested_effective_available >= quantity`) →167 `ship`, ship_quantity = quantity, reason `none`.1684. **Partial + transfer**: ship the usable requested-WH quantity169 (`ship_quantity = max(0, requested_effective_available)`), then cover the170 remainder `need = quantity - ship_quantity` from ONE source warehouse whose171 `transfer_surplus(src) >= need` (surplus above that warehouse's safety stock).172 → `transfer`, transfer_from = that source, transfer_quantity = need,173 reason `insufficient_effective_stock`. Emit a row in `transfer_requests`.1745. **Otherwise → backorder**: ship the usable part, backorder_quantity = remainder,175 reason `insufficient_effective_stock`.176177`requested_effective_available` reported on each line = effective_available at the178order's own warehouse (may be negative — report as computed).179180### Roll-ups & summary181- `blocked_orders` (top-level list AND summary count) = orders stopped at the182 account/customer-risk level (account_blocked, fraud_watch, account_review_required).183 NOT line-only product (inactive) reviews.184- `order_rollup.outcome` per order ∈ ready_to_ship | needs_transfer | has_backorder185 | manual_review | mixed_actions. If an order's lines have a single action class186 use that; if it mixes (e.g. one inactive manual_review line + one backorder line),187 use `mixed_actions`.188- summary integers: total_orders, total_lines, ship_lines, transfer_lines,189 backorder_lines, manual_review_lines, blocked_orders, transfer_units (sum of190 transfer_quantity), backorder_units (sum of backorder_quantity).191- Sort line_actions and transfer_requests by order_id then line_id; rollup by order_id.192193---194195## 6. KIT REPLENISHMENT PLANNING (BOM build run)196197Goal: for each component SKU needed by a kit run at a planning warehouse, decide198no-action / transfer / purchase, honoring existing PO coverage and overstock.199200Steps:2011. Pull each BOM in the memo. `total_required(sku)` = Σ over builds of202 `quantity_per_kit * build_quantity` (aggregate a shared SKU across BOMs).2032. `needed_by(sku)` = the earliest build_date among builds that consume the SKU.2043. `target_effective_available(sku)` = effective_available at the PLANNING warehouse.2054. `gap = total_required - target_effective_available`.2065. **Timely PO coverage**: `timely_po_qty` = Σ quantity of POs that are207 **same planning warehouse**, status **open OR confirmed** (NOT received — received208 stock is already in on_hand; NOT cancelled), AND `eta <= needed_by`. Collect209 their `coverage_po_ids` (sorted).2106. **Decision waterfall** (sets `final_action` + `exclusion_reason`):211 - `gap <= 0` and `target_effective_available >= overstock_threshold` →212 `overstock_excluded` / reason `target_overstock` (already over-stocked; add nothing).213 - `gap <= 0` (stocked, not overstocked) → `no_action_stocked` / reason `stocked_no_gap`.214 - `timely_po_qty >= gap` → `timely_po_covered` / reason `timely_po_covers_gap`.215 - else remaining = `gap - timely_po_qty`; cover as much as possible with216 transfers (surplus above safety from other warehouses), set `transfer_qty`;217 `purchase_requisition_qty = max(0, remaining - transfer_qty)`.218 - if purchase_requisition_qty == 0 → `transfer_only` / reason `none`.219 - else → `purchase_required` / reason `none`.2207. `transfer_requests`: one row per source per SKU (sku, from_warehouse_id,221 to_warehouse_id=planning WH, quantity, needed_by). Sort by sku asc, then222 quantity desc, then from_warehouse_id asc.2238. `purchase_requisitions`: sku, supplier_id (= product.supplier_id), warehouse_id224 (planning WH), quantity = purchase_requisition_qty, needed_by, unit_cost225 (= product.unit_cost, 2 dp), extended_cost = round(quantity*unit_cost, 2). Sort by sku.2269. `excluded_components`: components whose final_action is overstock_excluded /227 timely_po_covered / no_action_stocked, with `reason` ∈ target_overstock |228 timely_po_covers_gap | stocked_no_gap and `supporting_po_ids` (the covering POs,229 sorted; empty for overstock/stocked).23010. `kit_targets`: one row per BOM (bom_id, kit_name=BOM name, warehouse_id,231 build_quantity, build_date), sorted by bom_id.23211. summary: component_count (rows in component_plan), total_purchase_units,233 total_purchase_cost (2 dp), total_transfer_units, timely_po_covered_units234 (Σ timely_po_qty actually used to close a gap).235236`component_plan` sorted by sku; `task_id`/`plan_date` per template.237238---239240## 7. SUPPLIER INCIDENT SCORECARD (period quality review)2412421. Filter incident population with the API date window:243 `/incidents?start=<start>&end=<end>` — the window applies to **open_date** and is244 **inclusive on both ends**. (Q1 example: start=2026-01-01&end=2026-03-31.)2452. Group by supplier_id. A supplier is "in scope" only if it has >=1 filtered incident.2463. Per supplier compute:247 - `incident_count`, `incident_percentage` = count / total_filtered_population * 100,248 rounded to **1 decimal**.249 - `total_resolution_cost` = Σ resolution_cost (2 dp).250 - `avg_duration_days` (2 dp). Duration per incident = calendar days:251 closed → open_date→close_date; open → open_date→analysis_date.252 - `rma_count` (incident_type RMA), `work_order_count` (WORK_ORDER).253 - `open_incident_count` (status open).254 - `severe_incident_count` = severity in {high, critical}.255 - `recommendation_code` by precedence (first match):256 - **ESCALATE_SUPPLIER**: supplier `quality_status == quality_hold` with >=3 filtered257 incidents; OR any **critical RMA**; OR (rma_count >= 3 AND total cost >= 15000.00).258 - **PROCESS_REVIEW**: work_order_count >= 3 AND work_order_count > rma_count.259 - **WATCHLIST**: quality_status in {watch, quality_hold}; OR incident_count >= 4;260 OR total cost >= 12000.00; OR severe_incident_count >= 2.261 - **MONITOR**: none of the above.2624. `supplier_scorecard` sorted by supplier_id ascending.2635. `top_escalation_suppliers` = supplier_ids with code ESCALATE_SUPPLIER, sorted by264 incident_count desc, then total_resolution_cost desc, then supplier_id asc.2656. `highest_cost_supplier_id` = supplier with max total_resolution_cost.266 `highest_share_supplier_id` = supplier with max incident_count (i.e. highest share).2677. summary: filtered_incident_count, supplier_count, total_resolution_cost (2 dp),268 overall_rma_count, overall_work_order_count.269270---271272## 8. QUALITY-HOLD REPLENISHMENT CONTROL (per named supplier)2732741. Window from the request (`start`,`end`); filter incidents per supplier with275 `/incidents?start=&end=&supplier_id=`.2762. Per supplier compute: recent_incident_count, recent_rma_count,277 severe_or_critical_count (severity high|critical), open_incident_count,278 affected_skus (sorted unique), sample_incident_ids (sorted, **max 5**),279 quality_status (from /suppliers).2803. `held_po_ids` per supplier = that supplier's POs with status **open OR confirmed**281 (`/purchase_orders?supplier_id=&status=...`), sorted.2824. `decision` precedence:283 - `freeze_new_replenishment`: quality_status == quality_hold (hard stop).284 - `buyer_review_required`: quality_status == watch (or, if approved, elevated285 recent risk: recent_rma_count >= 2 OR severe_or_critical_count >= 2 OR286 open_incident_count >= 2).287 - `monitor_only`: approved supplier with no/low recent risk.2885. A supplier's `held_po_ids` are reported for frozen suppliers (and any whose289 replenishment is being stopped). `monitor_only` suppliers release their POs.2906. Top-level: `held_po_ids` = sorted unique union of all held PO ids;291 `release_supplier_ids` = suppliers whose decision is monitor_only (sorted).2927. summary: suppliers_reviewed, freeze_count, buyer_review_count, monitor_count,293 held_po_count (size of unique held set), total_recent_incidents.2948. supplier_decisions sorted by supplier_id ascending.295296---297298## 9. OUTPUT CONVENTIONS (apply to every task)299300- Return **only** the JSON object matching the task's `answer_template.json` — no301 prose, no markdown fences around it.302- Include EXACTLY the required top-level keys and every required item key; use the303 exact enum spellings from the template.304- **Currency** (`*_cost*`, `*_usd`, unit_cost, extended_cost, total_resolution_cost):305 round to **2 decimals**.306- **Percentages**: round to **1 decimal** (scorecard) unless template says otherwise.307- **Durations**: 2 decimals. **Quantities / counts / zone_distance / service_days /308 line_id**: integers.309- **Sorting**: obey the template's stated order exactly. Defaults: records by310 order_id; line lists by order_id then line_id; SKU lists ascending; supplier lists311 by supplier_id ascending; id lists ascending. Apply secondary/tertiary keys when312 specified (e.g. transfer_requests: sku asc, qty desc, from_warehouse asc).313- Emit zero-valued entries for required enum count maps (don't omit a decision class).314- Use the wave_id / task_id `required_value` from the template verbatim.315316---317318## 10. COMMON MISJUDGMENTS — explicit exclusion rules319320- **Do not** count reserved or quarantined as available. Available = on_hand −321 reserved − quarantined.322- **Do not** transfer below a source warehouse's safety stock. Only surplus moves.323- **Inactive SKUs** (`product.active == false`) never auto-ship — they go to324 manual_review / escalate_product_master, even if stock is plentiful.325- **Account block / fraud_watch / credit_watch / review_required** outrank stock and326 product status. A blocked or risk-flagged customer's order is held even with full327 stock; in allocation, ALL lines of that order become manual_review.328- **Overstock exclusion**: if a planning-WH SKU's effective_available already meets/329 exceeds its `overstock_threshold`, exclude it from replenishment (target_overstock)330 — never add stock to an overstocked item.331- **Timely-PO coverage** counts only **same-warehouse, open/confirmed** POs with332 `eta <= needed_by`. `received` POs are already in on_hand (don't double-count);333 `cancelled` never counts; a PO arriving after the build is not timely.334- **Critical RMA** alone forces ESCALATE_SUPPLIER regardless of count/cost.335- **Incident date window** filters `open_date` and is inclusive on both endpoints —336 use the API's `start`/`end` rather than client-side filtering when possible.337- **Open incidents** have `close_date == null`; their duration runs to the analysis338 date, and they count toward open_incident_count.339- Shipping weight is the **whole order's** summed line weight, not a single line; and340 quote from the order's own warehouse/zip/speed. Trust the API's returned total_cost.341- Watch out for missing inventory rows → effective_available = 0 (treat as shortage,342 not error).