# Purchase order — approval gates

Companion to **AI purchase order agent for eCommerce**.

Demo thresholds are **labels for the sample**, not FactualMinds buying limits. Replace every dollar and qty with finance policy.

## Flow

```text
Inventory risk brief
  → demand (forecast tool or velocity)
  → vendor (preferred + backup, lead time, last cost)
  → PO recommendation (qty, vendor, need-by, unit cost)
  → human approval (Cedar + buyer JWT)
  → createPurchaseOrder
```

The agent drafts. The buyer sends.

## Recommendation must include

| Field | Source tool | Fail if missing |
| ----- | ----------- | --------------- |
| SKU + qty | risk brief + `getDemandForecast` or velocity | Qty from chat only |
| Vendor | `getPreferredVendor` / last PO | Model-picked “cheaper” vendor with no tool |
| Lead time | `getVendorLeadTime` | Invented days |
| Unit cost | last PO or `getVendorQuote` | Hallucinated discount |
| Open POs | `getOpenPurchaseOrders` | Stacking on inbound |
| Inventory position | `getInventoryPosition` | Reserved treated as zero |

## Approval matrix (fill yours)

| Condition | Sample gate (replace) | Auto-send? |
| --------- | --------------------- | ---------- |
| Draft PO, any value | Buyer review | **No** — week one |
| Line value ≥ $X | Finance + buyer | No |
| New vendor | Vendor ops + finance | No |
| Qty > 2× 28-day velocity | Merch + buyer | No |
| PO change / cancel | Same as create | No |
| Below $X **and** preferred vendor **and** Policy ENFORCE | Optional later | Only after canary; still not shopper JWT |

## Cedar shape (not a live policy)

```text
# Context: AgentCore Gateway Policy. Default-deny writes.
DENY createPurchaseOrder UNLESS principal.role IN ["buyer", "admin"]
DENY sendPurchaseOrder  UNLESS principal.role == "buyer" AND amount <= finance.cap
# Prompt text is not this file.
```

`LOG_ONLY` is not approval. Prove DENY in non-prod before `ENFORCE`.
