@sanning/proof 0.12.0 → 0.13.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 +25 -12
- package/dist/agent-proof.d.ts +2 -2
- package/dist/agent-proof.js +4 -4
- package/dist/case-file.d.ts +126 -0
- package/dist/case-file.js +349 -0
- package/dist/case.d.ts +173 -26
- package/dist/case.js +469 -123
- package/dist/cli.d.ts +38 -5
- package/dist/cli.js +557 -208
- package/dist/crypto.d.ts +1 -1
- package/dist/crypto.js +5 -1
- package/dist/declaration.d.ts +58 -52
- package/dist/declaration.js +256 -33
- package/dist/evidence.d.ts +2 -0
- package/dist/evidence.js +134 -19
- package/dist/exit-codes.d.ts +17 -0
- package/dist/exit-codes.js +50 -0
- package/dist/grading.d.ts +28 -13
- package/dist/grading.js +90 -31
- package/dist/index.d.ts +10 -7
- package/dist/index.js +13 -6
- package/dist/message-parts.d.ts +11 -9
- package/dist/message-parts.js +11 -9
- package/dist/types.d.ts +1 -0
- package/dist/verifier.d.ts +9 -2
- package/dist/verifier.js +28 -12
- package/dist/zip-reader.d.ts +50 -0
- package/dist/zip-reader.js +220 -0
- package/package.json +2 -2
- package/src/agent-proof.ts +4 -4
- package/src/case-file.ts +419 -0
- package/src/case.ts +586 -132
- package/src/cli.ts +651 -206
- package/src/crypto.ts +5 -1
- package/src/declaration.ts +248 -52
- package/src/evidence.ts +142 -21
- package/src/exit-codes.ts +54 -0
- package/src/grading.ts +109 -52
- package/src/index.ts +58 -2
- package/src/message-parts.ts +11 -9
- package/src/types.ts +5 -0
- package/src/verifier.ts +35 -13
- package/src/zip-reader.ts +229 -0
- package/vectors/README.md +23 -5
- package/vectors/case-file-index.json +668 -0
- package/vectors/case-split.json +218 -9
- package/vectors/pack-grading.json +68 -4
- package/vectors/stamp-on-chain.json +3 -3
package/dist/case.d.ts
CHANGED
|
@@ -166,7 +166,9 @@
|
|
|
166
166
|
* gets, since that reads wrapper keys.
|
|
167
167
|
*
|
|
168
168
|
* Not exits: a record whose envelope verifies and whose content does not
|
|
169
|
-
* match its commitment is `RECORD_CONTENT_MISMATCH
|
|
169
|
+
* match its commitment is `RECORD_CONTENT_MISMATCH` where that content is
|
|
170
|
+
* inside the signed body and `RECORD_CONTENT_DEPENDENT` where it was handed
|
|
171
|
+
* in beside the pack (proof#159), and one that fails
|
|
170
172
|
* another check inside its pack is `RECORD_DOES_NOT_VERIFY_IN_ITS_PACK`.
|
|
171
173
|
* Both are named and both STAY in the pile, so neither unsigned content
|
|
172
174
|
* handed in beside a pack nor a broken inclusion proof removes a record
|
|
@@ -207,7 +209,9 @@
|
|
|
207
209
|
* verdict, exactly as `counterpart_absent` and `not_a_handoff_record` are
|
|
208
210
|
* findings beside a verdict in 4.1.
|
|
209
211
|
*
|
|
210
|
-
* A case with
|
|
212
|
+
* A case with any `failed` contribution is `failed`: a proven failure keeps
|
|
213
|
+
* the headline (5.5.4 v1.16, A17, proof#158). Otherwise a case with more than
|
|
214
|
+
* one outcome is `mixed` (anchor#198, criterion 4).
|
|
211
215
|
*
|
|
212
216
|
* WHAT THIS READER DOES NOT CLAIM
|
|
213
217
|
* ===============================
|
|
@@ -237,6 +241,8 @@
|
|
|
237
241
|
* sequence. Narrowing any of it here with `handoffs[]` is precisely the move
|
|
238
242
|
* that would reopen proof#137's door.
|
|
239
243
|
*/
|
|
244
|
+
import { type DeclarationRole } from "./declaration.js";
|
|
245
|
+
import { type PackGradeCauseKind, type PackVerdict } from "./grading.js";
|
|
240
246
|
import type { SideContentMap } from "./side-content.js";
|
|
241
247
|
/**
|
|
242
248
|
* The verdicts a case can reach. Every one is already in use in
|
|
@@ -550,17 +556,26 @@ export declare const PACK_KEY_UNREADABLE = "pack_key_unreadable";
|
|
|
550
556
|
*/
|
|
551
557
|
export declare const PACK_DOES_NOT_VERIFY = "pack_does_not_verify";
|
|
552
558
|
/**
|
|
553
|
-
* The pack's wrapper HOLDS and its
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
|
|
563
|
-
|
|
559
|
+
* The pack's wrapper HOLDS and its CASE GRADE is not `verified`
|
|
560
|
+
* (evidence-bundle 5.5.1 step 1 v1.20, A23; it replaces
|
|
561
|
+
* `pack_bundle_not_verified`, which carried the bundle status alone). The case
|
|
562
|
+
* grade is the pack grade of 5.4.5, taken twice: the SIGNED grade over the run
|
|
563
|
+
* with the side map empty, and the FULL grade over the run with it. The signed
|
|
564
|
+
* grade decides where it is `failed` or `malformed`; a failure only the full
|
|
565
|
+
* grade reaches is `incomplete`, because it rests on bytes nobody signed;
|
|
566
|
+
* otherwise the full grade. A body the verifier could not read is `malformed`,
|
|
567
|
+
* a body that is not one of the two event-carrying bodies takes the signed
|
|
568
|
+
* run's status, and a verifier that graded a different number of records than
|
|
569
|
+
* the pack holds takes the signed status, or `malformed` where that status is
|
|
570
|
+
* `verified`.
|
|
571
|
+
*
|
|
572
|
+
* The exception carries `status`, the case grade; `causes`, the 5.4.5 cause
|
|
573
|
+
* kinds of the grade that decided it (none in the first three branches); and
|
|
574
|
+
* `reasons`, the verifier's reasons from the run with the side map empty. It
|
|
575
|
+
* CONTRIBUTES the grade, and `incomplete` for `pending`, `not_found` or
|
|
576
|
+
* `mixed`, so the case verdict never reads above its weakest pack.
|
|
577
|
+
*/
|
|
578
|
+
export declare const PACK_GRADE_NOT_VERIFIED = "pack_grade_not_verified";
|
|
564
579
|
/**
|
|
565
580
|
* A record in a pack whose wrapper holds, whose OWN envelope does not verify
|
|
566
581
|
* (`EventResult.envelopeOk` is false). Not read by 4.1, and NAMED with the
|
|
@@ -581,12 +596,39 @@ export declare const RECORD_ENVELOPE_DOES_NOT_VERIFY = "record_envelope_does_not
|
|
|
581
596
|
export declare const RECORD_DOES_NOT_VERIFY_IN_ITS_PACK = "record_does_not_verify_in_its_pack";
|
|
582
597
|
/**
|
|
583
598
|
* A record whose envelope verifies and whose disclosed content does not hash to
|
|
584
|
-
* the
|
|
585
|
-
*
|
|
599
|
+
* the hash it commits to, its `content_hash` or a hand-off record's
|
|
600
|
+
* `message_hash` (evidence-bundle v1.19, A20) (`EventResult.contentOk` is false), with the
|
|
601
|
+
* side map EMPTY: the content is inside the signed body. The same mismatch from
|
|
602
|
+
* content handed in beside the pack is `RECORD_CONTENT_DEPENDENT` (proof#159).
|
|
603
|
+
* `failed`, and the record STAYS in the pile: content beside a pack is unsigned and often
|
|
586
604
|
* supplied by whoever assembled the case, and gate 3 on proof#140 showed that
|
|
587
605
|
* party erasing an honest verified pair by swapping it.
|
|
588
606
|
*/
|
|
589
607
|
export declare const RECORD_CONTENT_MISMATCH = "record_content_mismatch";
|
|
608
|
+
/**
|
|
609
|
+
* The two readings proof#147 did not reach, given its shape (proof#159, ruled
|
|
610
|
+
* by Phil 2026-09-22, evidence-bundle.md 5.5.4 v1.16, A17). A pack whose
|
|
611
|
+
* bundle verdict is `failed` ONLY when read with the unsigned content handed
|
|
612
|
+
* in beside it, and `failed` no longer when read with that map empty, is
|
|
613
|
+
* `PACK_BUNDLE_CONTENT_DEPENDENT`; a record whose content mismatch comes from
|
|
614
|
+
* that map alone is `RECORD_CONTENT_DEPENDENT`. Both are `incomplete`: the
|
|
615
|
+
* reader established that the bytes it was handed are not the bytes the record
|
|
616
|
+
* commits to, and nothing about the party that signed the record, because
|
|
617
|
+
* whoever assembled the case chose those bytes with no key. Up to v1.15 both
|
|
618
|
+
* readings carried `failed`, and one flipped nibble of accuser-supplied content
|
|
619
|
+
* put a `failed` against an intact pack; under A17's headline rule that would
|
|
620
|
+
* have become the case's headline.
|
|
621
|
+
*
|
|
622
|
+
* The test that separates the two is the one proof#159 states for the inverse:
|
|
623
|
+
* every deviation a signature covers still reads `failed` with the side map
|
|
624
|
+
* EMPTY. So the pack is verified twice, with the map and without it, and what
|
|
625
|
+
* fails without it is `PACK_GRADE_NOT_VERIFIED`, `RECORD_CONTENT_MISMATCH`
|
|
626
|
+
* (content inside the signed body) or `RECORD_DOES_NOT_VERIFY_IN_ITS_PACK`,
|
|
627
|
+
* each still `failed`. Emptying the map is the most a party that signed
|
|
628
|
+
* nothing can do to starve the check, and it cannot remove any of those.
|
|
629
|
+
*/
|
|
630
|
+
export declare const PACK_BUNDLE_CONTENT_DEPENDENT = "pack_bundle_content_dependent";
|
|
631
|
+
export declare const RECORD_CONTENT_DEPENDENT = "record_content_dependent";
|
|
590
632
|
/**
|
|
591
633
|
* A record signed under a ratified profile that is under quarantine
|
|
592
634
|
* (`CASE_QUARANTINED_PROFILES`, pending DL-63). Not read, in any kernel.
|
|
@@ -596,16 +638,19 @@ export declare const RECORD_PROFILE_QUARANTINED = "record_profile_quarantined";
|
|
|
596
638
|
/** The reader was handed no packs at all. */
|
|
597
639
|
export declare const CASE_HOLDS_NO_PACKS = "case_holds_no_packs";
|
|
598
640
|
/**
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
641
|
+
* The two NOTEs (5.5.3 v1.20): findings on the reading with no contribution,
|
|
642
|
+
* printed in the scope sentence so a clean verdict never hides either.
|
|
643
|
+
* `pack_undeclared` is a note only where the reading holds no hand-off record;
|
|
644
|
+
* where it holds one, it is the exception of that name.
|
|
602
645
|
*/
|
|
603
|
-
export declare const
|
|
646
|
+
export declare const CONTENT_WITHHELD_BY_DECLARATION = "content_withheld_by_declaration";
|
|
647
|
+
export declare const CASE_NOTE_KINDS: readonly ["pack_undeclared", "content_withheld_by_declaration"];
|
|
648
|
+
export type CaseNoteKind = (typeof CASE_NOTE_KINDS)[number];
|
|
604
649
|
/**
|
|
605
650
|
* Every exception this reader can report, as a closed set. A surface may render
|
|
606
651
|
* them and a test may assert over them; nothing outside this array is emitted.
|
|
607
652
|
*/
|
|
608
|
-
export declare const CASE_EXCEPTION_KINDS: readonly ["counterpart_absent", "counterpart_absent_from_counterparty_records", "counterpart_absent_signer_unknown", "counterpart_ambiguous", "counterpart_malformed", "pair_failed", "record_malformed", "record_unclaimed_by_its_pack", "record_bytes_withheld", "record_bytes_unreadable", "pack_declaration_deviates", "pack_declaration_content_dependent", "pack_declaration_unreadable", "pack_undeclared", "pack_body_type_unknown", "pack_holds_no_records", "pack_key_unreadable", "pack_does_not_verify", "
|
|
653
|
+
export declare const CASE_EXCEPTION_KINDS: readonly ["counterpart_absent", "counterpart_absent_from_counterparty_records", "counterpart_absent_signer_unknown", "counterpart_ambiguous", "counterpart_malformed", "pair_failed", "record_malformed", "record_unclaimed_by_its_pack", "record_bytes_withheld", "record_bytes_unreadable", "pack_declaration_deviates", "pack_declaration_content_dependent", "pack_declaration_unreadable", "pack_undeclared", "pack_body_type_unknown", "pack_holds_no_records", "pack_key_unreadable", "pack_does_not_verify", "pack_grade_not_verified", "pack_bundle_content_dependent", "record_envelope_does_not_verify", "record_does_not_verify_in_its_pack", "record_content_mismatch", "record_content_dependent", "record_profile_quarantined", "case_holds_no_packs"];
|
|
609
654
|
export type CaseExceptionKind = (typeof CASE_EXCEPTION_KINDS)[number];
|
|
610
655
|
/**
|
|
611
656
|
* One pack in a case, as a reader was handed it.
|
|
@@ -647,11 +692,18 @@ export interface CaseException {
|
|
|
647
692
|
* (v1.17, A20), and it is how many were set aside.
|
|
648
693
|
*/
|
|
649
694
|
count?: number;
|
|
650
|
-
/** The pack's
|
|
695
|
+
/** The pack's case grade, for `PACK_GRADE_NOT_VERIFIED`. */
|
|
651
696
|
status?: CaseVerdict;
|
|
697
|
+
/**
|
|
698
|
+
* The 5.4.5 cause kinds of the grade that decided the case grade, for
|
|
699
|
+
* `PACK_GRADE_NOT_VERIFIED`, in the grade's order. Empty where the grade was
|
|
700
|
+
* not computed (an unreadable body, a body that is not one of the two
|
|
701
|
+
* event-carrying ones, a verifier that graded too few records).
|
|
702
|
+
*/
|
|
703
|
+
causes?: PackGradeCauseKind[];
|
|
652
704
|
/**
|
|
653
705
|
* What the bundle verifier said, as it said it, for the kinds that carry a
|
|
654
|
-
* verifier's grading: `
|
|
706
|
+
* verifier's grading: `PACK_GRADE_NOT_VERIFIED` and the three record kinds
|
|
655
707
|
* graded on the record's own envelope and content.
|
|
656
708
|
*/
|
|
657
709
|
reasons?: string[];
|
|
@@ -672,6 +724,52 @@ export interface CaseRecordReading {
|
|
|
672
724
|
findings: string[];
|
|
673
725
|
failedChecks: string[];
|
|
674
726
|
counterparts: string[];
|
|
727
|
+
/**
|
|
728
|
+
* The role the pack's v2 declaration signs for this record, `handoff` or
|
|
729
|
+
* `step`, or `null` where the pack's declaration is absent, unreadable or
|
|
730
|
+
* v1, or does not declare the record (5.5.1 v1.20).
|
|
731
|
+
*/
|
|
732
|
+
role: DeclarationRole | null;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* One NOTE on the reading (5.5.3 v1.20): something true a reader needs and
|
|
736
|
+
* nothing a reader could not tell, so it carries no contribution.
|
|
737
|
+
*/
|
|
738
|
+
export interface CaseNote {
|
|
739
|
+
kind: CaseNoteKind;
|
|
740
|
+
/** Which pack, by the reader's own name for it. */
|
|
741
|
+
packRef: string;
|
|
742
|
+
/**
|
|
743
|
+
* For `CONTENT_WITHHELD_BY_DECLARATION`, how many of the pack's records its
|
|
744
|
+
* declaration withholds.
|
|
745
|
+
*/
|
|
746
|
+
count?: number;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* One pack as the reading read it, in the order the reader was given them
|
|
750
|
+
* (5.5.4 v1.20). A surface names a pack by `signingKey`, the key that signed
|
|
751
|
+
* its wrapper, and never by an organization (D10).
|
|
752
|
+
*/
|
|
753
|
+
export interface CasePackReading {
|
|
754
|
+
ref: string;
|
|
755
|
+
/** The wrapper key, normalized, or `null` where this reader could not read it. */
|
|
756
|
+
signingKey: string | null;
|
|
757
|
+
/**
|
|
758
|
+
* The case grade (5.5.1 step 1), or `null` where the wrapper did not hold or
|
|
759
|
+
* the key could not be read.
|
|
760
|
+
*/
|
|
761
|
+
grade: PackVerdict | null;
|
|
762
|
+
/**
|
|
763
|
+
* Records withheld by the pack's declaration (5.4.5): in scope for their
|
|
764
|
+
* signature and commitment only. Never counted as verified records.
|
|
765
|
+
*/
|
|
766
|
+
recordsWithheld: number;
|
|
767
|
+
/**
|
|
768
|
+
* `sanning.declaration/v1`, `sanning.declaration/v2`, or `null` where the
|
|
769
|
+
* pack carries no declaration, one this reader does not know, or a body this
|
|
770
|
+
* reader does not read.
|
|
771
|
+
*/
|
|
772
|
+
declarationVersion: string | null;
|
|
675
773
|
}
|
|
676
774
|
export interface CaseReading {
|
|
677
775
|
verdict: CaseVerdict;
|
|
@@ -714,6 +812,10 @@ export interface CaseReading {
|
|
|
714
812
|
* checked packs, which is false.
|
|
715
813
|
*/
|
|
716
814
|
onChainChecked: boolean;
|
|
815
|
+
/** The NOTEs, in pack order (5.5.3 v1.20). No contribution. */
|
|
816
|
+
notes: CaseNote[];
|
|
817
|
+
/** One reading per pack, in the order the reader was given them. */
|
|
818
|
+
packs: CasePackReading[];
|
|
717
819
|
}
|
|
718
820
|
/**
|
|
719
821
|
* Read a whole case: several packs in, one verdict and its exceptions out.
|
|
@@ -744,11 +846,56 @@ export interface CaseReading {
|
|
|
744
846
|
*/
|
|
745
847
|
export declare function readCase(packs: readonly CasePack[]): Promise<CaseReading>;
|
|
746
848
|
export declare function renderException(exception: CaseException): string;
|
|
849
|
+
/** The house wording for one NOTE. Offered, not imposed, as `renderException` is. */
|
|
850
|
+
export declare function renderCaseNote(note: CaseNote): string;
|
|
747
851
|
/**
|
|
748
|
-
*
|
|
852
|
+
* The scope sentence, printed directly under the headline (evidence-bundle
|
|
853
|
+
* 5.5.6 v1.20, A26), byte for byte the text `render_case_summary` returns.
|
|
749
854
|
*
|
|
750
|
-
*
|
|
751
|
-
* the
|
|
752
|
-
* that
|
|
855
|
+
* The packs in the reading; the distinct keys, compared as keys, that signed
|
|
856
|
+
* the wrapper of a pack whose wrapper held; the hand-off records; the
|
|
857
|
+
* exceptions; and that the reading was made offline. Where any pack holds
|
|
858
|
+
* records withheld by its declaration, their total; where any pack is noted
|
|
859
|
+
* `pack_undeclared`, how many. Those two lines are part of what the headline
|
|
860
|
+
* MEANS, and a surface MUST print them with it.
|
|
861
|
+
*
|
|
862
|
+
* What was not checked on the public record is no longer a clause here. It is
|
|
863
|
+
* the witness line (`renderWitnessLine`), printed with every headline.
|
|
753
864
|
*/
|
|
754
865
|
export declare function renderCaseSummary(reading: CaseReading): string;
|
|
866
|
+
/**
|
|
867
|
+
* The one display title of each of the eight 3 words. A surface prints the
|
|
868
|
+
* title, never the word, and never a title of its own (#173, A18). The wording
|
|
869
|
+
* is Will's to change through the glossary (DL-71); what each MEANS is pinned
|
|
870
|
+
* in the spec.
|
|
871
|
+
*/
|
|
872
|
+
export declare const VERDICT_DISPLAY_TITLES: Readonly<Record<string, string>>;
|
|
873
|
+
/**
|
|
874
|
+
* What a reader may rely on, for each of the six words a case reading reaches
|
|
875
|
+
* (5.5.6 v1.20, A26), the same for every drop. `pending` and `not_found`
|
|
876
|
+
* never head a case reading: they are witness states.
|
|
877
|
+
*/
|
|
878
|
+
export declare const CASE_RELIANCE: Readonly<Record<CaseVerdict, string>>;
|
|
879
|
+
/** The three witness states, and how each is printed (5.5.6, D7). No other. */
|
|
880
|
+
export declare const WITNESS_STATES: {
|
|
881
|
+
readonly confirmed: "Confirmed on the public record";
|
|
882
|
+
readonly not_checked: "Not checked";
|
|
883
|
+
readonly differs: "The public record holds different bytes";
|
|
884
|
+
};
|
|
885
|
+
export type WitnessState = keyof typeof WITNESS_STATES;
|
|
886
|
+
/**
|
|
887
|
+
* The witness line: a lookup of the public record, reported beside the
|
|
888
|
+
* headline and never in it (D7). It never raises or lowers the headline and
|
|
889
|
+
* never changes its title. `reasons` says why a `not_checked` line did not
|
|
890
|
+
* settle, in a fixed order; `services` names each service that answered, as
|
|
891
|
+
* the URL the lookup used: named, never trusted (6).
|
|
892
|
+
*/
|
|
893
|
+
export interface WitnessLine {
|
|
894
|
+
state: WitnessState;
|
|
895
|
+
reasons: string[];
|
|
896
|
+
services: string[];
|
|
897
|
+
}
|
|
898
|
+
/** The line printed where no lookup ran, which is every reading this kernel produces on its own. */
|
|
899
|
+
export declare const WITNESS_NOT_LOOKED_UP: Readonly<WitnessLine>;
|
|
900
|
+
/** The witness line as both kernels print it. */
|
|
901
|
+
export declare function renderWitnessLine(line: WitnessLine): string;
|