EIP.tools

EIP.tools

โš ๏ธ DraftStandards Track: ERC

ERC-8412: Preregistered Acceptance Criteria

Acceptance criteria and typed evidence obligations frozen on-chain before evidence exists, with verdicts itemized against them

Authors
Created2026-09-04
Discussion Linkhttps://ethereum-magicians.org/t/erc-8412-preregistered-acceptance-criteria/29609
Requires

Markdown

https://raw.githubusercontent.com/richard7463/ERCs...

EIP-GPT summary

Contents
AbstractMotivationThe stack verifies by recomputationSettlement layers therefore accept an opaque blobA deliverable digest proves identity, not adequacyChoosing a judge is not the same as fixing the criteriaThe four questions nobody can ask todayThe same problem has an institutional precedentWhy this needs a chainSpecification1. Terms2. Criteria document (off-chain)3. Evidence types4. Evidence bundle and attestation document (off-chain)5. Packed encodings6. Registry interface7. Contract-enforced invariants8. Off-chain invariants9. Indeterminacy and terminal resolution10. Optional bindingsRationaleBackwards CompatibilityReference ImplementationSecurity ConsiderationsCopyright

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):

StandardVerification primitive
OCP โ€” observation commitment protocolrecompute โ†’ compare โ†’ confirm inclusion
AI inference proof verificationverify(inputHash, outputHash, metadata, proof)
WYRIWE input provenanceraw_input_hash โ†’ sanitization_pipeline_hash โ†’ input_hash
Onchain proof layeranchor(agentIdScheme, agentId, proofHash)
Recomputable verification receiptsREPRODUCED / 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) where reason MAY be bytes32(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 bytes32 and DisputeStatus is None | 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): validationResponse carries a uint8 response and a free-form string 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

  1. What was promised, before work started?
  2. Is this the evidence that was required, bound to this task?
  3. What does the verifier's decision mean when the evidence is ambiguous?
  4. 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:

  • obligations MUST be a dense array ordered by index, starting at 0. Indices are the identity of an obligation and MUST NOT be reordered.

  • decisionRule MUST 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. decisionRule MUST 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 โ€” Satisfied if every required obligation is MET or WAIVED, otherwise NotSatisfied.
    • ALL_REQUIRED_AND_AT_LEAST(k) โ€” as ALL_REQUIRED, and additionally at least k optional obligations are MET.

    A decision rule yields only Satisfied or NotSatisfied; Indeterminate is governed by O4 and ยง9.

  • waiverAuthority MUST 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.

  • verifier MUST equal the verifier passed to preregister, and supersedes MUST equal the supersedes passed to preregister (null if and only if it is bytes32(0)). If verifierConstraint.allowed is present, it MUST contain verifier. 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 version of 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.

TypeREQUIRED constraint keys
PHOTOcaptureMetadata
VIDEOcaptureMetadata
GPS_TRACEcaptureMetadata, sampleIntervalSeconds
HUMAN_SIGNATUREsignerBinding
DOCUMENTmediaType
WITNESS_STATEMENTsignerBinding
DEVICE_READINGdeviceBinding, captureMetadata
AGENT_LOGagentBinding
GENERATED_ARTIFACTmodelBinding, 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:

BitsMeaning
00optional, not waivable
01required, not waivable
10optional, waivable
11required, waivable

obligationOutcomes โ€” recorded at attestation time:

