@sanning/proof 0.19.0 → 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 +343 -810
  9. package/dist/case.js +693 -1151
  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 +848 -1322
  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 +132 -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 +597 -580
  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
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "rule": "jcs-reader",
3
3
  "ruleVersion": 3,
4
- "statement": "How a kernel reads bytes that claim to be JCS(value) (RFC 8785). Five checks, none of them left to a built-in decoder's defaults: strict UTF-8, no LEADING byte-order mark, no non-finite literal, no object that names one member twice (I-JSON, RFC 7493; ruleVersion 3, proof#144), and no UNPAIRED surrogate in the parsed value. The fourth is not the first one twice: a surrogate written as the ASCII escape `\\ud800` survives every byte-level check, because the bytes are ASCII, and the parser produces the malformed code unit afterwards. Everything else a JSON parser rejects is rejected. A reader that accepts any of the rejected cases here is reading a set of bytes some other reader will read differently, and a producer chooses those bytes: that is a split verdict on one pack, not a spelling preference. The accepted cases matter as much as the rejected ones -- an honest body carrying astral characters, noncharacters, a U+FEFF inside a string value or combining marks is conformant and must keep verifying.",
4
+ "statement": "How a kernel reads bytes that claim to be JCS(value) (RFC 8785). Five checks, none of them left to a built-in decoder's defaults: strict UTF-8, no LEADING byte-order mark, no non-finite literal, no object that names one member twice (I-JSON, RFC 7493; ruleVersion 3), and no UNPAIRED surrogate in the parsed value. The fourth is not the first one twice: a surrogate written as the ASCII escape `\\ud800` survives every byte-level check, because the bytes are ASCII, and the parser produces the malformed code unit afterwards. Everything else a JSON parser rejects is rejected. A reader that accepts any of the rejected cases here is reading a set of bytes some other reader will read differently, and a producer chooses those bytes: that is a split verdict on one pack, not a spelling preference. The accepted cases matter as much as the rejected ones -- an honest body carrying astral characters, noncharacters, a U+FEFF inside a string value or combining marks is conformant and must keep verifying.",
5
5
  "home": "@sanning/proof -- ts/vectors/jcs-reader.json. This file is the RULE, not a test fixture of one implementation. TypeScript implements it in ts/src/verifier.ts as jcsParse and Python in src/sanning_proof/canonicalize.py as jcs_loads; ts/test/host-wording.test.ts and tests/test_host_wording.py hold BOTH kernels to this file, so neither can pass by agreeing with the other.",
6
6
  "howToUse": "Base64-decode `bytesB64`, hand the bytes to your kernel's JCS reader, and assert that it returns a value where `accept` is true and throws or raises where it is false. Never decode to a string first: half of these cases are ABOUT the decode, and a reader tested through a string has not been tested. Where a case carries `error`, the refusal's message is that exact string in both kernels: a duplicate's message is kernel wording, and a finding carries it.",
