Agent Action Capsule · explain
15 / 16 · From the September deck

The evidence report: one exchange, checked by anyone

One exchange becomes one file. Anyone it is handed to, an auditor, a customer or the other side, can check it on their own machine, offline, with no account. This page shows what such a check covers, what it leaves out, and which verifiers read the file today. The example is a real file from a live two-node run, and the verifier was run on it for this page.

One exchange becomes a file anyone can check offline Left: a node's local log. Step 1: the node's record of one exchange sits at position 1, followed by padding leaves, and a checkpoint signed over the log at MMR size 63. Step 2: in the middle, an evidence file of kind evidence-bundle/v2 is built from it, holding the record unchanged, checkpoint.cose (the signed checkpoint), an inclusion proof at leaf 0 for size 63, and a range root tied to the checkpoint by a consistency proof from size 1 to 63. Step 3: the file crosses a dashed line marked no account, no network, to a panel on the right labelled anyone: an auditor, a customer, the other side. Step 4: the panel runs capsule-emit verify --bundle offline and shows four passes: records, signatures, citation closure, checkpoint. Step 5: two fails, interval coverage and per-record membership, both completeness_certificate_invalid, because today's verifier does not accept a range root tied to the checkpoint by a consistency proof; witness receipt not shown; verdict INVALID. Step 6: under the file, a report page drawn from the verifier's result, which never checks anything itself, and a line saying the file holds digests, not the text, and does not show that the answer was right. node: its own log seq 1 · its half of the exchange padding leaves (to 32) seq 1 · its half of the exchange checkpoint, signed size 63 · root 2cedc227… key 801b5d57… request and answer kept as digests in the record, not text evidence file "bundle_kind": "evidence-bundle/v2" records: the record, unchanged checkpoint.cose: the signed checkpoint inclusion proof: leaf 0, size 63 range root (size 1), tied to the checkpoint by a consistency proof two-node-requester.json · 9,259 B no account · no network anyone an auditor, a customer, the other side capsule-emit verify --bundle ✓ records: each id recomputes ✓ signatures: every one checks ✓ citation closure: nothing missing ✓ checkpoint: signed, copy matches ✗ interval coverage ✗ per-record membership completeness_certificate_invalid – witness receipt: not shown INVALID exit 1 report: one readable page drawn from the verifier's result; it never checks anything itself not in the file: the text, or that the answer was right Values from capsule-emit test-vectors/evidence-file/two-node-requester.json (a live two-node run, 2026-10-01). The checks shown are the real output of capsule-emit 0.11.0 with agent-action-capsule 0.10.0, run on 2026-10-19.

1What it is

An evidence file is one AAC Evidence Bundle (evidence-bundle/v2): the records of one exchange, unchanged, with the signed checkpoint and proofs that place each record in its producer's log.

A verifier reads it offline and reports each claim on its own: the records, their signatures, citation closure, the checkpoint, coverage, membership and, when it is given witness keys, witness receipts.

The report is one readable HTML page drawn from that verifier's result; it does no checking of its own, and the same file can travel as a link fragment, inside an offline page, or as a download.

2Design choices

