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:

StepWhat it tests
DLP scanScans the prompt text for PII, secrets, and other sensitive entity types using the live DLP pipeline (if configured on the outpost).
Budget checkCompares current usage totals against budget_config thresholds in the policy bundle.
Routing checkResolves 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"
}
FieldTypeRequiredDescription
promptstringYesThe user message text to evaluate
providerstringNoProvider name (informational for the routing step)
modelstringNoModel name to resolve in the routing check
org_idstringNoOrg 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"
}
]
}
FieldTypeDescription
final_actionstringThe effective policy decision: ALLOW, BLOCK, REDACT, CANCEL, or PROMPT
combining_algorithmstringAlways "first_match"
evaluation_msfloatTotal simulation time in milliseconds
tracearrayOne entry per evaluation step

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

FieldTypeDescription
stepstringStep identifier (see below)
triggeredboolWhether this step produced an action that affects the final result
actionstringThe action this step recommends: ALLOW, BLOCK, REDACT, CANCEL, or PROMPT
detailstringHuman-readable explanation (present when there is additional context)
FieldTypeDescription
stepstring"dlp" when DLP is not configured, or "dlp_tier1_{tier_used}" (e.g. "dlp_tier1_regex", "dlp_tier1_deberta")
entitiesarrayDetected entities. Text is never returned — only type and character offsets.
entities[].typestringEntity type (e.g. AWS_ACCESS_KEY, CREDIT_CARD, EMAIL_ADDRESS)
entities[].startintStart character offset in the prompt (inclusive)
entities[].endintEnd character offset in the prompt (exclusive)
duration_msfloatDLP scan duration in milliseconds
tier_usedstringDLP 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".

FieldTypeDescription
stepstringAlways "budget_check"
total_requestsintCurrent period request count (from usage tracker, if available)
total_estimated_costfloatCurrent period estimated cost in USD
action_on_exceedstringBudget 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.

FieldTypeDescription
stepstringAlways "routing"
providerstringResolved provider name
model_idstringResolved model ID
errorbooltrue 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.


ValueMeaning
ALLOWRequest passes all policy checks.
BLOCKRequest is blocked. The prompt is not forwarded to the provider.
REDACTPrompt is redacted before forwarding (PII scrubbed).
CANCELRequest is silently cancelled (no error returned to caller).
PROMPTRequest 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.