@sanning/proof 0.19.1 → 0.20.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.
Files changed (98) hide show
  1. package/README.md +30 -29
  2. package/dist/agent-record.d.ts +62 -0
  3. package/dist/agent-record.js +527 -0
  4. package/dist/agent-schemas.generated.d.ts +15 -0
  5. package/dist/agent-schemas.generated.js +5759 -0
  6. package/dist/case-file.d.ts +32 -89
  7. package/dist/case-file.js +41 -93
  8. package/dist/case.d.ts +339 -822
  9. package/dist/case.js +667 -1160
  10. package/dist/chain.d.ts +19 -47
  11. package/dist/chain.js +78 -205
  12. package/dist/claims.d.ts +211 -0
  13. package/dist/claims.js +1081 -0
  14. package/dist/cli.d.ts +45 -68
  15. package/dist/cli.js +618 -1022
  16. package/dist/compose.js +23 -65
  17. package/dist/crypto.d.ts +7 -8
  18. package/dist/crypto.js +60 -147
  19. package/dist/declaration.d.ts +68 -194
  20. package/dist/declaration.js +175 -518
  21. package/dist/environment.d.ts +9 -30
  22. package/dist/environment.js +17 -66
  23. package/dist/evidence.d.ts +119 -160
  24. package/dist/evidence.js +744 -1103
  25. package/dist/exit-codes.d.ts +11 -27
  26. package/dist/exit-codes.js +24 -59
  27. package/dist/file-match.d.ts +33 -79
  28. package/dist/file-match.js +33 -69
  29. package/dist/grading.d.ts +98 -135
  30. package/dist/grading.js +224 -380
  31. package/dist/handoff.d.ts +62 -160
  32. package/dist/handoff.js +153 -393
  33. package/dist/index.d.ts +14 -10
  34. package/dist/index.js +60 -167
  35. package/dist/json-schema.d.ts +29 -0
  36. package/dist/json-schema.js +298 -0
  37. package/dist/merkle.js +16 -28
  38. package/dist/message-parts.d.ts +56 -212
  39. package/dist/message-parts.js +142 -502
  40. package/dist/side-content.d.ts +11 -22
  41. package/dist/side-content.js +22 -65
  42. package/dist/types.d.ts +17 -0
  43. package/dist/types.js +19 -5
  44. package/dist/verifier.d.ts +40 -114
  45. package/dist/verifier.js +196 -535
  46. package/dist/witness-cache.d.ts +24 -45
  47. package/dist/witness-cache.js +38 -81
  48. package/dist/witness-lookup.d.ts +36 -57
  49. package/dist/witness-lookup.js +89 -139
  50. package/dist/zip-reader.d.ts +18 -33
  51. package/dist/zip-reader.js +19 -34
  52. package/package.json +11 -3
  53. package/src/agent-record.ts +608 -0
  54. package/src/agent-schemas.generated.ts +5764 -0
  55. package/src/case-file.ts +45 -109
  56. package/src/case.ts +814 -1328
  57. package/src/chain.ts +85 -224
  58. package/src/claims.ts +1253 -0
  59. package/src/cli.ts +714 -1176
  60. package/src/compose.ts +33 -79
  61. package/src/crypto.ts +60 -147
  62. package/src/declaration.ts +219 -656
  63. package/src/environment.ts +17 -65
  64. package/src/evidence.ts +958 -1381
  65. package/src/exit-codes.ts +24 -63
  66. package/src/file-match.ts +40 -89
  67. package/src/grading.ts +287 -421
  68. package/src/handoff.ts +175 -427
  69. package/src/index.ts +131 -177
  70. package/src/json-schema.ts +295 -0
  71. package/src/merkle.ts +16 -28
  72. package/src/message-parts.ts +155 -533
  73. package/src/side-content.ts +25 -68
  74. package/src/types.ts +55 -36
  75. package/src/verifier.ts +202 -526
  76. package/src/witness-cache.ts +45 -94
  77. package/src/witness-lookup.ts +107 -177
  78. package/src/zip-reader.ts +20 -38
  79. package/vectors/README.md +52 -34
  80. package/vectors/agent-record.json +2175 -0
  81. package/vectors/case-file-index.json +1 -1
  82. package/vectors/case-split.json +2 -2
  83. package/vectors/chain-reading.json +3 -3
  84. package/vectors/file-match.json +285 -148
  85. package/vectors/jcs-reader.json +6 -6
  86. package/vectors/pack-grading.json +102 -25
  87. package/vectors/sandbox-evidence.json +573 -581
  88. package/vectors/stamp-on-chain.json +18 -18
  89. package/vectors/witness-cache.json +49 -49
  90. package/dist/agent-proof.d.ts +0 -28
  91. package/dist/agent-proof.js +0 -226
  92. package/dist/run-adapters.d.ts +0 -10
  93. package/dist/run-adapters.js +0 -35
  94. package/dist/run.d.ts +0 -209
  95. package/dist/run.js +0 -1405
  96. package/src/agent-proof.ts +0 -264
  97. package/src/run-adapters.ts +0 -44
  98. package/src/run.ts +0 -1598
