Skip to content
Warrantv0.1

Policies

The rules that decide release, escalation or refund.

A policy is an ordered list of score bands plus a set of reason-code overrides, and it is the only thing that decides what happens to a warrant once the verifier reports.

{
  "bands": [
    { "minScore": 1, "outcome": "release", "label": "clean pass" },
    { "minScore": 0.8, "outcome": "partial_release", "releasedBps": 5000 },
    { "minScore": 0, "outcome": "escalate", "label": "anything else" }
  ],
  "maxAmount": "50000000",
  "alwaysEscalate": ["source_unreachable"],
  "alwaysRefund": ["source_not_found"]
}

The four outcomes

A policy resolves to exactly one of release, partial_release, escalate or refund. There is no fifth answer and no way to decline to answer, because a policy that could abstain would leave funds held forever.

Bands are read from the top score down

Bands are sorted by minScore descending, and the first one the score reaches wins. The score comes from the verifier: the share of clauses that passed, stored as basis points so it is exact rather than a float you have to trust.

A partial_release band must carry releasedBps strictly between 0 and 10000. A band that pays nothing is a refund and a band that pays everything is a release, so neither needs to be spelled as a partial.

Validation happens when the policy is written, not when a warrant settles. A policy with no band at minScore: 0 is rejected with policy_no_floor_band, because a low score would otherwise match nothing and the money would sit.

Reason codes override the score

alwaysRefund is checked first, then alwaysEscalate, and only then the bands.

This ordering is deliberate. "The source did not exist" is not a quality judgement, and a band should not be allowed to pay out 50% on it just because two of four clauses happened to pass. A reason code describes what went wrong; a score describes how much went right, and they are not the same question.

Amounts are integer strings of the smallest unit

maxAmount follows the same convention as every amount on the wire: a string of digits in the asset's smallest unit, validated against ^[0-9]+$.

"8400000"    8.40 USDC
8400000      rejected — a JSON number
"8.40"       rejected — not the smallest unit

The string is not decoration. 9007199254740993 as a JSON number silently loses precision as a double, and this is a payments API. The decimal point is a display concern and lives in the console, never on the wire.

Which policy applies

Policies are per agent, resolved newest-version-first:

  1. the agent's own newest policy version, if it has one
  2. otherwise the organisation default — the policy with a null agentId
  3. otherwise the built-in default

The built-in default is the strictest sensible rule and pays only on a clean pass:

{
  "bands": [
    { "minScore": 1, "outcome": "release", "label": "clean pass" },
    { "minScore": 0, "outcome": "escalate", "label": "anything else" }
  ]
}

Versions, never edits

A policy row is never edited in place. Writing new rules creates a new version under the same name, and a warrant pins the version it ran under.

The rules_hash — a SHA-256 of the rules object — is recorded on the trace. So a settlement from March can be re-read against the exact rules that produced it, and the record proves which those were rather than asking you to take the current row's word for it.