Evidence quickstart
Verify a real evidence/v1 export offline under pinned keys, then watch a wrong key, a self-stated trust bundle and skipped signatures each change the result.
What you need
- A built
numiand a clone ofnuminance-spec(install). - The conformance fixtures. Run every command below from
conformance/evidence/v1inside the clone. It holdskeys/(public keys) andexports/(golden export directories). The example export isexports/closed-author: a change that ran to a Closed terminal state at pull-request level.
You do not need to generate an export. numi evidence export is designed and not in the open build; calling it is an unknown subcommand and exits 2.
The pinned-key run
numi evidence verify \
--runner-key keys/runner.pub \
--log-key keys/log.pub \
--log-origin numinance.test/log \
--complete \
exports/closed-authorchange: chg_01010101010101010101010101010101
records: 12, head sha256:8dec4e3d5cf4bd7650ef6010671298793c05493cb20c3dd946bc3ef805689e48
state: ended Closed
level: verified
chain: records link, hash and end as stated
signatures: verified under the pinned runner keys
anchor: head proved under the pinned log
attestation: signed, re-derived from the chain
credential_scopes: unsourced: no credential broker statement is in the attestation
network_policy: unsourced: no egress proxy statement is in the attestation
not applicable: deployment.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed)
not applicable: observation.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed)
result: verifiedThe flags
| Flag | What it does |
|---|---|
--runner-key FILE | A runner public key you pin (64 hex characters). Repeatable. Any pinned key may sign any record, the attestation or the manifest. |
--log-key FILE, --log-origin ORIGIN | The transparency log you pin. Give both or neither. This is what lets the head be proved as published. |
--complete | Fail if any part of the design list is absent. A part that is not applicable at PR level, such as deployment and observation, is not absent. |
--trust-bundle-keys | Trust the keys the export states about itself. Caps the result at self-consistent. |
--skip-signatures | Check no signature. Caps the result at unauthenticated. |
--allow-unanchored, --allow-incomplete, --allow-unsigned | Accept a named weakness; the level is suffixed with it. |
--expect-change CHG_ID, --expect-head DIGEST | Fail unless the chain is that change, or its head matches that digest. |
--json | One JSON object, including level_enum, weakened_by_flags and anchored_head_record_hash. |
Exactly one key mode is required. There is no built-in trust root: a key that comes from the export never reaches verified.
Wrong key: exit 3
Pin a different runner key and the same export fails.
change: chg_01010101010101010101010101010101
records: 0, head
state: open (no terminal record)
level: failed
chain: failed
signatures: not verified
anchor: not proved
attestation: none
credential_scopes: unsourced: no credential broker statement is in the attestation
network_policy: unsourced: no egress proxy statement is in the attestation
absent: deployment.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed; owner: release context (Gate B): a change that is released is deployed and observed by it)
absent: observation.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed; owner: release context (Gate B): a change that is released is deployed and observed by it)
FAIL signer_untrusted: a record names a key that is not trusted
FAIL part_contradiction: a part is declared not applicable and the chain does not bear it out
FAIL parts_absent: a part is absent and --complete was given
FAIL part_contradiction: a part is declared not applicable and the chain does not bear it out
FAIL parts_absent: a part is absent and --complete was given
result: failedExit 3 means the report has at least one finding. signer_untrusted is the root cause. The part_contradiction and parts_absent findings follow because a "not applicable" claim needs a verified chain behind it; when the chain did not verify, nothing shows the change closed at PR level, so each claim counts as a contradiction and the parts as absent.
Trust bundle only: exit 5
Ask the verifier to trust the keys the export states about itself:
numi evidence verify --trust-bundle-keys exports/closed-authorchange: chg_01010101010101010101010101010101
records: 12, head sha256:8dec4e3d5cf4bd7650ef6010671298793c05493cb20c3dd946bc3ef805689e48
state: ended Closed
level: self-consistent
chain: records link, hash and end as stated
signatures: verified under keys the export states only
anchor: not checked (no log pinned)
attestation: signed, re-derived from the chain
credential_scopes: unsourced: no credential broker statement is in the attestation
network_policy: unsourced: no egress proxy statement is in the attestation
not applicable: deployment.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed)
not applicable: observation.json (not applicable at PR level: the change closed from Merging (design section 6) and was never released, deployed or observed)
WEAK signatures verified only under keys the export states
WEAK the head was not proved under a pinned log
result: self-consistentExit 5 means a consistent export that is weaker than verified. The chain is intact, but an attacker who builds a whole chain and signs it with their own key would pass this check too. Self-consistency proves the directory agrees with itself, not that it came from the runner you trust.
Skipping signatures
numi evidence verify --skip-signatures --json exports/closed-author{"ok":false,"level":"unauthenticated","level_enum":"unauthenticated","weakened_by_flags":[],"weaknesses":["no signature was checked","the head was not proved under a pinned log"],"signatures":"not checked (--skip-signatures)","anchor":"not checked (no log pinned)"}The snippet shows the decision fields of the real report. The full object also carries change_id, records, head_record_hash, anchored_head_record_hash, ended, terminal_state, sealed, chain, attestation, not_applicable, credential_scopes and network_policy. Links, digests and re-derivations are still checked; only signatures are not.
What each level means
| Level | Meaning | Exit |
|---|---|---|
verified | Records link and hash, signatures check under your pinned runner keys, and the head is proved under your pinned log. | 0 |
unanchored, incomplete, unsigned | A single named weakness, reachable by passing the matching --allow- flag. | 5 without the flag, 0 with it, suffixed in the level |
self-consistent | Consistent, signed under keys the export itself states. | 5 |
unauthenticated | Consistent, but no signature was checked. | 5 |
failed | At least one finding. | 3 |
Reading results in automation
- A pass with an allowance, such as
verified, unanchored, exits 0. Never test whetherlevelstarts withverified. - A full pass is exit 0,
level_enumequal toverifiedand an emptyweakened_by_flags. Test all three. - A
verifiedresult can still list absent parts. Read theabsentlist in the JSON, or pass--complete. - Use
--expect-changeand--expect-headto bind the result to the change and head you expected, not just any valid chain.
What verified does and does not prove
verified proves provenance and chain integrity under the keys you pinned. It does not prove that the code is correct, that tests were thorough, that the model reasoned well, or that a compromised host logged every event. The two unsourced lines above are a reminder: the attestation carries no credential-broker or egress-proxy statement, so those claims are not backed here.
Inspect a chain interactively
The component below shows how records link into a chain and where each level of the verifier gains or loses its guarantee.
Evidence chain inspector
What does verification actually establish, and which inputs does it depend on?
Hash-linked records (drawing 6 of 12)
- seq 1link
previous_record_hash empty (sequence 1)
signature verified - seq 2link
links to previous
signature verified - seq 3link
links to previous
signature verified - seq 4link
links to previous
signature verified - seq 5link
links to previous
signature verified - seq 12 (head)link
terminal state: Closed
signature verified
attestation.json
signed summary, re-derived from the chain
verifiedhead-checkpoint + inclusion proof
checked under the pinned log key and origin
verifiedVerifier inputs (what you bring, not what the export says)
- ✓ pinned runner key(s)
- ✓ pinned log key + origin
- provenance/signers.json and any checkpoint in the export are claims, not trust.
numi evidence verify --runner-key keys/runner.pub --log-key keys/log.pub --log-origin numinance.test/log --complete exports/closed-author
simulated output, shape as in the real CLI
change: chg_01010101010101010101010101010101 records: 12, head sha256:8dec4e3d… state: ended Closed level: verified chain: records link, hash and end as stated signatures: verified under the pinned runner keys anchor: head proved under the pinned log attestation: signed, re-derived from the chain result: verified
exit 0
level: verifiedexit 0
Provenance and chain integrity hold under keys and a log you pinned.
What this does NOT prove, at any level
- The code is correct.
- The tests are thorough.
- The model reasoned well.
- Completeness against a compromised host: events it never logged are not in the chain.
Level verified, exit 0. No findings or weaknesses.
Text description
Illustrative and simulated: no export is read. The rules are those of docs/evidence/verification.md; the baseline report is the real output of the open verifier on the conformance export exports/closed-author.
- You must choose exactly one key mode. Pinned runner keys (
--runner-key) are the only way to reachverified.--trust-bundle-keystakes the keys the export claims and tops out atself-consistent.--skip-signaturestops out atunauthenticated. - A pinned log (
--log-keywith--log-origin) is needed to prove the head. Without it the result isunanchored(exit 5) unless--allow-unanchoredis given. - Any finding makes the level
failed(exit 3). Edit or remove a record:chain_broken. A chain signed by a key you did not pin:signer_untrusted. With keys from the export or signatures skipped, the same forged-but-consistent chain is not caught, which is why those levels are weaker. - Exit codes: 0 verified, 3 failed, 5 consistent but weaker than verified.
Verified does not prove the code is correct, the tests are thorough, the model reasoned well, or that a compromised host logged every event.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Exit 2, "exactly one key mode" | None or more than one of the pinned keys, --trust-bundle-keys, --skip-signatures. | Pass exactly one mode. |
| Exit 4 | The export directory does not exist. | Check the path relative to where you ran the command. |
Exit 3 with signer_untrusted | The pinned key is not the one that signed. | Pin the correct runner key, from a source you trust. |
Exit 3 with expectation_mismatch | --expect-change or --expect-head did not match. | You may be verifying a different chain than you expected. |
| Exit 5 | A consistent export weaker than verified. | Pin keys and a log, or decide explicitly which allowance you accept. |
Next steps
First plugin
Build the sample knowledge provider from source, see why it refuses to run by hand, and read how a plugin host launches and talks to it.
Status and supported surface
A source-backed matrix of what the public Numinance tree ships, what is designed, and what is deliberately not claimed. Dated 2026-11-09, spec revision 3c74d59.