# HITL approval architecture — eCommerce AI agents

Companion to **Human-in-the-loop AI agents for eCommerce**.

HITL is a **queue with evidence**, not a system prompt that says “ask a human if unsure.” Gateway Cedar is the first gate. The queue is the second. The model is neither.

## When the queue must exist (high blast radius)

| Action class | Why HITL | Typical evidence on the ticket |
| ------------ | -------- | ------------------------------ |
| High-value refund / createReturn | Money + fraud adjacency | Order id, status, refundUsd, RMA, Cedar decision |
| Pricing / discount issuance | Margin | SKU, list vs proposed, promo-engine id |
| Large purchase orders | Vendor + cash | Vendor id, qty, unit cost, buyer role |
| Fraud / disputes / chargeback language | Legal + processor | Ticket text, stop-writes flag, no refund tool |
| Account changes (email, address, payout) | Identity / PII | Claimed shopper id, proof step, associate JWT |
| Irreversible catalog / inventory writes | Live merch / ATP | Before/after fields, PIM version |

## Flow

```text
Agent turn
  → named tool proposal
  → Gateway Cedar (LOG_ONLY then ENFORCE)
  → DENY: stop, alarm, no queue spam
  → ALLOW under auto cap: workflow executes (idempotency key)
  → ALLOW but over HITL threshold OR irreversible: enqueue
  → Human (helpdesk / Slack / Next.js dashboard)
  → Approve → workflow executes (same key)
  → Reject → Memory note + customer-safe explanation
```

Next.js + TypeScript + Tailwind is a **typical ops dashboard** for replay and buttons. It is not the AgentCore runtime. A helpdesk-native queue is valid. A terminal is not a strategy.

## Ticket payload (illustrative JSON)

Context: not an OMS schema. Python 3.12+ if you later post this from a Lambda behind Gateway. `runtimeSessionId` on Harness data plane must be ≥33 characters.

```json
{
  "approvalId": "hitl-2026-08-27-001",
  "runtimeSessionId": "11111111-1111-1111-1111-111111111111",
  "harnessArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:harness/commerce-support",
  "proposedAction": "createReturn",
  "orderId": "ORD-1001",
  "refundUsd": 140,
  "identity": { "role": "associate", "sub": "assoc-19" },
  "cedarDecision": "ALLOW",
  "hitlReason": "refundUsd > storeCap75",
  "toolTrace": ["getOrder", "getShipment", "getReturnPolicy"],
  "idempotencyKey": "createReturn:ORD-1001:ret-88"
}
```

Approve must call the **workflow** (OMS return API), not a second unconstrained `InvokeHarness` turn with write tools still attached.

## Queue SLAs (worksheet — fill your numbers)

| Queue | Who | Suggested SLA | Fail closed |
| ----- | --- | ------------- | ----------- |
| Support HITL | CS lead | Same shift for refunds | No auto-approve on timeout |
| Merch HITL | Merchandiser | Before next publish window | Draft stays draft |
| Buyer HITL | Purchasing | Before vendor cutoff | PO stays draft |
| Fraud HITL | Risk | Before any goodwill | Writes stay DENY |

**Do not** auto-approve on SLA breach. Timeout → remain queued or expire to “human must re-open.” Auto-approve is Fully Automated with extra latency.

## Related

- Per-action levels: [`autonomy-spectrum-by-action.md`](autonomy-spectrum-by-action.md)
- Security: [`ecommerce-agent-security-checklist.md`](ecommerce-agent-security-checklist.md)
- Support week-one tools: [`support-agent-tool-policy.md`](support-agent-tool-policy.md)
