Skip to content

Outpost Policy Simulator

The outpost policy simulator runs a mock request through the local policy chain and returns a structured evaluation trace. It exercises the same decision logic as the live proxy but produces no side effects — no request is forwarded, no audit entry is written, and no usage is recorded.

Use the simulator to validate policy bundles before deploying to outpost nodes, and to diagnose unexpected BLOCK or CANCEL decisions in existing configurations.


The simulator executes three checks in sequence:

Step What it tests
DLP scan Scans the prompt text for PII, secrets, and other sensitive entity types using the live DLP pipeline (if configured on the outpost).
Budget check Compares current usage totals against budget_config thresholds in the policy bundle.
Routing check Resolves which provider and model ID would be selected for the requested model.

The simulator uses the first_match combining algorithm: the final_action is the action of the first triggered step. If no step triggers, final_action is ALLOW.

Steps are evaluated in order: DLP → Budget → Routing. Once a triggered step is found, evaluation stops and the remaining steps are still reported in the trace (with triggered: false).


The simulator is exposed as a POST endpoint on the outpost admin interface:

POST /admin/simulate
Content-Type: application/json
{
"prompt": "My AWS key is AKIAIOSFODNN7EXAMPLE",
"provider": "openai",
"model": "gpt-4o",
"org_id": "org-uuid-here"
}
Field Type Required Description
prompt string Yes The user message text to evaluate
provider string No Provider name (informational for the routing step)
model string No Model name to resolve in the routing check
org_id string No Org identifier for budget usage lookup
{
"final_action": "BLOCK",
"combining_algorithm": "first_match",
"evaluation_ms": 4.127,
"trace": [
{
"step": "dlp_tier1_regex",
"triggered": true,
"action": "BLOCK",
"entities": [
{"type": "AWS_ACCESS_KEY", "start": 14, "end": 34}
],
"duration_ms": 3.21,
"tier_used": "regex"
},
{
"step": "budget_check",
"triggered": false,
"action": "ALLOW",
"detail": "within budget",
"total_requests": 4823,
"total_estimated_cost": 12.47
},
{
"step": "routing",
"triggered": false,
"action": "ALLOW",
"provider": "openai",
"model_id": "gpt-4o"
}
]
}
Field Type Description
final_action string The effective policy decision: ALLOW, BLOCK, REDACT, CANCEL, or PROMPT
combining_algorithm string Always "first_match"
evaluation_ms float Total simulation time in milliseconds
trace array One entry per evaluation step

Each entry in trace has a common set of fields plus step-specific details.

Field Type Description
step string Step identifier (see below)
triggered bool Whether this step produced an action that affects the final result
action string The action this step recommends: ALLOW, BLOCK, REDACT, CANCEL, or PROMPT
detail string Human-readable explanation (present when there is additional context)
Field Type Description
step string "dlp" when DLP is not configured, or "dlp_tier1_{tier_used}" (e.g. "dlp_tier1_regex", "dlp_tier1_deberta")
entities array Detected entities. Text is never returned — only type and character offsets.
entities[].type string Entity type (e.g. AWS_ACCESS_KEY, CREDIT_CARD, EMAIL_ADDRESS)
entities[].start int Start character offset in the prompt (inclusive)
entities[].end int End character offset in the prompt (exclusive)
duration_ms float DLP scan duration in milliseconds
tier_used string DLP tier that produced the result (regex, ner, deberta)

When DLP is not configured on the outpost, the step returns triggered: false with detail: "DLP not configured".

Field Type Description
step string Always "budget_check"
total_requests int Current period request count (from usage tracker, if available)
total_estimated_cost float Current period estimated cost in USD
action_on_exceed string Budget enforcement mode: "block", "warn", or "log_only"

Budget check results when no budget_config is present in the policy bundle: triggered: false, detail: "no budget_config in policy bundle".

The triggered field is true only when action_on_exceed == "block" AND a cap is exceeded. warn and log_only modes set triggered: false even when a cap is exceeded.

Field Type Description
step string Always "routing"
provider string Resolved provider name
model_id string Resolved model ID
error bool true when the model could not be resolved to any configured provider

Routing resolution order:

  1. Check explicit routing_rules in the policy bundle for the requested model.
  2. Fall back to scanning each provider’s models list.

The routing step does not trigger a blocking action — it is informational and always has action: "ALLOW". If resolution fails, error: true is set on the step.


Value Meaning
ALLOW Request passes all policy checks.
BLOCK Request is blocked. The prompt is not forwarded to the provider.
REDACT Prompt is redacted before forwarding (PII scrubbed).
CANCEL Request is silently cancelled (no error returned to caller).
PROMPT Request is held for human review (PROMPT governance flow).

Before updating a policy bundle on a production outpost, run the simulator against representative prompts to verify the bundle produces expected outcomes:

Terminal window
# Test that a prompt with a credit card number is blocked
curl -s -X POST http://outpost-host:8080/admin/simulate \
-H "Content-Type: application/json" \
-d '{
"prompt": "Charge 4111111111111111 for the subscription",
"model": "gpt-4o"
}' | jq '.final_action, .trace[0].entities'

Expected: "BLOCK" with entities[0].type == "CREDIT_CARD".

When users report unexpected BLOCK decisions in production, reproduce the request with the simulator to identify which policy step triggered and why. The trace shows the exact step name, entity type, and budget values at the time of evaluation.

Test that a model name resolves to the expected provider and model ID before adding it to a routing rule:

Terminal window
curl -s -X POST http://outpost-host:8080/admin/simulate \
-H "Content-Type: application/json" \
-d '{
"prompt": "Hello",
"model": "claude-3-5-sonnet"
}' | jq '.trace[] | select(.step == "routing")'

Verify that budget enforcement behaves correctly before a cap is actually hit by temporarily setting a very low threshold in a test policy bundle and running the simulator with a real org_id to see how the budget step responds.


  • The simulator evaluates the local policy bundle on the outpost where it runs. It does not reflect any pending bundle updates that have not yet been applied to that outpost.
  • Budget check accuracy depends on the usage tracker having current data. If the usage tracker is unavailable, the budget step reports 0 requests and 0 cost and returns triggered: false.
  • The DLP step requires a configured dlp_pipeline on the outpost. When DLP is not initialized, the step is skipped with triggered: false.
  • The simulator does not evaluate org-level DLP overrides or group-level DLP configs — it uses the outpost’s local DLP pipeline only.