@sanning/proof 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/agent-proof.js +5 -0
- package/dist/chain.js +4 -4
- package/dist/cli.js +13 -10
- package/dist/compose.js +3 -3
- package/dist/crypto.js +1 -1
- package/dist/evidence.d.ts +29 -54
- package/dist/evidence.js +349 -141
- package/dist/grading.d.ts +1 -1
- package/dist/grading.js +22 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -6
- package/dist/verifier.d.ts +1 -0
- package/dist/verifier.js +66 -4
- package/package.json +2 -2
- package/src/agent-proof.ts +3 -0
- package/src/chain.ts +4 -4
- package/src/cli.ts +13 -10
- package/src/compose.ts +4 -4
- package/src/crypto.ts +1 -1
- package/src/evidence.ts +418 -196
- package/src/grading.ts +28 -5
- package/src/index.ts +5 -8
- package/src/verifier.ts +67 -4
- package/vectors/README.md +1 -1
- package/vectors/chain-reading.json +4 -4
- package/vectors/stamp-on-chain.json +3 -3
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ contentHashes(env); // all content hashes an envelope commits to, by event typ
|
|
|
53
53
|
|
|
54
54
|
## Verify a whole trace bundle: one command
|
|
55
55
|
|
|
56
|
-
The `@sanning/anchor` SDK hands a producer a set of `InclusionReceipt`s and can serialize them into one portable, self-verifying `sanning.evidence/v1` bundle (`body_type: sanning.anchor.trace/
|
|
56
|
+
The `@sanning/anchor` SDK hands a producer a set of `InclusionReceipt`s and can serialize them into one portable, self-verifying `sanning.evidence/v1` bundle (`body_type: sanning.anchor.trace/v3`). Verify the entire bundle (every event's signature + payload binding + Merkle inclusion, all offline) with the bundled CLI:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
59
|
npx @sanning/proof verify trace-bundle.json
|
|
@@ -61,7 +61,7 @@ npx @sanning/proof verify trace-bundle.json
|
|
|
61
61
|
npx @sanning/proof verify trace-bundle.json https://arweave.net,https://permagate.io
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
It prints a per-event + rollup verdict and exits on a pinned code: `0` verified · `1` a real failure (bad signature / tamper / broken inclusion) · `2` malformed bundle · `3` gateway-unavailable when an on-chain re-fetch was requested. The producer's asserted `verdict` is shown but **never trusted**, the displayed verdict is always recomputed from the body. The same CLI also verifies the agent's `sanning.agent.proof/v1` inclusion bundle (it sniffs `spec_version`), so one command covers anchor + agent.
|
|
64
|
+
It prints a per-event + rollup verdict and exits on a pinned code: `0` verified · `1` a real failure (bad signature / tamper / broken inclusion) · `2` malformed bundle · `3` gateway-unavailable when an on-chain re-fetch was requested. Only `arweave` witnesses are re-fetched: a checkpoint or stamp whose `anchor_ref.kind` is anything else is not checked, and with gateways passed the run answers `partial`, exit `3`. The producer's asserted `verdict` is shown but **never trusted**, the displayed verdict is always recomputed from the body. The same CLI also verifies the agent's `sanning.agent.proof/v1` inclusion bundle (it sniffs `spec_version`), so one command covers anchor + agent.
|
|
65
65
|
|
|
66
66
|
> The `verify` CLI is live in `@sanning/proof` ≥ 0.2.2, `npx @sanning/proof verify <bundle> [gateways]`. `verifyEvidenceBundle` is the programmatic API.
|
|
67
67
|
|
|
@@ -80,7 +80,7 @@ result.checkpoints; // per-checkpoint envelope / merkle-root / on-chain results
|
|
|
80
80
|
result.events; // per-event signature / payload-binding / inclusion results
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
A withheld `
|
|
83
|
+
A withheld `event_bytes` (external commitment, record not disclosed) leaves that event's payload binding **undetermined**, surfaced, never failed (the bundle stays cryptographically sound).
|
|
84
84
|
|
|
85
85
|
### …including the raw logs, when the holder discloses them
|
|
86
86
|
|
|
@@ -184,7 +184,7 @@ const ok = await verifyInclusion(
|
|
|
184
184
|
| Export | What it does |
|
|
185
185
|
|---|---|
|
|
186
186
|
| `verifyEnvelope(env, optionsOrContentHash?)` | The three load-bearing checks (spec-version registry, payload-hash recompute, Ed25519 over the signed scope) + optional content bind. Pass `{ payloadBytes }` for external-commitment envelopes. Returns `VerificationResult`. |
|
|
187
|
-
| `verifyEvidenceBundle(bundle, { gateways?, fetchImpl? })` | Verify a signed `sanning.evidence/v1`
|
|
187
|
+
| `verifyEvidenceBundle(bundle, { gateways?, fetchImpl? })` | Verify a signed `sanning.evidence/v1` bundle (`sanning.anchor.trace/v3`, `sanning.stamp.trace/v1`, `sanning.stamp.evidence/v2` or `sanning.evidence.export/v2`): wrapper signature + `body_hash` + every checkpoint + every event's inclusion, offline (optional on-chain re-fetch). Returns `EvidenceBundleResult`. Powers the `npx @sanning/proof verify` CLI. |
|
|
188
188
|
| `disclosedContent(bundle, { gateways?, content?, fetchImpl? })` | **Ingest:** verify a bundle, then hand back the DECODED raw bytes (`Uint8Array`) of every event whose disclosure bound to its committed `content_hash`, so materializing a received pack never means re-implementing the hex convention. Returns `DisclosedContentResult` (`content` map + per-event `verified` / `not_disclosed` / `undetermined` / `failed`, plus the full `verification`). |
|
|
189
189
|
| `gradePack(result, account, notes)` + `accountDisclosure(bundle, content)` / `completenessNotes(bundle)` / `renderCause(cause)` | **Pack grading:** what a SURFACE may claim about a pack: the bundle plus whatever disclosed bytes travelled with it. Three states, never two: `verified` only when every record's own bytes bound to its own commitment and nothing is missing, unreadable, surplus or omitted; `failed` on a proven mismatch; `incomplete` when a check could not be run. Absent evidence is UNKNOWN, never an accusation. Pure: no I/O; transport stays yours. Conformance table: `vectors/pack-grading.json`, shipped in this tarball. |
|
|
190
190
|
| `verifyAgentProofBundle(bundle, { gateways?, fetchImpl? })` / `isAgentProofSpec(v)` | Verify the agent producer's `sanning.agent.proof/v1` inclusion bundle. |
|
|
@@ -203,7 +203,7 @@ The primary signature covers `JCS(envelope minus signature minus co_signatures)`
|
|
|
203
203
|
|
|
204
204
|
## Why you can trust it (without trusting us)
|
|
205
205
|
|
|
206
|
-
Three **independent implementations** of this kernel exist: this package, the Python [`sanning-proof`](https://pypi.org/project/sanning-proof/) (PyPI), and and the MIT-licensed Go reference. The TypeScript and Python kernels are conformance-gated **byte-for-byte** in CI against one shared corpus, pinned per file by SHA-256 at cut tag `test-vectors-
|
|
206
|
+
Three **independent implementations** of this kernel exist: this package, the Python [`sanning-proof`](https://pypi.org/project/sanning-proof/) (PyPI), and and the MIT-licensed Go reference. The TypeScript and Python kernels are conformance-gated **byte-for-byte** in CI against one shared corpus, pinned per file by SHA-256 at cut tag `test-vectors-v4.0`, and a cross-kernel agreement gate re-runs the corpus plus adversarial negatives through both, asserting identical verdicts on identical bytes. The Go reference runs as a third leg of that same gate, built at the commit its vendoring pins.
|
|
207
207
|
|
|
208
208
|
That mutual gate is the point: anyone can verify these provenance records with **no Sanning code in the trust path**, write your own verifier against the specs that ship inside the [`sanning-proof`](https://pypi.org/project/sanning-proof/) sdist, and the corpus will tell you if it is conformant.
|
|
209
209
|
|
package/dist/agent-proof.js
CHANGED
|
@@ -77,6 +77,11 @@ export async function verifyAgentProofBundle(bundle, options = {}) {
|
|
|
77
77
|
errors.push("checkpoint envelope signature failed");
|
|
78
78
|
if (res.payloadHashOk !== true)
|
|
79
79
|
errors.push("checkpoint envelope payload binding failed");
|
|
80
|
+
// A malformed skeleton field (proof#95) fails the envelope with a valid
|
|
81
|
+
// signature and binding; name it rather than fail with no reason.
|
|
82
|
+
for (const m of res.errors)
|
|
83
|
+
if (m.startsWith("malformed "))
|
|
84
|
+
errors.push(`checkpoint envelope ${m}`);
|
|
80
85
|
const payload = (b.checkpoint_envelope.payload ?? {});
|
|
81
86
|
if (typeof payload.merkle_root === "string")
|
|
82
87
|
merkleRoot = payload.merkle_root;
|
package/dist/chain.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// event before it, and reporting what does not line up.
|
|
3
3
|
//
|
|
4
4
|
// WHY THIS LIVES IN THE KERNEL, BESIDE PACK GRADING.
|
|
5
|
-
// `sanning.events/
|
|
6
|
-
// shipped read it. The envelope verifier hashes each event's `
|
|
5
|
+
// `sanning.events/v2` records carry `previous_hash`, and until now nothing we
|
|
6
|
+
// shipped read it. The envelope verifier hashes each event's `event_bytes`
|
|
7
7
|
// and stops — `evidence.ts` says following the link is "consumer-layer logic
|
|
8
8
|
// above it", and it was right that a SINGLE-envelope verifier should not do
|
|
9
9
|
// it. But the consumer layer never did it either, so a bundle with an event
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// ---- WHAT THIS IS NOT ------------------------------------------------------
|
|
19
19
|
//
|
|
20
20
|
// It is not a completeness statement and it must never be read as one. The
|
|
21
|
-
// profile says so in its own words (`anchor/docs/profile-sanning.events-
|
|
21
|
+
// profile says so in its own words (`anchor/docs/profile-sanning.events-v2.md`
|
|
22
22
|
// §5): chain semantics are "deletion/reorder-evidence for the events present
|
|
23
23
|
// ... not a completeness proof." Drop the last N events of a chain and nothing
|
|
24
24
|
// here dangles; the record that would have pointed at them was never written.
|
|
@@ -178,7 +178,7 @@ async function groupChains(bundle) {
|
|
|
178
178
|
// event id an adapter pointer has nothing to resolve against.
|
|
179
179
|
if (eventId === null || publicKey === null)
|
|
180
180
|
continue;
|
|
181
|
-
const decoded = decodeRecord(entry?.
|
|
181
|
+
const decoded = decodeRecord(entry?.event_bytes);
|
|
182
182
|
if (decoded === null)
|
|
183
183
|
continue;
|
|
184
184
|
const { record, bytes } = decoded;
|
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// npx @sanning/proof verify <bundle.json> [comma,sep,gateways]
|
|
3
3
|
//
|
|
4
4
|
// One turnkey verifier for both producer bundles in the stack:
|
|
5
|
-
// - sanning.evidence/v1
|
|
6
|
-
//
|
|
5
|
+
// - sanning.evidence/v1: bodies sanning.anchor.trace/v3, sanning.stamp.trace/v1,
|
|
6
|
+
// sanning.stamp.evidence/v2 and sanning.evidence.export/v2
|
|
7
|
+
// - sanning.agent.proof/v1: the agent inclusion proof
|
|
7
8
|
// Dispatch is by sniffed spec_version; no flag tells the CLI which it is.
|
|
8
9
|
//
|
|
9
10
|
// Pinned exit codes (mirror `sanningd verify-status`):
|
|
@@ -163,8 +164,8 @@ export async function runCli(argv, io) {
|
|
|
163
164
|
// `proof bundle <source-bundle.json> --attestations <f> --key <f> [-o <out>]`
|
|
164
165
|
// (`proof export` still reaches this, undocumented — see the dispatch above.)
|
|
165
166
|
//
|
|
166
|
-
// Compose a signed, offline-verifiable sanning.evidence.export/
|
|
167
|
-
// source sanning.anchor.trace/
|
|
167
|
+
// Compose a signed, offline-verifiable sanning.evidence.export/v2 artifact from a
|
|
168
|
+
// source sanning.anchor.trace/v3 bundle + operator attestation records + an exporter
|
|
168
169
|
// Ed25519 key (evidence-export.md §5, composer). Writes the export to `-o <out>`
|
|
169
170
|
// (or stdout when omitted, so it can be piped straight into `proof verify`).
|
|
170
171
|
//
|
|
@@ -295,8 +296,8 @@ async function runBundle(rest, io) {
|
|
|
295
296
|
function usageExport(io) {
|
|
296
297
|
io.out("Usage: npx @sanning/proof bundle <source-bundle.json> --attestations <file> --key <file> [-o <out.json>]");
|
|
297
298
|
io.out("");
|
|
298
|
-
io.out("Compose a signed, offline-verifiable sanning.evidence.export/
|
|
299
|
-
io.out("sanning.anchor.trace/
|
|
299
|
+
io.out("Compose a signed, offline-verifiable sanning.evidence.export/v2 artifact from an");
|
|
300
|
+
io.out("sanning.anchor.trace/v3 source bundle + operator attestation records + an exporter");
|
|
300
301
|
io.out("Ed25519 key. The output verifies with `proof verify <out.json>`.");
|
|
301
302
|
io.out("");
|
|
302
303
|
io.out("--attestations <file> JSON array of attestation records (or {attestations:[...]}).");
|
|
@@ -567,10 +568,12 @@ function printUsage(io) {
|
|
|
567
568
|
io.out(" verify <bundle.json> [gateways] [--logs <path>] Verify a bundle");
|
|
568
569
|
io.out(" bundle <source.json> --attestations <f> --key <f> [-o] Create an attested bundle");
|
|
569
570
|
io.out("");
|
|
570
|
-
io.out("Verify a sanning.evidence/v1 (sanning.anchor.trace/
|
|
571
|
-
io.out("sanning.
|
|
572
|
-
io.out("
|
|
573
|
-
io.out("to also re-fetch
|
|
571
|
+
io.out("Verify a sanning.evidence/v1 bundle (body sanning.anchor.trace/v3,");
|
|
572
|
+
io.out("sanning.stamp.trace/v1, sanning.stamp.evidence/v2 or the attested export");
|
|
573
|
+
io.out("sanning.evidence.export/v2) or a sanning.agent.proof/v1 inclusion bundle,");
|
|
574
|
+
io.out("fully offline. Supply a comma-separated gateway list to also re-fetch");
|
|
575
|
+
io.out("each checkpoint and stamp on-chain. Only arweave witnesses are re-fetched;");
|
|
576
|
+
io.out("a witness of any other kind is not checked and the run exits 3.");
|
|
574
577
|
io.out("");
|
|
575
578
|
io.out("--logs <path> Bind disclosed raw logs to each event's committed");
|
|
576
579
|
io.out(" content_hash. Either shape works, and which one you");
|
package/dist/compose.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Attested-evidence-export composer (`proof export`, evidence-export.md §5,
|
|
2
2
|
// phase 2). The last-mile issuer/runtime job the kernel does NOT own (§5.1
|
|
3
|
-
// "Out of the kernel"): take a source `sanning.anchor.trace/
|
|
3
|
+
// "Out of the kernel"): take a source `sanning.anchor.trace/v3` bundle + a set of
|
|
4
4
|
// operator attestation records + an exporter Ed25519 key, and PRODUCE one signed,
|
|
5
|
-
// offline-verifiable `sanning.evidence.export/
|
|
5
|
+
// offline-verifiable `sanning.evidence.export/v2` artifact, exactly the bytes the
|
|
6
6
|
// kernel's verifyExportBody round-trip-verifies.
|
|
7
7
|
//
|
|
8
8
|
// This is the inverse of evidence.ts's verifyExportBody, and it is deliberately
|
|
@@ -24,7 +24,7 @@ import { EXPORT_BODY_TYPE, recomputeExportVerdict, } from "./evidence.js";
|
|
|
24
24
|
import { base64UrlToBytes, bytesToHex, ed25519PublicKey, ed25519Sign, sha256Hex, utf8, } from "./crypto.js";
|
|
25
25
|
import { jcs } from "./verifier.js";
|
|
26
26
|
const GENESIS = "GENESIS";
|
|
27
|
-
const EXPORT_SCHEMA =
|
|
27
|
+
const EXPORT_SCHEMA = EXPORT_BODY_TYPE;
|
|
28
28
|
// Transcode an attestation `signature` to the lowercase hex §2.2 mandates. The
|
|
29
29
|
// issuer emits either lowercase-hex or unpadded base64url; §2.2 stores hex, so
|
|
30
30
|
// this is the composer's boundary normalization. Heuristic mirrors the repo's
|
package/dist/crypto.js
CHANGED
|
@@ -72,7 +72,7 @@ export async function ed25519PublicKey(privateKeyHex) {
|
|
|
72
72
|
return bytesToHex(await ed.getPublicKeyAsync(hexToBytes(privateKeyHex)));
|
|
73
73
|
}
|
|
74
74
|
// ---------------------------------------------------------------------------
|
|
75
|
-
// RSA-PSS operator-attestation crypto (sanning.evidence.export/
|
|
75
|
+
// RSA-PSS operator-attestation crypto (sanning.evidence.export/v2)
|
|
76
76
|
//
|
|
77
77
|
// The attested-evidence-export body embeds operator attestations signed with
|
|
78
78
|
// RSA-PSS-SHA-256 over the JCS-canonical attestation payload; the operator key
|
package/dist/evidence.d.ts
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import type { Envelope } from "./types.js";
|
|
2
|
-
export declare const ANCHOR_TRACE_BODY_TYPE = "sanning.anchor.trace/
|
|
2
|
+
export declare const ANCHOR_TRACE_BODY_TYPE = "sanning.anchor.trace/v3";
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* defend (DL-30). Nothing new emits it.
|
|
4
|
+
* The name `event_bytes` replaced. Under the new majors a body entry that still
|
|
5
|
+
* carries it is a hard reject, never an ignored unknown field: ignored, it
|
|
6
|
+
* would read as a withheld record and the event would verify with nothing
|
|
7
|
+
* checked, the fail-open the new majors exist to prevent (governance.md §8,
|
|
8
|
+
* W-3).
|
|
10
9
|
*/
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
13
|
-
export declare const ANCHOR_TRACE_BODY_TYPES: readonly ["sanning.anchor.trace/v2", "sanning.anchor.trace/v1"];
|
|
14
|
-
export declare const EXPORT_BODY_TYPE = "sanning.evidence.export/v1";
|
|
10
|
+
export declare const LEGACY_EVENT_BYTES_FIELD = "record_bytes";
|
|
11
|
+
export declare const EXPORT_BODY_TYPE = "sanning.evidence.export/v2";
|
|
15
12
|
/**
|
|
16
13
|
* The Sanning-signed interval stamp body (evidence-bundle.md §5.2, DL-58).
|
|
17
14
|
*
|
|
18
15
|
* Its own `body_type` rather than a widened anchor-trace body, and the reason
|
|
19
16
|
* is the whole decision: an anchor-trace checkpoint carries a PRODUCER-signed
|
|
20
|
-
* `sanning.events/
|
|
17
|
+
* `sanning.events/v2` envelope, and a stamp has no producer signature at all:
|
|
21
18
|
* Sanning places it, under DL-52, for a customer who holds no chain identity.
|
|
22
19
|
* The two rejected options were making `envelope` optional and synthesising an
|
|
23
20
|
* envelope that Sanning signs; the second would have made a Sanning
|
|
@@ -25,7 +22,7 @@ export declare const EXPORT_BODY_TYPE = "sanning.evidence.export/v1";
|
|
|
25
22
|
* unrecoverable once witnessed.
|
|
26
23
|
*/
|
|
27
24
|
export declare const STAMP_TRACE_BODY_TYPE = "sanning.stamp.trace/v1";
|
|
28
|
-
export declare const STAMP_EVIDENCE_BODY_TYPE = "sanning.stamp.evidence/
|
|
25
|
+
export declare const STAMP_EVIDENCE_BODY_TYPE = "sanning.stamp.evidence/v2";
|
|
29
26
|
/**
|
|
30
27
|
* The version string INSIDE a witnessed stamp body — a different string from
|
|
31
28
|
* the `body_type` above, and the two are easy to confuse.
|
|
@@ -42,7 +39,6 @@ export interface EvidenceIssuer {
|
|
|
42
39
|
kind: string;
|
|
43
40
|
tenant_id?: string;
|
|
44
41
|
agent_id?: string;
|
|
45
|
-
producer_id?: string;
|
|
46
42
|
[k: string]: unknown;
|
|
47
43
|
}
|
|
48
44
|
export interface EvidenceVerdict {
|
|
@@ -71,9 +67,8 @@ export interface AnchorRef {
|
|
|
71
67
|
export interface TraceCheckpoint {
|
|
72
68
|
/**
|
|
73
69
|
* The checkpoint's identity and the join key, DERIVED: hex SHA-256 of the
|
|
74
|
-
* decoded `
|
|
75
|
-
*
|
|
76
|
-
* relabel a checkpoint and the bundle still verified.
|
|
70
|
+
* decoded `event_bytes`. Recomputed by the verifier, never taken from the
|
|
71
|
+
* label.
|
|
77
72
|
*/
|
|
78
73
|
checkpoint_ref: string;
|
|
79
74
|
/**
|
|
@@ -83,14 +78,7 @@ export interface TraceCheckpoint {
|
|
|
83
78
|
*/
|
|
84
79
|
anchor_ref?: AnchorRef;
|
|
85
80
|
envelope: Envelope;
|
|
86
|
-
|
|
87
|
-
merkle_root: string;
|
|
88
|
-
}
|
|
89
|
-
/** The frozen `sanning.anchor.trace/v1` checkpoint (§5.1.3). Read, never written. */
|
|
90
|
-
export interface TraceCheckpointV1 {
|
|
91
|
-
tx_id: string;
|
|
92
|
-
envelope: Envelope;
|
|
93
|
-
record_bytes: string;
|
|
81
|
+
event_bytes: string;
|
|
94
82
|
merkle_root: string;
|
|
95
83
|
}
|
|
96
84
|
export interface TraceInclusion {
|
|
@@ -98,12 +86,12 @@ export interface TraceInclusion {
|
|
|
98
86
|
leaf_index: number;
|
|
99
87
|
leaf_count: number;
|
|
100
88
|
audit_path: string[];
|
|
101
|
-
/** Resolves against `checkpoints[].checkpoint_ref`.
|
|
89
|
+
/** Resolves against `checkpoints[].checkpoint_ref`. */
|
|
102
90
|
checkpoint_ref: string;
|
|
103
91
|
}
|
|
104
92
|
export interface TraceEvent {
|
|
105
93
|
envelope: Envelope;
|
|
106
|
-
|
|
94
|
+
event_bytes?: string;
|
|
107
95
|
content?: string;
|
|
108
96
|
inclusion: TraceInclusion;
|
|
109
97
|
}
|
|
@@ -174,7 +162,7 @@ export interface StampEvidenceInclusion {
|
|
|
174
162
|
}
|
|
175
163
|
export interface StampEvidenceEvent {
|
|
176
164
|
envelope: Envelope;
|
|
177
|
-
|
|
165
|
+
event_bytes?: string;
|
|
178
166
|
content?: string;
|
|
179
167
|
inclusion: StampEvidenceInclusion;
|
|
180
168
|
}
|
|
@@ -211,23 +199,12 @@ export interface OnChainResult {
|
|
|
211
199
|
perGateway: PerGatewayOutcome[];
|
|
212
200
|
}
|
|
213
201
|
export interface CheckpointResult {
|
|
214
|
-
/**
|
|
215
|
-
* The checkpoint's join key AS THE BUNDLE SPELLS IT — the derived
|
|
216
|
-
* `checkpoint_ref` for a v2 body, the legacy `tx_id` for a frozen v1 body.
|
|
217
|
-
* Never re-derived across forms: a v1 bundle's key is its `tx_id`, because
|
|
218
|
-
* that is what its own events resolve against and what an attestation
|
|
219
|
-
* written against it carries.
|
|
220
|
-
*/
|
|
202
|
+
/** The derived `checkpoint_ref`, empty when it could not be derived. */
|
|
221
203
|
checkpointRef: string;
|
|
222
204
|
/**
|
|
223
|
-
* Where this checkpoint was witnessed
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
* witnessed, which is a normal state and NOT a deficiency. For a frozen v1
|
|
227
|
-
* checkpoint this is synthesised as `{ kind: "arweave", id: tx_id }`, which
|
|
228
|
-
* is exactly what v1's spec said the field was ("the Arweave TX the
|
|
229
|
-
* checkpoint envelope was anchored as"). The synthesis is reader-side only
|
|
230
|
-
* and never re-enters a signed artifact or a verdict.
|
|
205
|
+
* Where this checkpoint was witnessed. `null` when the checkpoint carries no
|
|
206
|
+
* `anchor_ref`: placed but not yet witnessed, which is a normal state and NOT
|
|
207
|
+
* a deficiency.
|
|
231
208
|
*/
|
|
232
209
|
anchorRef: AnchorRef | null;
|
|
233
210
|
envelopeOk: boolean;
|
|
@@ -299,12 +276,14 @@ export interface StampResult {
|
|
|
299
276
|
* ── The four states, and why none of them collapses ──
|
|
300
277
|
*
|
|
301
278
|
* `null` means not checked — no gateways were supplied, or this stamp names
|
|
302
|
-
* no witness to check
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
279
|
+
* no witness to check, or its `anchor_ref.kind` has no witness adapter, or
|
|
280
|
+
* its id is not one the adapter accepts; the witness was not checked. It is
|
|
281
|
+
* a statement about the RUN, never about the stamp. The other three are
|
|
282
|
+
* statements about the stamp and live in `onChain.rollup`: `confirm` (a
|
|
283
|
+
* gateway returned the witnessed bytes), `mismatch` (a gateway returned
|
|
284
|
+
* DIFFERENT bytes: a finding, and the only one of the four that fails
|
|
285
|
+
* anything), `unreachable` (we asked and nobody answered: an availability
|
|
286
|
+
* gap, never an accusation).
|
|
308
287
|
*
|
|
309
288
|
* Keeping "not checked" distinct from "unreachable" is the whole point. A
|
|
310
289
|
* surface handed a collapsed boolean cannot tell "no gateway could be
|
|
@@ -339,11 +318,7 @@ export interface EvidenceBundleResult {
|
|
|
339
318
|
errors: string[];
|
|
340
319
|
}
|
|
341
320
|
export interface AttestationRecord {
|
|
342
|
-
/**
|
|
343
|
-
* The source checkpoint this attestation binds to, spelled in the SOURCE
|
|
344
|
-
* bundle's vocabulary: `checkpoint_ref` for a v2 source, the legacy `tx_id`
|
|
345
|
-
* for a frozen v1 one. Not re-derived across forms.
|
|
346
|
-
*/
|
|
321
|
+
/** The source checkpoint's derived `checkpoint_ref` this attestation binds to. */
|
|
347
322
|
checkpoint_ref: string;
|
|
348
323
|
payload: AttestationPayload;
|
|
349
324
|
signature_alg: string;
|