Docs Guides

Five checks M0 to M4

LiveUpdated

View as Markdown

A policy is enforced twice by design: Enruta decides, then the rail’s own control decides again. Spelled out, that is five checks, each with a moment, a question and a failure action. The fifth, after settlement, is the one no agent-payment protocol writes down.

CheckWhenWhat is checkedOn failureStatus
M0Before the mandate is createdPolicy applicability: is there a signed policy that covers this agent, payee and category; is the agent paused; is a consent required and presentNo mandate; deny with no_matching_policy, agent_paused or consent_revokedLive
M1Before the credential is issuedWhether the request carries what the policy needs (intent_coverage); the agent’s identity anchors and the merchant check; the intent rules; payee, category, time window, per-payment cap, cumulative budget (atomic reservation), duplicate and idempotency; the approval threshold; the model’s verdict when the policy uses oneclarify with questions, deny or step_up; under a shadow policy, observeLive
M2Before the rail is calledThe credential is bound to the mandate; the amount within tolerance; the rail’s finality_class matches what the mandate was stamped with; on a crypto rail, the collateral is read againdenyLive
M3When the rail asksAmount, currency and merchant against the mandate, answered inside the issuer’s two-second windowThe authorization is refused: amount_exceeds_mandate, merchant_mismatch, mandate_consumed, mandate_expiredLive; 44 ms in production
M4After fulfillment and settlementFulfillment confirmed, cleared amount, refunds, the merchant’s order, all joined per mandateAn exception with a suggested action on the reconciliation line, into the weekly reportLive

Around the five there are two states: observe (shadow mode), where the checks run and nothing is enforced, and clarify (intent and clarification), where the request waits for the person’s answers before M1 runs again.

Two failures, two checks

Ten agents each request $100 with $500 left in the month. The only authority on the budget is M1’s atomic reservation (UPDATE budgets … WHERE reserved + spent + amount ≤ cap): the sixth mandate cannot be issued, and the remaining five are denied with over_budget. M3 catches a different class of error: a single-use card presented at another merchant, or a merchant trying to clear $120 on a $100 card, is refused by the rail with merchant_mismatch or amount_exceeds_mandate. Together they are the answer to “you budgeted $100 and spent $1,000”.

Where each check is recorded

CheckIn the record
M0, M1decision.checks[], decision.reasons[], decision.judgement, decision.risk; request.intent, agent.identity, payee.identity
M2mandate, card_control_state, execution
M3rail_authorization_record with answered_in_ms
M4The settlement_record and reconciliation_line records chained to the payment