package/dist/grading.d.ts CHANGED
@@ -1,38 +1,44 @@
1
1
  import type { DeclarationCheck, DeclarationContentKind, DeclarationDeviationKind, DeclarationVerdict } from "./declaration.js";
2
2
  import { type SideContentMap } from "./side-content.js";
3
- export declare const PACK_VERDICTS: readonly ["verified", "partial", "pending", "not_found", "mixed", "failed", "malformed", "incomplete"];
4
- export type PackVerdict = (typeof PACK_VERDICTS)[number];
3
+ import { type Problem, type ReasonKind, type Verdict } from "./claims.js";
4
+ export declare const PACK_VERDICTS: readonly ["verified", "failed", "incomplete"];
5
+ export type PackVerdict = Verdict;
5
6
  /**
6
- * The minimum this module reads out of a verification result.
7
- *
8
- * `EvidenceBundleResult` satisfies it structurally, so a consumer normally
9
- * passes the kernel's own result straight through. It is stated as a minimum
10
- * rather than an import so a surface running an OLDER pinned kernel — or one
11
- * grading a result it adapted from another verifier — can still be held to
12
- * this rule.
7
+ * The minimum this module reads from a verification result.
8
+ * `EvidenceBundleResult` satisfies it, and an adapted result from another
9
+ * verifier can satisfy it too.
13
10
  */
14
11
  export interface GradeInput {
15
12
  status: string | null | undefined;
13
+ /** The bundle could not be read as one (`EvidenceBundleResult.unreadable`). */
14
+ unreadable?: boolean;
16
15
  /**
17
- * `eventId` and `payloadBindingOk` are read by rule version 6 alone (A22):
18
- * an input that does not carry both is never withheld by its declaration,
19
- * so an adapter written for rule version 5 keeps the stricter reading.
16
+ * `eventId` and `payloadBindingOk` are read only for declared withholding
17
+ * (evidence-bundle §5.4.5). An input without both is never withheld, so it
18
+ * gets the stricter reading.
20
19
  */
21
20
  events: {
22
21
  ok: boolean;
23
22
  contentOk: boolean | null;
24
23
  eventId?: string;
25
24
  payloadBindingOk?: boolean | null;
25
+ /** The record's agent reading, where it is one (rule version 9). Its findings move nothing. */
26
+ agent?: {
27
+ verdict: string | null;
28
+ reason?: string;
29
+ at?: string;
30
+ reasons?: readonly {
31
+ reason: string;
32
+ at: string;
33
+ }[];
34
+ absent?: readonly string[];
35
+ } | null;
26
36
  }[];
27
37
  }
