@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/vectors/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # `vectors/` — conformance tables that ship to consumers
1
+ # `vectors/`: conformance tables that ship to consumers
2
2
 
3
- Unlike [`../../test-vectors/`](../../test-vectors/) — the tagged, vendored corpus
4
- for the kernel primitives — everything here is **inside the published package**
3
+ Unlike [`../../test-vectors/`](../../test-vectors/), the tagged, vendored corpus
4
+ for the kernel primitives, everything here is **inside the published package**
5
5
  (`files: ["vectors", …]`) and reaches downstream surfaces through npm.
6
6
 
7
7
  That distinction is the whole point. A rule that consumers must agree with needs
@@ -11,26 +11,26 @@ correctly.
11
11
  ## `stamp-on-chain.json`
12
12
 
13
13
  The rule that decides what re-fetching a **stamp's witness** from a gateway does
14
- and does not settle — the optional, online half of `sanning.stamp.trace/v1` and
14
+ and does not settle: the optional, online half of `sanning.stamp.trace/v1` and
15
15
  `sanning.stamp.evidence/v2` (`evidence-bundle.md` §5.2.4 / §5.3.4). Implemented
16
16
  by [`../src/evidence.ts`](../src/evidence.ts) and asserted against this table by
17
- [`../test/stamp-on-chain-vectors.test.ts`](../test/stamp-on-chain-vectors.test.ts)
18
- — **and by the Python kernel against the same bytes**, in
17
+ [`../test/stamp-on-chain-vectors.test.ts`](../test/stamp-on-chain-vectors.test.ts),
18
+ **and by the Python kernel against the same bytes**, in
19
19
  `tests/test_stamp_on_chain_vectors.py`, so neither kernel can pass by agreeing
20
20
  with the other.
21
21
 
22
22
  **The one thing a consumer must not do with it: collapse the four states into a
23
23
  boolean.** `not checked` · `confirm` · `mismatch` · `unreachable`. A reader that
24
24
  cannot tell the first from the last will report that no gateway could be reached
25
- on a run that contacted none — a false accusation manufactured by a missing
26
- state, and the defect this table was written after. Vendoring rules are the same
25
+ on a run that contacted none: a false accusation manufactured by a missing
26
+ state. Vendoring rules are the same
27
27
  three steps as below, against `vectors/stamp-on-chain.json`.
28
28
 
29
29
  ## `witness-cache.json`
30
30
 
31
31
  The rule that decides what a reader does with the witnessed-time cache, the
32
32
  unsigned `witness-cache.json` beside a pack's `bundle.json` (`evidence-bundle.md`
33
- §5.5.6 and §5.6.6, v1.25, A30). Implemented by [`../src/witness-cache.ts`](../src/witness-cache.ts)
33
+ §5.5.6 and §5.6.6). Implemented by [`../src/witness-cache.ts`](../src/witness-cache.ts)
34
34
  and the `case` command in [`../src/cli.ts`](../src/cli.ts), and asserted against
35
35
  this table by
36
36
  [`../test/witness-cache-vectors.test.ts`](../test/witness-cache-vectors.test.ts)
@@ -49,13 +49,12 @@ lookup settled stays labelled not checked.
49
49
  The rule that decides how a kernel reads bytes that claim to be `JCS(value)`
50
50
  (RFC 8785). Five checks, none of them left to a built-in decoder's defaults:
51
51
  **strict UTF-8**, **no leading byte-order mark**, **no non-finite literal**,