Chosen: one object, three ways to carry it: in a URL fragment, inside an offline HTML page, or at a hosted URL.
Rejected: a separate format per channel; the draft calls these “transports for one object, not distinct evidence formats”. A fragment is never sent to the server that serves the page. (disclosure-bundle §1, §9)
Chosen: the checkpoint is read only from its signed COSE form (checkpoint.cose); a JSON copy that differs from it fails the file.
Rejected: trusting the checkpoint as the producer wrote it; without a verified signature or witness receipt, coverage and membership are only relative to a checkpoint the producer asserted. (disclosure-bundle §6; capsule-emit evidence_file.py)
Chosen: an inclusion proof for every record, checked at its stated leaf index and against the checkpoint's size.
Rejected: a range proof over the two end records only; an interior record could be deleted or replaced while it still passes. (disclosure-bundle §6, §11)
Chosen: the report page never checks. It draws the result of check_evidence_file and refuses a result whose bundle digest is not the digest of the file it draws.
Rejected: a page with its own checks, or trusting the file's verification member, which the draft makes producer self-report that must not replace independent verification. (disclosure-bundle §10; capsule-viewer README)
Chosen: no witness is trusted by default. The verifier supplies a witness directory; without one no receipt is checked and the result says “not shown”.
Rejected: a built-in list of trusted witnesses; the file would then carry trust the reader never chose. Only a receipt that fails changes the verdict. (capsule-emit evidence_file.py)
Chosen: an export holds one scope (an exchange, a peer, a time window or a record) and refuses when none is given; the whole log only with --all. A scoped file says "selection": "producer-selected".
Rejected: exporting the whole log by default; a file meant for one counterparty would carry every other exchange. (capsule-emit CHANGELOG 0.9.0)
Chosen: records carry digests of the request and the answer. The content is shown only if the holder adds it as a disclosure, which the verifier rehashes and compares with the digest the record committed to. The disclosable fields are model_attestation.compute_attestation.agent_input_digest and agent_output_digest (a SHA-256 over the JCS form of the value); in the example they hold the same values as the effect digests.
Rejected: putting the text in the record; every holder of the file would then hold the conversation. (disclosure-envelope-00 abstract; disclosure-bundle §5)

3What it shows / what it does not

Shows

  • That nothing in a record changed since it was sealed: its capsule_id recomputes from its content.
  • Which key signed each record, and that the signature checks.
  • That the checkpoint is signed and that the file's copy matches what was signed, and whether the records' key is the checkpoint's key.
  • Where each record sits in the log, by an inclusion proof to the range root at the checkpoint's size, once coverage and membership pass.
  • That a witness registered the checkpoint, when the file carries a receipt and the verifier holds that witness's key.
  • That a disclosed request or answer matches the digest its record committed to.

Does not show

  • The text itself: the record holds digests only, unless the holder chooses to disclose it.
  • That the answer was right.
  • Who holds a key in the world: a key says who holds it, not who that is.
  • Anything about the records between the ones a producer chose to export.
  • That the other side recorded the same thing: one file is one node's records, and the verifier reads one file at a time. The two files of the example carry the same request and answer digests under two different keys; comparing them is a separate step.
  • Coverage and membership on the example file today: they fail on the current verifier (see Status).

4Example

The requester's file from a live two-node run on 2026-10-01: one exchange, the node's own record at log position 1, under that node's signed checkpoint. The vector's README says the producer pads its log to 32 leaves before a checkpoint, so the checkpoint's last leaf is padding, not a record. Long proofs, the record's attestation block and the model fields are elided below.

