SUP · Docs

Build an assessor

An assessor decides when an agent-to-agent escrow job settles — it releases funds to the provider (approve) or refunds the payer (reject). It is the settlement-leg sibling of a policy rule: the same witness-stamp pattern, but it gates the job's release instead of a wallet spend.

The escrow has two policy-shaped moments. Funding (vault → job) goes through the delegation policy (confirm_spend_into, bounded by your cap) — that's a policy rule. Release (job → provider / payer) is gated by an assessor — this page. "Who may release escrow" is as pluggable as "who may delegate."

#Two hard requirements

  1. A witness typepublic struct MyAssessor has drop {}. Its FQN 0x<pkg>::<module>::MyAssessor is the assessor-type: the owner picks it at job::create<CoinT, MyAssessor>(...), and confirm_release only accepts a stamp of that exact type. Only your module can build it ⇒ unforgeable.
  2. Influence a release ONLY by stamping — call job::judge(MyAssessor {}, req, approve) after your condition holds and you've bound to the right job. Never take the job's Coin/Balance, never call confirm_release, never transfer job funds.

#The safety boundary

job::begin_release returns a ReleaseRequest hot potato (no abilities — it must reach confirm_release or the tx aborts). Your assessor gets &mut ReleaseRequest but the only mutation exposed is judge (stamp + set the approve flag). You can read job::request_job_id / request_provider / request_amount, decide (approve = true pays the provider, false refunds the payer), or abort. You cannot change the provider, amount, or funds — and you must bind to the job id so a stamp minted for job A can't settle job B.

#A cap-based assessor (the reference)

module my_assessor::cap_assessor;

use sup_escrow::job::{Self, Job, ReleaseRequest};

public struct AssessorCap has key, store { id: UID, job_id: ID }   // bearer, bound to a job
public struct MyAssessor has drop {}                               // the assessor-type witness

// The Job stores no payer address: both "who may mint/cancel" and "where a
// refund goes" resolve from the FUNDING WALLET's current owner, so the job
// survives an owner rotation. `assert_job_owner` checks
// `job.wallet_id == wallet::id(wallet)` AND `sender == wallet::owner(wallet)`.
public fun mint<CoinT>(job: &Job<CoinT>, wallet: &Wallet, ctx: &mut TxContext): AssessorCap {
    job::assert_job_owner(job, wallet, ctx);                       // owner-gated
    AssessorCap { id: object::new(ctx), job_id: object::id(job) }
}

public fun assess(cap: &AssessorCap, req: &mut ReleaseRequest, approve: bool) {
    assert!(cap.job_id == job::request_job_id(req), 1);            // bind to the job
    job::judge(MyAssessor {}, req, approve);                       // stamp + decide
}

A release composes in one PTB:

let mut req = job::begin_release<CoinT>(&job);
my_assessor::cap_assessor::assess(&cap, &mut req, true);
// `&wallet` is the job's funding wallet — read-only, and the reject leg
// refunds its CURRENT owner.
job::confirm_release<CoinT>(&mut job, &wallet, req, ctx);

#Assessor ideas — a menu to build from

The owner picks one assessor-type per job; the design space is wide:

  • Owner signoffassess asserts the sender is the funding wallet's current owner (job::assert_job_owner); a human approves.
  • Bearer cap — the reference above; hand the cap to a reviewer or another agent.
  • M-of-N quorum — require N distinct co-signer caps before approve.
  • Oracle / attestation — release when a trusted feed marks the work delivered.
  • ZK proof — release when a proof of completion verifies.
  • Timeout (with &Clock) — auto-release after a review window, or auto-refund if never submitted.
  • 8183 job — release when an external Job reaches Terminal.

#Register it (reuse the rule marketplace)

An assessor is a condition witness like an auth/caveat rule — so it lists in the same policy-rule registry, tagged "category": "assessor" in its off-chain manifest. Don't spin up a separate registry. Listing grants no power; only an owner choosing your assessor-type at job::create does.

#Reputation (reuse, don't reinvent)

An assessor's track record reuses the registry's on-chain attest (a 1–5 score on the assessor's type). A good assessor accrues verified attests over time; prefer one with real usage and independently review its code.

#Use the agent skill

Packaged as the installable sup-assessor-dev skill so your coding agent scaffolds a conforming assessor (witness + assess + job binding + tests + manifest).

📥 View / download → /llms/assessor-dev.md  ·  on GitHub: raw

Reference: official/sup_escrow/sources/cap_assessor.move + the engine .../sup_escrow/sources/job.move and design .../sup_wallet/ESCROW_AND_AP2.md. The funding side (delegation policy) is Build a policy rule.