A policy file is an ordered list of rules, and the first rule that matches a subject, verb, scope, and conditions decides the action. That gives you a lot of room to make a mistake. Pinned floors are the part of the engine that stops a policy author from waving through something dangerous, by accident or on purpose.
What a floor is
A floor is a built-in minimum decision the engine enforces at load time, no matter what your rules say. A normal rule is something you write; a floor is something the engine already knows. Certain action lanes carry a built-in promise: they can never resolve weaker than require_approval.
The check runs when the policy is parsed, not when an action arrives. So a policy that breaks a floor never loads — it is rejected before it can gate a single action. There is no window where a bad policy is live and quietly allowing things it should not.
A floor is not a lint warning you can ignore. A policy that contradicts one is rejected at load — the engine refuses to run it. The safe default for any unmatched dangerous lane is also require_approval, so a gap in your rules fails closed, not open.
The dangerous lanes
Four lanes are floored. Each maps to an action verb, and each carries the same floor: it cannot be allowed without human approval.
| Lane | Verb | Floor |
|---|---|---|
| Payments | payment | require_approval |
| Deletes | delete | require_approval |
| Account changes | account_change | require_approval |
| Large data exports | data_export | require_approval |
These are the actions where a wrong move is expensive and hard to undo: money leaves, records vanish, credentials change, data walks out the door. The floor says a human with their own key has to stand behind each one. That human approval is what lifts a receipt from L0 to L1.
Tighten, never bypass
A floor sets a minimum, not a maximum. You are free to make a dangerous lane stricter — you just cannot make it looser than the floor. Tightening is exactly what most real policies do:
- Require more than one approver — a finance lead and a CFO must both co-sign, not just one person.
- Lower a threshold so approval kicks in earlier — route every payment over $1,000 instead of over $5,000.
- Block outright — a
blockdecision is stricter than approval, so blocking a lane is always allowed. - Add a tighter
sla_minutesso the approval cannot sit unanswered.
Here is a rule that tightens the payment floor. It keeps require_approval and adds two named approvers and a shorter SLA — the engine accepts it because it asks for more, not less:
# Allowed: the floor for payments is require_approval.# This rule TIGHTENS it — two approvers, a faster SLA.[[rule]]id = "pay-large"order = 10enabled = truesubject = { kind = "any" }verb = "payment"scope = "*"conditions = [ { field = "amount_usd", op = "gt", value = 5000, display = "amount over $5,000" },]decision = "require_approval"approvers = ["finance-lead", "cfo"]sla_minutes = 30
The one thing you can never write is a rule that resolves a floored lane to allow with no human in the loop. That is the single move a floor forbids.
The [FLOOR_BYPASS] error
When a rule would allow-without-approval a dangerous lane, the engine rejects the whole policy at load with a [FLOOR_BYPASS] error that names the offending rule id and verb. The policy below tries to auto-allow every payment:
# Rejected at LOAD time. You cannot allow a payment# without human approval — payment is a floored lane.[[rule]]id = "pay-auto"order = 10enabled = truesubject = { kind = "any" }verb = "payment"scope = "*"conditions = []decision = "allow"
Loading it fails. The error identifies precisely which rule broke the floor and on which verb, so the fix is unambiguous:
[FLOOR_BYPASS] rule "pay-auto" cannot allow verb "payment" without approvalTwo error families guard the load path. A [FLOOR_BYPASS] means the file parsed fine but a rule contradicts a pinned floor. A [PARSE] means the file is malformed — bad TOML, a missing field, or a value the engine cannot read — and never reaches the floor check at all. Both stop the policy from loading.
Either error aborts the load, which means the policy is never activated. The control plane re-runs the same checks, so a policy that fails locally also fails on the server — there is no path where a floor-bypassing file slips into production.
Checked before you deploy
You do not have to push a policy to find out it breaks a floor. The exact same engine logic runs in the browser, so the editor catches it the moment you write it. Two functions back this:
parsePolicy— reads the TOML and surfaces a[PARSE]error if the file is malformed.validateNoFloorBypass— runs the floor check and surfaces the[FLOOR_BYPASS]error, with the same rule id and verb you would see on the server.
The browser, Node, and Python all call the one Rust core — nothing is reimplemented — so the reason string you read in the editor is byte-identical to the one the engine would produce at deploy. You see the real verdict, not a guess, before anything ships. See Test & deploy for the full simulate-then-deploy loop, and the browser verifier for how the WASM surface runs these checks locally.
A floor guarantees that a loaded policy can never auto-allow a dangerous lane: the structure is sound and a person must co-sign before it can proceed. It constrains authorization — no dangerous action runs unsigned — not the outcome; it does not say whether the co-signer approved wisely.