{
  "bundle_kind": "evidence-bundle/v2",
  "bundle_version": "2",
  "checkpoint": {
    "cose": "0oRYc6QBJwN4H2FwcGxpY2F0aW9uL2NsbC1jaGVja3BvaW50K2Nib3IE…",
    "key_id": "801b5d574bb2bceca9f1fa4d7ce7f2149c0ba0212568b5242ced6b18205b7d47",
    "kind": "mmr_checkpoint",
    "log_id": "capsule-emit-mesh",
    "mmr_size": 63,
    "root": "2cedc227a0aecb56f1bb72aa7cc169eb6967a48b9b66c21e7c63c9512249b289",
    "timestamp": "2026-10-01T23:04:00.000Z",
    …
  },
  "completeness": {
    "closure_depth": 0,
    "payloads_mode": "selected",
    "records_mode": "complete",
    "suppressed_fields": []
  },
  "completeness_certificate": {
    "consistency_proof": { "kind": "consistency", "size_a": 1, "size_b": 63, … },
    "first_seq": 1,
    "last_seq": 1,
    "log_id": "capsule-emit-mesh",
    "memberships": {
      "08fc833a97fc869f92b8f76a8294a5d7d04f7a6ebc93a267034f66e2ea9a83ae": {
        "inclusion_proof": { "kind": "inclusion", "leaf_index": 0, "size": 63, … },
        "log_coordinates": { "leaf_index": 0, "log_id": "capsule-emit-mesh", "seq": 1 }
      }
    },
    "range_root": "1e292f3accb33f911f04687d376ceeddc4c665bc2b36678ffb08c44e391f1a57",
    …
  },
  "records": [
    {
      "capsule_id": "08fc833a97fc869f92b8f76a8294a5d7d04f7a6ebc93a267034f66e2ea9a83ae",
      "effect": {
        "request_digest": "3670c98d6f9d026e3902531c114b0b6f6369ca6bfdc2e6da57613d0bd61bb040",
        "response_digest": "f96206ab6366acb7189a6ed2cb22f7d6ff071547ca631fd1529accb710a2ff70",
        "status": "confirmed",
        "type": "inference_completion",
        …
      },
      "key_id": "801b5d574bb2bceca9f1fa4d7ce7f2149c0ba0212568b5242ced6b18205b7d47",
      "spec_version": "draft-mih-scitt-agent-action-capsule-05",
      "timestamp": "2026-10-01T23:04:00.000Z",
      …
    }
  ],
  "root": "08fc833a97fc869f92b8f76a8294a5d7d04f7a6ebc93a267034f66e2ea9a83ae"
}
FieldTypeMeaning
bundle_kindstringevidence-bundle/v2, the Evidence Bundle of disclosure-bundle-00.
roothexcapsule_id of the record the file's claim starts from.
recordsarrayThe records, byte for byte as sealed; here one, the requester's half.
effect.request_digesthexDigest of the request; the request text is not in the file.
effect.response_digesthexDigest of the answer; the answer text is not in the file.
key_idhexThe key that signed the record; here also the checkpoint's key.
checkpoint.cosebase64urlThe signed checkpoint; its log, size, root, key and time are read from this, not from the JSON beside it.
completeness.closure_depthintegerCitation edges followed; 0 means the root record alone.
membershipsobjectPer record: its position (seq, leaf_index = seq - 1) and its inclusion proof at the checkpoint's size.
range_roothexRoot of the log as it stood just after the record (size 1).
consistency_proofobjectTies that size-1 root to the checkpoint's size-63 root.

Source: action-state-group/capsule-emit:test-vectors/evidence-file/two-node-requester.json @ d51a934ebf9d3efa3c86e7f27aaafe2bc06ac05d (added in capsule-emit PR 248). Its sibling two-node-provider.json holds the provider's half: the same request_digest and response_digest, signed by a different key (75860843…).

The offline check, run for this page on 2026-10-19 with capsule-emit 0.11.0 and agent-action-capsule 0.10.0 from PyPI:

$ capsule-emit verify --bundle two-node-requester.json
  PASS       Every record is intact: its id recomputes from its content.
  PASS       Every record is signed, and every signature checks.
  PASS       Every record the file's records cite, to the stated depth, is in the file.
  PASS       The log's checkpoint is signed, and the file's copy of it matches what was signed.
  FAIL       The proof that these records are one unbroken stretch of the log does not check.
               completeness_certificate_invalid
  FAIL       At least one record's proof of being in the log does not check.
               completeness_certificate_invalid
  NOT SHOWN  No witness receipt is checked: the file carries none, or no key is known for its witness.
               witness_receipt_absent

1 record(s) in log capsule-emit-mesh, under a checkpoint signed 2026-10-01T23:04:00.000Z; its key signed every record
INVALID

The vector's own README expects exactly this: coverage and membership need an agent-action-capsule that accepts a range root tied to the checkpoint by a consistency proof, and until then the file is INVALID. Its test accepts that state, or VALID once the verifier changes, and nothing else. The provider's file gives the same result.

5Status

Two different files: the general evidence file has verifiers and a report page, while the mesh plugin's own button still saves a different shape.

