# Stock and Reorder Agent — workflow specification

For a small or medium retailer selling online, in a marketplace, and in one or
more shops. The agent watches stock, forecasts the next three weeks, and drafts
purchase orders. The owner approves anything above their limit.

Live example: `/examples/retail-ecommerce` · Decision engine:
`src/lib/retail/reorder.ts` · Evaluation set: `src/content/retail/evals.ts`
(32 scenarios, run with `npm test`).

---

## 1. Goal

Keep the products that sell available without tying up cash in stock that does
not move. Remove the weekly job of checking every product by hand, without
removing the owner's control over spending.

**Success is measured on four numbers** (see §9): stockout rate, overstock days,
cash tied up in stock, and time spent on reordering.

## 2. Inputs

| Input | Shape | Source | Required |
| --- | --- | --- | --- |
| Daily unit sales per product, per channel | integer, 0…n | Shop platform, marketplace, POS | Yes |
| Stock on hand | integer | Inventory system or shop platform | Yes |
| Open purchase orders | units + expected date | Purchase order system | Yes |
| Supplier catalogue | MOQ, unit cost, lead time | Supplier records | Yes |
| Approved supplier list | supplier names | Owner settings | Yes |
| Spending limits | per order, per week | Owner settings | Yes |
| Do-not-reorder list | SKUs | Owner settings | No |
| Planned promotions | SKU, uplift %, date range | Owner calendar | No |
| Stock count corrections | SKU, counted units | Owner or staff | No |

Read-only access is requested for sales, stock, and open orders. Write access is
limited to **draft** purchase orders in the connected system.

## 3. Outputs

1. **Draft purchase orders**, one per supplier, with quantities, cost, and the
   reasoning attached.
2. **Approval requests** for orders over the limit, new suppliers, unusual data,
   or anything the agent is not allowed to decide.
3. **A weekly summary** for the owner: what was ordered and why, what is at risk,
   what is overstocked, what was held and why.
4. **An audit log entry** for every decision, including the inputs used and the
   outcome after the order arrived.

## 4. Tools the agent uses

- `read_sales(sku, from, to)` — read-only.
- `read_stock(sku)` — read-only.
- `read_open_orders(sku)` — read-only.
- `read_supplier(supplier_id)` — read-only.
- `draft_purchase_order(supplier_id, lines[])` — writes a draft only. Never
  sends an order to a supplier.
- `request_approval(order_id, reason)` — sends the owner a message with the draft
  attached.
- `log_decision(entry)` — append-only audit log.

No tool can change prices, product descriptions, customer records, or anything
customer-facing.

## 5. Decision rules

Processed per product, most urgent first (fewest days of cover).

1. **Do-not-reorder list** → stop. Record `blocked`.
2. **Invalid data** (negative on-hand, missing sales days, fewer than 14 usable
   days) → stop and ask. Record `hold`.
3. **Unusual demand** — any day above 4× the median daily sales in the last 30
   days → stop and ask. A human decides whether it was a bulk order, a data
   error, or real demand.
4. **Forecast** — the next 21 days, as a range:
   - weekday multiplier = that weekday's average ÷ the overall daily average,
     clamped to 0.6–1.6;
   - recent momentum = last 7 days, blended 60/40 with the 28-day baseline;
   - the blended rate is then limited to 0.6×–1.5× the 28-day baseline, so one
     unusual week cannot move the forecast too far;
   - planned promotion uplift applied after seasonality;
   - low = expected × 0.8, high = expected × 1.25.
5. **Reorder quantity** — `max(0, expected daily × (lead time + 7 safety days) −
   on hand − on order)`, rounded **up** to the supplier's MOQ multiple.
6. **Spending checks**, in this order:
   - new supplier → approval;
   - order value > per-order cap → approval;
   - committed this week + order value > weekly cap → approval;
   - otherwise → draft.
7. **Nothing needed** → record `none` with the days of cover, so the owner can
   see the agent checked.

Limits are inclusive: an order exactly at the cap is allowed.

## 6. Thresholds (defaults, all configurable)

| Setting | Default | Why |
| --- | --- | --- |
| Forecast horizon | 21 days | Three weeks covers most supplier cycles |
| Safety days | 7 | Absorbs a normal week of demand variation |
| Forecast band | 0.8× – 1.25× | Shows uncertainty instead of one false-precise number |
| Per-order cap | $600 | Owner-set; above this a person approves |
| Weekly cap | $2,500 | Owner-set; protects cash flow |
| Anomaly threshold | 4× median day | Separates a bulk order or data error from demand |
| Minimum history | 14 days | Below this the forecast is not reliable |
| MOQ rounding | supplier MOQ | Suppliers will not ship partial minimums |

