@colophon-claims/verify 0.1.0 → 0.2.1
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 +23 -9
- package/dist/admission/contracts.d.ts +483 -0
- package/dist/admission/contracts.js +285 -0
- package/dist/admission/index.d.ts +2 -0
- package/dist/admission/index.js +2 -0
- package/dist/admission/prompted-commitment.d.ts +19 -0
- package/dist/admission/prompted-commitment.js +52 -0
- package/dist/admission/prompted-selection.d.ts +24 -0
- package/dist/admission/prompted-selection.js +85 -0
- package/dist/admission/verification.d.ts +17 -3
- package/dist/admission/verification.js +230 -49
- package/dist/assets.d.ts +21 -1
- package/dist/assets.js +60 -3
- package/dist/binding/beacon-binding.d.ts +230 -0
- package/dist/binding/beacon-binding.js +325 -0
- package/dist/binding/report-face.d.ts +45 -0
- package/dist/binding/report-face.js +153 -0
- package/dist/cli.js +74 -12
- package/dist/index.d.ts +14 -3
- package/dist/index.js +16 -3
- package/dist/manifest.d.ts +30 -4
- package/dist/manifest.js +30 -0
- package/dist/materialize.d.ts +7 -0
- package/dist/materialize.js +7 -0
- package/dist/outcome.d.ts +31 -0
- package/dist/outcome.js +45 -0
- package/dist/profile/binary-qualification.js +6 -0
- package/dist/profile/claim-consistency.d.ts +8 -1
- package/dist/profile/claim-consistency.js +4 -4
- package/dist/profile/claim.d.ts +203 -1
- package/dist/profile/claim.js +192 -43
- package/dist/profile/disclosure.d.ts +273 -0
- package/dist/profile/disclosure.js +240 -0
- package/dist/profile/pinning-evidence.d.ts +1 -1
- package/dist/profile/run-results.d.ts +8 -2
- package/dist/profile/run-results.js +9 -3
- package/dist/profile/task-selection.d.ts +69 -0
- package/dist/profile/task-selection.js +140 -0
- package/dist/reader-instructions.d.ts +38 -1
- package/dist/reader-instructions.js +42 -2
- package/dist/schema.d.ts +13 -2
- package/dist/schema.js +39 -8
- package/dist/signers.d.ts +48 -0
- package/dist/signers.js +77 -0
- package/dist/verify.d.ts +20 -6
- package/dist/verify.js +156 -31
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -14
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task-selection provenance, verified against the records that carry it (issue #2980).
|
|
3
|
+
*
|
|
4
|
+
* The declaration is a closed-vocabulary value sealed into the Run record's
|
|
5
|
+
* `task-selection/v1` extension. Sealing makes it unforgeable after the lock; it does not make it
|
|
6
|
+
* true. What remains for a cold verifier is the part sealing cannot settle: whether the *other*
|
|
7
|
+
* sealed records are consistent with what the declaration asserts.
|
|
8
|
+
*
|
|
9
|
+
* In this record model the *selection is the Benchmark record itself*: the Run seals a Benchmark
|
|
10
|
+
* digest, and `expectedCellSet` is the full cartesian product `items x arms x replicates`, so the
|
|
11
|
+
* Matrix always covers every Benchmark item exactly. Comparing the Matrix's task digests against
|
|
12
|
+
* the Benchmark's items — the first thing this module tried — is therefore dead code. What is left
|
|
13
|
+
* is the Benchmark's own reveal policy and whether anyone declared the set at all.
|
|
14
|
+
*
|
|
15
|
+
* These checks are refusals, not endorsements, and the asymmetry is the point: each one names a
|
|
16
|
+
* declaration the records positively contradict. None of them can establish that a declaration is
|
|
17
|
+
* TRUE, because the bundle carries no independent witness of an upstream set. `assertTaskSelection-
|
|
18
|
+
* Consistency` below says exactly where that boundary falls and why the tempting rule on the other
|
|
19
|
+
* side of it is unsound.
|
|
20
|
+
*/
|
|
21
|
+
import { compareCalendarStrictRfc3339Instants, readTaskSelectionMode, } from "@jinn-network/benchmarking-records";
|
|
22
|
+
import { refuse } from "./errors.js";
|
|
23
|
+
/** The verification path every refusal here is reported under. Adding a new named check would be a
|
|
24
|
+
* bundle-format bump — the claim pins the check list byte-for-byte — so these refusals join the
|
|
25
|
+
* existing `claim-consistency` check, which is exactly the question they answer. */
|
|
26
|
+
const PATH = "claim-consistency";
|
|
27
|
+
/**
|
|
28
|
+
* Whether the Benchmark's items were PROVABLY still withheld when the Run sealed against them.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately one-directional, and the reason is a real trap. The only instant a cold verifier
|
|
31
|
+
* can read out of a sealed Run is `closeAt`, which is the run's CLOSE, not its lock —
|
|
32
|
+
* `closeAt = lockedAt + policy.closeAfterMs` with a strictly positive interval (24h by default),
|
|
33
|
+
* and `lockedAt` lives only in product-local state that no bundle carries. So `notBefore <= closeAt`
|
|
34
|
+
* establishes nothing about the lock: a schedule opening twelve hours into a twenty-four-hour run
|
|
35
|
+
* satisfies it while the items were plainly withheld at the lock. Only the far side is safe —
|
|
36
|
+
* `notBefore >= closeAt > lockedAt` proves withholding — so that is the only comparison made.
|
|
37
|
+
*
|
|
38
|
+
* The comparator is the records package's own, not `Date.parse`, and that is a correctness
|
|
39
|
+
* requirement rather than a preference. These fields are validated by `isCalendarStrictRfc3339`,
|
|
40
|
+
* which accepts leap seconds; V8's `Date.parse` returns `NaN` for exactly those spellings, and
|
|
41
|
+
* `NaN >= x` is `false`. Left on `Date.parse`, a claimant could seal
|
|
42
|
+
* `notBefore: "2026-12-31T23:59:60Z"` — items withheld past the run's end — declare
|
|
43
|
+
* `fixed-public-set`, and have both this check and the producer's pre-lock gate wave it through.
|
|
44
|
+
* An uncomparable pair fails CLOSED for the same reason: it cannot arise from schema-valid records,
|
|
45
|
+
* so treating it as proof of withholding costs nothing and removes the fail-open shape entirely.
|
|
46
|
+
*
|
|
47
|
+
* A `scheduled` reveal with no `notBefore` fails closed on the same principle. The Benchmark schema
|
|
48
|
+
* leaves `notBefore` optional under every policy, so `{ "policy": "scheduled" }` seals cleanly while
|
|
49
|
+
* announcing no instant at which the items become readable — strictly more withheld than
|
|
50
|
+
* `after-run`, which at least names the run's end. Reading it as open would hand a claimant a
|
|
51
|
+
* one-key evasion of the only reveal-policy teeth `fixed-public-set` has: delete the field, and a
|
|
52
|
+
* privately assembled set passes the check that `after-run` fails.
|
|
53
|
+
*/
|
|
54
|
+
function withheldAtLock(benchmark, closeAt) {
|
|
55
|
+
const { policy, notBefore } = benchmark.reveal;
|
|
56
|
+
if (policy === "after-run")
|
|
57
|
+
return true;
|
|
58
|
+
if (policy !== "scheduled")
|
|
59
|
+
return false;
|
|
60
|
+
if (notBefore === undefined)
|
|
61
|
+
return true;
|
|
62
|
+
const order = compareCalendarStrictRfc3339Instants(notBefore, closeAt);
|
|
63
|
+
return order === undefined || order >= 0;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The declared mode, refusing rather than throwing raw on bytes the Run schema would not have
|
|
67
|
+
* sealed. Exported so any reader that resolves the mode does so through this refusal posture
|
|
68
|
+
* rather than re-deriving it with its own error handling. No presentation asset consumes it today
|
|
69
|
+
* -- the report face renders nothing for task selection until issue #3416 -- so its only callers
|
|
70
|
+
* are `taskSelectionContradiction` below and its own tests.
|
|
71
|
+
*/
|
|
72
|
+
export function declaredTaskSelectionMode(runRecord) {
|
|
73
|
+
try {
|
|
74
|
+
return readTaskSelectionMode(runRecord);
|
|
75
|
+
}
|
|
76
|
+
catch (cause) {
|
|
77
|
+
refuse("record-integrity", PATH, `the Run's declared task selection is not one of the recorded selection modes: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The way the sealed records contradict a declared task-selection mode, or `undefined` when they
|
|
82
|
+
* do not. Pure, and shared deliberately: the producer calls it BEFORE the lock so a contradiction
|
|
83
|
+
* is a draft-validation refusal the claimant can still act on, and the cold verifier calls it after
|
|
84
|
+
* the fact through {@link assertTaskSelectionConsistency}. One rule, two postures — a second copy
|
|
85
|
+
* would be free to drift into refusing at publish what it accepted at lock, which is the worst
|
|
86
|
+
* possible place to disagree.
|
|
87
|
+
*
|
|
88
|
+
* Two contradictions, both provable from bundle bytes:
|
|
89
|
+
*
|
|
90
|
+
* 1. **`fixed-public-set` over an undeclared set.** A set nobody declared is not a publicly
|
|
91
|
+
* declared set, so the Benchmark record must at least name an `author`.
|
|
92
|
+
* 2. **Reveal policy that cannot coexist with the mode.** `fixed-public-set` is refused when the
|
|
93
|
+
* items were provably withheld at the lock; `drawn-post-lock` is refused when they were
|
|
94
|
+
* `immediate` — open the moment the record existed, so the Run sealed against a set the
|
|
95
|
+
* claimant could already read, and nothing was drawn afterwards.
|
|
96
|
+
*
|
|
97
|
+
* What this deliberately does NOT do is decide the stronger modes from `benchmark.author` versus
|
|
98
|
+
* `run.owner`. That rule looks decisive and is not: `author` is a self-declaration the design spec
|
|
99
|
+
* marks non-authoritative, and every task-set intake in this product re-authors the Benchmark under
|
|
100
|
+
* the workspace's own key (`intake/workspace-authored.ts`), which is also the Run's owner. Enforcing
|
|
101
|
+
* on it would refuse every bundle this product can produce, making two of the three vocabulary
|
|
102
|
+
* values dead letters.
|
|
103
|
+
*
|
|
104
|
+
* So the honest boundary: these checks catch declarations the records positively contradict, but
|
|
105
|
+
* none can prove a `fixed-public-set` claim TRUE — the bundle carries no independent witness of the
|
|
106
|
+
* upstream set. `PUBLIC-BUNDLE.md` says so in the same words, because a gap a reader can see is
|
|
107
|
+
* worth more than one a rule pretends to close.
|
|
108
|
+
*
|
|
109
|
+
* `claimant-chosen` is unconstrained on purpose. It asserts nothing about anyone but the claimant,
|
|
110
|
+
* so nothing can contradict it, and constraining it would only make the honest answer the
|
|
111
|
+
* expensive one.
|
|
112
|
+
*/
|
|
113
|
+
export function taskSelectionContradiction(input) {
|
|
114
|
+
const { benchmarkRecord, runRecord } = input;
|
|
115
|
+
const declared = declaredTaskSelectionMode(runRecord);
|
|
116
|
+
if (declared === undefined || declared === "claimant-chosen")
|
|
117
|
+
return undefined;
|
|
118
|
+
if (declared === "fixed-public-set") {
|
|
119
|
+
if (benchmarkRecord.author === undefined) {
|
|
120
|
+
return "task selection is declared fixed-public-set but the Benchmark record names no author,"
|
|
121
|
+
+ " so the set it describes was never publicly declared by anyone";
|
|
122
|
+
}
|
|
123
|
+
if (withheldAtLock(benchmarkRecord, runRecord.closeAt)) {
|
|
124
|
+
return "task selection is declared fixed-public-set but the Benchmark's reveal policy withholds"
|
|
125
|
+
+ " its items past the end of the run, so they were not public when the run was locked";
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
if (benchmarkRecord.reveal.policy === "immediate") {
|
|
130
|
+
return "task selection is declared drawn-post-lock but the Benchmark reveals its items"
|
|
131
|
+
+ " immediately, so the run was locked against a set the claimant could already read";
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
/** The cold verifier's posture over {@link taskSelectionContradiction}: a typed record refusal. */
|
|
136
|
+
export function assertTaskSelectionConsistency(input) {
|
|
137
|
+
const contradiction = taskSelectionContradiction(input);
|
|
138
|
+
if (contradiction !== undefined)
|
|
139
|
+
refuse("record-integrity", PATH, contradiction);
|
|
140
|
+
}
|
|
@@ -20,7 +20,36 @@ export declare const PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND: "npx @col
|
|
|
20
20
|
* `EVIDENCE_NATIVE_BUNDLE_V5_CHECKS`.
|
|
21
21
|
*/
|
|
22
22
|
export declare const PUBLIC_BUNDLE_V6_CHECKS: readonly ["manifest", "evidence-closure", "trust", "matrix-rederivation", "report-verification", "claim-consistency", "integrity-anchors"];
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* The anchored binary-qualification closure runs exactly the anchored list (issue #3205): the
|
|
25
|
+
* qualification projection changes what `evidence-closure` and `claim-consistency` examine, not
|
|
26
|
+
* which checks run.
|
|
27
|
+
*/
|
|
28
|
+
export declare const PUBLIC_BUNDLE_V7_CHECKS: readonly ["manifest", "evidence-closure", "trust", "matrix-rederivation", "report-verification", "claim-consistency", "integrity-anchors"];
|
|
29
|
+
/**
|
|
30
|
+
* Unlike every earlier closure, this one does NOT stamp the first public 0.1 line: no released
|
|
31
|
+
* verifier before 0.2.1 understands `benchmark-product-public-bundle/7`, and a claim naming a
|
|
32
|
+
* reader that cannot read it would be an instruction to fail. 0.2.1 is also the line that carries
|
|
33
|
+
* the prompted-screening admission surface a binary claim may need.
|
|
34
|
+
*/
|
|
35
|
+
export declare const PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
36
|
+
export declare const PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
37
|
+
/**
|
|
38
|
+
* The disclosed closure's check list (disclosure-specification-record design §7, issue #2839): v7's
|
|
39
|
+
* seven plus `disclosure-specification`, **last**. It runs after `claim-consistency` because the
|
|
40
|
+
* claim's `disclosure` section is among the things it compares, and it is **always present** on this
|
|
41
|
+
* format — a disclosed bundle whose record was stripped is a closure failure, not a shorter list.
|
|
42
|
+
*/
|
|
43
|
+
export declare const PUBLIC_BUNDLE_V8_CHECKS: readonly ["manifest", "evidence-closure", "trust", "matrix-rederivation", "report-verification", "claim-consistency", "integrity-anchors", "disclosure-specification"];
|
|
44
|
+
/**
|
|
45
|
+
* Like v7 and for the same reason: no released reader before 0.2.1 understands
|
|
46
|
+
* `benchmark-product-public-bundle/8`, and a claim naming a reader that cannot read it would be an
|
|
47
|
+
* instruction to fail. The disclosed closure ships in the same unpublished 0.2.1 line as v7, so it
|
|
48
|
+
* pins that line rather than minting a third.
|
|
49
|
+
*/
|
|
50
|
+
export declare const PUBLIC_BUNDLE_V8_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
51
|
+
export declare const PUBLIC_BUNDLE_V8_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
52
|
+
/** Every format through v6 stamps the same first public 0.1 line; v7 is the first that cannot. */
|
|
24
53
|
export declare const PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS: {
|
|
25
54
|
readonly "benchmark-product-public-bundle/2": {
|
|
26
55
|
readonly command: "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
|
|
@@ -38,4 +67,12 @@ export declare const PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS: {
|
|
|
38
67
|
readonly command: "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
|
|
39
68
|
readonly compatibleCommand: "npx @colophon-claims/verify@0.1 <bundle-dir>";
|
|
40
69
|
};
|
|
70
|
+
readonly "benchmark-product-public-bundle/7": {
|
|
71
|
+
readonly command: "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
72
|
+
readonly compatibleCommand: "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
73
|
+
};
|
|
74
|
+
readonly "benchmark-product-public-bundle/8": {
|
|
75
|
+
readonly command: "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
76
|
+
readonly compatibleCommand: "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
77
|
+
};
|
|
41
78
|
};
|
|
@@ -30,7 +30,39 @@ export const PUBLIC_BUNDLE_V6_CHECKS = [
|
|
|
30
30
|
...PUBLIC_BUNDLE_VERIFICATION_CHECKS,
|
|
31
31
|
"integrity-anchors",
|
|
32
32
|
];
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* The anchored binary-qualification closure runs exactly the anchored list (issue #3205): the
|
|
35
|
+
* qualification projection changes what `evidence-closure` and `claim-consistency` examine, not
|
|
36
|
+
* which checks run.
|
|
37
|
+
*/
|
|
38
|
+
export const PUBLIC_BUNDLE_V7_CHECKS = PUBLIC_BUNDLE_V6_CHECKS;
|
|
39
|
+
/**
|
|
40
|
+
* Unlike every earlier closure, this one does NOT stamp the first public 0.1 line: no released
|
|
41
|
+
* verifier before 0.2.1 understands `benchmark-product-public-bundle/7`, and a claim naming a
|
|
42
|
+
* reader that cannot read it would be an instruction to fail. 0.2.1 is also the line that carries
|
|
43
|
+
* the prompted-screening admission surface a binary claim may need.
|
|
44
|
+
*/
|
|
45
|
+
export const PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
46
|
+
export const PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
47
|
+
/**
|
|
48
|
+
* The disclosed closure's check list (disclosure-specification-record design §7, issue #2839): v7's
|
|
49
|
+
* seven plus `disclosure-specification`, **last**. It runs after `claim-consistency` because the
|
|
50
|
+
* claim's `disclosure` section is among the things it compares, and it is **always present** on this
|
|
51
|
+
* format — a disclosed bundle whose record was stripped is a closure failure, not a shorter list.
|
|
52
|
+
*/
|
|
53
|
+
export const PUBLIC_BUNDLE_V8_CHECKS = [
|
|
54
|
+
...PUBLIC_BUNDLE_V7_CHECKS,
|
|
55
|
+
"disclosure-specification",
|
|
56
|
+
];
|
|
57
|
+
/**
|
|
58
|
+
* Like v7 and for the same reason: no released reader before 0.2.1 understands
|
|
59
|
+
* `benchmark-product-public-bundle/8`, and a claim naming a reader that cannot read it would be an
|
|
60
|
+
* instruction to fail. The disclosed closure ships in the same unpublished 0.2.1 line as v7, so it
|
|
61
|
+
* pins that line rather than minting a third.
|
|
62
|
+
*/
|
|
63
|
+
export const PUBLIC_BUNDLE_V8_VERIFICATION_COMMAND = PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND;
|
|
64
|
+
export const PUBLIC_BUNDLE_V8_COMPATIBLE_VERIFICATION_COMMAND = PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND;
|
|
65
|
+
/** Every format through v6 stamps the same first public 0.1 line; v7 is the first that cannot. */
|
|
34
66
|
export const PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS = {
|
|
35
67
|
[BUNDLE_FORMAT]: {
|
|
36
68
|
command: PUBLIC_BUNDLE_VERIFICATION_COMMAND,
|
|
@@ -48,5 +80,13 @@ export const PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS = {
|
|
|
48
80
|
command: PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND,
|
|
49
81
|
compatibleCommand: PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND,
|
|
50
82
|
},
|
|
83
|
+
[BUNDLE_V7_FORMAT]: {
|
|
84
|
+
command: PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND,
|
|
85
|
+
compatibleCommand: PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND,
|
|
86
|
+
},
|
|
87
|
+
[BUNDLE_V8_FORMAT]: {
|
|
88
|
+
command: PUBLIC_BUNDLE_V8_VERIFICATION_COMMAND,
|
|
89
|
+
compatibleCommand: PUBLIC_BUNDLE_V8_COMPATIBLE_VERIFICATION_COMMAND,
|
|
90
|
+
},
|
|
51
91
|
};
|
|
52
|
-
import { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT } from "./manifest.js";
|
|
92
|
+
import { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, BUNDLE_V7_FORMAT, BUNDLE_V8_FORMAT, } from "./manifest.js";
|
package/dist/schema.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ export declare const BUNDLE_ASSEMBLY_FORMAT: "benchmark-product-assembly/2";
|
|
|
6
6
|
export declare const BUNDLE_V4_TRUST_FORMAT: "benchmark-product-public-trust/4";
|
|
7
7
|
export declare const BUNDLE_V4_EVIDENCE_FORMAT: "benchmark-product-evidence-catalog/4";
|
|
8
8
|
export declare const BUNDLE_QUALIFICATION_FORMAT: "benchmark-product-binary-qualification/1";
|
|
9
|
-
export declare const BUNDLE_V4_EVIDENCE_ROLES: readonly ["task", "runtime-selection", "evaluation-spec", "admission-receipt", "solve-submission", "run-pinning-evidence", "evaluation-submission", "solve-delivery", "solve-output", "evaluation-task", "evaluation-delivery", "verdict", "item-bank", "source-manifest", "admission-index", "admission-manifest", "replacement-ledger", "source-item", "judge-instrument", "analysis-context", "label-resolution", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "snapshot-probe", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs"];
|
|
9
|
+
export declare const BUNDLE_V4_EVIDENCE_ROLES: readonly ["task", "runtime-selection", "evaluation-spec", "admission-receipt", "solve-submission", "run-pinning-evidence", "evaluation-submission", "solve-delivery", "solve-output", "evaluation-task", "evaluation-delivery", "verdict", "item-bank", "source-manifest", "admission-index", "admission-manifest", "replacement-ledger", "source-item", "judge-instrument", "analysis-context", "label-resolution", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "snapshot-probe", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs", "screening-prompt", "screening-procedure", "screening-pool", "screening-sample-commitment", "screening-transcript", "disclosure-specification"];
|
|
10
10
|
export type BundleV4EvidenceRole = (typeof BUNDLE_V4_EVIDENCE_ROLES)[number];
|
|
11
|
-
export declare const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs"];
|
|
11
|
+
export declare const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs", "screening-prompt", "screening-procedure", "screening-pool", "screening-sample-commitment", "screening-transcript"];
|
|
12
12
|
export declare const BundleTrustSchema: z.ZodObject<{
|
|
13
13
|
format: z.ZodLiteral<"benchmark-product-public-trust/2">;
|
|
14
14
|
selfRun: z.ZodObject<{
|
|
@@ -100,6 +100,7 @@ export declare const BundleV4EvidenceCatalogSchema: z.ZodObject<{
|
|
|
100
100
|
records: z.ZodArray<z.ZodObject<{
|
|
101
101
|
sha256: z.ZodString;
|
|
102
102
|
roles: z.ZodArray<z.ZodEnum<{
|
|
103
|
+
"disclosure-specification": "disclosure-specification";
|
|
103
104
|
task: "task";
|
|
104
105
|
"runtime-selection": "runtime-selection";
|
|
105
106
|
"evaluation-spec": "evaluation-spec";
|
|
@@ -136,6 +137,11 @@ export declare const BundleV4EvidenceCatalogSchema: z.ZodObject<{
|
|
|
136
137
|
"screening-instrument": "screening-instrument";
|
|
137
138
|
"screening-sampling-script": "screening-sampling-script";
|
|
138
139
|
"screening-raw-outputs": "screening-raw-outputs";
|
|
140
|
+
"screening-prompt": "screening-prompt";
|
|
141
|
+
"screening-procedure": "screening-procedure";
|
|
142
|
+
"screening-pool": "screening-pool";
|
|
143
|
+
"screening-sample-commitment": "screening-sample-commitment";
|
|
144
|
+
"screening-transcript": "screening-transcript";
|
|
139
145
|
}>>;
|
|
140
146
|
}, z.core.$strict>>;
|
|
141
147
|
}, z.core.$strict>;
|
|
@@ -197,6 +203,11 @@ export declare const BundleQualificationSchema: z.ZodObject<{
|
|
|
197
203
|
"screening-instrument": "screening-instrument";
|
|
198
204
|
"screening-sampling-script": "screening-sampling-script";
|
|
199
205
|
"screening-raw-outputs": "screening-raw-outputs";
|
|
206
|
+
"screening-prompt": "screening-prompt";
|
|
207
|
+
"screening-procedure": "screening-procedure";
|
|
208
|
+
"screening-pool": "screening-pool";
|
|
209
|
+
"screening-sample-commitment": "screening-sample-commitment";
|
|
210
|
+
"screening-transcript": "screening-transcript";
|
|
200
211
|
}>>;
|
|
201
212
|
}, z.core.$strict>>;
|
|
202
213
|
reachableSha256s: z.ZodArray<z.ZodString>;
|
package/dist/schema.js
CHANGED
|
@@ -52,6 +52,22 @@ export const BUNDLE_V4_EVIDENCE_ROLES = [
|
|
|
52
52
|
"screening-instrument",
|
|
53
53
|
"screening-sampling-script",
|
|
54
54
|
"screening-raw-outputs",
|
|
55
|
+
"screening-prompt",
|
|
56
|
+
"screening-procedure",
|
|
57
|
+
"screening-pool",
|
|
58
|
+
"screening-sample-commitment",
|
|
59
|
+
"screening-transcript",
|
|
60
|
+
// Appended at the very end (disclosure-specification-record design §6.2, issue #2839). Appending
|
|
61
|
+
// is the ONLY additive move available here: this array's index order is the frozen role-ordering
|
|
62
|
+
// map used by both the catalog schema's ordering refinement and the bundle writer, so inserting
|
|
63
|
+
// anywhere earlier would re-order existing bundles' role arrays and move their bytes. The /2
|
|
64
|
+
// catalog is a SEPARATE constant (`BUNDLE_EVIDENCE_ROLES` below) and is untouched by this append.
|
|
65
|
+
//
|
|
66
|
+
// The token is admitted on every v4-graph closure, because the enum is one shared constant and
|
|
67
|
+
// there is no per-closure role vocabulary. What keeps a disclosure record off an earlier closure
|
|
68
|
+
// is that nothing DERIVES the role there: off `/8` the Report extension is never read, so the
|
|
69
|
+
// evidence closure's own size and per-digest guards refuse the record as unreachable (§6.5.2).
|
|
70
|
+
"disclosure-specification",
|
|
55
71
|
];
|
|
56
72
|
export const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES = [
|
|
57
73
|
"admission-manifest", "replacement-ledger", "source-item", "label-resolution",
|
|
@@ -68,6 +84,11 @@ export const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES = [
|
|
|
68
84
|
"screening-instrument",
|
|
69
85
|
"screening-sampling-script",
|
|
70
86
|
"screening-raw-outputs",
|
|
87
|
+
"screening-prompt",
|
|
88
|
+
"screening-procedure",
|
|
89
|
+
"screening-pool",
|
|
90
|
+
"screening-sample-commitment",
|
|
91
|
+
"screening-transcript",
|
|
71
92
|
];
|
|
72
93
|
const PublicKeySchema = z.object({
|
|
73
94
|
keyId: z.string().min(1),
|
|
@@ -205,6 +226,12 @@ const PrefixedSha256Schema = z.string().regex(/^sha256:[a-f0-9]{64}$/u);
|
|
|
205
226
|
const IDENTIFIER_NAME = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/u;
|
|
206
227
|
export const BundleQualificationSchema = z.strictObject({
|
|
207
228
|
format: z.literal(BUNDLE_QUALIFICATION_FORMAT),
|
|
229
|
+
// Deliberately NOT widened when a later closure allocates a new claim id (issue #3205's
|
|
230
|
+
// claim-package/5; the same resolution the disclosure-record design reached in its §6.5.1).
|
|
231
|
+
// This field names WHICH CLAIM PROJECTION SHAPE the qualification graph was built for, and the
|
|
232
|
+
// anchors section changes nothing about that graph: the qualification projection under /5 is
|
|
233
|
+
// byte-identical to the one under /2. Widening the literal would make this schema co-vary with
|
|
234
|
+
// an unrelated section, and would need widening again for every future closure.
|
|
208
235
|
claimSchema: z.literal("benchmark-product.claim-package/2"),
|
|
209
236
|
sourceManifestSha256: PrefixedSha256Schema,
|
|
210
237
|
admissionManifestSha256: PrefixedSha256Schema,
|
|
@@ -317,12 +344,11 @@ export const BundleQualificationSchema = z.strictObject({
|
|
|
317
344
|
"human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster",
|
|
318
345
|
"review-visibility-receipt", "review-reveal-receipt",
|
|
319
346
|
];
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
"screening-
|
|
324
|
-
"screening-
|
|
325
|
-
"screening-raw-outputs",
|
|
347
|
+
const commonScreeningEvidenceRoles = ["screening-table", "screening-reveal-receipt", "screening-sampling-script"];
|
|
348
|
+
const legacyScreeningEvidenceRoles = ["screening-instrument", "screening-raw-outputs"];
|
|
349
|
+
const promptedScreeningEvidenceRoles = [
|
|
350
|
+
"screening-prompt", "screening-procedure", "screening-pool",
|
|
351
|
+
"screening-sample-commitment", "screening-transcript",
|
|
326
352
|
];
|
|
327
353
|
if (qualification.truthAdmission === "two-human-unanimous") {
|
|
328
354
|
if (humanEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) === 0)
|
|
@@ -340,10 +366,15 @@ export const BundleQualificationSchema = z.strictObject({
|
|
|
340
366
|
// silently inheriting the screened one's evidence rules.
|
|
341
367
|
}
|
|
342
368
|
else if (qualification.truthAdmission === "screened-operator-sampled") {
|
|
343
|
-
|
|
369
|
+
const legacyRoleSet = legacyScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 1)
|
|
370
|
+
&& promptedScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 0);
|
|
371
|
+
const promptedRoleSet = promptedScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 1)
|
|
372
|
+
&& legacyScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 0);
|
|
373
|
+
if (commonScreeningEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) !== 1)
|
|
374
|
+
|| (!legacyRoleSet && !promptedRoleSet)
|
|
344
375
|
|| humanEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) !== 0)
|
|
345
376
|
|| (roleCounts.get("operator-assertion") ?? 0) !== 0) {
|
|
346
|
-
ctx.addIssue({ code: "custom", path: ["admissionRecords"], message: "screened admission must carry exactly one
|
|
377
|
+
ctx.addIssue({ code: "custom", path: ["admissionRecords"], message: "screened admission must carry exactly one complete legacy-v1 or prompted-v2 screening record set and no human-review evidence or operator assertion" });
|
|
347
378
|
}
|
|
348
379
|
const screeningInstrument = qualification.admissionRecords.find((entry) => (entry.roles.includes("screening-instrument")));
|
|
349
380
|
if (screeningInstrument !== undefined
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { BundleTrust, BundleV4Trust } from "./schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Who signed, in reader terms. The bundle's own identifiers select signatures and join records,
|
|
4
|
+
* so they stay exact on the machine surface; the human surface is given the role instead
|
|
5
|
+
* (issue #3024).
|
|
6
|
+
*/
|
|
7
|
+
export type PublicBundleSignerRole = "publisher" | "automated-grader" | "human-reviewer" | "label-admission";
|
|
8
|
+
export interface PublicBundleSigner {
|
|
9
|
+
readonly role: PublicBundleSignerRole;
|
|
10
|
+
/** The load-bearing signer identity, verbatim. Machine surface only. */
|
|
11
|
+
readonly identity: string;
|
|
12
|
+
/** The exact key the signature selection resolved to. Machine surface only. */
|
|
13
|
+
readonly keyId: string;
|
|
14
|
+
/**
|
|
15
|
+
* `same-operator` where the bundle itself declares that the key is workspace-minted under the
|
|
16
|
+
* publisher's own custody; `undeclared` where it makes no custody statement. Never a claim that
|
|
17
|
+
* a signer is an independent party -- no bundle format can establish that.
|
|
18
|
+
*/
|
|
19
|
+
readonly custody: "same-operator" | "undeclared";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Signers of a v2/v4/v6/v7 bundle, read from its already-authenticated `trust/public-keys.json`
|
|
23
|
+
* and the Matrix verdict closure the `trust` check validated it against.
|
|
24
|
+
*
|
|
25
|
+
* Every group this returns is ground-truthed rather than merely declared: `trust.evaluators` is
|
|
26
|
+
* pinned to exactly the union of the Matrix-referenced evaluators and the admission reviewers, and
|
|
27
|
+
* each reviewer binding to the authenticated signed review closure. That union is why the two roles
|
|
28
|
+
* are read from the two sets separately -- an identity that both graded cells and signed reviews is
|
|
29
|
+
* in both, and classifying reviewer-first would print one fewer grader than actually graded. Both
|
|
30
|
+
* trust grammars pin `selfRun.custody: "workspace-minted"` and `partyIndependence:
|
|
31
|
+
* "not-established"`, so same-operator custody is a fact of the parsed record, not an inference.
|
|
32
|
+
*
|
|
33
|
+
* Admission authorities are deliberately absent: the v4 grammar pins every authority keyId to the
|
|
34
|
+
* report key, so listing them would count the publisher's one key twice under two headings.
|
|
35
|
+
*/
|
|
36
|
+
export declare function legacyBundleSigners(trust: BundleTrust | BundleV4Trust, verdictEvaluators: ReadonlySet<string>): readonly PublicBundleSigner[];
|
|
37
|
+
/**
|
|
38
|
+
* Signers of a v5 evidence-native bundle, read from the same authenticated `claim-package.json`
|
|
39
|
+
* bytes the closure verified.
|
|
40
|
+
*
|
|
41
|
+
* `claim.trust.signers` is a publisher-written declaration used by the closure only as a lookup
|
|
42
|
+
* table: a surplus entry there is never contradicted, because no signature ever selects it. So this
|
|
43
|
+
* keeps only the keys that actually carried a signature the closure accepted
|
|
44
|
+
* (`verifiedSignerKeyIds`). Without that filter a bundle could declare a human reviewer, or a dozen
|
|
45
|
+
* graders, that signed nothing and have the checker print them as fact. The claim package declares
|
|
46
|
+
* no custody, so nothing here upgrades a signer to same-operator either.
|
|
47
|
+
*/
|
|
48
|
+
export declare function evidenceNativeBundleSigners(claimPackageBytes: Uint8Array, verifiedSignerKeyIds: readonly string[]): readonly PublicBundleSigner[];
|
package/dist/signers.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { parseEvidenceNativeClaimPackageV3 } from "@jinn-network/benchmarking-protocol";
|
|
2
|
+
function deduplicate(signers) {
|
|
3
|
+
const seen = new Set();
|
|
4
|
+
return signers.filter((signer) => {
|
|
5
|
+
const key = `${signer.role} ${signer.keyId}`;
|
|
6
|
+
if (seen.has(key))
|
|
7
|
+
return false;
|
|
8
|
+
seen.add(key);
|
|
9
|
+
return true;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Signers of a v2/v4/v6/v7 bundle, read from its already-authenticated `trust/public-keys.json`
|
|
14
|
+
* and the Matrix verdict closure the `trust` check validated it against.
|
|
15
|
+
*
|
|
16
|
+
* Every group this returns is ground-truthed rather than merely declared: `trust.evaluators` is
|
|
17
|
+
* pinned to exactly the union of the Matrix-referenced evaluators and the admission reviewers, and
|
|
18
|
+
* each reviewer binding to the authenticated signed review closure. That union is why the two roles
|
|
19
|
+
* are read from the two sets separately -- an identity that both graded cells and signed reviews is
|
|
20
|
+
* in both, and classifying reviewer-first would print one fewer grader than actually graded. Both
|
|
21
|
+
* trust grammars pin `selfRun.custody: "workspace-minted"` and `partyIndependence:
|
|
22
|
+
* "not-established"`, so same-operator custody is a fact of the parsed record, not an inference.
|
|
23
|
+
*
|
|
24
|
+
* Admission authorities are deliberately absent: the v4 grammar pins every authority keyId to the
|
|
25
|
+
* report key, so listing them would count the publisher's one key twice under two headings.
|
|
26
|
+
*/
|
|
27
|
+
export function legacyBundleSigners(trust, verdictEvaluators) {
|
|
28
|
+
const reviewers = new Set("admission" in trust ? trust.admission.reviewers.map((entry) => entry.evaluator) : []);
|
|
29
|
+
return deduplicate([
|
|
30
|
+
{ role: "publisher", identity: trust.report.author, keyId: trust.report.keyId, custody: "same-operator" },
|
|
31
|
+
...trust.evaluators.flatMap((entry) => {
|
|
32
|
+
const roles = [];
|
|
33
|
+
// The trust set equals verdicts + reviewers, so "in neither" is unreachable; if a future
|
|
34
|
+
// widening makes it reachable, a signer must still be shown rather than silently dropped.
|
|
35
|
+
if (verdictEvaluators.has(entry.evaluator) || !reviewers.has(entry.evaluator))
|
|
36
|
+
roles.push("automated-grader");
|
|
37
|
+
if (reviewers.has(entry.evaluator))
|
|
38
|
+
roles.push("human-reviewer");
|
|
39
|
+
return roles.map((role) => ({
|
|
40
|
+
role,
|
|
41
|
+
identity: entry.evaluator,
|
|
42
|
+
keyId: entry.keyId,
|
|
43
|
+
custody: "same-operator",
|
|
44
|
+
}));
|
|
45
|
+
}),
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
// Keyed to the purpose union rather than to `string`, so a protocol widening is a build failure
|
|
49
|
+
// here instead of an `undefined` role reaching the reader's screen.
|
|
50
|
+
const EVIDENCE_NATIVE_PURPOSE_ROLES = {
|
|
51
|
+
report: "publisher",
|
|
52
|
+
"automated-evaluator": "automated-grader",
|
|
53
|
+
"human-reviewer": "human-reviewer",
|
|
54
|
+
"label-admission": "label-admission",
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Signers of a v5 evidence-native bundle, read from the same authenticated `claim-package.json`
|
|
58
|
+
* bytes the closure verified.
|
|
59
|
+
*
|
|
60
|
+
* `claim.trust.signers` is a publisher-written declaration used by the closure only as a lookup
|
|
61
|
+
* table: a surplus entry there is never contradicted, because no signature ever selects it. So this
|
|
62
|
+
* keeps only the keys that actually carried a signature the closure accepted
|
|
63
|
+
* (`verifiedSignerKeyIds`). Without that filter a bundle could declare a human reviewer, or a dozen
|
|
64
|
+
* graders, that signed nothing and have the checker print them as fact. The claim package declares
|
|
65
|
+
* no custody, so nothing here upgrades a signer to same-operator either.
|
|
66
|
+
*/
|
|
67
|
+
export function evidenceNativeBundleSigners(claimPackageBytes, verifiedSignerKeyIds) {
|
|
68
|
+
const verified = new Set(verifiedSignerKeyIds);
|
|
69
|
+
return deduplicate(parseEvidenceNativeClaimPackageV3(claimPackageBytes).trust.signers
|
|
70
|
+
.filter((signer) => verified.has(signer.keyId))
|
|
71
|
+
.map((signer) => ({
|
|
72
|
+
role: EVIDENCE_NATIVE_PURPOSE_ROLES[signer.purpose],
|
|
73
|
+
identity: signer.identity,
|
|
74
|
+
keyId: signer.keyId,
|
|
75
|
+
custody: "undeclared",
|
|
76
|
+
})));
|
|
77
|
+
}
|
package/dist/verify.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { type EvidenceNativePortableBundleVerification } from "@jinn-network/benchmarking-evidence";
|
|
2
|
+
import { type PublicBundleSigner } from "./signers.js";
|
|
2
3
|
import { type InspectRuntimeMethodDisclosure } from "./profile/inspect-disclosure.js";
|
|
3
4
|
import { type PublicComparisonView } from "./comparison.js";
|
|
4
5
|
import { type VerifiedBundleSnapshot, type VerifyBundleSnapshotDeps } from "./manifest.js";
|
|
6
|
+
import { type DisclosureSpecificationReport } from "./profile/disclosure.js";
|
|
5
7
|
import { type IntegrityAnchorsReport, type PublicBundleAnchorTrustMaterial } from "./anchor/check.js";
|
|
6
8
|
import { type BinaryItemBankEntry, type BinarySourceManifestEntry } from "./admission/intake.js";
|
|
7
9
|
export type PublicBundleVerificationCheck = "manifest" | "evidence-closure" | "trust" | "matrix-rederivation" | "report-verification" | "claim-consistency"
|
|
8
|
-
/** Always present for `benchmark-product-public-bundle/6`,
|
|
9
|
-
* (anchor-evidence design §8, §12). */
|
|
10
|
-
| "integrity-anchors"
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
/** Always present for the anchored closures, `benchmark-product-public-bundle/6`, `/7`, and `/8`,
|
|
11
|
+
* never for any earlier one (anchor-evidence design §8, §12). */
|
|
12
|
+
| "integrity-anchors"
|
|
13
|
+
/** Always present for `benchmark-product-public-bundle/8`, never for any earlier closure
|
|
14
|
+
* (disclosure-specification-record design §7, issue #2839). Runs last: the claim's `disclosure`
|
|
15
|
+
* section is among the things it depends on having already been byte-compared. */
|
|
16
|
+
| "disclosure-specification";
|
|
17
|
+
export interface LegacyPublicBundleVerificationResult extends PublicBundleSignerDisclosure {
|
|
18
|
+
readonly format: "benchmark-product-public-bundle/2" | "benchmark-product-public-bundle/4" | "benchmark-product-public-bundle/6" | "benchmark-product-public-bundle/7" | "benchmark-product-public-bundle/8";
|
|
13
19
|
readonly identity: string;
|
|
14
20
|
readonly checks: readonly PublicBundleVerificationCheck[];
|
|
15
21
|
readonly benchmarkSha256: string;
|
|
@@ -22,6 +28,10 @@ export interface LegacyPublicBundleVerificationResult {
|
|
|
22
28
|
* subject's context outcome (anchor-evidence design §8). Statuses are disclosed facts, not a
|
|
23
29
|
* summary — nothing here is folded into a single verified badge. */
|
|
24
30
|
readonly anchors?: IntegrityAnchorsReport;
|
|
31
|
+
/** Present exactly for the disclosed closure (issue #2839, design §7 step 11): the sealed record's
|
|
32
|
+
* identity and all six variables' statuses. Statuses are DISCLOSED FACTS, never folded into a
|
|
33
|
+
* single badge and never counted — the same posture `anchors` takes, and for the same reason. */
|
|
34
|
+
readonly disclosure?: DisclosureSpecificationReport;
|
|
25
35
|
readonly qualification?: {
|
|
26
36
|
readonly publicationGrade: boolean;
|
|
27
37
|
readonly truthAdmission: "two-human-unanimous" | "operator-only" | "screened-operator-sampled";
|
|
@@ -32,7 +42,11 @@ export interface LegacyPublicBundleVerificationResult {
|
|
|
32
42
|
readonly exclusionCount: number;
|
|
33
43
|
};
|
|
34
44
|
}
|
|
35
|
-
|
|
45
|
+
/** Who signed the bundle, with the identifiers the human surface deliberately does not print. */
|
|
46
|
+
export interface PublicBundleSignerDisclosure {
|
|
47
|
+
readonly signers?: readonly PublicBundleSigner[];
|
|
48
|
+
}
|
|
49
|
+
export type PublicBundleVerificationResult = LegacyPublicBundleVerificationResult | (EvidenceNativePortableBundleVerification & PublicBundleSignerDisclosure);
|
|
36
50
|
export interface VerifyPublicBundleDeps extends VerifyBundleSnapshotDeps {
|
|
37
51
|
/**
|
|
38
52
|
* Trust material for the `integrity-anchors` check (anchor-evidence design §8 step 3): timestamp
|