28
38
  /**
29
- * The account of which records disclosed bytes, and what could not be used.
30
- *
31
- * An empty account is NOT a clean bill of health: callers gate on this, never
32
- * on the absence of mismatches. The old readers wrapped the disclosure read in
33
- * `try {} catch {}` and fell back to an empty map, so deleting every log turned
34
- * every content check undetermined, left every event `ok`, and printed a
35
- * verified verdict over zero hashed bytes.
39
+ * Which records disclosed bytes, and what could not be used. An empty account
40
+ * is not a clean result: callers gate on this, never on the absence of
41
+ * mismatches.
36
42
  */
37
43
  export interface DisclosureAccount {
38
44
  /** `event_id`s the bundle presents, in bundle order. */
@@ -50,8 +56,8 @@ export interface DisclosureAccount {
50
56
  extra: string[];
51
57
  }
52
58
  /**
53
- * A completeness note: the pack presents a different number of records for a
54
- * checkpoint than that checkpoint's SIGNED record commits to.
59
+ * The pack presents a different number of records for a checkpoint than that
60
+ * checkpoint's signed record commits to.
55
61
  */
56
62
  export type CompletenessNote = {
57
63
  checkpointRef: string;
@@ -64,21 +70,14 @@ export type CompletenessNote = {
64
70
  presented: null;
65
71
  kind: "unreadable";
66
72
  };
67
- export declare const PACK_GRADE_CAUSE_KINDS: readonly ["records_omitted", "records_surplus", "leaf_count_unreadable", "no_disclosure", "missing_disclosure", "unreadable_disclosure", "unaccounted_disclosure", "declaration_deviation", "declaration_content_dependent"];
73
+ export declare const PACK_GRADE_CAUSE_KINDS: readonly ["records_omitted", "records_surplus", "leaf_count_unreadable", "no_disclosure", "missing_disclosure", "unreadable_disclosure", "unaccounted_disclosure", "declaration_deviation", "declaration_content_dependent", "agent_record_nonconforming", "agent_record_incomplete"];
68
74
  export type PackGradeCauseKind = (typeof PACK_GRADE_CAUSE_KINDS)[number];
69
- /**
70
- * One reason a pack is not `verified`, as data.
71
- *
72
- * Structured because the two surfaces that used to derive this rule also
73
- * derived its prose, and prose is the part that drifts hardest and matters
74
- * least. `renderCause` produces the house wording; a surface with its own
75
- * voice reads the fields.
76
- */
75
+ /** One reason a pack is not `verified`, as data. `renderCause` gives the house wording. */
77
76
  export interface PackGradeCause {
78
77
  kind: PackGradeCauseKind;
79
78
  /** The checkpoint this is about, for the completeness kinds. */
80
79
  checkpointRef?: string;
81
- /** The count a checkpoint's signed record commits to. */
80
+ /** The count the checkpoint's signed record commits to. */
82
81
  signed?: number;
83
82
  /** The count the pack actually presents for that checkpoint. */
84
83
  presented?: number;
@@ -96,148 +95,112 @@ export interface PackGradeCause {
96
95
  * `declaration_content_dependent`.
97
96
  */
98
97
  deviation?: DeclarationDeviationKind | DeclarationContentKind;
98
+ /**
99
+ * The JSON Pointer the agent reading's reason is about, for
100
+ * `agent_record_nonconforming` and `agent_record_incomplete`; `reason` is its reason
101
+ * code (agent-events.md section 10.1).
102
+ */
103
+ at?: string;
104
+ /**
105
+ * For `agent_record_incomplete` with `listed_record_absent`, the `event_id` the
106
+ * closing record lists and the pack does not hold.
107
+ */
108
+ listedEventId?: string;
99
109
  }
100
110
  export interface PackGrade {
101
111
  verdict: PackVerdict;
112
+ /** `changed` or `nonconforming` where `verdict` is `failed`. */
113
+ reasonKind?: ReasonKind;
114
+ /**
115
+ * Every problem behind the verdict, each mapped to one claim and one state
116
+ * (`claims.ts`): the bundle's own, then the causes', then the declaration's.
117
+ * Empty exactly where `verdict` is `verified`.
118
+ */
119
+ problems: Problem[];
102
120
  /** Records whose OWN bytes bound to their OWN commitment. Nothing else. */
103
121
  recordsVerified: number;
104
122
  recordsFailed: number;
105
123
  recordsUndetermined: number;
106
124
  causes: PackGradeCause[];
107
125
  /**
108
- * The declaration check's own verdict, carried so a consumer that reads only
109
- * this value can tell a declared pack from an undeclared one. Absent when no
110
- * check was passed, which is the pre-§5.4 call.
126
+ * The declaration check's verdict, so a consumer can tell a declared pack
127
+ * from an undeclared one. Absent when no check was passed.
111
128
  */
112
129
  declaration?: DeclarationVerdict;
113
130
  /**
114
- * Records WITHHELD BY THEIR DECLARATION (rule version 6, evidence-bundle
115
- * 5.4.5 v1.20, A22): a readable declaration lists them in
116
- * `declaredWithheld`, their `ok` is true, their `contentOk` is `null` and
117
- * their `payloadBindingOk` is true. Never counted in `recordsVerified`: no
118
- * byte of their content was hashed, and a surface MUST NOT print them as
119
- * verified records.
131
+ * Records withheld by their declaration (evidence-bundle §5.4.5). Never
132
+ * counted in `recordsVerified`: none of their content was hashed, and a
133
+ * surface must not print them as verified.
120
134
  */
121
135
  recordsWithheld: number;
122
136
  /** Their `event_id`s, in bundle order. */
123
137
  withheldEventIds: string[];
124
138
  }
125
139
  /**
126
- * Account for the disclosed bytes a pack handed us against the records its
127
- * bundle presents.
140
+ * Accounts for the disclosed bytes in `content` against the records the bundle
141
+ * presents. `content` is the map `verifyEvidenceBundle` takes; prefer a `Map`,
142
+ * since on a plain object an `event_id` of `__proto__` never lands. A zero-byte
143
+ * entry is present, not missing, so a truncated log cannot read as unknown.
128
144
  *
129
- * `content` is the same map `verifyEvidenceBundle` takes — a plain object or a
130
- * `Map` — so a caller builds it once and uses it for both. Prefer the `Map`:
131
- * an `event_id` is producer-chosen, and on a plain object `__proto__` is not a
132
- * key but a prototype setter, so bytes written under that id never land. A
133
- * ZERO-BYTE entry is present, not missing: bytes were supplied, the check ran,
134
- * and the mismatch the verifier reports stands. A truncated log must not be
135
- * able to launder itself into "unknown".
136
- *
137
- * A CONVENIENCE, NOT THE ONLY WAY TO BUILD AN ACCOUNT — and the difference
138
- * matters for one field. `extra` here can only ever name keys the content map
139
- * carries, so a transport whose surplus is not representable as a map entry
140
- * cannot report it through this function: a pack directory holding
141
- * `logs/notes.txt`, or a second file for a record already accounted for, is
142
- * invisible to a map built by iterating the bundle's own events. A consumer
143
- * reading a DIRECTORY should build `DisclosureAccount` itself from the real
144
- * listing and pass that to `gradePack` — the rule takes an account, never a
145
- * bundle, precisely so the transport can say things the map cannot.
145
+ * `extra` can only name map keys. A consumer reading a directory must build
146
+ * `DisclosureAccount` from the real listing to report surplus files.
146
147
  */
147
148
  export declare function accountDisclosure(bundle: unknown, content: SideContentMap): DisclosureAccount;
148
149
  /**
149
- * A JSON number read by its value: an integer within 2**53 - 1, or null.
150
- * `Number.isSafeInteger`, mirrored by `_js_safe_integer` in
151
- * `src/sanning_proof/chain.py`, so `2.0` is 2 in both kernels and
152
- * `9007199254740993`, which this parser rounds, is unreadable in both.
150
+ * A JSON number read by its value: an integer within 2**53 - 1, or null. So
151
+ * `2.0` is 2, and `9007199254740993`, which the parser rounds, is unreadable.
153
152
  */
154
153
  export declare function safeInteger(value: unknown): number | null;
155
- /** The `leaf_count` a checkpoint's SIGNED record commits to, or null if unreadable. */
154
+ /** The `leaf_count` a checkpoint's signed record commits to, or null if unreadable. */
156
155
  export declare function signedLeafCount(checkpoint: {
157
156
  event_bytes?: unknown;
158
157
  } | null | undefined): number | null;
159
158
  /**
160
- * Omission — the failure a per-record check structurally cannot see.
161
- *
162
- * Drop records from a pack and every SURVIVOR still verifies perfectly:
163
- * signatures, inclusion proofs, content hashes, all green. The number that
164
- * exposes it is already in the pack and already signed — each checkpoint's
165
- * record commits to the `leaf_count` of the tree it anchored. This compares
166
- * that against how many records the pack presents for that checkpoint.
167
- *
168
- * A checkpoint whose signed count cannot be read is `unreadable`: a
169
- * completeness check we could not run is UNKNOWN, never a pass.
159
+ * Omission, which a per-record check cannot see: drop records and every
160
+ * survivor still verifies. Compares each checkpoint's signed `leaf_count` with
161
+ * the records the pack presents for it. An unreadable count is `unreadable`:
162
+ * a check we could not run is unknown, never a pass.
170
163
  */
171
164
  export declare function completenessNotes(bundle: unknown): CompletenessNote[];
172
165
  /**
173
- * Every reason this pack is not `verified`, in the order a reader should hear
174
- * them: what is missing from the whole, then what is missing from the parts.
166
+ * Every reason this pack is not `verified`, in reading order: what the pack
167
+ * claimed, then what is missing from the whole, then from the parts.
175
168
  */
176
- export declare function gradeCauses(account: DisclosureAccount, notes: readonly CompletenessNote[], declaration?: DeclarationCheck | null, withheld?: readonly string[]): PackGradeCause[];
169
+ export declare function gradeCauses(account: DisclosureAccount, notes: readonly CompletenessNote[], declaration?: DeclarationCheck | null, withheld?: readonly string[], events?: GradeInput["events"]): PackGradeCause[];
177
170
  /**
178
- * The verdict a surface may print, and the counts it may print beside it.
171
+ * The verdict a surface may print, and the counts beside it.
179
172
  *
180
- * The invariant, stated so a mutation test can kill it: `verified` is reachable
181
- * ONLY when every record's supplied bytes bound to its own commitment, or
182
- * (rule version 6) the record is withheld by its declaration, and nothing is
173
+ * Invariant: `verified` only when every record's bytes bound to its own
174
+ * commitment or the record is withheld by its declaration, and nothing is
183
175
  * missing, unreadable, surplus or omitted.
184
176
  *
185
- * Precedence: malformed > failed > incomplete > the kernel's own headline.
186
- * A hard verdict wins — "the bytes are absent" is never reported as failure
187
- * (§5.1: undetermined, not failed), and a proven mismatch is never softened
188
- * into absence. The last branch passes the kernel's headline through unchanged:
189
- * this rule DOWNGRADES a verdict, it never invents one.
190
- *
191
- * ── the declaration (optional fourth argument) ──────────────────────────────
192
- *
193
- * `declaration` is what `checkDeclaration` in `./declaration.ts` made of the
194
- * pack's own signed statement of what it holds (`evidence-bundle.md` §5.4). A
195
- * deviation from it is a PROVEN mismatch between what the pack claimed and
196
- * what it carries, so it FAILS the pack and each deviation becomes its own
197
- * cause. It must never soften into absence: that is how a trimmed hand-over
198
- * reads as an innocent gap.
199
- *
200
- * A check that came back `partial` splits in THREE (proof#147), and the first
201
- * of the three is not about the declaration's readability at all. The other
202
- * two split on whether the body carried a `declaration` member.
203
- *
204
- * content-dependent the pack and the UNSIGNED content beside it do not
205
- * line up (proof#147). Each finding is its own cause
206
- * and the pack is `incomplete`. It must never reach
207
- * `failed`: whoever assembles a case fills in the
208
- * side-content map, so an accuser holding an intact
209
- * pack could otherwise put its holder into `failed`
210
- * with no key at all, by dropping one file or adding
211
- * one. `failed` is left to what a signature covers.
212
- * no declaration at all nothing moves. Every pack built before §5.4 is
213
- * this case, and re-grading them would move pinned
214
- * exit codes for artifacts already in customers'
215
- * hands.
216
- * present and unreadable the pack is `incomplete`. `declaration_version` is
217
- * chosen by the same party that assembles the pack
218
- * and has no accept-set, so a holder who trims a
219
- * record and then writes one unreadable field can
220
- * re-seal the pack with its own key and hand a
221
- * reader a clean verdict over evidence of the trim
222
- * sitting inside the signed body. UNKNOWN is the
223
- * only honest answer to a claim the reader cannot
224
- * read, and it adds no cause: `PackGrade.declaration`
225
- * says why.
226
- *
227
- * `verified` adds nothing and moves nothing.
228
- *
229
- * Omitting the argument entirely is the pre-§5.4 behavior, unchanged, and
230
- * `PackGrade.declaration` is then absent.
177
+ * Every problem (the bundle's, each cause, the declaration's) maps to one claim
178
+ * and one state (`claims.ts`) and the verdict is read off the claims (rule
179
+ * version 9): `failed` where a claim is disproven, else `incomplete` where one
180
+ * is not proven, else `verified`. Absent bytes are never a disproof (section
181
+ * 5.1), and a proven mismatch is never softened into absence. An agent record's
182
+ * findings move nothing.
183
+ *
184
+ * `declaration` is `checkDeclaration`'s result for the pack's signed statement
185
+ * of what it holds (§5.4):
186
+ * deviation a proven mismatch: the pack fails, one cause each
187
+ * content-dependent the pack and its unsigned side content disagree:
188
+ * `incomplete`, never `failed`, since whoever builds
189
+ * the side-content map could otherwise fail an intact
190
+ * pack without a key
191
+ * no declaration nothing moves
192
+ * present and unreadable `incomplete`, with no cause and one problem,
193
+ * `pack_declaration_unreadable` (or
194
+ * `declaration_not_checked` for a chain claim this
195
+ * call was given no reading for): the pack's holder
196
+ * picks `declaration_version`, so an unreadable one
197
+ * could otherwise hide a trimmed record
198
+ * Omitting the argument leaves `PackGrade.declaration` absent.
231
199
  */
232
200
  export declare function gradePack(result: GradeInput, account: DisclosureAccount, notes: readonly CompletenessNote[], declaration?: DeclarationCheck | null): PackGrade;
233
201
  /**
234
- * The house wording for one cause.
235
- *
236
- * Offered, not imposed: a surface with its own voice reads the fields on
237
- * `PackGradeCause` instead. What must not vary between surfaces is the verdict
238
- * and the counts, and those come from `gradePack`.
239
- *
240
- * The `subject` names what the pack is from the reader's position — "this pack"
241
- * on a page someone dropped a file onto, "the pack" in a CLI report.
202
+ * The house wording for one cause. Optional: a surface may read the fields
203
+ * instead; the verdict and counts are what must not vary. `subject` is "this
204
+ * pack" on a page and "the pack" in a CLI report.
242
205
  */
243
206
  export declare function renderCause(cause: PackGradeCause, subject?: string): string;