7
- "whyItExists": "Round four of proof#140 put a strict decoder on the TypeScript side of three sites and left json.loads(<bytes>) on the Python side of two. CPython hands bytes to detect_encoding and decodes with errors='surrogatepass', so Python became the LENIENT kernel: a sanning.anchor.trace/v3 pack whose checkpoint record bytes were BOM + JCS(record), re-sealed so the pack verifies, read `verified` with zero exceptions in Python and `mixed` in TypeScript. The full ladder, the case leg and CI were green over it. Both guards were source assertions over different module sets, and the TypeScript one stated the false premise in its own comment. One table both kernels read is the fix for that.",
7
+ "whyItExists": "A strict decoder at the TypeScript sites beside json.loads(<bytes>) on the Python side would split the kernels. CPython hands bytes to detect_encoding and decodes with errors='surrogatepass', so Python became the LENIENT kernel: a sanning.anchor.trace/v3 pack whose checkpoint record bytes were BOM + JCS(record), re-sealed so the pack verifies, read `verified` with zero exceptions in Python and `mixed` in TypeScript. One table both kernels read keeps them from splitting.",
8
8
  "cases": [
9
9
  {
10
10
  "id": "plain",
@@ -52,7 +52,7 @@
52
52
  "id": "escaped-lone-surrogate-high",
53
53
  "bytesB64": "eyJrIjoiY1x1ZDgwMHgifQ==",
54
54
  "accept": false,
55
- "why": "a high surrogate written as the ASCII escape `\\ud800`, with no low surrogate after it. PURE ASCII ON THE WIRE, which is the whole point: the strict UTF-8 decode above cannot see it, and both kernels accepted it while their own text said they refuse a lone surrogate. I-JSON (RFC 7493 2.1) forbids an unpaired surrogate and RFC 8785 cannot emit one, since it serializes to UTF-8 and UTF-8 has no encoding for a surrogate code point. Accepted, it is not a lenience anyone can live with: the Python kernel could not then encode the value for a sort key, `read_chains` raised, and the CLI reported `no event chain was found to follow in this bundle` for a bundle whose chains TypeScript read and named a finding on (proof#154)"
55
+ "why": "a high surrogate written as the ASCII escape `\\ud800`, with no low surrogate after it. PURE ASCII ON THE WIRE, which is the whole point: the strict UTF-8 decode above cannot see it, and a reader that accepts it contradicts its own refusal of a lone surrogate. I-JSON (RFC 7493 2.1) forbids an unpaired surrogate and RFC 8785 cannot emit one, since it serializes to UTF-8 and UTF-8 has no encoding for a surrogate code point. Accepted, it is not a lenience anyone can live with: the Python kernel could not then encode the value for a sort key, `read_chains` raised, and the CLI reported `no event chain was found to follow in this bundle` for a bundle whose chains TypeScript read and named a finding on"
56
56
  },
57
57
  {
58
58
  "id": "escaped-lone-surrogate-low",
@@ -82,7 +82,7 @@
82
82
  "id": "raw-0x80",
83
83
  "bytesB64": "eyJhIjoieIB5In0=",
84
84
  "accept": false,
85
- "why": "a continuation byte with no lead byte: not UTF-8 at all. The case gate 4 found, where `new TextDecoder()` substituted U+FFFD and read `verified`"
85
+ "why": "a continuation byte with no lead byte: not UTF-8 at all. `new TextDecoder()` would substitute U+FFFD and read `verified`"
86
86
  },
87
87
  {
88
88
  "id": "overlong-solidus",
@@ -167,7 +167,7 @@
167
167
  "bytesB64": "eyJzcGVjX3ZlcnNpb24iOiJqdW5rIiwic3BlY192ZXJzaW9uIjoic2FubmluZy5ldmVudHMvdjIifQ==",
168
168
  "accept": false,
169
169
  "error": "duplicate key \"spec_version\"",
170
- "why": "an object that names one member twice (proof#144). I-JSON (RFC 7493 section 2.3), which RFC 8785 is defined over, forbids it, and RFC 8785 cannot emit it. `json.loads` and `JSON.parse` both keep the LAST value and say nothing, so a reader that looks at the first sees junk while the kernel verifies the second"
170
+ "why": "an object that names one member twice. I-JSON (RFC 7493 section 2.3), which RFC 8785 is defined over, forbids it, and RFC 8785 cannot emit it. `json.loads` and `JSON.parse` both keep the LAST value and say nothing, so a reader that looks at the first sees junk while the kernel verifies the second"
171
171
  },
172
172
  {
173
173
  "id": "duplicate-nested",
@@ -239,7 +239,7 @@
239
239
  "id": "case-variant-names",
240
240
  "bytesB64": "eyJzcGVjX3ZlcnNpb24iOiJzYW5uaW5nLmV2ZW50cy92MiIsIlNwZWNfVmVyc2lvbiI6Imp1bmsiLCJcdTAxN2ZwZWNfdmVyc2lvbiI6Imp1bmsifQ==",
241
241
  "accept": true,
242
- "why": "names that differ only in case, or by a look-alike such as the long s U+017F, are DIFFERENT names to I-JSON and to both parsers, and this rule does not refuse them. No spec in this repository pins how a reader treats a key that folds to a defined one; to every reader here it is an unknown member, and unknown members are ignored. The Go bundle reader in sanning-io/agent refuses these at the top level of a bundle, which is a recorded Go divergence (proof#144)"
242
+ "why": "names that differ only in case, or by a look-alike such as the long s U+017F, are DIFFERENT names to I-JSON and to both parsers, and this rule does not refuse them. No spec in this repository pins how a reader treats a key that folds to a defined one; to every reader here it is an unknown member, and unknown members are ignored. The Go bundle reader in sanning-io/agent refuses these at the top level of a bundle, which is a recorded Go divergence"
243
243
  }
244
244
  ]
