Dry-run vs enforce (the two dials)
An action fires only when both the SDK firewall mode and the per-rule execution mode say enforce. Default is dry-run.
TokenPolice has two dials, and a rule only acts — blocks, reroutes — when both are turned to enforce. This is deliberate: it lets you watch what a rule would do before you let it do anything.
Dial 1 — the SDK firewall mode
Set once, app-wide, in tp.init(). It has three settings:
firewall | What happens |
|---|---|
"dry_run" (default) | Runs the full check on every call and records what it would do — but never blocks or reroutes. Watch mode. |
"enforce" | Same checks, but now actions actually fire. |
"off" | No checks at all. Calls are still logged for your dashboard, but no rule can ever act. |
tp.init(
api_key=os.environ["TOKENPOLICE_API_KEY"],
base_url="https://collect.tokenpolice.ai",
firewall="dry_run", # start here; flip to "enforce" when ready
)Dial 2 — the rule's execution mode
Every firewall rule you create in the dashboard has its own mode: Dry-run (the default for a new rule) or Enforce. This lets you roll out one rule at a time — flip a single rule to Enforce while the rest keep watching.
Both must say enforce
An action only fires when the SDK dial and that rule's dial both say enforce:
SDK firewall | Rule mode | Result |
|---|---|---|
dry_run | Dry-run | Logged as would-block — nothing happens |
dry_run | Enforce | Logged as would-block — nothing happens |
enforce | Dry-run | Logged as would-block — nothing happens |
enforce | Enforce | The action fires (e.g. TokenPoliceBlockedError) |
off | (either) | No check runs at all |
In any dry-run combination, TokenPolice records the decision as a would-block so you can see the impact in the dashboard — it just doesn't touch your call. There's no separate "shadow" mode; dry-run is the watch mode.
Notify rules have no dial. A rule whose action is Notify doesn't change your call, so there's nothing to hold back: it has no Enforce / Dry-run setting and it sends its alert whichever way the SDK dial is set. The two dials govern the actions that touch traffic — Block and Reroute.
The rollout you'll actually do
Start with firewall="dry_run". Add your rules. Watch the would-block entries pile up in
the dashboard and confirm they match what you expect.
Flip the one rule you trust to Enforce in the dashboard. Nothing changes yet — the SDK
dial is still dry_run.
When you're ready to go live, set firewall="enforce". Now every Enforce rule acts; any rule
still on Dry-run keeps watching.

