Chio/Docs
LOGIN · JOIN

The Delivery Contract

Make payment conditional on receiving the committed output by checking its digest in the kernel before capture.

Concept chio@5f63e6e

On this page

Agents can buy another system’s work under terms checked at delivery. The grant commits to a digest of the expected output, and the kernel compares the delivered value with it before capturing payment. A mismatch releases the hold and records a denial with zero currency charged.

The kernel can enforce it because it governs both the call that returns the output and the capture of the payment hold. The Cognition Market uses it for paid finding reveals, and any call on the durable, output-aware execution path can carry it. Unpriced calls need no delivery commitment.

A grant can commit to the bytes it pays for

Consider an executor whose complete final JSON value is {"text":"ready"}. With one string property, its canonical UTF-8 form is exactly the compact JSON below, with no trailing newline. The SHA-256 is calculated from those bytes, not captured from a payment run.

Complete final value · canonical bytesjson
{"text":"ready"}
SHA-256 commitment
203ff3603ac6fda47de11921349c1a4c5a2177edb87beb07eeea129b0594a11f
A changed final valuejson
{"text":"changed"}
SHA-256
e97aeabd4ca363c10046e89eaf8f8f1cdb755970c17690a6dc4bb31d8d6a010a

The committed value matches and can proceed to capture once the remaining checks pass. The changed value is refused after delivery: the reversible hold is released and zero is charged, while the dispatched budgeted invocation remains consumed.

Commit to the final value the executor returns, after any output transformation. If the protocol wraps the document in an envelope, hash the canonical envelope rather than its decoded text. The captured market purchase does this on a real finding reveal: the buyer commits to the envelope’s canonical JSON digest, media type and base64 payload included.

The constraint’s wire form and variants

Constraint is an adjacently tagged enum in crates/core/chio-core-types/src/capability/scope.rs: a type tag, a value, and deny_unknown_fields. The digest variant serializes as below, with the design record’s placeholder in place of a digest.

wire form of the digest constraintjson
{"type":"output_digest_sha256","value":"<64 lowercase hex>"}

Three variants carry delivery policy:

  • OutputDigestSha256(String), wire tag output_digest_sha256. An Allow is valid only if the final post-transform output content hash equals this digest, a canonical lowercase 64-character hex SHA-256 digest.
  • RequireFindingPurchase(Box<FindingPurchaseMarkerV1>), wire tag require_finding_purchase. One purchased finding reveal. The provider-signed marker names the finding and listing being sold and closes over the settlement rail.
  • RequireFindingRecovery(Box<FindingRecoveryMarkerV1>), wire tag require_finding_recovery. A bounded no-charge redelivery of a finding whose paid delivery already settled. Recovery never satisfies a purchase marker and never enters a payment path.

Attenuation of all three is structural equality: a child grant keeps a digest or marker only by carrying the identical one, so a delegation cannot loosen or drop the expected output. Unlike the argument-side constraints, the request matcher admits the digest variant only as a carrier; the comparison runs at the output-aware terminal.

Three inputs decide whether a call can settle

The settlement check reads three facts: whether the grant commits to a digest, whether the tool delivered a single value, and whether that value’s digest equals the commitment. Without a commitment, this check never denies. A committed call settles only when a single value arrived with a matching digest.

