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.
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
checkpoint.cose); a JSON copy that differs from it fails the file.evidence_file.py)check_evidence_file and refuses a result whose bundle digest is not the digest of the file it draws.verification member, which the draft makes producer self-report that must not replace independent verification. (disclosure-bundle §10; capsule-viewer README)evidence_file.py)--all. A scoped file says "selection": "producer-selected".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.3What it shows / what it does not
Shows
- That nothing in a record changed since it was sealed: its
capsule_idrecomputes 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"
}
| Field | Type | Meaning |
|---|---|---|
| bundle_kind | string | evidence-bundle/v2, the Evidence Bundle of disclosure-bundle-00. |
| root | hex | capsule_id of the record the file's claim starts from. |
| records | array | The records, byte for byte as sealed; here one, the requester's half. |
| effect.request_digest | hex | Digest of the request; the request text is not in the file. |
| effect.response_digest | hex | Digest of the answer; the answer text is not in the file. |
| key_id | hex | The key that signed the record; here also the checkpoint's key. |
| checkpoint.cose | base64url | The signed checkpoint; its log, size, root, key and time are read from this, not from the JSON beside it. |
| completeness.closure_depth | integer | Citation edges followed; 0 means the root record alone. |
| memberships | object | Per record: its position (seq, leaf_index = seq - 1) and its inclusion proof at the checkpoint's size. |
| range_root | hex | Root of the log as it stood just after the record (size 1). |
| consistency_proof | object | Ties 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.
| Piece | Status | Evidence |
|---|---|---|
Offline verifier: capsule-emit verify --bundle | Live | In 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 --bundle | Pre-release | Published 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/bundle | Live page | Answered 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_report | Built | Merged 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 ID | Built | Released 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” buttons | Built, unread | The 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 range | Not yet accepted | agent-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
- Internet-Draft draft-mih-zhang-agent-disclosure-bundle-00 — the Evidence Bundle: transports, closure, disclosure overlay, the three completeness claims, verification.
- Internet-Draft draft-mih-agent-disclosure-envelope-00 — revealing the content behind a digest-only field without changing the record or its capsule_id.
- Internet-Draft draft-mih-scitt-agent-action-capsule-05 — the record, its capsule_id and its signature.
- Internet-Draft draft-mih-scitt-checkpointed-local-log-02 — the local log, its signed checkpoints, and inclusion and consistency proofs.
- RFC RFC 9942 — COSE Receipts.
- RFC RFC 9943 — SCITT architecture.
- RFC RFC 9052 — COSE; the checkpoint and the record signatures are COSE_Sign1.
- Code action-state-group/capsule-emit —
verify --bundle,export, and the evidence-file vectors. - Code action-state-group/capsule-viewer — the evidence report page.