52
- **no object that names one member twice** (I-JSON, RFC 7493; rule version 3,
53
- proof#144), and **no unpaired surrogate in the parsed value**. A duplicate is
52
+ **no object that names one member twice** (I-JSON, RFC 7493), and **no unpaired surrogate in the parsed value**. A duplicate is
54
53
  refused with the same message in both kernels, `duplicate key "<name>"`, and a
55
54
  case that carries `error` pins that exact string. The fourth is not the first one
56
55
  twice: a surrogate written as the ASCII escape `\ud800` survives every
57
56
  byte-level check, because the bytes are ASCII, and the parser produces the
58
- malformed code unit afterwards (proof#154).
57
+ malformed code unit afterwards.
59
58
  Implemented by [`../src/verifier.ts`](../src/verifier.ts) as `jcsParse` and by
60
59
  `src/sanning_proof/canonicalize.py` as `jcs_loads`, and asserted against this
61
60
  table by [`../test/host-wording.test.ts`](../test/host-wording.test.ts) **and by
@@ -68,7 +67,7 @@ BOM. Python's `json.loads(<bytes>)` is not `bytes.decode("utf-8")` then
68
67
  `json.loads`: CPython sniffs the encoding and decodes with
69
68
  `errors="surrogatepass"`, so it strips a BOM too, accepts a UTF-16 or UTF-32
70
69
  body, and passes a lone surrogate and a CESU-8 pair through. Both defaults have
71
- shipped a split verdict on one pack that verifies (proof#140, gates 4 and 5).
70
+ shipped a split verdict on one pack that verifies.
72
71
 
73
72
  **The accepted cases matter as much as the rejected ones.** An honest body
74
73
  carrying astral characters, a noncharacter, a U+FEFF *inside a string value* or
@@ -84,8 +83,8 @@ been tested.
84
83
 
85
84
  ## `pack-grading.json`
86
85
 
87
- The rule that decides whether a **pack** — a signed bundle plus whatever
88
- disclosed bytes travelled beside it — is `verified`, `failed` or `incomplete`.
86
+ The rule that decides whether a **pack**, a signed bundle plus whatever
87
+ disclosed bytes travelled beside it, is `verified`, `failed` or `incomplete`.
89
88
  Implemented by [`../src/grading.ts`](../src/grading.ts) and asserted against this
90
89
  table by [`../test/grading.test.ts`](../test/grading.test.ts).
91
90
 
@@ -110,30 +109,30 @@ One implementation, no table to keep in step, no drift to guard against.
110
109
  An older pinned kernel, another language, a surface that adapts a result from
111
110
  somewhere else. Then, and only then:
112
111
 
113
- 1. **Vendor this file byte-for-byte.** Not "equivalent" — identical. A vendored
112
+ 1. **Vendor this file byte-for-byte.** Not "equivalent": identical. A vendored
114
113
  copy that is not byte-identical to this one is a defect, not a variant.
115
114
  2. **Assert your derivation against it** in your own suite, so an implementation
116
115
  that drifts from the rule goes red in your repo.
117
116
  3. **Run a drift check in CI** that compares your copy against the copy in
118
117
  `node_modules/@sanning/proof/vectors/pack-grading.json` and fails on any
119
- difference — *and fails when it cannot find a copy to compare against.* A
118
+ difference, *and fails when it cannot find a copy to compare against.* A
120
119
  drift check that skips when its source is missing is not a check.
121
120
 
122
121
  Step 3 is the one people skip, and it is the one that matters. Steps 1 and 2
123
122
  catch an implementation drifting from its own table. Only step 3 catches the
124
- table itself being edited on one side — which is the failure that actually
125
- happened, and the reason this file moved here.
123
+ table itself being edited on one side, and that is why this file ships in the
124
+ package.
126
125
 
127
126
  ### Shape
128
127
 
129
128
  | Key | Meaning |
130
129
  |---|---|
131
130
  | `ruleVersion` | Bumped when a case's expectation changes **or a case is added**. An implementation asserts the version it was written against, so a table it does not understand fails loudly rather than passing vacuously. Currently **6**: `evidence-bundle.md` §5.4.5, where a record withheld by a readable declaration is counted apart and holds the pack at nothing. |
132
- | `kernelEventClasses` | The six per-event outcome classes a verification result can carry, named so a case can be written as counts rather than as a hand-built bundle. The two added at rule version 6, `withheldBound` and `withheldUnbound`, carry an `eventId` and a `payloadBindingOk`; `howToUse` says how an adapter builds them. |
131
+ | `kernelEventClasses` | The six per-event outcome classes a verification result can carry, named so a case can be written as counts rather than as a hand-built bundle. Two of them, `withheldBound` and `withheldUnbound`, carry an `eventId` and a `payloadBindingOk`; `howToUse` says how an adapter builds them. |
133
132
  | `cases[].kernel` | The verification result to grade, as class counts. |
134
133
  | `cases[].logs` | The disclosure account: how many records the bundle presents, and how many disclosed usable bytes. |
135
- | `cases[].omissions` | Completeness notes — a checkpoint's signed `leaf_count` against the records the pack presents for it. |
136
- | `cases[].expect` | The verdict, the three counts, how many causes the grade must carry, and, from rule version 6, `recordsWithheld` where a case pins it. |
134
+ | `cases[].omissions` | Completeness notes: a checkpoint's signed `leaf_count` against the records the pack presents for it. |
135
+ | `cases[].expect` | The verdict, the three counts, how many causes the grade must carry, and `recordsWithheld` where a case pins it. |
137
136
 
138
137
  Nothing in a case names a transport. A directory read and a browser drop produce
139
138
  the same account and must produce the same verdict; a table that encoded one
@@ -142,7 +141,7 @@ surface's mechanism would let the other one drift while staying green.
142
141
  ## `case-file-index.json`
143
142
 
144
143
  How a reader compares a case file's index, `contents.json`, with the folder it
145
- sits at the root of (`evidence-bundle.md` §5.6.3, v1.20 A25). One pure function
144
+ sits at the root of (`evidence-bundle.md` §5.6.3). One pure function
146
145
  in both kernels, `readCaseFileIndex` in [`../src/case-file.ts`](../src/case-file.ts)
147
146
  and `read_case_file_index` in `src/sanning_proof/case_file.py`, asserted against
148
147
  this table by [`../test/case-file-index.test.ts`](../test/case-file-index.test.ts)
@@ -159,7 +158,7 @@ literals.
159
158
  ## `file-match.json`
160
159
 
161
160
  How a reader matches files handed in beside a pack against the commitments its
162
- signed records make (`evidence-bundle.md` §5.7, v1.24 A29, proof#92). One pure
161
+ signed records make (`evidence-bundle.md` §5.7). One pure
163
162
  reading in both kernels, `matchFiles` and `matchCaseFiles` in
164
163
  [`../src/file-match.ts`](../src/file-match.ts) and `match_files` and
165
164
  `match_case_files` in `src/sanning_proof/file_match.py`, asserted against this
@@ -173,8 +172,8 @@ matched by its SHA-256 and by nothing else**, and **no match moves a verdict**:
173
172
  a surface that matched by name, or took a hash from a field no record's key
174
173
  signed, would vouch for a file the pack never committed to. Written by
175
174
  `tools/gen-vectors/gen_file_match_vectors.py`, whose expectations are written
176
- by hand from what it built. Rule version 2 (A43, proof#204) adds `pack_index`
177
- and `record_index` to every commitment and every `not_read` entry: the pack's
175
+ by hand from what it built. Every commitment and every `not_read` entry
176
+ carries `pack_index` and `record_index`: the pack's
178
177
  position among the row's packs in `mode: case` (`null` in `mode: pack`) and
179
178
  the record's position among the events the pack presents, both read off the
180
179
  packs the row names.
@@ -182,8 +181,7 @@ packs the row names.
182
181
  ## `case-split.json`
183
182
 
184
183
  How `case` turns the folders it was handed into packs: the verify page's
185
- splitting rule (`sanning-io/verify-page` `src/lib/case.ts` `splitCase`,
186
- `src/lib/pack.ts` `assemble`) over a walk whose rules are the command's own,
184
+ splitting rule (`splitCase`) over a walk whose rules are the command's own,
187
185
  restated in [`../src/cli.ts`](../src/cli.ts) and `src/sanning_proof/cli.py`
188
186
  because the page's code lives in the page. Two tables and the limits:
189
187
 
@@ -192,7 +190,7 @@ because the page's code lives in the page. Two tables and the limits:
192
190
  the packs, the outside paths and the paths that are not regular files, or
193
191
  the refusal. The rows include the decision file unpacked, a symbolic link
194
192
  under `logs/`, each side of the depth and entry limits, names that are not
195
- UTF-8, and (v1.20, A25) a case file unpacked and as a `.zip` argument, with
193
+ UTF-8, and a case file unpacked and as a `.zip` argument, with
196
194
  the entries a reader lists and never reads and the archives it refuses.
197
195
  - `parses`: how `bundle.json` bytes become JSON through the reader `verify`
198
196
  and `case` share, including each side of the nesting limit.
@@ -205,8 +203,7 @@ run through both commands by `cross-kernel/run_case_cli.sh`.
205
203
 
206
204
  Every expectation is a literal written in
207
205
  `tools/gen-vectors/gen_case_split_vectors.py`, not the output of either
208
- kernel. The splitting rows were graded against the page's own code when the
209
- table was first written. The walk rows (links, depth, entry count, names, a
206
+ kernel. The splitting rows match the page's own splitting. The walk rows (links, depth, entry count, names, a
210
207
  `.zip` argument) and the reader rows are the command's own rules, and the page
211
208
  does not share them: it opens a dropped `.zip`, drops a leading byte-order
212
209
  mark, and reads whatever the browser hands it for a link, a bad name or a deep
@@ -248,6 +245,27 @@ TypeScript verdict line and the Python `Gateways` line exactly.
248
245
  Two more members: `stoppedEarly` holds packs whose verification stops before
249
246
  any witness is read, each of which must print and write the same with
250
247
  `--gateways`, reachable or not, as offline (the Python `Gateways` line names
251
- the gateways passed); `agentProof` holds an agent proof signed `dev`, which the
252
- TypeScript `verify` prints as `SANDBOX` with exit 5 and the Python one, which
253
- implements no agent-proof verifier, refuses with exit 2.
248
+ the gateways passed); `retiredAgentProof` holds a `sanning.agent.proof/v1` proof signed `dev`, which
249
+ both `verify` commands read malformed, exit 2, and never as sandbox evidence: no
250
+ kernel reads that retired format.
251
+
252
+ ## `agent-record.json`
253
+
254
+ How a kernel reads one `agent.*` record on its own: steps 1 to 6 of
255
+ `agent-events.md` §10, in the `sanning-io/specs` release pinned in
256
+ [`../../vendor/specs/`](../../vendor/specs/). Implemented by `readAgentRecord`
257
+ in [`../src/agent-record.ts`](../src/agent-record.ts), against the schemas
258
+ bundled in [`../src/agent-schemas.generated.ts`](../src/agent-schemas.generated.ts),
259
+ and asserted against this table by
260
+ [`../test/agent-record.test.ts`](../test/agent-record.test.ts). The pinned
261
+ release's own cases are asserted by
262
+ [`../test/agent-conformance.test.ts`](../test/agent-conformance.test.ts). Every
263
+ expectation is written by hand in
264
+ `tools/gen-vectors/gen_agent_record_table.py`, which writes this file. The
265
+ Python kernel does not read `agent.*` records yet, so only the TypeScript
266
+ kernel asserts this table today.
267
+
268
+ **The one thing a consumer must not do with it: read `partial` as a pass.** A
269
+ record whose `extras.event_schema` names a version the kernel does not know,
270
+ `sanning.agent/1.1` or `sanning.agent/2`, reads `partial`: the kernel holds no
271
+ schema to check it against. It is never `verified` and never `malformed`.