> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aperium.apps.hillspire.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing a policy

> Dry-run a guardrail policy against sample input and read its exact verdict.

The dry-run tester runs a single policy against a sample you supply and shows
exactly what it would decide — the aggregate action plus each guardrail's
observation. It writes no audit entry and has no runtime side effects.

<Warning>
  **This is the way to observe a policy's behavior in v1.** Because authored
  policies do not yet enforce at runtime (see
  [How guardrails enforce today](/admins/guardrails/how-it-enforces)), the
  dry-run is the only place you'll see a policy fire. Requires the
  `guardrail.test` capability.
</Warning>

## Running a dry-run

<Steps>
  <Step title="Open the tester">
    From the [Policies](/admins/guardrails/policies) table, open a row's overflow
    menu and choose **Test**. A dry-run panel opens beneath the table for that
    policy.
  </Step>

  <Step title="Enter sample input">
    Type a **sample input** — the user message, response text, or tool-argument
    payload the policy should evaluate. The tester infers the stage from the
    policy and builds a synthetic context around your text.
  </Step>

  <Step title="Optionally override the mode">
    Leave **mode override** on *Use policy mode*, or pick `enforce`, `monitor`,
    or `disabled` to answer "what would happen if I flipped this policy to that
    mode?" without changing the saved policy. A policy evaluated as `disabled`
    returns Allow without invoking the rule.
  </Step>

  <Step title="Run the test">
    Click **Run test**. The result renders in place.
  </Step>
</Steps>

## Reading the result

The response has two levels:

* **Aggregate** — the single action the stage would produce (`allow`, `block`,
  `confirm`, or `modify`) and a reason. This is what the caller would see.
* **Observations** — one line per guardrail that ran, showing its name, the mode
  it ran in, its action, and its reason. This is where you see *why* the
  aggregate came out the way it did.

Every result ends with the note **"DRY RUN — no audit emitted, no runtime side
effects."** as a reminder that nothing was recorded or enforced.

<Tip>
  A good tuning loop: create the policy in Monitor, dry-run it against a handful
  of representative real and adversarial samples, override the mode to `enforce`
  to confirm the aggregate flips as expected, then switch the saved policy to
  Enforce once the runtime wire-in ships.
</Tip>

## Behind the scenes

The tester calls `POST /api/admin/guardrails/policies/{id}/test`. It constructs a
synthetic context from your sample and evaluates just that one policy — it does
not run the rest of your policy set, does not touch the real turn pipeline, and
does not persist anything.

<Info>
  The API also accepts an optional structured context (actor roles,
  capabilities, tool name) for tool- and input-stage tests. The console form
  exposes sample input and mode override; richer context can be supplied through
  the API directly. Verify field names against your deployment before relying on
  them.
</Info>
