Northwind Components ERP — Task Group 007 Skill
Environment
Base URL: http://34.46.77.124:8007
All tasks use this shared Northwind ERP API. Ignore any prompt text that references localhost or 127.0.0.1:8007 — the remote URL above is authoritative. Do not run env/setup.sh or python server.py locally.
API Endpoints (inferred from task patterns)
| Endpoint |
Purpose |
GET /orders |
List sales orders; filter ?wave_id=... or by order_id |
GET /orders/{order_id} |
Single order with lines, customer, warehouse |
GET /products / GET /products/{sku} |
Product master (name, unit_cost, supplier_id, is_active, etc.) |
GET /customers / GET /customers/{id} |
Customer accounts (status, credit_hold, fraud_flag) |
GET /inventory |
Global inventory snapshot |
GET /inventory/{warehouse_id} |
Warehouse-level inventory by SKU |
GET /warehouses |
Warehouse list |
GET /suppliers / GET /suppliers/{id} |
Supplier master (name, quality_status) |
GET /incidents |
Quality/supplier incidents; filter ?open_date__gte=...&open_date__lte=... or ?supplier_id=... |
GET /boms/{bom_id} |
Bill of materials (components, quantities) |
GET /purchase-orders |
Purchase orders; filter ?status=open,confirmed&warehouse_id=... or ?supplier_id=... |
GET /shipping-quotes |
Parcel/shipping quotes; params: origin warehouse, destination zip/zone, weight, speed |
Common Field Conventions
Precision
- Currency (USD): always rounded to 2 decimal places (
total_cost_usd, unit_cost, extended_cost, total_resolution_cost)
- Percentages: rounded to 1 decimal place (
incident_percentage)
- Durations (days): rounded to 2 decimal places (
avg_duration_days)
- Quantities / counts: integers only
Dates
- All dates use
YYYY-MM-DD string format
- Duration for closed incidents: calendar days from
open_date to close_date
- Duration for open incidents: calendar days from
open_date to analysis_date
Sort Ordering (universal rules)
| Context |
Sort |
| Records within a wave/queue |
order_id ascending (lexicographic string sort) |
| Lines within an order |
line_id ascending (numeric) |
| SKU lists (any array of SKUs) |
string ascending |
| Order IDs in summary lists |
string ascending |
| PO IDs / incident IDs in arrays |
string ascending |
| Supplier scorecard rows |
supplier_id ascending |
| Transfer requests |
sku asc → quantity desc → from_warehouse_id asc |
| Component plan rows |
sku ascending |
| Purchase requisitions |
sku ascending |
| Excluded components |
sku ascending |
| Top escalation suppliers |
incident_count desc → total_resolution_cost desc → supplier_id asc |
Empty Collections
Empty lists must be [], never null or omitted. This applies to shortage_skus, inactive_skus, low_stock_skus, coverage_po_ids, supporting_po_ids, held_po_ids, affected_skus, etc.
Nullable Fields
Only transfer_from in allocation line actions is nullable — use null when a line has no transfer source. All other fields use their zero-value or empty list.
Inventory Semantics
Effective available = on_hand − quarantined − reserved − normal_operating_buffer
This value can be negative (meaning the warehouse has a deficit/backlog). Do not floor at zero.
target_effective_available in replenishment plans and requested_effective_available in allocation tasks both use this formula.
- A negative effective available means current stock cannot meet the request; a positive value below the required quantity means partial coverage.
Task 1: Expedite Queue (Dispatch Control)
Template: Records sorted by order_id ascending, with per-order classification and a wave summary.
Per-Order Logic (ordered checks)
Customer exception — check account status FIRST:
account_blocked → final_decision = reject_hold, next_action = hold_credit_or_fraud
fraud_watch → final_decision = reject_hold, next_action = hold_credit_or_fraud
credit_watch → final_decision = manual_review, next_action = send_account_review
review_required → final_decision = manual_review, next_action = send_account_review
none → continue to inventory check
Inventory status — classify each line's SKU:
- Any SKU with
is_active = false → flag as inactive_sku
- Any SKU where requested qty > available qty → flag as
shortage
- Any SKU where available qty is within a low-stock threshold → flag as
low_stock
- Combine flags: if both inactive and shortage exist →
inactive_and_shortage
- If all lines are fully available →
ready
Final decision (when customer_exception is none or only review_required):
ready → ship_now / release_to_pick
low_stock (no shortage, no inactive) → delayed_release / delay_and_monitor
shortage or inactive_and_shortage → backorder / create_backorder
- Any
inactive_sku → manual_review / escalate_product_master
When customer_exception = review_required, the decision is always manual_review / send_account_review regardless of inventory.
Shipping quote: Always fetch from the API for every order (even if not shipping). Use the order's warehouse as origin and requested shipping speed.
Summary
decision_counts: count of each final_decision across all orders
total_shipping_cost_usd: sum of all shipping_quote.total_cost_usd
blocked_order_ids: orders with final_decision = reject_hold
manual_review_order_ids: orders with final_decision = manual_review
backorder_order_ids: orders with final_decision = backorder
inactive_sku_order_ids: orders with at least one inactive SKU
Enum Tables
| inventory_status |
customer_exception |
final_decision |
next_action |
ready |
none |
ship_now |
release_to_pick |
low_stock |
review_required |
delayed_release |
delay_and_monitor |
shortage |
account_blocked |
manual_review |
send_account_review |
inactive_sku |
fraud_watch |
backorder |
create_backorder |
inactive_and_shortage |
credit_watch |
reject_hold |
hold_credit_or_fraud |
|
|
|
escalate_product_master |
Task 2: Production Replenishment (BOM Kit Build)
Template: Kit targets, component plan, transfer/purchase requests, exclusions, summary.
Component Plan Calculation
- total_required = sum across BOMs of (bom_component_qty × build_quantity)
- target_effective_available = on_hand − quarantined − reserved − buffer at the target warehouse (can be negative)
- timely_po_qty = total open/confirmed PO quantity for the SKU at the target warehouse (delivery before build_date)
- gap = total_required − target_effective_available − timely_po_qty
- Do NOT floor target_effective_available at zero. A negative effective available means the warehouse has a deficit — that deficit adds to the gap (subtracting a negative = adding).
- If gap ≤ 0 → covered (existing stock + POs are sufficient)
- transfer_qty: pull from other warehouses' effective available (non-protected stock), up to the gap
- purchase_requisition_qty: remaining gap after transfers
Final Action Decision
| Condition |
final_action |
exclusion_reason |
| target_effective_available ≥ total_required → overstock (buffer is already subtracted from effective_available) |
overstock_excluded |
target_overstock |
| timely PO covers all of the gap |
timely_po_covered |
timely_po_covers_gap |
| gap = 0 from existing stock alone |
no_action_stocked |
stocked_no_gap |
| gap > 0, covered by transfers only |
transfer_only |
none |
| gap > 0, needs purchase |
purchase_required |
none |
Purchase Requisition Fields
supplier_id: from product master (/products/{sku})
warehouse_id: the target build warehouse
unit_cost: from product master
extended_cost: round(quantity × unit_cost, 2)
needed_by: the latest build_date among BOMs requiring this SKU
Summary
component_count: total distinct SKUs in component_plan
total_purchase_units: sum of purchase_requisition_qty
total_purchase_cost: sum of extended_cost, rounded to 2 decimals
total_transfer_units: sum of transfer_qty
timely_po_covered_units: sum of (total_required − target_effective_available) for components whose final_action is timely_po_covered — i.e., the portion of required quantity that the PO effectively satisfies, not the raw PO quantity
Task 3: Supplier Incident Scorecard
Template: Analysis window, supplier-level metrics, recommendation codes, escalation list.
Data Gathering
- Query
/incidents filtered by open_date within the window (inclusive)
- Query
/suppliers for names and quality_status
- Only suppliers with ≥1 filtered incident appear on the scorecard
Per-Supplier Metrics
incident_percentage = round(supplier_incident_count / total_filtered_incidents × 100, 1)
avg_duration_days = round(mean of per-incident durations, 2)
rma_count = count of incidents with type = RMA
work_order_count = count of incidents with type = WORK_ORDER
open_incident_count = count where status != closed
severe_incident_count = count where severity is high or critical
Recommendation Code (first match wins, highest precedence first)
ESCALATE_SUPPLIER (any of):
quality_status = quality_hold AND incident_count ≥ 3
- Any RMA incident with
severity = critical
rma_count ≥ 3 AND total_resolution_cost ≥ 15000.00
PROCESS_REVIEW:
work_order_count ≥ 3 AND work_order_count > rma_count
WATCHLIST (any of):
quality_status is watch or quality_hold
incident_count ≥ 4
total_resolution_cost ≥ 12000.00
severe_incident_count ≥ 2
MONITOR: fallback when none of the above match.
Derived Fields
top_escalation_suppliers: supplier_ids where recommendation = ESCALATE_SUPPLIER, sorted by incident_count desc → total_resolution_cost desc → supplier_id asc
highest_cost_supplier_id: supplier with max total_resolution_cost
highest_share_supplier_id: supplier with max incident_count (tie-break: higher total_resolution_cost, then lower supplier_id)
Task 4: Allocation Desk (Transfer Wave)
Template: Line-level decisions, transfer requests, blocked orders, order rollup, summary.
Per-Line Logic (ordered checks)
Account / risk check FIRST:
account_blocked → action = manual_review, primary_reason = account_blocked
fraud_watch → action = manual_review, primary_reason = fraud_watch
account_review_required → action = manual_review, primary_reason = account_review_required
When any account-level flag fires, ALL lines on that order get manual_review regardless of inventory. Set ship_quantity=0, transfer_from=null, transfer_quantity=0, backorder_quantity=0.
Product check:
is_active = false → action = manual_review, primary_reason = inactive_product
Inventory check:
requested_effective_available ≥ line_quantity → action = ship, ship_quantity = line_quantity, primary_reason = none
requested_effective_available < line_quantity but another warehouse has enough effective available → action = transfer, ship_quantity = max(0, requested_effective_available), transfer_quantity = line_quantity − ship_quantity, choose ONE source warehouse, primary_reason = none
- No warehouse can cover →
action = backorder, backorder_quantity = line_quantity − max(0, ship_quantity), primary_reason = insufficient_effective_stock
Transfer Source Selection
Pick the single warehouse (not the requested one) with the most effective available for the SKU to serve as transfer_from.
Blocked Orders
Orders stopped at the account or customer-risk level: account_blocked, fraud_watch, or account_review_required. NOT orders with only product-level (inactive_product) or inventory-only issues. When any line on an order has an account-level primary_reason, the entire order is blocked.
Order Rollup Logic
| Condition |
outcome |
All lines are ship |
ready_to_ship |
At least one transfer, no backorder/manual_review |
needs_transfer |
At least one backorder, no manual_review |
has_backorder |
All lines manual_review (same reason) |
manual_review |
Mix of ship + (backorder/transfer/manual_review) |
mixed_actions |
Summary Counts
All integer counts. blocked_orders = count of distinct blocked order IDs, not total lines.
Task 5: Procurement Control (Quality Hold Review)
Template: Supplier decisions, held PO aggregation, release list, summary.
Per-Supplier Decision Logic
For each target supplier, query recent incidents (within the analysis window), supplier quality_status from /suppliers, and open/confirmed POs from /purchase-orders.
Decision rules (first match):
freeze_new_replenishment: quality_status = quality_hold → hard-freeze all open/confirmed POs for this supplier. Status alone triggers this regardless of incident counts.
buyer_review_required: quality_status = watch AND severe_or_critical_count ≥ 2 → flag for human review; hold open/confirmed POs pending buyer decision. (RMA count and total incident count are reported but do not independently drive escalation for watch-status suppliers.)
monitor_only: quality_status = watch with severe_or_critical_count < 2, or approved status with no concerning patterns. No POs are held; the supplier is released for normal replenishment.
Per-Supplier Fields
affected_skus: distinct SKUs from recent incidents, sorted ascending
sample_incident_ids: up to 5 most recent incident IDs, sorted ascending
held_po_ids: open/confirmed POs for the supplier, sorted ascending
severe_or_critical_count: incidents with severity high or critical
Aggregation
held_po_ids (top-level): sorted unique union of all per-supplier held_po_ids
release_supplier_ids: supplier_ids where decision = monitor_only, sorted ascending
Reusable Decision Precedence
Across all task types:
- Account / risk status always takes priority over inventory or product checks.
- Product master inactive status is checked before inventory availability.
- Inventory effective available is computed as
on_hand − (quarantined + reserved + buffer), may be negative.
- Enums are exact strings — use the controlled vocabulary as listed in each task's answer template, no synonyms or abbreviations.
- When a higher-severity condition applies, lower-severity checks are suppressed for that record.
1---2name: fewshot-attempt-01-343description: Northwind Components ERP — Task Group 007 Skill4---5# Northwind Components ERP — Task Group 007 Skill67## Environment89**Base URL:** `http://34.46.77.124:8007`1011All tasks use this shared Northwind ERP API. Ignore any prompt text that references localhost or `127.0.0.1:8007` — the remote URL above is authoritative. Do not run `env/setup.sh` or `python server.py` locally.1213## API Endpoints (inferred from task patterns)1415| Endpoint | Purpose |16|---|---|17| `GET /orders` | List sales orders; filter `?wave_id=...` or by order_id |18| `GET /orders/{order_id}` | Single order with lines, customer, warehouse |19| `GET /products` / `GET /products/{sku}` | Product master (name, unit_cost, supplier_id, is_active, etc.) |20| `GET /customers` / `GET /customers/{id}` | Customer accounts (status, credit_hold, fraud_flag) |21| `GET /inventory` | Global inventory snapshot |22| `GET /inventory/{warehouse_id}` | Warehouse-level inventory by SKU |23| `GET /warehouses` | Warehouse list |24| `GET /suppliers` / `GET /suppliers/{id}` | Supplier master (name, quality_status) |25| `GET /incidents` | Quality/supplier incidents; filter `?open_date__gte=...&open_date__lte=...` or `?supplier_id=...` |26| `GET /boms/{bom_id}` | Bill of materials (components, quantities) |27| `GET /purchase-orders` | Purchase orders; filter `?status=open,confirmed&warehouse_id=...` or `?supplier_id=...` |28| `GET /shipping-quotes` | Parcel/shipping quotes; params: origin warehouse, destination zip/zone, weight, speed |2930## Common Field Conventions3132### Precision33- **Currency (USD):** always rounded to **2 decimal places** (`total_cost_usd`, `unit_cost`, `extended_cost`, `total_resolution_cost`)34- **Percentages:** rounded to **1 decimal place** (`incident_percentage`)35- **Durations (days):** rounded to **2 decimal places** (`avg_duration_days`)36- **Quantities / counts:** integers only3738### Dates39- All dates use `YYYY-MM-DD` string format40- Duration for closed incidents: calendar days from `open_date` to `close_date`41- Duration for open incidents: calendar days from `open_date` to `analysis_date`4243### Sort Ordering (universal rules)4445| Context | Sort |46|---|---|47| Records within a wave/queue | `order_id` ascending (lexicographic string sort) |48| Lines within an order | `line_id` ascending (numeric) |49| SKU lists (any array of SKUs) | string ascending |50| Order IDs in summary lists | string ascending |51| PO IDs / incident IDs in arrays | string ascending |52| Supplier scorecard rows | `supplier_id` ascending |53| Transfer requests | `sku` asc → `quantity` desc → `from_warehouse_id` asc |54| Component plan rows | `sku` ascending |55| Purchase requisitions | `sku` ascending |56| Excluded components | `sku` ascending |57| Top escalation suppliers | `incident_count` desc → `total_resolution_cost` desc → `supplier_id` asc |5859### Empty Collections60Empty lists must be `[]`, never `null` or omitted. This applies to `shortage_skus`, `inactive_skus`, `low_stock_skus`, `coverage_po_ids`, `supporting_po_ids`, `held_po_ids`, `affected_skus`, etc.6162### Nullable Fields63Only `transfer_from` in allocation line actions is nullable — use `null` when a line has no transfer source. All other fields use their zero-value or empty list.6465## Inventory Semantics6667**Effective available** = `on_hand − quarantined − reserved − normal_operating_buffer`6869This value **can be negative** (meaning the warehouse has a deficit/backlog). Do not floor at zero.7071- `target_effective_available` in replenishment plans and `requested_effective_available` in allocation tasks both use this formula.72- A negative effective available means current stock cannot meet the request; a positive value below the required quantity means partial coverage.7374## Task 1: Expedite Queue (Dispatch Control)7576**Template:** Records sorted by `order_id` ascending, with per-order classification and a wave summary.7778### Per-Order Logic (ordered checks)79801. **Customer exception** — check account status FIRST:81 - `account_blocked` → `final_decision = reject_hold`, `next_action = hold_credit_or_fraud`82 - `fraud_watch` → `final_decision = reject_hold`, `next_action = hold_credit_or_fraud`83 - `credit_watch` → `final_decision = manual_review`, `next_action = send_account_review`84 - `review_required` → `final_decision = manual_review`, `next_action = send_account_review`85 - `none` → continue to inventory check86872. **Inventory status** — classify each line's SKU:88 - Any SKU with `is_active = false` → flag as `inactive_sku`89 - Any SKU where requested qty > available qty → flag as `shortage`90 - Any SKU where available qty is within a low-stock threshold → flag as `low_stock`91 - Combine flags: if both inactive and shortage exist → `inactive_and_shortage`92 - If all lines are fully available → `ready`93943. **Final decision** (when customer_exception is `none` or only `review_required`):95 - `ready` → `ship_now` / `release_to_pick`96 - `low_stock` (no shortage, no inactive) → `delayed_release` / `delay_and_monitor`97 - `shortage` or `inactive_and_shortage` → `backorder` / `create_backorder`98 - Any `inactive_sku` → `manual_review` / `escalate_product_master`99100 When `customer_exception = review_required`, the decision is always `manual_review` / `send_account_review` regardless of inventory.1011024. **Shipping quote:** Always fetch from the API for every order (even if not shipping). Use the order's warehouse as origin and requested shipping speed.103104### Summary105- `decision_counts`: count of each `final_decision` across all orders106- `total_shipping_cost_usd`: sum of all `shipping_quote.total_cost_usd`107- `blocked_order_ids`: orders with `final_decision = reject_hold`108- `manual_review_order_ids`: orders with `final_decision = manual_review`109- `backorder_order_ids`: orders with `final_decision = backorder`110- `inactive_sku_order_ids`: orders with at least one inactive SKU111112### Enum Tables113114| inventory_status | customer_exception | final_decision | next_action |115|---|---|---|---|116| `ready` | `none` | `ship_now` | `release_to_pick` |117| `low_stock` | `review_required` | `delayed_release` | `delay_and_monitor` |118| `shortage` | `account_blocked` | `manual_review` | `send_account_review` |119| `inactive_sku` | `fraud_watch` | `backorder` | `create_backorder` |120| `inactive_and_shortage` | `credit_watch` | `reject_hold` | `hold_credit_or_fraud` |121| | | | `escalate_product_master` |122123## Task 2: Production Replenishment (BOM Kit Build)124125**Template:** Kit targets, component plan, transfer/purchase requests, exclusions, summary.126127### Component Plan Calculation1281291. **total_required** = sum across BOMs of (bom_component_qty × build_quantity)1302. **target_effective_available** = on_hand − quarantined − reserved − buffer at the target warehouse (can be negative)1313. **timely_po_qty** = total open/confirmed PO quantity for the SKU at the target warehouse (delivery before build_date)1324. **gap** = total_required − target_effective_available − timely_po_qty133 - Do NOT floor target_effective_available at zero. A negative effective available means the warehouse has a deficit — that deficit adds to the gap (subtracting a negative = adding).134 - If gap ≤ 0 → covered (existing stock + POs are sufficient)1355. **transfer_qty**: pull from other warehouses' effective available (non-protected stock), up to the gap1366. **purchase_requisition_qty**: remaining gap after transfers137138### Final Action Decision139140| Condition | final_action | exclusion_reason |141|---|---|---|142| target_effective_available ≥ total_required → overstock (buffer is already subtracted from effective_available) | `overstock_excluded` | `target_overstock` |143| timely PO covers all of the gap | `timely_po_covered` | `timely_po_covers_gap` |144| gap = 0 from existing stock alone | `no_action_stocked` | `stocked_no_gap` |145| gap > 0, covered by transfers only | `transfer_only` | `none` |146| gap > 0, needs purchase | `purchase_required` | `none` |147148### Purchase Requisition Fields149150- `supplier_id`: from product master (`/products/{sku}`)151- `warehouse_id`: the target build warehouse152- `unit_cost`: from product master153- `extended_cost`: `round(quantity × unit_cost, 2)`154- `needed_by`: the latest build_date among BOMs requiring this SKU155156### Summary157- `component_count`: total distinct SKUs in component_plan158- `total_purchase_units`: sum of `purchase_requisition_qty`159- `total_purchase_cost`: sum of `extended_cost`, rounded to 2 decimals160- `total_transfer_units`: sum of transfer_qty161- `timely_po_covered_units`: sum of (total_required − target_effective_available) for components whose final_action is `timely_po_covered` — i.e., the portion of required quantity that the PO effectively satisfies, not the raw PO quantity162163## Task 3: Supplier Incident Scorecard164165**Template:** Analysis window, supplier-level metrics, recommendation codes, escalation list.166167### Data Gathering168- Query `/incidents` filtered by `open_date` within the window (inclusive)169- Query `/suppliers` for names and `quality_status`170- Only suppliers with ≥1 filtered incident appear on the scorecard171172### Per-Supplier Metrics173- `incident_percentage` = `round(supplier_incident_count / total_filtered_incidents × 100, 1)`174- `avg_duration_days` = `round(mean of per-incident durations, 2)`175- `rma_count` = count of incidents with `type = RMA`176- `work_order_count` = count of incidents with `type = WORK_ORDER`177- `open_incident_count` = count where `status != closed`178- `severe_incident_count` = count where `severity` is `high` or `critical`179180### Recommendation Code (first match wins, highest precedence first)1811821. **ESCALATE_SUPPLIER** (any of):183 - `quality_status = quality_hold` AND `incident_count ≥ 3`184 - Any RMA incident with `severity = critical`185 - `rma_count ≥ 3` AND `total_resolution_cost ≥ 15000.00`1861872. **PROCESS_REVIEW**:188 - `work_order_count ≥ 3` AND `work_order_count > rma_count`1891903. **WATCHLIST** (any of):191 - `quality_status` is `watch` or `quality_hold`192 - `incident_count ≥ 4`193 - `total_resolution_cost ≥ 12000.00`194 - `severe_incident_count ≥ 2`1951964. **MONITOR**: fallback when none of the above match.197198### Derived Fields199- `top_escalation_suppliers`: supplier_ids where recommendation = `ESCALATE_SUPPLIER`, sorted by `incident_count` desc → `total_resolution_cost` desc → `supplier_id` asc200- `highest_cost_supplier_id`: supplier with max `total_resolution_cost`201- `highest_share_supplier_id`: supplier with max `incident_count` (tie-break: higher total_resolution_cost, then lower supplier_id)202203## Task 4: Allocation Desk (Transfer Wave)204205**Template:** Line-level decisions, transfer requests, blocked orders, order rollup, summary.206207### Per-Line Logic (ordered checks)2082091. **Account / risk check FIRST:**210 - `account_blocked` → `action = manual_review`, `primary_reason = account_blocked`211 - `fraud_watch` → `action = manual_review`, `primary_reason = fraud_watch`212 - `account_review_required` → `action = manual_review`, `primary_reason = account_review_required`213 214 When any account-level flag fires, ALL lines on that order get `manual_review` regardless of inventory. Set `ship_quantity=0, transfer_from=null, transfer_quantity=0, backorder_quantity=0`.2152162. **Product check:**217 - `is_active = false` → `action = manual_review`, `primary_reason = inactive_product`2182193. **Inventory check:**220 - `requested_effective_available ≥ line_quantity` → `action = ship`, `ship_quantity = line_quantity`, `primary_reason = none`221 - `requested_effective_available < line_quantity` but another warehouse has enough effective available → `action = transfer`, `ship_quantity = max(0, requested_effective_available)`, `transfer_quantity = line_quantity − ship_quantity`, choose ONE source warehouse, `primary_reason = none`222 - No warehouse can cover → `action = backorder`, `backorder_quantity = line_quantity − max(0, ship_quantity)`, `primary_reason = insufficient_effective_stock`223224### Transfer Source Selection225Pick the single warehouse (not the requested one) with the most effective available for the SKU to serve as `transfer_from`.226227### Blocked Orders228Orders stopped at the account or customer-risk level: `account_blocked`, `fraud_watch`, or `account_review_required`. NOT orders with only product-level (`inactive_product`) or inventory-only issues. When any line on an order has an account-level primary_reason, the entire order is blocked.229230### Order Rollup Logic231| Condition | outcome |232|---|---|233| All lines are `ship` | `ready_to_ship` |234| At least one `transfer`, no `backorder`/`manual_review` | `needs_transfer` |235| At least one `backorder`, no `manual_review` | `has_backorder` |236| All lines `manual_review` (same reason) | `manual_review` |237| Mix of `ship` + (`backorder`/`transfer`/`manual_review`) | `mixed_actions` |238239### Summary Counts240All integer counts. `blocked_orders` = count of distinct blocked order IDs, not total lines.241242## Task 5: Procurement Control (Quality Hold Review)243244**Template:** Supplier decisions, held PO aggregation, release list, summary.245246### Per-Supplier Decision Logic247For each target supplier, query recent incidents (within the analysis window), supplier quality_status from `/suppliers`, and open/confirmed POs from `/purchase-orders`.248249**Decision rules (first match):**2502511. **freeze_new_replenishment**: `quality_status = quality_hold` → hard-freeze all open/confirmed POs for this supplier. Status alone triggers this regardless of incident counts.2522532. **buyer_review_required**: `quality_status = watch` AND `severe_or_critical_count ≥ 2` → flag for human review; hold open/confirmed POs pending buyer decision. (RMA count and total incident count are reported but do not independently drive escalation for watch-status suppliers.)2542553. **monitor_only**: `quality_status = watch` with `severe_or_critical_count < 2`, or `approved` status with no concerning patterns. No POs are held; the supplier is released for normal replenishment.256257### Per-Supplier Fields258- `affected_skus`: distinct SKUs from recent incidents, sorted ascending259- `sample_incident_ids`: up to 5 most recent incident IDs, sorted ascending260- `held_po_ids`: open/confirmed POs for the supplier, sorted ascending261- `severe_or_critical_count`: incidents with severity `high` or `critical`262263### Aggregation264- `held_po_ids` (top-level): sorted unique union of all per-supplier `held_po_ids`265- `release_supplier_ids`: supplier_ids where `decision = monitor_only`, sorted ascending266267## Reusable Decision Precedence268269Across all task types:2702711. **Account / risk status always takes priority** over inventory or product checks.2722. **Product master inactive status** is checked before inventory availability.2733. **Inventory effective available** is computed as `on_hand − (quarantined + reserved + buffer)`, may be negative.2744. **Enums are exact strings** — use the controlled vocabulary as listed in each task's answer template, no synonyms or abbreviations.2755. **When a higher-severity condition applies**, lower-severity checks are suppressed for that record.