The delivery settlement function on the eight corners of a cubee : expected = observedd : value deliveredcc = 1 : digest committedc = 0 : nothing committed00001110
denies(c,d,e)=c∧¬(d∧e)\htmlClass{role-deny}{\mathrm{denies}}(\htmlClass{cor-parent}{c}, \htmlClass{role-call}{d}, \htmlClass{cor-relation}{e}) = \htmlClass{cor-parent}{c} \wedge \neg(\htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e})
pinned by the harness assertionsA1
c∧¬ denies⇒d∧e\htmlClass{cor-parent}{c} \wedge \neg\,\htmlClass{role-deny}{\mathrm{denies}} \Rightarrow \htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e}
A2
¬ c⇒¬ denies\neg\,\htmlClass{cor-parent}{c} \Rightarrow \neg\,\htmlClass{role-deny}{\mathrm{denies}}
A3
c∧¬ d⇒denies\htmlClass{cor-parent}{c} \wedge \neg\,\htmlClass{role-call}{d} \Rightarrow \htmlClass{role-deny}{\mathrm{denies}}
A4
c∧d∧e⇒¬ denies\htmlClass{cor-parent}{c} \wedge \htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e} \Rightarrow \neg\,\htmlClass{role-deny}{\mathrm{denies}}
R
denies retry=denies\htmlClass{role-deny}{\mathrm{denies}}_{\,\mathrm{retry}} = \htmlClass{role-deny}{\mathrm{denies}}
denies(1,1,0)=1∧¬(1∧0)=1\htmlClass{role-deny}{\mathrm{denies}}(1, 1, 0) = 1 \wedge \neg(1 \wedge 0) = \htmlClass{role-deny}{1}
digest differs from the commitmentguard: delivery_contractresult: mismatchedhold released, zero captured
The delivery settlement function on the eight corners of a cubee : digests equald : value deliveredcc = 1 : digest committedc = 0 : nothing committed00001110
denies(1,1,0)=1∧¬(1∧0)=1\htmlClass{role-deny}{\mathrm{denies}}(1, 1, 0) = 1 \wedge \neg(1 \wedge 0) = \htmlClass{role-deny}{1}
digest differs from the commitmentguard: delivery_contractresult: mismatchedhold released, zero captured

Corner c 1, d 1, e 0: the delivery check denies settlement. digest differs from the commitment; guard: delivery_contract; result: mismatched; hold released, zero captured.

denies(c,d,e)=c∧¬(d∧e)A1: c∧¬ denies⇒d∧eA2: ¬ c⇒¬ deniesA3: c∧¬ d⇒deniesA4: c∧d∧e⇒¬ deniesR: denies retry=denies\begin{gathered} \htmlClass{role-deny}{\mathrm{denies}}(\htmlClass{cor-parent}{c}, \htmlClass{role-call}{d}, \htmlClass{cor-relation}{e}) = \htmlClass{cor-parent}{c} \wedge \neg(\htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e}) \\[8pt] \begin{aligned} \mathrm{A1}&:\ \htmlClass{cor-parent}{c} \wedge \neg\,\htmlClass{role-deny}{\mathrm{denies}} \Rightarrow \htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e} \\ \mathrm{A2}&:\ \neg\,\htmlClass{cor-parent}{c} \Rightarrow \neg\,\htmlClass{role-deny}{\mathrm{denies}} \\ \mathrm{A3}&:\ \htmlClass{cor-parent}{c} \wedge \neg\,\htmlClass{role-call}{d} \Rightarrow \htmlClass{role-deny}{\mathrm{denies}} \\ \mathrm{A4}&:\ \htmlClass{cor-parent}{c} \wedge \htmlClass{role-call}{d} \wedge \htmlClass{cor-relation}{e} \Rightarrow \neg\,\htmlClass{role-deny}{\mathrm{denies}} \\ \mathrm{R}&:\ \htmlClass{role-deny}{\mathrm{denies}}_{\,\mathrm{retry}} = \htmlClass{role-deny}{\mathrm{denies}} \end{aligned} \end{gathered}
In Rust · kani_public_harnesses.rs:172921 lines
let constrained = kani::any::<bool>();
let delivered_value = kani::any::<bool>();
// … committed = Some(expected) when constrained
let denies = delivery_denies_settlement(committed, observed_str, delivered_value);
if constrained && !denies {
    assert!(delivered_value);
    assert!(expected == observed);
    assert!(delivery_contract_admits(expected_str, observed_str) == DeliveryVerdict::Allow);
}
if !constrained {
    assert!(!denies);
}
if constrained && !delivered_value {
    assert!(denies);
}
if constrained && delivered_value && expected == observed {
    assert!(!denies);
}

let retry = delivery_denies_settlement(committed, observed_str, delivered_value);
assert!(retry == denies);
The Kani harness ranges over every 4-byte expected and observed value and both flags; the cube collects its eight cases. A match means only that this check does not deny: other delivery and policy checks still decide the call. Kani covers the comparison, not the hold release around it, and a mismatched Deny publishes a redaction hash rather than the payload’s digest.

The Kani harness asserts each combination the figure draws. A match establishes content identity: the final canonical value has the committed digest. The remaining checks still apply, so a match alone does not imply Allow. A claim that a finding is correct or useful needs its own evidence.