BitsMeaning
00UNMET
01MET
10WAIVED
11NOT_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 preregister MUST record block.timestamp as registeredAt and MUST reject expiry <= block.timestamp.
  • E2 obligationFlags and obligationOutcomes MUST be ceil(2 * obligationCount / 8) bytes with zero trailing pad bits.
  • E3 At most one attestation per preregistrationId, and attestOutcome MUST revert unless msg.sender is the verifier recorded at preregistration.
  • E4 verdict == Satisfied requires every required obligation to be MET or WAIVED.
  • E5 WAIVED MUST appear only where the waivable flag bit is set.
  • E6 NOT_APPLICABLE MUST NOT appear for a required obligation.
  • E7 attestOutcome MUST revert once block.timestamp > expiry.
  • E8 resolveExpired MUST revert if block.timestamp <= expiry, if an attestation exists, or if the preregistration has been superseded, and MUST set the verdict to ExpiredUnresolved. It MUST be permissionless. (E7 and E8 are disjoint by construction: at block.timestamp == expiry only attestation is possible.)
  • E9 attestOutcome MUST reject any verdict other than Satisfied, NotSatisfied, or Indeterminate. In particular None and ExpiredUnresolved cannot be attested; the latter is produced only by resolveExpired.
  • E10 Once any terminal verdict is recorded for a preregistrationId, including ExpiredUnresolved, no function may record or replace a verdict for it. attestOutcome MUST revert in that case.
  • E11 verdict == NotSatisfied or verdict == Indeterminate requires at least one obligation to be UNMET. A work claim with no unmet obligation cannot be recorded as failed or as undecided.
  • E12 preregister with supersedes != bytes32(0) MUST revert unless the named preregistration exists, has the same author and taskRef, has not already been superseded, and either has no recorded verdict or has verdict Indeterminate. On success the registry MUST record supersededBy on the prior preregistration.
  • E13 attestOutcome MUST revert on a preregistration that has been superseded.
  • E14 preregister MUST reject verifier == address(0). It SHOULD reject verifier == msg.sender.

8. Off-chain invariants

Checkable by any party holding the criteria document and the bundle:

  • O1 Every bundle item's captureMetadata.timestamp MUST be greater than or equal to the preregistration's registeredAt. Evidence MUST NOT predate the criteria that judge it.
  • O2 Every obligation marked MET MUST be covered by at least one bundle item whose obligationIndex equals that obligation's index and whose constraints in ยง3 are satisfied. At minimum, a checker MUST verify that every key listed in the obligation's captureMetadata constraint is present in the item's captureMetadata, that notBefore (if present) does not exceed the item's timestamp, and that mediaType (if present) equals the item's mediaType. Salted commitments are opened only by parties holding the salt.
  • O3 Every WAIVED outcome MUST correspond to exactly one waiver record in the attestation document, signed by the waiverAuthority named in the criteria (ยง4). No waiver record may name an obligation whose outcome is not WAIVED.
  • O4 If verdict is Satisfied or NotSatisfied, it MUST equal the value produced by applying decisionRule to obligationOutcomes, and undecided MUST be empty. If verdict is Indeterminate, decisionRule MUST NOT yield Satisfied, undecided MUST be non-empty, and every index in undecided MUST be UNMET in obligationOutcomes.
  • O5 The published documents MUST match the chain: criteriaDigest, bundleDigest and attestationDigest MUST be the digests of the published documents; the criteria document's taskRef, expiry, verifier and supersedes, its number of obligations, and the required / waivable flags of each obligation MUST equal the values registered on-chain; the attestation document's preregistrationId, bundleDigest, verdict and obligationOutcomes MUST equal the recorded attestation; and verifier MUST appear in verifierConstraint.allowed if 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 supersedes field names the prior preregistrationId (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 registeredAt cannot 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 call resolveExpired, producing the terminal ExpiredUnresolved.
  • Settlement layers MUST treat ExpiredUnresolved as non-satisfaction for the purpose of releasing funds, and MUST record it distinctly from NotSatisfied. "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.

StandardBinding
ERC-8004The attestation MAY be posted via validationResponse; the tag SHOULD carry the preregistrationId.
ERC-8126verifierConstraint.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 commitmentcriteriaDigest 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 layercriteriaDigest MAY additionally be anchored via anchor(...).
Staked weighted verification gateThe 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 receiptsWhere 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 protocoldeliverable MAY be set to bundleDigest; reason MAY be set to attestationDigest.
ERC-8196Out 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.sol runs them on the EVM with Foundry.
  • vectors/offchain/ โ€” complete document packages for O1โ€“O5 with real digests and EIP-712 waiver signatures, run against verifier/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 and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth