VERIFIED. This page tells
you exactly what you may conclude from that, and what you may not.
The limits are specified in evidence-bundle.md §5.3.4, which ships inside the
sanning-proof package and is the normative source. This page is the plain
reading. See Wire formats for how to open it.
What a verified pack proves
For every event in the pack:- The agent signed it. An Ed25519 signature over the envelope, checked against the public key embedded in the artifact.
- The record matches its commitment, where the agent disclosed the bytes. The
disclosed record hashes to the
payload_hashthe signature covers. - It was included in the witnessed set. An RFC 9162 inclusion proof from the event’s leaf to the Merkle root committed inside the signed stamp.
What it does not claim
It is not completeness. A pack proves the events it carries were committed to that root. It says nothing about events the agent chose not to include. “Every step is here” is not a claim this artifact can make. If completeness matters to you, ask the agent what the pack covers and check that claim separately. Three different things get called completeness, and only the first two are proved here:
It is not proof the chain was consulted. A
verified verdict is offline and
internally consistent, and it names a witness. Confirming that the witness actually
holds those bytes is a separate, online act. Run the kernel with a gateway to do it, or
fetch the transaction yourself.
It is not identity. The envelope carries a public key, and a key is not a person.
Binding a key to an organization happens out of band. Agent identity informs a reader;
it never gates verification.
It is not a statement about a per-agent slice. A stamp covers an interval across a
whole organization. The pack carries only its own events, so it cannot tell you what else
that organization anchored in the same interval.
From 0.14.0, a verified drop carries one reliance sentence. Every pack and every
case reading states, in one sentence, what a
verified result there means you can
rely on, and names a hand-off clause only when the drop actually holds a hand-off. It
replaces wording written for a hand-off reading that read oddly on a pack holding only
one agent’s own steps.What a failure means
If the kernel printsFAILED, it names the record that broke and why. The pack itself
carries an asserted verdict from whoever produced it, and the kernel throws that away
and recomputes. Where the two disagree, the recomputed answer wins, and the output
says the asserted verdict and the recomputed one by name, noting that the recomputed
one is the one that counts.
That is the property worth understanding. You are not reading the agent’s claim about
their own evidence. You are reading your own machine’s answer.
What “undetermined” means
A pack can verify while leaving some things unknown, and the kernel distinguishes that from failure on purpose.
Absent evidence is reported as absent, never as failure. If an agent withheld the
bytes for a record, its content binding is undetermined. That is an agent exercising
minimum disclosure, not a defect, and treating it as tampering would be wrong.
A verdict over a case
A case reading is one reader’s reading over the packs it was handed: several packs that together hold both sides of one or more hand-offs, often from two organizations. A reader drops every pack together and gets one case verdict, with every exception named. It needs@sanning/proof or
sanning-proof 0.13.0 or later. A formed pair verifies only when each record
names the other’s signer, and a pair that does not fails the check
counterparty_named.
The verdict is reached by one rule. Every hand-off whose two sides were found
and checked contributes a verdict, and so does every exception. If they all say
the same word, that word is the case verdict. If they differ, and none of them
is a proven failure, the case is mixed. Any proven failure keeps the
headline: a case with even one failed contribution reads failed. A case
reads verified only when there is no exception at all.
Each kind of exception contributes one verdict word, as the following table
shows:
Two more land in the “reader could not tell” group: more than one record on
the other side could be a hand-off’s counterpart (fan-in, fan-out, or several
messages one way), and a pack declares a record under the wrong role: a
record marked
handoff that no pair claims, or a record marked step that is
actually a hand-off side. A candidate that another record already
accounts for is set aside before the reader grades, so an honest exchange of
several messages in one direction reads verified. A step record, such as
a closing record, is signed as one under sanning.declaration/v2 and sits
outside the hand-off scope test entirely, so a full pack, hand-offs and step
records together, reads cleanly. What a hand-off record does not prove
says what each exception looks like and why the reader cannot resolve it on
its own.
One kind carries a pack’s own verdict instead: a pack whose signature holds and
which does not verify on its own passes its verdict to the case, so a case never
reads better than its weakest pack. A pack whose declaration says a record’s
content is withheld on purpose is not one of these: it still reads verified,
and the reading’s notes (never an exception) say how many records are
withheld.
A missing side is an exception, never a failure. No pack signed by the
counterparty’s key was in what you dropped; that is not proof the counterparty
recorded nothing, and it is not tampering. The kernel prints each exception in
its own words, under a scope sentence that names the packs, the signing
keys, the hand-off records and the exceptions in the reading, and a witness
line that says whether any witness was looked up on the public record,
independently of the headline.
To read a case from your own code, pass the packs to readCase (read_case
in Python). The case command does the same from a terminal, as
Hand over and verify a case
shows.
ref. Two packs can carry one ref, and one pack can carry an
event_id twice, so a ref is a label for a person and never a join. The
following table lists the fields a consumer joins on. Only the TypeScript readCase
result is camelCase (packIndex); case --json from either command (npx @sanning/proof or the Python sanning-proof) and the Python read_case use
pack_index.
records lists every record of every pack, not only the ones that were read.
Each carries a status:
read_clean: the record went into the reading and no exception or declaration finding names it. The status says nothing about its pack, so read the pack’s grade beside it.read_flagged: the record went into the reading, and an exception or a declaration finding names it.not_read: the record never went into the reading. Itsreasonis the kind of the exception that says why.
ref, or read records as “the records that were
read”, must change. No verdict, exception kind, contribution or exit code moves.
Run it with one directory per pack, each holding bundle.json and, when the
pack has one, logs/. Over an honest case with every record withheld on
purpose, both languages print the same lines:
Next
Verify at the command line
The two commands, and what each exit code means.