Unsupported carriers are refused before dispatch

A commitment is useful only where payment can still be withheld. The kernel refuses an unsupported digest-constrained request before it issues an execution nonce, consumes invocation quota, or authorizes payment:

  • A no-output authorization path. Execution-nonce preflight authorizes without producing output, so a selected grant carrying the constraint is denied there.
  • A path with no release. After grant selection the kernel reads the payment adapter’s rail mode, and it denies a request with no durable admission record, a configured rail other than ReversibleHold (a PrepaidFinal rail settles inside the authorize call), or a governed MustPrepay request before authorize_payment_if_needed runs. No prepayment settles.
  • A downgraded carrier. The request matcher rejects Constraint::Custom("output_digest_sha256", ..) with InvalidConstraint, because failing only that grant would let an unconstrained sibling serve the call. A kernel that does not know the variant cannot deserialize the token (the tag is adjacent and unknown fields are denied), so it denies the call.

These refusals carry urn:chio:error:kernel:delivery-contract-unsupported-carrier: a request that carried a delivery contract the evaluator cannot enforce.

The kernel checks output before payment capture

On the paid path, reversible payment authorization happens before dispatch, and the comparison precedes capture. The durable admission operation records each step:

  1. Hold. The kernel authorizes a reversible payment hold before the tool runs. On the budgeted durable path, dispatch also captures one invocation, which a later mismatch does not restore.
  2. Dispatch and finalize. After the tool returns, the operation moves to finalizing. finalize_durable_tool_return in crates/kernel/chio-kernel/src/kernel/admission_coordinator/terminal.rs refuses to start from any other state.
  3. Hash. The kernel runs the post-invocation transforms, then receipt_content_for_output takes the SHA-256 of the canonical JSON bytes of the whole response value: the observed digest.
  4. Compare. evaluate_delivery calls delivery_denies_settlement in chio_kernel_core::formal_core, a pure function that denies unless the output is a single value whose digest delivery_contract_admits finds byte-identical to the expected digest.
  5. Plan payment. The delivery checks contribute to the terminal decision, which is folded into post_guard_decision_digest. Only then does durable_payment_disposition plan the payment.

A match captures; a mismatch charges nothing

When the digest matches and the remaining delivery checks allow completion, a positive realized cost is captured from the hold, and a successful zero-cost call releases it. The kernel signs an Allow whose delivery_contract block reads result: matched.

On a mismatch the operation moves to denied_after_delivery, which is legal only from finalizing. The settlement disposition is ContractualZeroCharge: the open hold is released, zero is captured, and realized spend reconciles to zero. The kernel signs a Deny whose decision.guard is delivery_contract, with the block reading result: mismatched.

The Deny receipt’s financial.cost_charged is zero, and the invocation captured with dispatch stays consumed. A replayed terminal finds the same release already recorded in the payment journal and issues no second release.

The admission states

When payment applies, the hold sits on a ReversibleHold payment rail, and a mismatch settles by releasing it. The admission operation is the durable record of the governed call: AdmissionOperationState has 18 states, 7 of them terminal, and denied_after_delivery is the terminal a mismatch reaches. Its doc comment in the enum states the outcome: The delivered output did not match a grant's committed output digest. A signed Deny is persisted; the open hold is released and zero is captured.

crates/kernel/chio-kernel/src/admission_operation.rs167-189rust
pub enum AdmissionOperationState {
    Prepared,
    BrokerAttemptRegistered,
    ApprovalRequired,
    BudgetAuthorized,
    ApprovalReserved,
    ReadyToDispatch,
    CapturePending,
    DispatchCommitted,
    Finalizing,
    Completed,
    CompensatedBeforeDispatch,
    NotAcceptedAfterDispatchCommit,
    OutcomeUnknownAfterDispatch,
    /// The delivered output did not match a grant's committed output
    /// digest. A signed Deny is persisted; the open hold is released and
    /// zero is captured.
    DeniedAfterDelivery,
    MutationReady,
    MutationSubmitted,
    EconomicMutationApplied,
    EconomicMutationNotApplied,
}

A mismatched Deny does not confirm the payload

The actual output and its digest stay in the durable outcome store for privileged challenge handling. The public receipt’s content_hash and observed_digest carry a deterministic redaction hash derived from the expected digest. That hash is independent of the mismatched payload, so a candidate payload cannot be checked against the Deny.