245
245
  }
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "rule": "pack-grading",
3
- "ruleVersion": 6,
4
- "statement": "What a verification surface may CLAIM about a pack it was handed. verified is reachable ONLY when every record's own bytes bound to its own commitment and nothing is missing, unreadable, surplus or omitted. Absent or unreadable evidence is incomplete (UNKNOWN), never failed and never verified. A hard kernel verdict wins: malformed > failed > incomplete > the kernel's own headline. A pack that DEVIATES from its own signed declaration (evidence-bundle.md \u00a75.4) is failed, and every deviation is a cause: a declared record that is absent, a present record nobody declared, or a record the pack declared withheld whose bytes its own SIGNED BODY supplies. A reading that rests instead on the UNSIGNED content handed in beside a pack is not a deviation and never reaches failed (proof#147): each content-dependent finding is its own cause and carries the pack to incomplete, because whoever assembles a case fills that map in, so an accuser holding an intact pack could otherwise reach failed with no key at all. A deviation and a content-dependent finding together are still failed, because the deviation reads off the signed body and a failing check wins. A declaration check that came back partial therefore splits in THREE, and only two of the three turn on the declaration's readability: no declaration member in the body at all moves nothing, because every pack built before \u00a75.4 is that case; a declaration the reader CANNOT READ makes the pack incomplete, because declaration_version is chosen by the party that assembles the pack and has no accept-set, so an unreadable claim must never reach a clean verdict; and a declaration the reader read perfectly well whose disclosure only unsigned bytes could settle makes the pack incomplete as well, named as what the reader could not establish rather than as what the holder did. The grade carries the declaration check verdict in its own output field, so a consumer that keeps only the grade can still tell a declared pack from an undeclared one. Rule version 6 (evidence-bundle.md \u00a75.4.5 v1.20, A22): a record is WITHHELD BY ITS DECLARATION when a readable declaration lists it in declared_withheld, its ok is true, its contentOk is null and its payloadBindingOk is true; it counts in recordsWithheld and never in recordsVerified, it is taken out of expected and missing before the disclosure causes are computed, and it holds the pack at nothing, so a pack whose every record its declaration withholds grades verified with recordsVerified zero. A record that fails any of the four, a pack with no readable declaration, and an input that does not carry eventId and payloadBindingOk keep rule version 5's reading.",
3
+ "ruleVersion": 9,
4
+ "statement": "What a verification surface may claim about a pack it was handed. Rule version 8 (evidence-bundle.md section 5.4.5): every problem the bundle verifier found, every cause and the declaration check each map to one of six claims (signed, unchanged, witnessed, complete, agreed, follows_rules) and one state (proven, disproven, not_proven), and the pack verdict is read off the claims: failed where a claim is disproven, else incomplete where a claim is not proven, else verified. verified is reachable only when every record's own bytes bound to its own commitment and nothing is missing, unreadable, surplus or omitted. Absent or unreadable evidence is not proven, so incomplete, never failed and never verified. A bundle status this rule cannot interpret is not proven too. A pack that deviates from its own signed declaration (evidence-bundle.md section 5.4) is failed, and every deviation is a cause: a declared record that is absent, a present record nobody declared, or a record the pack declared withheld whose bytes its own signed body supplies. A reading that rests instead on the unsigned content handed in beside a pack is not a deviation and never reaches failed: each content-dependent finding is its own cause and carries the pack to incomplete, because whoever assembles a case fills that map in, so an accuser holding an intact pack could otherwise reach failed with no key at all. A deviation and a content-dependent finding together are still failed, because the deviation reads off the signed body and a disproof wins. A declaration check that came back incomplete therefore splits in three, and only two of the three turn on the declaration's readability: no declaration member in the body at all moves nothing, because the complete claim is then out of scope; a declaration the reader cannot read makes the pack incomplete, because declaration_version is chosen by the party that assembles the pack and has no accept-set, so an unreadable claim must never reach a clean verdict; and a declaration the reader read perfectly well whose disclosure only unsigned bytes could settle makes the pack incomplete as well, named as what the reader could not establish rather than as what the holder did. The grade carries the declaration check verdict in its own output field, so a consumer that keeps only the grade can still tell a declared pack from an undeclared one. Rule version 6: a record is withheld by its declaration when a readable declaration lists it in declared_withheld, its ok is true, its contentOk is null and its payloadBindingOk is true; it counts in recordsWithheld and never in recordsVerified, it is taken out of expected and missing before the disclosure causes are computed, and it holds the pack at nothing, so a pack whose every record its declaration withholds grades verified with recordsVerified zero. A record that fails any of the four, a pack with no readable declaration, and an input that does not carry eventId and payloadBindingOk keep rule version 5's reading. Rule version 7 (agent-events.md section 10): each record's agent reading is an input. Rule version 9: every reason of an agent reading that is not verified is a cause, after the declaration's causes, in bundle order and then in the reading's own order. A reason that reads incomplete (event_schema_unknown, a vocabulary version this reader does not know, or listed_record_absent, a record a closing record lists and the pack does not hold) is agent_record_incomplete and is not proven, so incomplete. Every other reason is agent_record_nonconforming: the record is signed and intact and does not follow its vocabulary, so it disproves follows_rules and the pack is failed with the reason kind nonconforming, and a disproof of any other claim beside it makes the reason kind changed. A closing record that lists two records the pack does not hold is two causes. A finding on an agent record is never a cause and moves nothing.",
5
5
  "home": "@sanning/proof — ts/vectors/pack-grading.json. This file is the RULE, not a test fixture of one implementation. The kernel implements it in ts/src/grading.ts and is held to it by ts/test/grading.test.ts.",
