Skip to main content
Source of truth: ARCHITECTURE.md sections 16.1 and 16.2, implemented in libs/risk. The types are TypeScript because a type is harder to misread than a paragraph. They are the contract, not an implementation.

Decision

The checks are a fixed set of typed, pure functions inside the risk engine. The thresholds they read are a versioned, signed JSON document. The policy is not an interpreted rules language and not an external rules engine. The reasoning is on Spend policy.

PolicyDocument

The label traded-asset marks the ERC-20 base a close sells. Such a token is allowlisted with approve (and, if ever needed, transfer) only, is held to the recipient rule, counts 0 against both caps, and is never itself a recipient.

Ledger, Violation, Decision

A rejection returns every violation found, not only the first, so monitoring sees the full shape of a bad proposal. The risk engine evaluates the plan, not the intent. Every Decision is logged with policyVersion and policyHash, so a past approval can be replayed against the exact document that produced it.

Proposal and plan types

The trading module submits only a plan whose hash equals the approved planHash.

ReallocationProposal

The plan is exactly two calls: approve(reallocationContract, total) on the settlement asset, then reallocate(evaluation, policyHash, credits) on the contract labeled reallocation. The engine rejects a plan that does not encode the proposal exactly (plan-hash-mismatch), and re-checks from the ledger what the contract checks on-chain, under the three separate violations reallocation-party, reallocation-policy, and reallocation-bound.

How policy versions are authorized

Policy documents live in an append-only table with the document, its hash, the signer address, and the signature. Each version is signed (EIP-191) by an operator key distinct from every session key and pinned in the worker’s configuration. On load the engine verifies the signature, the previousHash chain back to version 1, and that effectiveFrom never moves backward. A failure yields policy-unverified for every request.

How the schema versions

version changes when a threshold changes. That is data, signed, and deployed without code. schemaVersion changes when a field or a check is added or removed. That is a code change reviewed in a pull request that updates ARCHITECTURE.md section 16. The engine accepts only the schemaVersion values it was built for and treats any other as policy-unverified.
Last modified on October 13, 2026