The kernel merges the block last and rejects caller or hook metadata that already carries a delivery_contract key. Its two digest fields below show the schema’s pattern, not a digest.

metadata.delivery_contract, schema shapejson
{
  "schema": "chio.delivery-contract.v1",
  "expected_digest": "^[0-9a-f]{64}$",
  "observed_digest": "^[0-9a-f]{64}$",
  "result": "matched"
}

Every field is required and no others are admitted. The block feeds the receipt id and the signing body, so the enclosing receipt authenticates it and it carries no signature of its own. It appears only on a digest-constrained request, because its presence would change every other receipt id.

A mismatch carries urn:chio:error:kernel:delivery-contract-digest-mismatch: a delivered output that did not hash to the frozen expected digest. Both error URNs are registered in spec/errors/registry.yaml.

A reproducible build can be a payment condition

The same constraint works outside the market wherever the buyer knows the right bytes in advance. Every honest build of one source revision produces the same bytes, so you, holding a reference build of pricing-rs, can pay your partner's build agent to reproduce it, and pay only when the bytes agree.

The application defines the value the build tool returns; for a binary, that is a canonical JSON envelope carrying the bytes. You compute the digest of that value from your reference build and places it in the agent’s grant as output_digest_sha256.

  • The reproduced binary matches. The kernel captures the realized cost from the hold and signs an Allow with result: matched.
  • Different bytes, from a stale cache entry, a patched dependency, or a substituted binary, end in denied_after_delivery: a signed Deny, the hold released, zero currency charged, and one invocation consumed.

A tool server that substitutes bytes is paid nothing, whatever it reports, because the kernel hashes the final post-transform value itself before any payment decision. Each attempt consumes one invocation, so the grant’s max_invocations bounds how many deliveries one grant can test. How the agent produced the bytes is outside what the digest records, and outside the market a mismatch carries no seller sanction: the signed Deny is the record.

Read more in What You Can Build.

What is proved, and where it stops

The contract ships on the durable admission path, in finalize_durable_tool_return and the replay path that rebuilds the same receipt from persisted state. The non-durable path lacks this output-aware settlement finalizer, so it refuses the constraint before dispatch. The formal claim is narrower than the shipped behavior; Formal Assurance explains how to read a claim’s evidence and its edge.

The proof record
  • Status. Proved.
  • Claim. Settlement is admitted only on an Allow, an Allow under a digest requirement implies the expected and observed digests are equal, and a deniedAfterDelivery decision never opens the settlement gate. Over the Rust functions, a constrained delivery that is not denied is a single-value delivery with byte-identical digests.
  • Subject. The bounded Lean model Chio.Proofs.DeliveryContract over four opaque digest identities, and the pure functions delivery_contract_admits and delivery_denies_settlement in chio_kernel_core::formal_core.
  • Evidence. Theorems settlement_admission_requires_verified_evidence, allow_requires_verified_evidence, and denied_after_delivery_cannot_settle in formal/lean4/Chio/Chio/Proofs/DeliveryContract.lean; the Kani harness public_delivery_contract_allow_implies_digest_match registered in .kani/harnesses.toml.
  • Assumptions. Digest identities are opaque and already validated. The model’s finding-purchase Boolean is an input recording the composition boundary with purchase admission; the model does not verify a purchase.
  • Limit. The model does not implement SHA-256, canonical JSON, signatures, persistence, payment rails, or external settlement, and it is not a refinement proof of the Rust finalizer. The Kani harness covers the comparison functions, not the state transition or the hold release around them.

Three properties of the shipped check bound what a record can tell you:

  • It binds one canonical JSON value. A Stream output uses a different content-binding format and never satisfies this contract, even if its aggregate digest matches. A no-output Allow hashes to sha256_hex(b"null"), which the admission gate rejects as an expected digest.
  • It compares the final post-transform value. A post-invocation transform produces a mismatch when the final value no longer hashes to the commitment, and a commitment can intentionally describe the transformed value.
  • It records that the value differed, not why. The block is generic delivery evidence; a finding reveal attaches a sibling finding_delivery block for the purchase-specific checks, and a generic digest denial alone triggers no seller sanction.

Follow the money and the record