## 7. Human checkpoints

- **Owner sets** the per-order cap, the weekly cap, the approved supplier list,
  and the do-not-reorder list.
- **Approval required** for: any order above the per-order cap; any order that
  would break the weekly cap; any new supplier; any product on the do-not-reorder
  list that somehow reaches the order step; any data-quality hold.
- **Owner can pause** the agent at any time, for one product or the whole shop.
- **The agent never sends** a purchase order to a supplier. Drafts only.

## 8. Guardrails

- Hard per-order and per-week spending caps, enforced in code, not in a prompt.
- Read-only sales, stock, and order access. Write access only to draft POs.
- Cannot change prices, promotions, product content, or customer data.
- Stops and alerts when sales data is missing, duplicated, or implausible.
- One draft per supplier per run; a second run within 24 hours reuses the draft
  instead of creating a duplicate.
- Every message to the owner names the product, the numbers, and the reason.
- If any tool call fails, the run stops with a partial report. It never guesses
  a stock level.

## 9. Failure handling

| Failure | Behaviour |
| --- | --- |
| Sales feed late | Wait up to 2 hours, then run with a visible "data as of" timestamp; do not order products with missing days |
| Duplicate sales rows | De-duplicate by order ID; if the total changes by more than 10%, hold the run |
| Supplier catalogue missing MOQ | Hold the product and ask for the MOQ |
| Purchase order system down | Keep the drafts locally, retry, and report the outage |
| Forecast error after the fact | Log actual vs forecast, and surface the error in the weekly summary |
| Owner does not respond | No order is placed; the product stays on the at-risk list |

## 10. Metrics

| Metric | Definition | Why it matters in plain words |
| --- | --- | --- |
| Stockout rate | Days a sellable product had zero stock ÷ days it was listed | How often a customer leaves empty-handed |
| Overstock days | Days of stock above 8 weeks of forecast demand | How long cash sits on a shelf |
| Cash tied up in stock | On-hand units × unit cost | Money you cannot spend elsewhere |
| Reorder time | Minutes a person spends checking stock and raising orders per week | The hours the agent gives back |
| Forecast error | Mean absolute percentage error of the 21-day forecast | Whether the agent's numbers can be trusted |
| Approval rate | Approved ÷ requested | Whether the limits are set sensibly |

We do not publish a promised improvement for any of these. The pilot measures the
shop's own baseline for four weeks before the agent drafts anything.

## 11. Integrations

- **Shop platforms:** Shopify, WooCommerce, BigCommerce (read sales and stock;
  write draft purchase orders where the platform supports it).
- **Marketplaces:** Amazon, eBay, Etsy via their APIs or a consolidated feed.
- **Accounting / inventory:** Xero, QuickBooks, Cin7, Linnworks via CSV export
  first; API later if the volume justifies it.
- **Messaging:** email and Slack/Teams for approvals; the owner replies
  "approve", "hold", or "change quantity".
- **Data handling:** credentials live in the server environment, never in the
  browser. Sales data is stored per shop, deleted 90 days after the run unless
  the owner asks to keep it. No customer names or addresses are read.

## 12. Audit log format

```json
{
  "run_id": "run_2026_10_19_0700",
  "at": "2026-10-19T07:00:04Z",
  "sku": "HW-101",
  "action": "draft_purchase_order",
  "inputs": {
    "on_hand": 18,
    "on_order": 0,
    "lead_time_days": 10,
    "moq": 12,
    "unit_cost": 7.5,
    "forecast_low": 78,
    "forecast_high": 122,
    "forecast_expected": 98,
    "weekly_spent": 240
  },
  "decision": { "qty": 120, "cost": 900, "status": "approval" },
  "reason": "Order value above the 600 per-order limit",
  "approval": { "requested_from": "owner", "responded_at": null },
  "outcome": { "received_at": null, "stockout_days": null }
}
```

## 13. Evaluation set

`src/content/retail/evals.ts` holds 32 scenarios: steady seller, urgent low
stock, overstock, do-not-reorder, new supplier, over the cap, exactly at the cap,
weekly cap boundaries, duplicate on-order, missing sales day, short history,
negative stock, demand spike, weekend seasonality, planned promotion, MOQ
rounding, long lead time, slow mover, new product, large MOQ, high unit cost,
seasonal decline, no weekly budget, several missing days, fractional averages,
incoming stock, and safety-stock gaps.

`npm test` runs every scenario against the same engine the demo uses. A scenario
fails if the status, quantity, MOQ rounding, or spend limit is wrong.
