Resolution, Disputes, and Settlement
Three distinct moments, in order: resolve records a verdict, the dispute window lets anyone challenge it, and settlement actually moves the escrowed money and stamps a receipt. Conflating the first and last is the most common pact mistake - a resolved pact has paid nobody yet.
Resolving
Only the creator or a platform admin may resolve, and only from open,
claimed, or locked; anyone else gets 403 insufficient_permissions.
Markets name a winning --outcome; the other kinds pass --fulfilled
(present = kept / claim accepted / covered event happened, absent =
failed):
snug pact resolve --pact-id pact_b95d... --fulfilled --evidence "strava screenshots attached"{
"status": "resolved",
"receipt": null,
"resolution": {
"fulfilled": true,
"resolved_by": "docs-wave",
"verifier": "manual",
"detail": "strava screenshots attached",
"resolved_at": "2026-08-28T14:16:59.675338Z",
"dispute_window_ends_at": "2026-08-29T14:16:59.675338Z"
}
}Note receipt: null - the verdict is recorded and the dispute window is
open, but nothing has been paid.
Verifiers
The pact's verifier, fixed at creation, decides how much the resolver's word counts:
manual- the resolve call itself is the verdict.arbiter- the evidence and claimed verdict are handed to the Arbiter LLM judge against the pact's--rubric(falling back to the description); an aggregate score of at least 0.5 verifies. The server must have an LLM provider configured or resolution fails with400 resolution_failed.hitl- resolution is gated on human approval. The first resolve call files a HITL request with the pact's--approverlist and returns403 verifier_mismatch: hitl decision is still pending. Once enough approvers respond, resolving again completes:
snug pact resolve --pact-id $PACT --fulfilled # 403 verifier_mismatch, files the request
# as the approver:
snug hitl approval respond --request-id pact_${PACT}_0 --approve
# as the creator, again:
snug pact resolve --pact-id $PACT --fulfilled
# -> status: resolved, resolution.external_ref: pact_pact_a0ff..._0A rejection (or a rejected arbiter verdict) still resolves the pact - as
fulfilled: false, which routes the money accordingly.
The dispute window
While status is resolved and the window is open, anyone may file one
dispute; the configured bond (100 by default) is escrowed from the
challenger. After dispute_window_ends_at it is 409 dispute_window_closed, and a second dispute is 409 invalid_transition.
snug pact dispute --pact-id pact_b95d... --statement "the screenshots are from last week"The creator or an admin judges it:
snug pact resolve-dispute --pact-id pact_b95d... --uphold # omit --uphold to dismiss- Upheld - the resolution rewinds: status back to
open, resolution and claimant cleared, bond returned, and the finished dispute is archived inmetadata.dispute_history. The pact can be resolved again from scratch. - Dismissed - the bond forfeits to the creator and the pact settles immediately.
Including the rewind leaving claimant: null and one
dispute_history entry.
When settlement runs
Settlement fires in exactly two places: the background sweeper settles
each resolved pact once its dispute window closes, and a dismissed dispute
settles on the spot. The sweeper (which also reopens lapsed bounty claims)
is off by default - without PACT_SWEEPER_ENABLED=true a resolved
pact whose window expires undisputed stays resolved forever and its
escrow is stranded, so enable it anywhere pacts are real.
Receipts
Settlement writes a SettlementReceipt onto the pact: escrowed and
distributed totals, per-beneficiary legs, Treasury transfer ids, and a
SHA-256 receipt hash. A settled market, captured live (600 on the winning
outcome, 400 against, 5% creator fee):
{
"escrowed_total": 1000,
"distributed_total": 1000,
"dust": 0,
"legs": [
{ "beneficiary_id": "docs4-other", "category": "payout", "amount": 980 },
{ "beneficiary_id": "docs-wave", "category": "creator_fee", "amount": 20 }
],
"receipt_hash": "sha256:d8f1a64b47c5...",
"transfer_ids": ["txn_0527a7f7c7bd...", "txn_8929b889ac8a..."]
}Where the money goes, per kind:
- Oath - fulfilled returns the stake (
return); failed routes it to the forfeit destination (slash, e.g. toburn_sink). - Bounty - fulfilled pays the claimant (
payout); failed or unclaimed refunds the creator (refund). - Market - winners get their stake back plus a pro-rata share of the
losing pool after the creator fee; if nobody backed the winner, all
positions are refunded (
void_refund). Integer division remainders (dust) go to the first winner, and the receipt is rejected outright if legs stop summing to the pool. - Pool - fulfilled pays
pool_payout_amount(capped at the reserve) to the beneficiary and refunds the remainder to contributors pro-rata; unfulfilled refunds everything pro-rata.
Settled market positions show their final payout in
snug pact positions (settled: true, payout: 980 for the example
above).
Voiding
snug pact void unwinds an open, claimed, or locked pact: every
stake, position, and contribution is refunded and the status becomes
voided. A settled pact cannot be voided
(409 invalid_transition: pact in Settled cannot be voided), and a voided
pact has no receipt - refunds are plain transfers, not a settlement.