6
6
  "consumers": "A surface that grades packs SHOULD call the kernel's gradePack rather than derive the rule again. A surface that cannot yet (an older pinned kernel, another language) vendors this file byte-for-byte, asserts its own derivation against it, and runs a drift check that compares its copy against the copy shipped in the @sanning/proof tarball at vectors/pack-grading.json. A vendored copy that is not byte-identical to this one is a defect, not a variant.",
7
- "howToUse": "Adapt a kernel verification result and a disclosure account into the shapes below, call gradePack, and assert the expectations. `kernel` gives the per-event outcome classes the kernel returns; `logs` gives the account of which records disclosed bytes; `omissions` gives the signed-leaf_count completeness notes. Nothing here depends on how the bytes were transported: a directory read and a browser drop produce the same account and must produce the same verdict. `declaration`, where a case carries one, gives the declaration check's verdict, whether the body carried a declaration member at all, and how many deviations it found; pass a check of that shape as gradePack's optional fourth argument. A case with no `declaration` key calls gradePack with three arguments, which is the pre-§5.4 behavior and must not move, and its `expect.declaration` is absent. Rule version 6: `kernel.withheldBound` and `kernel.withheldUnbound` events carry eventId withheld-0, withheld-1 and so on, in that order, and payloadBindingOk true and null respectively, unless `kernel.v5Adapter` is true, in which case they carry neither field; `logs.withheld` adds that many of those ids to the account's expected AND missing lists, after the counted ones; `declaration.declaredWithheld` is how many of them, from withheld-0, the check lists in declared_withheld (0 where absent); and `expect.recordsWithheld`, where present, is the grade's count of records withheld by their declaration.",
7
+ "howToUse": "Adapt a kernel verification result and a disclosure account into the shapes below, call gradePack, and assert the expectations. `kernel` gives the per-event outcome classes the kernel returns; `logs` gives the account of which records disclosed bytes; `omissions` gives the signed-leaf_count completeness notes. Nothing here depends on how the bytes were transported: a directory read and a browser drop produce the same account and must produce the same verdict. `declaration`, where a case carries one, gives the declaration check's verdict, whether the body carried a declaration member at all, and how many deviations it found; pass a check of that shape as gradePack's optional fourth argument. A case with no `declaration` key calls gradePack with three arguments, which is the pre-§5.4 behavior and must not move, and its `expect.declaration` is absent. Rule version 6: `kernel.withheldBound` and `kernel.withheldUnbound` events carry eventId withheld-0, withheld-1 and so on, in that order, and payloadBindingOk true and null respectively, unless `kernel.v5Adapter` is true, in which case they carry neither field; `logs.withheld` adds that many of those ids to the account's expected AND missing lists, after the counted ones; `declaration.declaredWithheld` is how many of them, from withheld-0, the check lists in declared_withheld (0 where absent); and `expect.recordsWithheld`, where present, is the grade's count of records withheld by their declaration. Rule version 9: `kernel.agentFailed`, `kernel.agentIncomplete`, `kernel.agentTwoAbsent` and `kernel.agentFindings` are events with eventId agent-0, agent-1 and so on, in that order after every other class, each with ok true and contentOk true and an `agent` reading of verdict failed (reason bad_value at /metadata/run/seq), incomplete (reason event_schema_unknown at /extras/event_schema), incomplete with two reasons (listed_record_absent at /metadata/closing/record_ids/0 and at /metadata/closing/record_ids/2) and verified with the finding unended, respectively; each reading that is not verified carries `reasons`, every reason in order; every other event carries no agent reading. Their bytes count in `logs` like any record whose content bound.",
8
8
  "kernelEventClasses": {
9
9
  "okBound": "{ ok: true, contentOk: true } — the record's own bytes hashed to its own commitment",
10
10
  "okUnknown": "{ ok: true, contentOk: null } — structurally fine, but no bytes were disclosed",
11
11
  "mismatched": "{ ok: false, contentOk: false } — the bytes disagree with the commitment",
12
12
  "brokenNoContent": "{ ok: false, contentOk: null } — the record itself does not verify",
13
13
  "withheldBound": "{ eventId: withheld-<i>, ok: true, contentOk: null, payloadBindingOk: true } — no content bound, the record bytes bound to the envelope (rule version 6)",
14
- "withheldUnbound": "{ eventId: withheld-<i>, ok: true, contentOk: null, payloadBindingOk: null } — no content bound, and the record bytes did not travel either (rule version 6)"
14
+ "withheldUnbound": "{ eventId: withheld-<i>, ok: true, contentOk: null, payloadBindingOk: null } — no content bound, and the record bytes did not travel either (rule version 6)",
15
+ "agentFailed": "{ eventId: agent-<i>, ok: true, contentOk: true, agent: { verdict: failed, reason: bad_value, at: /metadata/run/seq, reasons: [{ reason: bad_value, at: /metadata/run/seq }], findings: [] } }: an agent record that does not follow its vocabulary (rule version 9)",
16
+ "agentIncomplete": "{ eventId: agent-<i>, ok: true, contentOk: true, agent: { verdict: incomplete, reason: event_schema_unknown, at: /extras/event_schema, reasons: [{ reason: event_schema_unknown, at: /extras/event_schema }], findings: [] } }: an agent record this reader could not read to the end (rule version 9)",
17
+ "agentTwoAbsent": "{ eventId: agent-<i>, ok: true, contentOk: true, agent: { verdict: incomplete, reason: listed_record_absent, at: /metadata/closing/record_ids/0, reasons: [{ reason: listed_record_absent, at: /metadata/closing/record_ids/0 }, { reason: listed_record_absent, at: /metadata/closing/record_ids/2 }], findings: [] } }: a closing record whose first and third listed records the pack does not hold (rule version 9)",
18
+ "agentFindings": "{ eventId: agent-<i>, ok: true, contentOk: true, agent: { verdict: verified, findings: [unended] } }: a verified agent record with a finding (rule version 7)"
15
19
  },