PieceStatusEvidence
Offline verifier: capsule-emit verify --bundleLiveIn capsule-emit since 0.9.0; since 0.11.0 (2026-10-16) the checks are agent-action-capsule's strict verify_bundle. Run on the example above on 2026-10-19. python/capsule_emit/evidence_file.py @ d51a934ebf9d3efa3c86e7f27aaafe2bc06ac05d.
Offline verifier: capsulectl verify --bundlePre-releasePublished as GitHub pre-release capsulectl v0.1.0-rc16 on 2026-10-14 (tag commit bfeae1aa73c149aa7ffb4de39f0b9990c03b87e0); listed in capsule-cli's README there and at main @ 551b5c616641d15089eb0aac747f5c90aa29bf69. Not run for this page.
In the browser: verify.agentactioncapsule.org/bundleLive pageAnswered HTTP 200 on 2026-10-19. Per scitt-cose's README @ ac9d3b90d058ff609497573a68402e561fa99404, a dropped evidence file is read in the browser and never uploaded; integrity, sequence and range membership are checked there, and the signature step shows “skip” in the browser. The deployed revision was not checked, and the example was not dropped on it.
Report page: capsule_viewer.evidence_reportBuiltMerged in capsule-viewer (README “Evidence report page”, main @ 204e07a87cae17886b87f1324a5040a4aec6b8bf), moved from capsule-emit in 0.10.0; not on PyPI. Run on the example on 2026-10-19, it wrote a page saying INVALID (exit 1). Its evidence extra pins capsule-emit below 0.10, so it was run with agent-action-capsule 0.9.1. capsule-cli's capsulectl report build --bundle writes a page only for a file verify --bundle calls VALID (its README).
Scoped export: capsule-emit export LEDGER_DIR --exchange IDBuiltReleased in capsule-emit 0.9.0 (CHANGELOG). It reads a ledger directory of capsules.jsonl and checkpoints.jsonl; the in-tree plugin uses the same file names (crates/evidence-plugin/src/data_dir.rs and checkpoint_cadence.rs, capsules @ efcada74026a2e18b9e62d77432888a31bbe9de4), but the export was not run on that plugin's ledger for this page.
The mesh plugin's “Save evidence file” buttonsBuilt, unreadThe Exchanges button saves mesh-ledger-exchanges-evidence/1, the node's own view of the exchange rows, and the Integrity button mesh-ledger-integrity-evidence/1; neither is an Evidence Bundle (web-ui/src/features/capsules/lib/exchange-export.ts, capsules release v0.1.4 @ b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad and main @ efcada74026a2e18b9e62d77432888a31bbe9de4). A text search of the main branch of every repository in this project's mirror, on 2026-10-19, found either schema only in the plugin itself: no verifier reads them.
Coverage and membership with a consistency-tied rangeNot yet acceptedagent-action-capsule 0.10.0 reports completeness_certificate_invalid (run above). The disclosure-bundle draft (§6) asks for the proof material that binds the range root to the checkpoint; the vector's README reads it as allowing this form; the draft text does not say so explicitly.

Evidence: action-state-group/capsule-emit @ d51a934ebf9d3efa3c86e7f27aaafe2bc06ac05d (CHANGELOG.md, python/capsule_emit/evidence_file.py, test-vectors/evidence-file/); action-state-group/capsule-viewer @ 204e07a87cae17886b87f1324a5040a4aec6b8bf; action-state-group/capsule-cli @ 551b5c616641d15089eb0aac747f5c90aa29bf69; action-state-group/scitt-cose @ ac9d3b90d058ff609497573a68402e561fa99404; action-state-group/agent-action-capsule @ 2ef8aeb49e2334e24c404bd62d3fdb161770873c; Mesh-LLM/capsules @ efcada74026a2e18b9e62d77432888a31bbe9de4 and tag v0.1.4 @ b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad (all checked 2026-10-19).

6Specs