Abstract
Existing agent verification standards establish a verdict by recomputation: a verifier re-derives a digest from known inputs and compares it. That works only where a function maps the artifact to the verdict. Much of what agents pay for is judged rather than computed โ a deliverable produced by a model at temperature above zero, a human review, an on-site inspection, an identity-bound action only a person can perform. None of these can be re-derived, so recomputation-based verification returns a permanently indeterminate result.
This ERC replaces re-derivation with preregistration. The acceptance criteria and the typed evidence obligations that would satisfy a claim are registered and timestamped on-chain before any evidence exists. The resulting verdict is itemized against those frozen criteria: for every registered obligation, the verifier records whether it was met, waived, or unmet. A third party can then refute the verdict on the record, using criteria that provably predate the evidence.
The specification defines one registry interface, three off-chain document schemas, a packed itemized-verdict encoding, contract-enforced consistency invariants, and a mandatory terminal resolution for indeterminate cases. Evidence file formats, forensic methods, payment, and identity are out of scope.
Motivation
The stack verifies by recomputation
Every verification primitive in the current agent stack reduces to re-deriving a value and comparing it (status as of 2026-09-04):
| Standard | Verification primitive |
|---|---|
| OCP โ observation commitment protocol | recompute โ compare โ confirm inclusion |
| AI inference proof verification | verify(inputHash, outputHash, metadata, proof) |
| WYRIWE input provenance | raw_input_hash โ sanitization_pipeline_hash โ input_hash |
| Onchain proof layer | anchor(agentIdScheme, agentId, proofHash) |
| Recomputable verification receipts | REPRODUCED / DIVERGED / CANNOT_RECOMPUTE |
The primitive is sound wherever a verdict is a function of the artifact. The boundary it cannot cross is not digital versus physical โ it is computed versus judged.
Two clear cases sit on the far side of that boundary:
- A singular event. "The technician was on site at 14:03" cannot be re-executed, and no amount of evidence makes it recomputable. The photograph, the GPS trace and the countersignature are artifacts of one unrepeatable event.
- A generated deliverable. A model called at temperature above zero does not return the same bytes twice, and provider-side model revisions break reproduction even at temperature zero. Anchoring the record of an inference is possible and already standardised; re-deriving the deliverable is not. More importantly, "does this deliverable satisfy what was asked for" was never a recomputation question in the first place.
The recomputable-receipt draft states the consequence in its own normative text: a recomputation
status of CANNOT_RECOMPUTE MUST NOT be converted into UNVERIFIABLE,
REFUTED, DIVERGED, or a default false value. Under that rule, every judged
outcome remains permanently in CANNOT_RECOMPUTE โ a state its own specification
forbids collapsing into a settleable verdict. The gap is a direct consequence of a
correct guard clause, not a defect in it.
Settlement layers therefore accept an opaque blob
Because no standard describes what a judged outcome claim must contain, the layers that move money treat the outcome as one opaque word:
- ERC-8183 (Agentic Commerce, Draft):
submit(uint256 jobId, bytes32 deliverable, bytes optParams);complete(uint256 jobId, bytes32 reason, bytes optParams)wherereasonMAY bebytes32(0). Decisions are complete-or-reject. - Task market protocol. Actor-agnostic โ requesters and workers may be humans, agents or devices โ but the deliverable is a bare
bytes32andDisputeStatusisNone | Open | Resolved, with no indeterminate state. - Staked weighted verification gate. Weighted third-party verification over an
evidenceHash, with the format of that hash explicitly out of scope. - ERC-8004 (Trustless Agents, Draft):
validationResponsecarries auint8 responseand a free-formstring tag.
None of these can be disputed. A uint8, a score, or a complete call carries
no statement of what was required, so there is nothing for a challenger to
contradict.
A deliverable digest proves identity, not adequacy
The construction settlement layers converge on is to release payment when the
digest of the returned artifact matches a commitment recorded when the order was
accepted โ payment against a hash rather than against a promise. ERC-8183 and
the task-market-protocol draft both reduce the deliverable to a bare bytes32 for this purpose, and
deployed agent-to-agent marketplaces describe their escrow release in those exact
terms.
The construction is sound and worth having. What it establishes is identity: the artifact settled against is the one that was committed to, so it cannot be substituted afterwards. It establishes nothing about adequacy. A digest is taken over bytes, not over a requirement. The digest of an artifact that misses the point matches its commitment exactly as cleanly as the digest of one that satisfies it.
The designs themselves acknowledge this, because they place a challenge window
after the match โ the task-market-protocol draft carries a DisputeStatus, and deployments add a fixed
contest period. It is worth enumerating what a challenger can raise there.
Substitution of the artifact is already excluded by the digest. Non-delivery is
already visible as an absent commitment. Lateness is already visible from the
timestamps. What remains is whether the artifact was good enough to pay for โ the
one question the digest did not answer. A challenge window is an admission that
matching the hash did not settle the matter.
And once it opens, the challenger is in the position described in the previous section: nothing on the record states what the artifact was required to contain, so the dispute resolves to whichever party a venue finds more credible. The asymmetry is sharpest where a design does not merely withhold payment but slashes a staked counterparty. Withholding leaves both parties where they started; slashing moves value on the strength of a finding that nothing on the record can contradict.
This is also why the boundary above is computed versus judged rather than digital
versus physical. A purely digital deliverable can hash exactly, be committed to
before it is revealed, and be anchored beyond dispute, and the adequacy question
is untouched by all three. Freezing the artifact and freezing the criteria are
separate acts, but they share a primitive: a commitment is agnostic to what its
digest is over, so committing criteriaDigest before any evidence exists is the
same commit-then-prove-inclusion shape that observation-commitment standards
already standardize. The gap is not the freezing act itself. It is what sits on
top of the frozen digest: a typed, itemized obligation encoding and a contract
rule that makes a Satisfied verdict over a required UNMET unrepresentable
rather than merely detectable.
Choosing a judge is not the same as fixing the criteria
Where recomputation fails, the prevailing answer is to appoint a judge: weighted third-party verification on-chain, or a model asked to grade the deliverable off-chain. Both are useful and neither addresses this gap.
The staked-weighted-verification draft stakes and weights verifiers over an evidenceHash and explicitly puts
the format of that hash out of scope. It decides who judges and how their votes
aggregate. It says nothing about what the judge was required to check, so a
unanimous weighted pass over criteria nobody recorded is still unfalsifiable.
The off-chain pattern is worse in one specific way. A grading rubric held in a prompt can be edited after the output is in hand, and the record retains no trace of the edit. That is outcome switching in the strict sense โ selecting the criterion after seeing the result โ reintroduced at the exact point where the money moves. Appointing a judge and freezing the criteria are orthogonal; this ERC supplies the second and composes with any implementation of the first.
The four questions nobody can ask today
- What was promised, before work started?
- Is this the evidence that was required, bound to this task?
- What does the verifier's decision mean when the evidence is ambiguous?
- Can the basis for settlement be independently reconstructed later?
The same problem has an institutional precedent
Clinical research faced this structure and resolved it. A patient's course cannot be replayed, so a result can be reported against whichever endpoint happened to look favourable once the data were in โ outcome switching. The answer was preregistration: the primary outcome and the analysis plan are registered before enrolment, and since 1 July 2005 the ICMJE has made registration a precondition of publication.
The second half of that history is what this ERC is actually about. Registration alone did not stop outcome switching. The COMPare project (Centre for Evidence-Based Medicine, Oxford, October 2015 โ January 2016) checked trial reports in five major journals against their own registry entries and found switching still widespread. The reason is structural: a registry that stores a plan but never compares it against the report leaves the comparison to whoever is willing to do it by hand, one paper at a time.
That sets the design target. Registering the criteria is necessary but inert. The contribution here is that the comparison between the frozen criteria and the rendered verdict is mechanical (ยง7): outcome switching stops being misconduct that a diligent reader might catch and becomes a revert.
Why this needs a chain
The entire value of a preregistration is that it predates the evidence. Off-chain,
timestamps are forgeable and criteria can be backdated after seeing the photos.
Block ordering is the only mechanism that lets an unrelated third party check
"these criteria were fixed before this evidence existed." That temporal claim is
the sole reason this belongs on-chain, and it is the same argument the OCP draft
makes for inclusion proofs. Consequently, preregister does not need to carry
its own commitment semantics: a registry MAY register criteriaDigest as an
observation commitment and let the inclusion proof supply the ordering claim.
Clinical preregistration buys that property by trusting a registrar. Between an agent, an operator and a verifier who share no institution, there is no registrar to trust; block ordering is what replaces one.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
1. Terms
- Criteria author โ the party that fixes the acceptance criteria. Typically the delegating agent or the task requester.
- Operator โ the party that performs the outcome-bearing step. May be human, agent, or device. This ERC does not distinguish them.
- Verifier โ the party that renders a verdict against the preregistered criteria.
- Obligation โ one typed evidence requirement, identified by its index in the preregistered criteria document.
2. Criteria document (off-chain)
The criteria document is a canonical JSON object. Its digest is registered on-chain. It MUST contain:
{
"version": "1",
"taskRef": "0x<32 bytes>",
"supersedes": "0x<preregistrationId> | null",
"decisionRule": "<expression over obligation outcomes>",
"obligations": [
{
"index": 0,
"type": "PHOTO",
"required": true,
"waivable": false,
"constraints": {
"captureMetadata": ["timestamp", "geolocation"],
"geofence": { "commitment": "0x<salted commitment>" },
"notBefore": 1788000000
}
}
],
"waiverAuthority": "0x<address> | null",
"verifier": "0x<address>",
"verifierConstraint": { "allowed": ["0x..."], "maxRiskScore": 20 },
"expiry": 1788600000,
"terminalOnExpiry": "REFUND_WITH_RECORD | HOLD | REVERIFY"
}Rules:
-
obligationsMUST be a dense array ordered byindex, starting at 0. Indices are the identity of an obligation and MUST NOT be reordered. -
decisionRuleMUST be evaluable by a third party over the obligation outcomes alone. Free-form prose MUST NOT appear here; human-readable acceptance text MAY be carried in a separate field whose digest is included in the document.decisionRuleMUST be one of the standard rules below or a reverse-DNS namespaced identifier (io.example.rule-v1) whose definition is published by its namespace owner:ALL_REQUIREDโSatisfiedif every required obligation isMETorWAIVED, otherwiseNotSatisfied.ALL_REQUIRED_AND_AT_LEAST(k)โ asALL_REQUIRED, and additionally at leastkoptional obligations areMET.
A decision rule yields only
SatisfiedorNotSatisfied;Indeterminateis governed by O4 and ยง9. -
waiverAuthorityMUST be present and non-null if any obligation has"waivable": true. -
verifierConstraint.maxRiskScore, if present, is an ERC-8126 ceiling: a verifier whose current score exceeds it MUST NOT be accepted. Lower scores are safer under ERC-8126. -
verifierMUST equal theverifierpassed topreregister, andsupersedesMUST equal thesupersedespassed topreregister(nullif and only if it isbytes32(0)). IfverifierConstraint.allowedis present, it MUST containverifier. The verifier MAY be a contract account (for example a committee, multisig, or appeal contract that attests only once its own process is final). -
Consumers MUST ignore top-level fields and constraint keys they do not recognise if those fields use a reverse-DNS namespace. Unnamespaced fields not defined by this ERC are reserved. This lets profiles add requirements (for example a minimum evidence strength per obligation) without changing the
versionof existing documents. -
Canonicalization: JCS (RFC 8785).
criteriaDigest = keccak256(jcs(document)). Documents defined by this ERC MUST NOT contain non-integer numbers, so that canonicalization does not depend on floating-point serialisation.
3. Evidence types
This ERC defines the following type identifiers and their REQUIRED constraint keys. It does not define file formats or forensic methods.
| Type | REQUIRED constraint keys |
|---|---|
PHOTO | captureMetadata |
VIDEO | captureMetadata |
GPS_TRACE | captureMetadata, sampleIntervalSeconds |
HUMAN_SIGNATURE | signerBinding |
DOCUMENT | mediaType |
WITNESS_STATEMENT | signerBinding |
DEVICE_READING | deviceBinding, captureMetadata |
AGENT_LOG | agentBinding |
GENERATED_ARTIFACT | modelBinding, mediaType |
Implementations MAY define additional types using a reverse-DNS namespace
(io.example.customType). Unnamespaced identifiers are reserved for this ERC.
4. Evidence bundle and attestation document (off-chain)
The bundle is a canonical JSON object with version, preregistrationId, and
an items array. Each item MUST carry obligationIndex, digest, mediaType,
a content locator, and a captureMetadata object whose timestamp is an integer
in Unix seconds. Every item MUST bind the preregistrationId. For a GENERATED_ARTIFACT, captureMetadata.timestamp is
the time the artifact was produced and modelBinding MUST identify the model and
the parameters it was produced under.
bundleDigest = keccak256(jcs(bundle)). The bundle encoding MAY reuse the
ERC-8326 canonical bundle anchor or the recomputable-receipt draft's evidence-set descriptor; this
ERC constrains which obligations must be covered, not how bytes are packed.
Attestation document. attestationDigest = keccak256(jcs(attestation)),
where the attestation document MUST contain:
{
"version": "1",
"preregistrationId": "0x<32 bytes>",
"bundleDigest": "0x<32 bytes>",
"verdict": "Satisfied | NotSatisfied | Indeterminate",
"obligationOutcomes": "0x<packed, as recorded on-chain>",
"waivers": [
{ "obligationIndex": 1, "reasonDigest": "0x<32 bytes>", "signature": "0x<65 bytes>" }
],
"undecided": [0]
}Waiver record. Each waivers entry is an EIP-712 signature by
the waiverAuthority over
Waiver(bytes32 preregistrationId,uint16 obligationIndex,bytes32 reasonDigest)signed against the domain
{ name: "ERC-8412", version: "1", chainId, verifyingContract }where chainId and verifyingContract are those of the registry. Binding the
registry and the preregistrationId prevents a waiver from being replayed onto
another task. Where waiverAuthority is a contract, the signature MAY instead be
validated with ERC-1271.
5. Packed encodings
Two bits per obligation, most-significant-bit first. Obligation i occupies bits
[2i, 2i+1] of the byte stream. Length MUST be ceil(2n/8) bytes for n
obligations, and trailing pad bits MUST be zero.
obligationFlags โ fixed at preregistration time:
| Bits | Meaning |
|---|---|
00 | optional, not waivable |
01 | required, not waivable |
10 | optional, waivable |
11 | required, waivable |
obligationOutcomes โ recorded at attestation time:
| Bits | Meaning |
|---|---|
00 | UNMET |
01 | MET |
10 | WAIVED |
11 | NOT_APPLICABLE |
Registering the flags on-chain is what makes the invariants in ยง7 machine-checked rather than advisory.
6. Registry interface
interface IPreregisteredCriteria {
enum Verdict { None, Satisfied, NotSatisfied, Indeterminate, ExpiredUnresolved }
event CriteriaPreregistered(
bytes32 indexed preregistrationId,
address indexed author,
bytes32 criteriaDigest,
bytes32 indexed taskRef,
uint16 obligationCount,
bytes obligationFlags,
uint64 expiry,
address verifier,
bytes32 supersedes
);
event OutcomeAttested(
bytes32 indexed preregistrationId,
address indexed verifier,
bytes32 bundleDigest,
bytes32 attestationDigest,
Verdict verdict,
bytes obligationOutcomes
);
event ExpiredResolved(bytes32 indexed preregistrationId, address indexed caller);
function preregister(
bytes32 criteriaDigest,
bytes32 taskRef,
uint16 obligationCount,
bytes calldata obligationFlags,
uint64 expiry,
address verifier,
bytes32 supersedes
) external returns (bytes32 preregistrationId);
function attestOutcome(
bytes32 preregistrationId,
bytes32 bundleDigest,
bytes32 attestationDigest,
Verdict verdict,
bytes calldata obligationOutcomes
) external;
function resolveExpired(bytes32 preregistrationId) external;
function getPreregistration(bytes32 preregistrationId) external view returns (
address author, bytes32 criteriaDigest, bytes32 taskRef,
uint16 obligationCount, bytes memory obligationFlags,
uint64 expiry, uint64 registeredAt,
address verifier, bytes32 supersedes, bytes32 supersededBy
);
function getAttestation(bytes32 preregistrationId) external view returns (
address verifier, bytes32 bundleDigest, bytes32 attestationDigest,
Verdict verdict, bytes memory obligationOutcomes, uint64 attestedAt
);
}preregistrationId MUST equal
keccak256(abi.encode(block.chainid, address(this), msg.sender, criteriaDigest, taskRef)).
A registry MUST revert on a duplicate preregistrationId.
Implementations MUST support ERC-165 and MUST return true for the
IPreregisteredCriteria interface identifier.
7. Contract-enforced invariants
A conforming registry MUST enforce all of the following, reverting otherwise.
- E1
preregisterMUST recordblock.timestampasregisteredAtand MUST rejectexpiry <= block.timestamp. - E2
obligationFlagsandobligationOutcomesMUST beceil(2 * obligationCount / 8)bytes with zero trailing pad bits. - E3 At most one attestation per
preregistrationId, andattestOutcomeMUST revert unlessmsg.senderis theverifierrecorded at preregistration. - E4
verdict == Satisfiedrequires every required obligation to beMETorWAIVED. - E5
WAIVEDMUST appear only where the waivable flag bit is set. - E6
NOT_APPLICABLEMUST NOT appear for a required obligation. - E7
attestOutcomeMUST revert onceblock.timestamp > expiry. - E8
resolveExpiredMUST revert ifblock.timestamp <= expiry, if an attestation exists, or if the preregistration has been superseded, and MUST set the verdict toExpiredUnresolved. It MUST be permissionless. (E7 and E8 are disjoint by construction: atblock.timestamp == expiryonly attestation is possible.) - E9
attestOutcomeMUST reject any verdict other thanSatisfied,NotSatisfied, orIndeterminate. In particularNoneandExpiredUnresolvedcannot be attested; the latter is produced only byresolveExpired. - E10 Once any terminal verdict is recorded for a
preregistrationId, includingExpiredUnresolved, no function may record or replace a verdict for it.attestOutcomeMUST revert in that case. - E11
verdict == NotSatisfiedorverdict == Indeterminaterequires at least one obligation to beUNMET. A work claim with no unmet obligation cannot be recorded as failed or as undecided. - E12
preregisterwithsupersedes != bytes32(0)MUST revert unless the named preregistration exists, has the sameauthorandtaskRef, has not already been superseded, and either has no recorded verdict or has verdictIndeterminate. On success the registry MUST recordsupersededByon the prior preregistration. - E13
attestOutcomeMUST revert on a preregistration that has been superseded. - E14
preregisterMUST rejectverifier == address(0). It SHOULD rejectverifier == msg.sender.
8. Off-chain invariants
Checkable by any party holding the criteria document and the bundle:
- O1 Every bundle item's
captureMetadata.timestampMUST be greater than or equal to the preregistration'sregisteredAt. Evidence MUST NOT predate the criteria that judge it. - O2 Every obligation marked
METMUST be covered by at least one bundle item whoseobligationIndexequals that obligation's index and whose constraints in ยง3 are satisfied. At minimum, a checker MUST verify that every key listed in the obligation'scaptureMetadataconstraint is present in the item'scaptureMetadata, thatnotBefore(if present) does not exceed the item's timestamp, and thatmediaType(if present) equals the item'smediaType. Salted commitments are opened only by parties holding the salt. - O3 Every
WAIVEDoutcome MUST correspond to exactly one waiver record in the attestation document, signed by thewaiverAuthoritynamed in the criteria (ยง4). No waiver record may name an obligation whose outcome is notWAIVED. - O4 If
verdictisSatisfiedorNotSatisfied, it MUST equal the value produced by applyingdecisionRuletoobligationOutcomes, andundecidedMUST be empty. IfverdictisIndeterminate,decisionRuleMUST NOT yieldSatisfied,undecidedMUST be non-empty, and every index inundecidedMUST beUNMETinobligationOutcomes. - O5 The published documents MUST match the chain:
criteriaDigest,bundleDigestandattestationDigestMUST be the digests of the published documents; the criteria document'staskRef,expiry,verifierandsupersedes, its number of obligations, and therequired/waivableflags of each obligation MUST equal the values registered on-chain; the attestation document'spreregistrationId,bundleDigest,verdictandobligationOutcomesMUST equal the recorded attestation; andverifierMUST appear inverifierConstraint.allowedif that list is present. A mismatch in the flags matters most: a required obligation registered as optional escapes E4.
A verdict violating O1โO4 is refuted, not merely disputed: the contradiction is derivable from published artifacts without trusting either party.
9. Indeterminacy and terminal resolution
Indeterminate is a first-class verdict. A verifier facing evidence that neither
satisfies nor fails the criteria MUST be able to say so rather than being forced
into a binary answer.
An obligation the verifier could not decide is encoded UNMET in
obligationOutcomes, since it was not shown to be met, and its index is listed in
the attestation document's undecided array. This keeps the two-bit encoding
unchanged while letting a reader distinguish "shown unmet" from "not decided".
Verdict is an outcome-claim state: its subject is the work, judged against
the preregistered criteria. It is not a statement about the verification
machinery. In particular, Indeterminate MUST NOT be derived from, mapped onto,
or collapsed into ERC-8126 VerificationStatus.Inconclusive, which reports that
a verification layer reached no conclusion about an agent. The two describe
different subjects โ an outcome and a verifier โ and a registry MUST NOT set
either from the other.
Indeterminacy MUST NOT be able to strand a settlement:
- To re-verify, the criteria author preregisters a new criteria document whose
supersedesfield names the priorpreregistrationId(E12). Attestations are immutable; the audit trail is the chain of preregistrations, recorded on-chain in both directions. A superseded preregistration can no longer be attested (E13) or expired (E8), so at most one preregistration per chain is live. - Superseding re-starts the evidence clock: by O1, evidence captured before the
new
registeredAtcannot satisfy the new criteria. Settlement layers SHOULD therefore treat a supersession made before any attestation, without the operator's consent, as a cancellation by the criteria author rather than as a failure by the operator. - If neither an attestation nor a superseding preregistration exists at
expiry, anyone MAY callresolveExpired, producing the terminalExpiredUnresolved. - Settlement layers MUST treat
ExpiredUnresolvedas non-satisfaction for the purpose of releasing funds, and MUST record it distinctly fromNotSatisfied. "We could not tell" is not "the operator failed", and conflating them poisons any reputation system built on top.
A confidence score is deliberately absent. Publishing one invites downstream
consumers to threshold it, which reintroduces the forced binary decision that
Indeterminate exists to prevent.
10. Optional bindings
These are OPTIONAL. Conformance does not require any other standard beyond ERC-165.
| Standard | Binding |
|---|---|
| ERC-8004 | The attestation MAY be posted via validationResponse; the tag SHOULD carry the preregistrationId. |
| ERC-8126 | verifierConstraint.maxRiskScore is a ceiling on the verifier's own score. VerificationStatus MUST NOT be mapped to this ERC's Verdict, in either direction (ยง9). |
| OCP โ observation commitment | criteriaDigest MAY be registered as an observation commitment; the inclusion proof then supplies the ordering claim for "criteria predate evidence" without this ERC reimplementing commitment semantics. |
| Onchain proof layer | criteriaDigest MAY additionally be anchored via anchor(...). |
| Staked weighted verification gate | The staked weighted gate MAY judge against this ERC's criteriaDigest and set its evidenceHash to bundleDigest. Selecting judges and fixing criteria are orthogonal. |
| Recomputable verification receipts | Where a receipt's recomputation status is CANNOT_RECOMPUTE, this ERC supplies the alternative basis for a verdict. The two are complementary. |
| ERC-8183 / Task market protocol | deliverable MAY be set to bundleDigest; reason MAY be set to attestationDigest. |
| ERC-8196 | Out of scope. ERC-8196 stops at authorization time; this ERC begins after execution. |
Rationale
Why not a recomputable-receipt profile. The recomputable-receipt draft describes what a receipt looks like after verification happened. It does not, and by its own guard clause cannot, supply a basis for a verdict when recomputation is impossible. The missing artifact is created before the work, which is outside a receipt format's remit. The two compose: this ERC produces the basis, the recomputable-receipt draft records the outcome.
Why not an ERC-8183 or task-market-protocol extension. Both are escrow state machines. A
preregistration must be usable without escrow โ audit, insurance and dispute
resolution consume it with no funds in play โ and both standards deliberately keep
the deliverable opaque so as not to constrain applications. Giving bytes32
meaning is a separate concern from holding money.
Why a deliverable digest is not a substitute. The obvious objection is that
the deliverable is already hashed, so the record is already fixed. It is, but a
digest binds the artifact, not the requirement, and the two are independent: an
artifact can be committed to perfectly and still be judged against criteria
written afterwards. The criteriaDigest and the bundleDigest are therefore
distinct fields with distinct ordering constraints โ the first MUST predate the
evidence, the second cannot. Collapsing them into one commitment would fix what
was delivered while leaving what was owed unrecorded, which is the state the
Motivation describes.
Why not an ERC-8004 content profile. ERC-8004's Validation Registry answers
whether a response authentically came from a validator. It intentionally says
nothing about what the response asserts. Adding outcome semantics to a uint8
plus a free-form string tag would either overload the tag or amount to this
specification embedded in another one.
Why not a staked-weighted-verification extension. The staked-weighted-verification draft selects and weights judges. This ERC fixes what they are judging, before there is anything to judge. A weighted gate with unrecorded criteria produces a verdict no one can contradict, and frozen criteria without a gate still leave the choice of verifier open; neither subsumes the other. Composing them is a one-line binding (ยง10) rather than an extension.
Why obligation flags go on-chain. Without them, "the verifier declared success
while a required obligation was unmet" is only detectable by a human reading two
JSON files. With them, it is a revert. The preregistration becomes binding rather
than aspirational, at a cost of ceil(2n/8) bytes.
Why indices rather than names. Fixed integer indices make the packed encodings unambiguous and make reordering a detectable change of digest.
What the record is for once a dispute leaves the chain. Disputes over judged
work end up in venues that do not execute Solidity: an insurance claim, a card
chargeback, an arbitration, a small-claims filing. Those venues do not need a
score, they need an answer to "what was required, and when was that fixed?" An
itemized verdict against criteria that provably predate the evidence gives them a
set of separately contestable statements with an identified criteria author, an
identified verifier, and a named waiver authority. A uint8 cannot be
cross-examined. Liability lands in the same place: because every WAIVED outcome
must name the authority that signed it (O3), accepting an unmet obligation is a
recorded decision by an identified party rather than an anonymous pass. And
because ExpiredUnresolved is recorded distinctly from NotSatisfied, "nobody
could tell" does not quietly become "the operator failed" โ an allocation of
fault the record does not support.
What is not claimed as novel. Typed evidence containers exist (ERC-8326,
recomputable-receipt draft). Tri-state verdicts exist โ ERC-8126 is Final and defines
VerificationStatus { Passed, Failed, Inconclusive }. Digest anchoring exists
(onchain-proof-layer and observation-commitment drafts), and a commitment is
agnostic to what its digest is over โ freezing criteria is the same primitive
applied to a different object. Escrow exists. The contribution is what sits on
the frozen digest: verdicts itemized against typed, preregistered obligations,
making a Satisfied verdict over a required UNMET unrepresentable at the
contract layer; and a mandatory terminal state so indeterminacy cannot strand
funds.
Why the indeterminate state is defined here rather than added to ERC-8126.
The obvious economy would be to reuse VerificationStatus.Inconclusive. It does
not fit, because the two statuses have different subjects. ERC-8126 reports the
result of verifying an agent; Inconclusive there means the verification layer
reached no conclusion. This ERC reports whether work met criteria fixed before
the work began; Indeterminate here means the evidence resolves neither way. A
verification layer can be perfectly conclusive about a verifier while the outcome
it judged remains indeterminate, and the reverse. Folding an outcome-level state
into an agent-level enum would make every consumer guess which subject a given
value refers to, so ยง9 forbids mapping between them.
What this specification does not claim. It does not verify truth about the world, does not establish that evidence is authentic, does not detect synthetic media, and does not make criteria fair. It makes a judgment auditable against conditions that could not have been chosen after the fact. Every remaining assumption stays with the verifier, in the open.
Backwards Compatibility
No backwards compatibility issues. This ERC introduces new interfaces and does not modify existing ones.
Reference Implementation
An open-source implementation of the loop task โ execution โ proof โ verify โ settle with typed evidence, ex-ante proof obligations and an abstaining verifier
is available; one conditional USDC settlement on Base mainnet released after
verification:
0xee543bc107b411edd0202131b82172eb6efaf29c10457e33d2900ae890a72cf0.
A reference registry, an executable model, a reference off-chain verifier and conformance vectors are in the ERC-8412 reference implementation:
contracts/PreregisteredCriteria.solโ registry implementing ยง6 and E1โE14.vectors/onchain/โ cases for E1โE14, each naming the invariant it exercises;contracts/test/Vectors.t.solruns them on the EVM with Foundry.vectors/offchain/โ complete document packages for O1โO5 with real digests and EIP-712 waiver signatures, run againstverifier/verify.py.tools/mutation_test.pyโ disables each invariant in turn and confirms at least one vector fails, so every invariant is exercised.
The underlying model is described in When May an Agent Claim Success? Verification Contracts for Open-World Outcomes.
Security Considerations
Criteria author as verifier. If one party writes the criteria and also renders
the verdict, preregistration constrains nothing but self-consistency. The registry
records author and verifier separately so the collapse is publicly visible.
Implementations SHOULD reject author == verifier (E14) and MUST NOT hide it.
Attestation front-running. Because a preregistration admits exactly one
attestation (E3) and attestations are immutable (E10), an unrestricted
attestOutcome would let any observer occupy the slot first with an arbitrary
verdict. Binding the verifier at preregistration and requiring
msg.sender == verifier removes this. Committees and appeals compose by making
verifier a contract that attests only once its own process is final.
Asymmetric protection. E4 stops a false Satisfied; E11 stops the mirror
case, a NotSatisfied recorded while every obligation was met or waived. Both
directions matter: the first protects whoever pays, the second protects whoever
did the work.
Waiver abuse. A waiverAuthority able to waive every obligation reduces the
criteria to that party's discretion. The waiverAuthority SHOULD NOT be the
verifier; otherwise the verifier can convert any unmet waivable obligation into
a pass on its own signature. Waivers are itemized and attributable, so the
abuse is visible; specifications built on this ERC SHOULD bound how many required
obligations may be waivable.
Evidence replay. O1 makes reuse of pre-existing evidence detectable: capture
timestamps must not precede registeredAt, and every item binds preregistrationId.
This bounds replay but does not prove capture time; a lying capture device
defeats it. Devices SHOULD attest capture metadata independently.
Verifier collusion and Sybil verifiers. Out of scope. Verifier bonding and
slashing belong to a staking layer; verifierConstraint only expresses who is
eligible.
Griefing by preregistration. Preregistrations are cheap and unrestricted. Registries serving a market SHOULD rate-limit or require a deposit at the application layer.
Expiry as denial of service. A verifier who stays silent forces
ExpiredUnresolved. That is why terminal resolution is permissionless and why
ExpiredUnresolved MUST be recorded distinctly: silence is attributable.
Personal data. Real-world evidence is personal data. Capture metadata routinely contains an operator's location, device identifiers, and timestamps.
- Only digests appear on-chain. Criteria and evidence content MUST be stored off-chain.
- Personal fields inside the criteria document (geofences, operator identifiers) MUST be represented as salted commitments, never plaintext.
- This ERC MUST NOT be implemented in a way that requires plaintext personal data
on-chain, and implementations MUST NOT place it in
aux-style fields. - Digests are permanent. Salts MUST be per-task, since a reused salt makes a location or identity enumerable across every task it appears in.
Copyright
Copyright and related rights waived via CC0.
