Per-instance baselines and four-axis scoring trigger auto-pause when an agent's behaviour deviates significantly from its own historical pattern. Compromise is a separate, manual state that requires key rotation to clear.
Pause states
agent_instances.pause_state is an enum:
none— normal operation.auto_paused— fired by the anomaly scorer. Principal can lift with a single click in the dashboard or viaPOST /api/v1/instances/{id}/resume.suspected_compromise— manual flag, fired by the principal (POST /api/v1/instances/{id}/report-compromise) or admin (POST /api/v1/admin/instances/{id}/flag-compromised). Cleared only byinstance.rotate_key— except pauses that mirror an admin account suspension (paused_reasonprefixprincipal_suspended:), which key rotation preserves and only admin unsuspension lifts.
Hard rule (route-helper layer + MCP dispatch): a paused instance
fails every state-changing route with HTTP 403 and code
instance_auto_paused or instance_compromise_paused. Reads still
work so the principal can investigate.
Anomaly scorer (pure)
Four axes:
| Axis | Function | Score |
|---|---|---|
spend_rate |
scoreSpendRate(observed_pph, baseline) |
z-score (clamped to ≥ 0) |
category_distribution |
scoreCategoryDistribution(observed, baseline) |
Jensen-Shannon divergence |
seller_distribution |
scoreSellerDistribution(observed, baseline) |
JSD |
time_of_day |
scoreTimeOfDay(observed[24], baseline[24]) |
JSD over 24-bin UTC histogram |
Thresholds:
- Spend-rate:
k_warn=2.5,k_pause=4.0(defaults; per-platform override viaagent_platforms.anomaly_k_warn_x10/_pause_x10). - JSD axes: warn at
k * 0.05, pause atk * 0.10.
Combine rule (combineAxisDecisions):
- Any single axis crossing pause → pause.
- Two axes simultaneously crossing warn → pause.
- One axis warn → warn.
- Otherwise no_action.
Cold-start floor:
learning_untilis set tonow + 7 dayson instance creation. Pause is suppressed until both the timestamp passes andconfirmed_orders_count >= LEARNING_MIN_ORDERS (20).PAUSE_FLOOR_ORDERS = 5is a hard floor regardless of learning state.
Self-instances skip scoring entirely.
Hooks
confirmPurchaseIntentcallsscoreInstanceActionafter the order insert (outside the tx, so a transaction rollback doesn't lose the pause record). Best-effort: errors are logged, never undo a confirmed order.- Hourly worker
recomputeAllBaselinesrefreshesagent_instance_baselinesfrom the last 30 days of orders.
Notifications
instance_auto_paused— principal in-app + email; webhook for non-interactive principals.instance_compromise_reported— principal and platform contact email.instance_compromise_resumed— fired whenrotate_keylifts the pause.
Resume flows
auto_paused→noneviaPOST /api/v1/instances/{id}/resume(principal-only). Resets the baseline to zero so the next 24 h aren't immediately re-flagged. Audit row written.suspected_compromise→ cleared atomically whenrotateInstanceKeyis called on a compromised instance. The new secret hash and the pause clear write in one transaction. Pauses applied by admin account suspension survive rotation; they clear only when the admin unsuspends the principal.
Internal-AI explanation
When a pause fires, an explanation worker runs against the internal Anthropic key:
- Model:
INTERNAL_MODEL(claude-haiku-4-5-20251001). - Cap: 400 output tokens.
- Persisted into
anomaly_events.explanation+explanation_model_version. - Daily budget cap:
PHASE_F_AI_BUDGET_PENCE(default £50/day). - Kill switch:
AGENT_AI_INTERNAL_DISABLED=truewrites a placeholder. - Failure path (network error, missing key) writes the same placeholder; the pause itself is unaffected.
Effects on delegation and seller actions
- Delegation envelope drawdowns: refused for paused instances at the actor-resolution layer. Existing balances are preserved (so refunds still flow); new draws fail.
- Seller actions: paused instances cannot ship, accept returns, respond to reviews, or respond to disputes. Reads still work.
Feature flags
AGENT_ANOMALY_DETECTION_ENABLED— global kill switch on the scorer hook + worker. Whenfalse, baselines still recompute (cheap) but no events fire and no pauses trigger.agent_platforms.anomaly_pause_enabled— per-platform opt-out for pause; warn-class events still record. Defaulttrue.
Schema
| Table | Purpose |
|---|---|
agent_instance_baselines |
One row per instance; the four-axis baseline (UTC time-of-day, top-N seller dist, leaf-slug category dist, spend-rate mean+stdev). Recomputed hourly. |
anomaly_events |
Append-only journal — one row per axis per scoring call. decision, score, threshold_warn, threshold_pause, explanation (when populated). |
agent_instances.pause_state + paused_at/paused_reason/paused_event_id/paused_by_principal_id/learning_until |
Live state. |