Roll out with shadow mode, then enforce
Try a plan on real traffic without blocking anyone. When the “would denies” look right, switch to enforce from the console, with no deploy.
Two modes, one decision
Section titled “Two modes, one decision”Every plan has a mode. The mode never changes the decision. It only tells your code what to do with a deny.
| enforce | shadow | |
|---|---|---|
| On allow | Run the tool. | Run the tool. |
| On deny | Don’t run the tool. | Run the tool anyway. The deny is recorded as a “would deny”. |
| Use it for | Real limits | Trying a plan on real traffic without blocking anyone |
decision is allow or mode is shadow.Roll it out
Section titled “Roll it out”-
Start the plan in shadow
Section titled “Start the plan in shadow”New plans you create in the console start in shadow: the mode menu on Add plan says “shadow (start here)”. The two sandbox plans you get at sign-up,
pilotandprod, are in enforce, so the “6th call is a deny” demo works. -
Follow the mode in your code
Section titled “Follow the mode in your code”A deny is always HTTP 200, in both modes. Check the
modefield in the answer and apply the rule:python if status != 200:e = body["error"] # branch on e["code"], never on the message...if body["decision"] == "allow":print(f"allow: run the tool ({left}, request_id {request_id})")return 0if body["mode"] == "shadow":print(f"would deny (shadow): {body['reason']}, run the tool anyway ({left}, request_id {request_id})")return 0print(f"deny: {body['reason']}, don't run the tool ({left}, resets {body['resets_at']}, request_id {request_id})")return 2Leave
modeout of your requests so the plan’s setting applies. If you send"mode": "shadow"or"mode": "enforce", that pins it for the call and the console switch has no effect. -
Watch the would-denies
Section titled “Watch the would-denies”Allowed calls count toward the plan limit the same way in both modes and denies never do, so the count is already right when you switch. Denies are always free.
- Overview: “N calls in the last 7 days would have been denied (shadow mode, so they ran)”, with a link to the Plans page.
- Decisions: the decision column reads would deny (call ran), and the mode column says
shadow. - Export (CSV or JSON): a shadow deny has
decision=denyandmode=shadow. Filter on themodecolumn to separate the two.
-
Switch to enforce
Section titled “Switch to enforce”- Open the Plans page.
- On the plan’s row, click switch to enforce.
Your running server picks up the new mode on its next call, with no deploy, as long as your code doesn’t pin a mode. The switch is recorded in Console → Change log. To roll back, click switch to shadow.
With the Node SDK
Section titled “With the Node SDK”Prefer our Node SDK? Install it with npm install ordainer; the Node / Express quickstart walks through it.
With mode unset (the default), the SDK follows the plan’s mode from each answer. Your server log shows a line like this for a shadow deny:
[ordainer] shadow: would deny tool=research.run reason=quota_exceeded remaining=0/5 request_id=req_… (call allowed)To pin a mode instead:
const ordainer = new Ordainer({ mode: 'shadow' });A pinned mode overrides the console. Remove the pin to follow the console again. To send would-denies to your own metrics, pass onDecision: (d) => …; d.wouldDeny is true for shadow denies.
Your caller never sees a would-deny: in shadow the tool runs and returns its normal answer. Before you copy anything from req.ordainer into a response, read What your caller sees in shadow.
Shadow mode at the test limit
Section titled “Shadow mode at the test limit”Shadow mode never blocks a call because of a plan or test limit. After your test keys reach their monthly limit, each shadow call still counts and is logged as a would-deny with the reason test_limit_reached, and the answer still tells your tool to run. To protect the service, shadow calls have a safety ceiling of 10 times your test limit. Past it, they return HTTP 429 with safety_limit_reached until your test usage resets at the start of the next month (UTC), and those calls aren’t counted or recorded. That’s a safety limit, not a deny. Our SDK (version 1.2.0 and later) lets the tool run automatically. If you call our API directly, we recommend letting the tool run and logging the error. If you reach it, email support@ordainer.ai.
Not the same thing as fail open
Section titled “Not the same thing as fail open”Shadow is about what to do with a real decision. Fail open / fail closed is about what to do when we can’t answer (timeout, network error, server error). They are separate settings. See Fail open vs fail closed.