Verifier
The generator proposes. The contract decides.
Source: task_contracts.py, TASK_CONTRACTS.md, spec/protocol.md §2.2 and spec/spend-guard-interface.md.
Referee rules (implemented)
- Each checker recomputes what a correct answer must be from the task input alone. It never imports the job code.
- It returns
(ok, reasons)and never raises an error. Malformed or hostile output fails closed. - A task with no contract is FAILED.
- The test suite throws 54 task-specific junk answers and 4 generic kinds of junk at five contracts, and every one comes back FAILED with a stated reason. A correct answer replayed against a different input is also FAILED.
Three states, not two
OK Evidence present, and every check passed.
FAILED Evidence present, and a check failed.
UNKNOWN Evidence missing, malformed or timed out. Never counts as success.
The referee returns (ok, reasons). verdict.py maps (True, []) to OK and (False, reasons) to FAILED. A missing, malformed or timed-out referee result is UNKNOWN. The adapter is in verdict.py in the public snapshot.
The spend-guard rule
This rule is specified in spec/spend-guard-interface.md at aox-protocol@526916c. The signed VerifiedCompletion is not a working feature. The snapshot states the rule as:
The guard releases a testnet payment for agent work only if it holds a valid, unexpired, unused, correctly bound AOX VerifiedCompletion with outcome = pass from an allowlisted verifier. Anything else is DENY.
outcome = pass is that snapshot's specified word. These pages name verdicts OK, FAILED, and UNKNOWN.
A specified VerifiedCompletion carries the contract id, version and hash; input and deliverable hashes; the verifier id and key id; the outcome and per-check results; a guard_binding hash that ties it to one payment intent; an expiry of 24 h or less; a single-use nonce; and an Ed25519 signature over its canonical bytes. That signature is specified, not yet built.
The specified guard has 12 checks. Mainnet or unknown chain ids are denied. A sim attestation is denied. A replayed nonce is denied. A swapped payee or amount breaks the binding. If AOX is unreachable, the answer is deny, never allow-and-log.
The signed VerifiedCompletion is a written interface. No signing key exists. What is in code, in the public snapshot, is a simpler gate. Base Sepolia testnet only. The gate releases only for an aox-verdict-receipt@1 that replays with verdict OK. A bare “OK” is refused, and each receipt releases once. The default demo is simulated and makes no network call. A Base Sepolia transaction is off by default. It is an opt-in testnet-only path (python3 demo.py --live-testnet). Mainnet chain ids are denied. Single-use holds per ledger file, not globally. The receipt is an unkeyed SHA-256, so it replays but does not authenticate an author.
Limits we state up front
- The ledger is an unkeyed SHA-256 chain. It's replayable and internally consistent, not tamper-proof.
- One operator runs every component, so verifier independence across operators is impossible today (
spec/protocol.md§9). - Agent verifiers, spot checks and disputes aren't implemented.