16
20
  "cases": [
17
21
  {
@@ -40,7 +44,7 @@
40
44
  },
41
45
  {
42
46
  "id": "one-log-deleted",
43
- "why": "absent bytes are UNKNOWN — never verified, never failed (P-10)",
47
+ "why": "absent bytes are unknown — never verified, never failed (P-10)",
44
48
  "kernel": { "status": "verified", "okBound": 25, "okUnknown": 1, "mismatched": 0, "brokenNoContent": 0 },
45
49
  "logs": { "expected": 26, "present": 25, "missing": 1, "unreadable": 0, "extra": 0 },
46
50
  "omissions": [],
@@ -48,7 +52,7 @@
48
52
  },
49
53
  {
50
54
  "id": "every-log-deleted",
51
- "why": "the silent-catch regression: zero bytes hashed must never read as a verified pack",
55
+ "why": "the silent-catch case: zero bytes hashed must never read as a verified pack",
52
56
  "kernel": { "status": "verified", "okBound": 0, "okUnknown": 26, "mismatched": 0, "brokenNoContent": 0 },
53
57
  "logs": { "expected": 26, "present": 0, "missing": 26, "unreadable": 0, "extra": 0 },
54
58
  "omissions": [],
@@ -56,7 +60,7 @@
56
60
  },
57
61
  {
58
62
  "id": "withheld-record-clean-account",
59
- "why": "the case the terminal got wrong (proof#110). A bundle the kernel grades `verified` under evidence-bundle.md §3, holding one record the producer WITHHELD. The disclosure account is clean, and correctly so: no bytes were ever expected for a record that was never offered, so nothing is missing, unreadable, surplus or omitted and there is no cause to report. The record is still unhashed. The PACK is `incomplete` while the BUNDLE is `verified`: the two enums are distinct, and an undetermined record ON ITS OWN is enough to downgrade, with no cause beside it. Every other incomplete case here carries a cause, so a surface could satisfy all of them by keying off `causes` alone and still print a green verdict over a record nobody checked, which is exactly what `proof verify` did.",
63
+ "why": "the case the terminal got wrong. A bundle the kernel grades `verified` under evidence-bundle.md §3, holding one record the producer WITHHELD. The disclosure account is clean, and correctly so: no bytes were ever expected for a record that was never offered, so nothing is missing, unreadable, surplus or omitted and there is no cause to report. The record is still unhashed. The PACK is `incomplete` while the BUNDLE is `verified`: the two enums are distinct, and an undetermined record ON ITS OWN is enough to downgrade, with no cause beside it. Every other incomplete case here carries a cause, so a surface could satisfy all of them by keying off `causes` alone and still print a green verdict over a record nobody checked, which is exactly what `proof verify` did.",
60
64
  "kernel": { "status": "verified", "okBound": 2, "okUnknown": 1, "mismatched": 0, "brokenNoContent": 0 },
61
65
  "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
62
66
  "omissions": [],
@@ -64,7 +68,7 @@
64
68
  },
65
69
  {
66
70
  "id": "one-log-unreadable",
67
- "why": "a file we could not read is our fault, not the record's — UNKNOWN",
71
+ "why": "a file we could not read is our fault, not the record's — unknown",
68
72
  "kernel": { "status": "verified", "okBound": 25, "okUnknown": 1, "mismatched": 0, "brokenNoContent": 0 },
69
73
  "logs": { "expected": 26, "present": 25, "missing": 0, "unreadable": 1, "extra": 0 },
70
74
  "omissions": [],
@@ -96,7 +100,7 @@
96
100
  },
97
101
  {
98
102
  "id": "leaf-count-unreadable",
99
- "why": "a completeness check we could not run is UNKNOWN, not a pass",
103
+ "why": "a completeness check we could not run is unknown, not a pass",
100
104
  "kernel": { "status": "verified", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
101
105
  "logs": { "expected": 26, "present": 26, "missing": 0, "unreadable": 0, "extra": 0 },
102
106
  "omissions": [{ "kind": "unreadable", "checkpointRef": "TX", "signed": null, "presented": null }],
@@ -105,10 +109,10 @@
105
109
  {
106
110
  "id": "malformed-wins",
107
111
  "why": "an unreadable bundle is named for what it is, whatever else is true",
108
- "kernel": { "status": "malformed", "okBound": 0, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
112
+ "kernel": { "status": "incomplete", "okBound": 0, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
109
113
  "logs": { "expected": 0, "present": 0, "missing": 0, "unreadable": 0, "extra": 0 },
110
114
  "omissions": [],
111
- "expect": { "verdict": "malformed", "recordsVerified": 0, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0 }
115
+ "expect": { "verdict": "incomplete", "recordsVerified": 0, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0 }
112
116
  },
113
117
  {
114
118
  "id": "tamper-beats-absence",
@@ -129,14 +133,14 @@
129
133
  {
130
134
  "id": "kernel-headline-passes-through",
131
135
  "why": "this rule downgrades a verdict; it never invents one",
132
- "kernel": { "status": "partial", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
136
+ "kernel": { "status": "incomplete", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
133
137
  "logs": { "expected": 26, "present": 26, "missing": 0, "unreadable": 0, "extra": 0 },
134
138
  "omissions": [],
135
- "expect": { "verdict": "partial", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0 }
139
+ "expect": { "verdict": "incomplete", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0 }
136
140
  },
137
141
  {
138
142
  "id": "unknown-headline-is-not-repeated",
139
- "why": "a headline this rule cannot interpret is a check it could not run — UNKNOWN, never repeated verbatim. The status a surface prints must not be attacker-chosen: passing an uninterpreted string through is how a pack could be headlined with the one word the trust model forbids",
143
+ "why": "a headline this rule cannot interpret is a check it could not run — unknown, never repeated verbatim. The status a surface prints must not be attacker-chosen: passing an uninterpreted string through is how a pack could be headlined with the one word the trust model forbids",
140
144
  "kernel": { "status": "SAFE", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
141
145
  "logs": { "expected": 26, "present": 26, "missing": 0, "unreadable": 0, "extra": 0 },
142
146
  "omissions": [],
@@ -162,7 +166,7 @@
162
166
  },
163
167
  {
164
168
  "id": "declaration-content-dependent",
165
- "why": "the pack agrees with its own claim everywhere its signature reaches, and does not line up with the UNSIGNED content handed in beside it. A NAMED cause and incomplete, never failed: an accuser holding an intact pack reaches this by dropping one file or adding one, with no key at all (proof#147)",
169
+ "why": "the pack agrees with its own claim everywhere its signature reaches, and does not line up with the UNSIGNED content handed in beside it. A NAMED cause and incomplete, never failed: an accuser holding an intact pack reaches this by dropping one file or adding one, with no key at all",
166
170
  "kernel": {
167
171
  "status": "verified",
168
172
  "okBound": 26,
@@ -179,7 +183,7 @@
179
183
  },
180
184
  "omissions": [],
181
185
  "declaration": {
182
- "verdict": "partial",
186
+ "verdict": "incomplete",
183
187
  "present": true,
184
188
  "deviations": 0,
185
189
  "contentFindings": 1
@@ -190,7 +194,7 @@
190
194
  "recordsFailed": 0,
191
195
  "recordsUndetermined": 0,
192
196
  "causeCount": 1,
193
- "declaration": "partial"
197
+ "declaration": "incomplete"
194
198
  }
195
199
  },
196
200
  {
@@ -250,8 +254,8 @@
250
254
  "kernel": { "status": "verified", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
251
255
  "logs": { "expected": 26, "present": 26, "missing": 0, "unreadable": 0, "extra": 0 },
252
256
  "omissions": [],
253
- "declaration": { "verdict": "partial", "present": false, "deviations": 0 },
254
- "expect": { "verdict": "verified", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0, "declaration": "partial" }
257
+ "declaration": { "verdict": "incomplete", "present": false, "deviations": 0 },
258
+ "expect": { "verdict": "verified", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0, "declaration": "incomplete" }
255
259
  },
256
260
  {
257
261
  "id": "declaration-unreadable-is-incomplete",
@@ -259,8 +263,8 @@
259
263
  "kernel": { "status": "verified", "okBound": 26, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0 },
260
264
  "logs": { "expected": 26, "present": 26, "missing": 0, "unreadable": 0, "extra": 0 },
261
265
  "omissions": [],
262
- "declaration": { "verdict": "partial", "present": true, "deviations": 0 },
263
- "expect": { "verdict": "incomplete", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0, "declaration": "partial" }
266
+ "declaration": { "verdict": "incomplete", "present": true, "deviations": 0 },
267
+ "expect": { "verdict": "incomplete", "recordsVerified": 26, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0, "declaration": "incomplete" }
264
268
  },
265
269
  {
266
270
  "id": "withheld-by-declaration",
@@ -303,8 +307,8 @@
303
307
  "kernel": { "status": "verified", "okBound": 2, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "withheldBound": 1, "withheldUnbound": 0 },
304
308
  "logs": { "expected": 3, "present": 2, "missing": 0, "unreadable": 0, "extra": 0, "withheld": 1 },
305
309
  "omissions": [],
306
- "declaration": { "verdict": "partial", "present": true, "deviations": 0, "declaredWithheld": 0 },
307
- "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 1, "recordsWithheld": 0, "causeCount": 1, "declaration": "partial" }
310
+ "declaration": { "verdict": "incomplete", "present": true, "deviations": 0, "declaredWithheld": 0 },
311
+ "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 1, "recordsWithheld": 0, "causeCount": 1, "declaration": "incomplete" }
308
312
  },
309
313
  {
310
314
  "id": "withheld-and-side-bytes",
@@ -312,8 +316,8 @@
312
316
  "kernel": { "status": "verified", "okBound": 2, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "withheldBound": 1, "withheldUnbound": 0 },
313
317
  "logs": { "expected": 3, "present": 2, "missing": 0, "unreadable": 0, "extra": 0, "withheld": 1 },
314
318
  "omissions": [],
315
- "declaration": { "verdict": "partial", "present": true, "deviations": 0, "contentFindings": 1, "declaredWithheld": 1 },
316
- "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "recordsWithheld": 1, "causeCount": 1, "declaration": "partial" }
319
+ "declaration": { "verdict": "incomplete", "present": true, "deviations": 0, "contentFindings": 1, "declaredWithheld": 1 },
320
+ "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "recordsWithheld": 1, "causeCount": 1, "declaration": "incomplete" }
317
321
  },
318
322
  {
319
323
  "id": "withheld-v5-adapter",
@@ -323,6 +327,79 @@
323
327
  "omissions": [],
324
328
  "declaration": { "verdict": "verified", "present": true, "deviations": 0, "declaredWithheld": 1 },
325
329
  "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 1, "recordsWithheld": 0, "causeCount": 1, "declaration": "verified" }
330
+ },
331
+ {
332
+ "id": "agent-record-failed",
333
+ "why": "an agent record whose envelope verified and whose content bound, and which breaks its vocabulary: signed and intact, so the pack is failed with the reason kind nonconforming (rule version 9)",
334
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentFailed": 1 },
335
+ "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
336
+ "omissions": [],
337
+ "expect": { "verdict": "failed", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 1 }
338
+ },
339
+ {
340
+ "id": "agent-failed-beside-a-mismatch",
341
+ "why": "a proven content mismatch beside an agent record that fails: failed with the reason kind changed, with the agent record still a cause",
342
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 1, "brokenNoContent": 0, "agentFailed": 1 },
343
+ "logs": { "expected": 3, "present": 3, "missing": 0, "unreadable": 0, "extra": 0 },
344
+ "omissions": [],
345
+ "expect": { "verdict": "failed", "recordsVerified": 2, "recordsFailed": 1, "recordsUndetermined": 0, "causeCount": 1 }
346
+ },
347
+ {
348
+ "id": "agent-failed-beside-a-deviation",
349
+ "why": "a pack that deviates from its own declaration fails, and the agent record that fails is named beside the deviation",
350
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentFailed": 1 },
351
+ "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
352
+ "omissions": [],
353
+ "declaration": { "verdict": "failed", "present": true, "deviations": 1 },
354
+ "expect": { "verdict": "failed", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 2, "declaration": "failed" }
355
+ },
356
+ {
357
+ "id": "agent-failed-in-an-incomplete-bundle",
358
+ "why": "a bundle status this rule cannot read is not proven, and an agent record beside it that does not follow its vocabulary disproves follows_rules: a disproof outranks anything not proven, so the pack is failed (reason kind nonconforming)",
359
+ "kernel": { "status": "incomplete", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentFailed": 1 },
360
+ "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
361
+ "omissions": [],
362
+ "expect": { "verdict": "failed", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 1 }
363
+ },
364
+ {
365
+ "id": "agent-failed-beside-missing-bytes",
366
+ "why": "a disproof outranks anything not proven: a pack holding an agent record that fails and a record whose bytes did not travel is failed with the reason kind nonconforming, with both causes",
367
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 1, "mismatched": 0, "brokenNoContent": 0, "agentFailed": 1 },
368
+ "logs": { "expected": 3, "present": 2, "missing": 1, "unreadable": 0, "extra": 0 },
369
+ "omissions": [],
370
+ "expect": { "verdict": "failed", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 1, "causeCount": 2 }
371
+ },
372
+ {
373
+ "id": "agent-record-incomplete",
374
+ "why": "an agent record naming a vocabulary version this reader does not know reads incomplete, which holds the pack at incomplete, never verified and never failed",
375
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentIncomplete": 1 },
376
+ "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
377
+ "omissions": [],
378
+ "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 1 }
379
+ },
380
+ {
381
+ "id": "agent-closing-two-records-absent",
382
+ "why": "a closing record that lists two records the pack does not hold reads incomplete with two reasons, and each is a cause: incomplete, never failed, with two causes",
383
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentTwoAbsent": 1 },
384
+ "logs": { "expected": 2, "present": 2, "missing": 0, "unreadable": 0, "extra": 0 },
385
+ "omissions": [],
386
+ "expect": { "verdict": "incomplete", "recordsVerified": 2, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 2 }
387
+ },
388
+ {
389
+ "id": "agent-failed-and-incomplete",
390
+ "why": "an agent record that fails and one that reads incomplete: failed with the reason kind nonconforming, with one cause each in bundle order",
391
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentFailed": 1, "agentIncomplete": 1 },
392
+ "logs": { "expected": 3, "present": 3, "missing": 0, "unreadable": 0, "extra": 0 },
393
+ "omissions": [],
394
+ "expect": { "verdict": "failed", "recordsVerified": 3, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 2 }
395
+ },
396
+ {
397
+ "id": "agent-findings-only",
398
+ "why": "a finding is reported beside its record and moves nothing: two verified agent records each with the finding unended leave the pack verified with no cause",
399
+ "kernel": { "status": "verified", "okBound": 1, "okUnknown": 0, "mismatched": 0, "brokenNoContent": 0, "agentFindings": 2 },
400
+ "logs": { "expected": 3, "present": 3, "missing": 0, "unreadable": 0, "extra": 0 },
401
+ "omissions": [],
402
+ "expect": { "verdict": "verified", "recordsVerified": 3, "recordsFailed": 0, "recordsUndetermined": 0, "causeCount": 0 }
326
403
  }
327
404
  ]
328
405
  }