@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,153 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* The report face for `beacon-binding/1` (issue #2976, acceptance criteria 3 and 4): which binding
|
|
4
|
+
* applied, in plain words, and what it does and does not establish.
|
|
5
|
+
*
|
|
6
|
+
* Two rules carried over from `../profile/anchor-claims.ts`, whose conditional honesty copy this
|
|
7
|
+
* mirrors:
|
|
8
|
+
*
|
|
9
|
+
* - **Single-sourced, never mirrored.** `@colophon-claims/core` already depends on this package, so
|
|
10
|
+
* producer and reader render the same function rather than two copies that can drift.
|
|
11
|
+
* - **The words key on facts, not on configuration.** Every value in a sentence below comes from
|
|
12
|
+
* the verified binding itself, so the text is identical for every reader.
|
|
13
|
+
*
|
|
14
|
+
* A third rule follows from issue #3322: **a sentence claims unchosen-ness only where the seal
|
|
15
|
+
* established it.** A beacon that merely postdates the seal makes the value unpredictable and
|
|
16
|
+
* leaves the operator choosing among the values that postdate it. So both sentences carry
|
|
17
|
+
* `roundChoiceClause`, which asserts the second property under `seal-derived` and retracts it under
|
|
18
|
+
* `operator-chosen` rather than letting either branch imply it.
|
|
19
|
+
*
|
|
20
|
+
* A fourth rule is this module's own, and is the whole point of the originating issue: **the census
|
|
21
|
+
* sentence says it is the weaker binding.** Ordering-only binding shows the run's order was fixed by
|
|
22
|
+
* randomness that postdates the seal; it does not show the population was, because with a census
|
|
23
|
+
* there was no population choice to make. Letting the two modes share one confident sentence would
|
|
24
|
+
* be the failure this feature exists to prevent. Issue #3425 subjects that sentence to the third
|
|
25
|
+
* rule as well: `censusOrderClause` asserts the postdating only under `proven-offline`, and concedes
|
|
26
|
+
* it under `attributive` in the register the sampled opening already uses, because the clauses on
|
|
27
|
+
* either side of it concede exactly that.
|
|
28
|
+
*/
|
|
29
|
+
import { BEACON_BINDING_PROCEDURE, BEACON_SOURCES, } from "./beacon-binding.js";
|
|
30
|
+
export function runBindingClass(binding) {
|
|
31
|
+
if (binding === undefined)
|
|
32
|
+
return "none";
|
|
33
|
+
return binding.mode === "sampled" ? "beacon-drawn-slate" : "beacon-ordering-only";
|
|
34
|
+
}
|
|
35
|
+
/** `<source display name> round <n>`, the one rendering every sentence below uses. */
|
|
36
|
+
function beaconName(binding) {
|
|
37
|
+
return `${BEACON_SOURCES[binding.beacon.source].displayName} round ${binding.beacon.round}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* How the sentence may talk about the beacon postdating the seal. `proven-offline` asserts,
|
|
41
|
+
* because the source's own published schedule turns the round number into a time by arithmetic.
|
|
42
|
+
* `attributive` reports what the chain asserts and names what checking it takes -- the same
|
|
43
|
+
* assertive/attributive split `anchoredPreRegistrationSentence` draws between a timestamp token
|
|
44
|
+
* and an OpenTimestamps commitment.
|
|
45
|
+
*/
|
|
46
|
+
function postSealClause(binding) {
|
|
47
|
+
return binding.postSeal === "proven-offline"
|
|
48
|
+
? `a value that did not exist until ${binding.beaconInstant}, after this run was sealed at ${binding.sealedAt}`
|
|
49
|
+
: `a value the chain places after this run's seal at ${binding.sealedAt} — establishing that ordering `
|
|
50
|
+
+ "requires block headers on the reader's side, so it is what the chain asserts rather than something "
|
|
51
|
+
+ "this bundle proves";
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What the run's choice of ROUND does or does not add (issue #3322). A beacon that merely postdates
|
|
55
|
+
* the seal leaves the operator picking among realized values, and a sentence that names only the
|
|
56
|
+
* value's unpredictability reads as though it had ruled that out. So the clause is not decoration:
|
|
57
|
+
* under `seal-derived` it states the second property and then names the residue that survives it
|
|
58
|
+
* (the source choice), and under `operator-chosen` it retracts the property in the same plain
|
|
59
|
+
* register the census branch uses about its own weaker binding.
|
|
60
|
+
*/
|
|
61
|
+
function roundChoiceClause(binding) {
|
|
62
|
+
// Name the thing a chosen round would actually have moved. Saying "the result" for both modes
|
|
63
|
+
// made the census clause read as a retraction of a population claim a census never makes: with a
|
|
64
|
+
// census the population is the whole declared one whatever round applies, and only the ORDER
|
|
65
|
+
// moves. The residue named under `seal-derived` is likewise the SOURCE, not a count of sources:
|
|
66
|
+
// one admitted source is indexed by block height, where no round follows from a seal at all, so
|
|
67
|
+
// its alternatives are every height published since rather than a single candidate.
|
|
68
|
+
const derived = binding.mode === "sampled" ? "slate" : "order";
|
|
69
|
+
if (binding.roundBasis === "seal-derived") {
|
|
70
|
+
// Only a scheduled source reaches here: `requiredBeaconRound` derives nothing for a height, so
|
|
71
|
+
// an `attributive` binding is `operator-chosen` by construction.
|
|
72
|
+
return "The round was not the operator's to pick either: it is the first round this source publishes after "
|
|
73
|
+
+ "the seal, so the seal instant alone fixes it. What choosing remains is the source — this procedure "
|
|
74
|
+
+ "admits other beacons, one of them indexed by block height, where no round follows from a seal at all — "
|
|
75
|
+
+ "so an operator could have bound a different source instead.";
|
|
76
|
+
}
|
|
77
|
+
if (binding.postSeal === "attributive") {
|
|
78
|
+
// Say no more here than the postdating clause two sentences earlier already conceded. Claiming
|
|
79
|
+
// the value was unpredictable would assert exactly what this branch cannot check: nothing in
|
|
80
|
+
// the bundle places this height after the seal, so nothing rules out a height that predates it.
|
|
81
|
+
return `No round follows from a seal on a height-indexed source, so this height was the operator's choice — `
|
|
82
|
+
+ `and on the reader's side it is the chain, not this bundle, that places it after the seal at all. Any `
|
|
83
|
+
+ `other height would have derived a different ${derived} from the same inputs.`;
|
|
84
|
+
}
|
|
85
|
+
return `Which post-seal value applied was still the operator's choice: this binding names a round selected after `
|
|
86
|
+
+ `the seal, and every round the source published in between was an available alternative deriving a `
|
|
87
|
+
+ `different ${derived} from the same inputs. The value could not have been predicted; this ${derived} is `
|
|
88
|
+
+ `nonetheless one of several the operator could have realized by waiting.`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* What the census binding shows about the ORDER (issue #3425). The postdating half keys on
|
|
92
|
+
* `postSeal` for the same reason the sampled opening does: on a height-indexed source nothing in
|
|
93
|
+
* the bundle places the value after the seal, so asserting that the order was fixed by randomness
|
|
94
|
+
* postdating it would be conceded by `postSealClause` two clauses earlier and again by
|
|
95
|
+
* `roundChoiceClause` two clauses later. The population half is unconditional -- a census makes no
|
|
96
|
+
* population choice on any basis.
|
|
97
|
+
*/
|
|
98
|
+
function censusOrderClause(binding) {
|
|
99
|
+
const order = binding.postSeal === "proven-offline"
|
|
100
|
+
? "It shows the run's order was fixed by randomness postdating the seal"
|
|
101
|
+
: "It shows the run's order was tied to a value this bundle cannot place after the seal";
|
|
102
|
+
return `${order}; it does not show the population was, because a census makes no population choice.`;
|
|
103
|
+
}
|
|
104
|
+
const RECOMPUTE_CLAUSE = `Any reader recomputes the derivation offline from the sealed digest, the published beacon value and the `
|
|
105
|
+
+ `item identities alone, by procedure ${BEACON_BINDING_PROCEDURE}; the verifier fails the run when its `
|
|
106
|
+
+ "recomputation disagrees.";
|
|
107
|
+
/**
|
|
108
|
+
* The one sentence that states which binding applied. `undefined` yields the unbound statement,
|
|
109
|
+
* which is a claim about the run too: nothing about it was drawn from post-seal randomness.
|
|
110
|
+
*/
|
|
111
|
+
export function runBindingSentence(binding) {
|
|
112
|
+
if (binding === undefined) {
|
|
113
|
+
return "This run is bound to no public randomness: its seal shows the design existed by a given time, and "
|
|
114
|
+
+ "nothing establishes that execution followed the seal rather than preceding it.";
|
|
115
|
+
}
|
|
116
|
+
if (binding.mode === "sampled") {
|
|
117
|
+
// The "could not have been selected after the fact" claim is the one issue #3322 exists to
|
|
118
|
+
// stop overstating, so it appears ONLY on the branch where the seal named the round. Under
|
|
119
|
+
// `operator-chosen` it is not merely unproven, it is false -- selecting the slate after the
|
|
120
|
+
// fact needed no prediction at all, only waiting for a round whose derivation the operator
|
|
121
|
+
// liked -- so it is dropped rather than hedged.
|
|
122
|
+
//
|
|
123
|
+
// The opening keys on `postSeal` as well, for the same reason `roundChoiceClause` does: under
|
|
124
|
+
// `attributive` nothing in the bundle places the height after the seal, so an opening that
|
|
125
|
+
// called the value unpredictable would assert what the branch cannot check -- and would be
|
|
126
|
+
// retracted two clauses later by the very postdating clause it introduces.
|
|
127
|
+
const opening = binding.roundBasis === "seal-derived"
|
|
128
|
+
? "This run's slate was drawn, not chosen"
|
|
129
|
+
: binding.postSeal === "attributive"
|
|
130
|
+
? "This run's slate was drawn from a value this bundle cannot place after the seal"
|
|
131
|
+
: "This run's slate was drawn from a value it could not have predicted";
|
|
132
|
+
const unpredictabilityClause = binding.roundBasis === "seal-derived"
|
|
133
|
+
? "Selecting the slate after the fact would have required predicting that value. "
|
|
134
|
+
: "";
|
|
135
|
+
return `${opening}: its ${binding.sample.length} items were derived from a `
|
|
136
|
+
+ `declared pool of ${binding.poolSize} by procedure ${BEACON_BINDING_PROCEDURE}, keyed on this run's sealed `
|
|
137
|
+
+ `digest together with ${beaconName(binding)} — ${postSealClause(binding)}. `
|
|
138
|
+
+ `${unpredictabilityClause}${roundChoiceClause(binding)} ${RECOMPUTE_CLAUSE}`;
|
|
139
|
+
}
|
|
140
|
+
return `This run evaluated its whole declared population of ${binding.poolSize} items, so no slate was selected `
|
|
141
|
+
+ `and none could be selected after the fact. The beacon binds execution ORDER only: the order was derived by `
|
|
142
|
+
+ `procedure ${BEACON_BINDING_PROCEDURE} from this run's sealed digest together with ${beaconName(binding)} — `
|
|
143
|
+
+ `${postSealClause(binding)}. This is a weaker binding than a beacon-drawn slate. `
|
|
144
|
+
+ `${censusOrderClause(binding)} ${roundChoiceClause(binding)} ${RECOMPUTE_CLAUSE}`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The venue-limits list with the binding statement appended. Returns the list unchanged when the
|
|
148
|
+
* run carries no binding, so every run that predates this feature keeps its exact limits bytes --
|
|
149
|
+
* the same additive posture `anchoredVenueLimits` takes for an unanchored run.
|
|
150
|
+
*/
|
|
151
|
+
export function runBoundVenueLimits(limits, binding) {
|
|
152
|
+
return binding === undefined ? limits : [...limits, runBindingSentence(binding)];
|
|
153
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { SUPPORTED_BUNDLE_FORMATS } from "./manifest.js";
|
|
3
|
-
import {
|
|
4
|
-
import { PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V6_CHECKS } from "./reader-instructions.js";
|
|
3
|
+
import { summarizeVerificationOutcome } from "./outcome.js";
|
|
5
4
|
import { verifyPublicBundle } from "./verify.js";
|
|
6
5
|
import { VERIFIER_VERSION } from "./version.js";
|
|
7
6
|
export { VERIFIER_VERSION } from "./version.js";
|
|
@@ -75,29 +74,82 @@ function renderAnchorReport(report) {
|
|
|
75
74
|
: report.anchors.map(renderAnchor).join("\n");
|
|
76
75
|
return `\nAnchors\n${anchors}\n\nAnchor subjects\n${report.subjects.map(renderSubject).join("\n")}\n`;
|
|
77
76
|
}
|
|
77
|
+
const SIGNER_ROLE_NAMES = {
|
|
78
|
+
publisher: "publisher",
|
|
79
|
+
"automated-grader": "automated grader",
|
|
80
|
+
"human-reviewer": "human reviewer",
|
|
81
|
+
"label-admission": "label admission",
|
|
82
|
+
};
|
|
83
|
+
/** The role in plain words. `urn:`/`did:key` identifiers stay in `--json`, where they are the join
|
|
84
|
+
* key a reader actually needs them for; on this surface they are noise a reader has to decode.
|
|
85
|
+
* Undeclared custody is stated rather than left blank: a reader who has seen the same-operator
|
|
86
|
+
* suffix elsewhere would otherwise read its absence as an independence claim, which no bundle
|
|
87
|
+
* format can establish. The publisher takes no suffix -- it *is* the operator the others are
|
|
88
|
+
* measured against. */
|
|
89
|
+
function renderSignerGroup(role, custody, count) {
|
|
90
|
+
const suffix = role === "publisher"
|
|
91
|
+
? ""
|
|
92
|
+
: custody === "same-operator" ? " \u2014 same operator" : " \u2014 custody not declared";
|
|
93
|
+
return ` ${SIGNER_ROLE_NAMES[role]}${suffix} \u00b7 ${count} ${count === 1 ? "key" : "keys"}`;
|
|
94
|
+
}
|
|
95
|
+
function renderSigners(signers) {
|
|
96
|
+
const counts = new Map();
|
|
97
|
+
for (const signer of signers) {
|
|
98
|
+
const key = `${signer.role} ${signer.custody}`;
|
|
99
|
+
const group = counts.get(key);
|
|
100
|
+
if (group === undefined)
|
|
101
|
+
counts.set(key, { role: signer.role, custody: signer.custody, count: 1 });
|
|
102
|
+
else
|
|
103
|
+
group.count += 1;
|
|
104
|
+
}
|
|
105
|
+
// The role-name record's own key order is the print order; a second parallel list would drift.
|
|
106
|
+
const order = Object.keys(SIGNER_ROLE_NAMES);
|
|
107
|
+
const groups = [...counts.values()]
|
|
108
|
+
.sort((left, right) => order.indexOf(left.role) - order.indexOf(right.role));
|
|
109
|
+
return `\nSigned by\n${groups.map((group) => renderSignerGroup(group.role, group.custody, group.count)).join("\n")}\n`;
|
|
110
|
+
}
|
|
78
111
|
export function renderVerifiedBundle(result) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
// A metadata-first bundle carries artifact digests without their bytes. Printing "passed" for a
|
|
113
|
+
// check that read nothing would be the one claim this format cannot afford, so the deferred check
|
|
114
|
+
// prints as not fetched and is counted out of the passed total.
|
|
115
|
+
const outcome = summarizeVerificationOutcome(result);
|
|
116
|
+
const artifactContent = outcome.artifactContent;
|
|
117
|
+
const checks = outcome.outcomes
|
|
118
|
+
.map(({ check, state }) => `${check.padEnd(24)}${state}`)
|
|
119
|
+
.join("\n");
|
|
120
|
+
const totalChecks = outcome.total;
|
|
85
121
|
const identity = result.identity.startsWith("sha256:") ? result.identity : `sha256:${result.identity}`;
|
|
86
122
|
const anchors = "anchors" in result && result.anchors !== undefined
|
|
87
123
|
? renderAnchorReport(result.anchors)
|
|
88
124
|
: "";
|
|
125
|
+
const signers = result.signers === undefined || result.signers.length === 0
|
|
126
|
+
? ""
|
|
127
|
+
: renderSigners(result.signers);
|
|
128
|
+
// Naming the digests is what makes the deferred check completable: they are the addresses to
|
|
129
|
+
// fetch and the expectations to check the fetched bytes against. Adding a body to this directory
|
|
130
|
+
// is not the completion path -- it would break the manifest closure the bundle is identified by,
|
|
131
|
+
// so the reader is pointed at the full-evidence bundle instead.
|
|
132
|
+
const artifactContentReport = artifactContent === undefined
|
|
133
|
+
? ""
|
|
134
|
+
: `\nArtifact content\n ${artifactContent.notFetched} artifact ${artifactContent.notFetched === 1 ? "body was" : "bodies were"} not fetched. This bundle carries their\n exact digests, not their bytes:\n${artifactContent.notFetchedDigests.map((digest) => ` sha256:${digest}`).join("\n")}\n Check fetched bytes against those digests yourself, or verify the\n full-evidence bundle, which carries them.\n`;
|
|
135
|
+
const artifactContentLimit = artifactContent === undefined
|
|
136
|
+
? ""
|
|
137
|
+
: "\nEverything above was checked against the bytes this bundle carries. The artifact\ncontents themselves were not read, so nothing here says what they contain.";
|
|
89
138
|
const anchorLimits = anchors === ""
|
|
90
139
|
? ""
|
|
91
140
|
: "\nAn anchor dates the bytes it covers and says nothing else about the run: not\nthat results were produced after it, and not that the anchoring authority is\nindependent of the bundle's owner.";
|
|
92
|
-
|
|
141
|
+
const verdictLine = outcome.notFetched === 0
|
|
142
|
+
? `Verified: ${outcome.passed} of ${totalChecks} checks passed`
|
|
143
|
+
: `Verified: ${outcome.passed} of ${totalChecks} checks passed, ${outcome.notFetched} not fetched`;
|
|
144
|
+
return `${verdictLine}
|
|
93
145
|
Bundle: ${identity}
|
|
94
146
|
Format: ${result.format}
|
|
95
147
|
|
|
96
148
|
${checks}
|
|
97
|
-
${anchors}
|
|
149
|
+
${signers}${artifactContentReport}${anchors}
|
|
98
150
|
This checks the bundle's integrity, evidence closure, calculations, report,
|
|
99
151
|
and claim consistency. It does not prove that the machine that produced the
|
|
100
|
-
bundle was honest or that the compared identities are independent parties.${anchorLimits}
|
|
152
|
+
bundle was honest or that the compared identities are independent parties.${artifactContentLimit}${anchorLimits}
|
|
101
153
|
No files were uploaded.
|
|
102
154
|
Protocol identifiers name https://spec.jinn.network/…. That origin is not hosted yet.
|
|
103
155
|
Verification uses the exact platform bytes installed from npm.
|
|
@@ -132,6 +184,16 @@ function readBlockHeaders(bytes, path) {
|
|
|
132
184
|
};
|
|
133
185
|
});
|
|
134
186
|
}
|
|
187
|
+
/** `urn:…` and `did:key:z…` as they appear inside a refusal message. The base58btc class stops a
|
|
188
|
+
* `did:key` match before a trailing `:reason` suffix the message appended. */
|
|
189
|
+
const RAW_IDENTIFIER = /urn:[^\s,;)"']+|did:key:z[1-9A-HJ-NP-Za-km-z]+/gu;
|
|
190
|
+
/** A refusal names the signer it refused, and on the machine surface that identifier is the whole
|
|
191
|
+
* point. On the human surface it is a string a reader cannot act on, so the same rule as the
|
|
192
|
+
* verified report applies: the identifier lives in `--json` (issue #3024). What failed, and where,
|
|
193
|
+
* is untouched. */
|
|
194
|
+
function withoutRawIdentifiers(message) {
|
|
195
|
+
return message.replace(RAW_IDENTIFIER, "<identifier: see --json>");
|
|
196
|
+
}
|
|
135
197
|
function parseArguments(args) {
|
|
136
198
|
const positional = [];
|
|
137
199
|
const tsaRoots = [];
|
|
@@ -199,7 +261,7 @@ export async function runVerifierCli(args, deps = {}) {
|
|
|
199
261
|
const stdout = parsed.json
|
|
200
262
|
? `${JSON.stringify({ ok: false, verifierVersion: VERIFIER_VERSION, supportedFormats: SUPPORTED_BUNDLE_FORMATS, code, message: error.message })}\n`
|
|
201
263
|
: "";
|
|
202
|
-
const stderr = parsed.json ? "" : `colophon-verify: ${error.message}\n`;
|
|
264
|
+
const stderr = parsed.json ? "" : `colophon-verify: ${withoutRawIdentifiers(error.message)}\n`;
|
|
203
265
|
return { exitCode: code === "record-integrity" ? 1 : 2, stdout, stderr };
|
|
204
266
|
}
|
|
205
267
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { verifyPublicBundle, verifyPublicBundleSnapshot } from "./verify.js";
|
|
2
2
|
export type { PublicBundleVerificationCheck, PublicBundleVerificationResult, VerifiedPublicBundleSnapshot, VerifyPublicBundleDeps, } from "./verify.js";
|
|
3
|
+
export type { PublicBundleSigner, PublicBundleSignerRole } from "./signers.js";
|
|
3
4
|
export { derivePublicComparison } from "./comparison.js";
|
|
4
5
|
export type { DerivePublicComparisonInput, PublicComparisonCell, PublicComparisonOutput, PublicComparisonTask, PublicComparisonVerdict, PublicComparisonView, PublicDescriptiveComparison, } from "./comparison.js";
|
|
5
6
|
export { buildPublicAssets } from "./assets.js";
|
|
7
|
+
export { assertTaskSelectionConsistency, taskSelectionContradiction } from "./profile/task-selection.js";
|
|
6
8
|
export type { PublicAssetInput } from "./assets.js";
|
|
7
9
|
export { anchorCertificateReader, anchorChainVerifier, anchorSignatureVerifier, nodeCryptoAnchorPorts, } from "./anchor/ports.js";
|
|
8
10
|
export { evaluateIntegrityAnchors } from "./anchor/check.js";
|
|
@@ -10,14 +12,23 @@ export type { AnchorProofStatus, AnchorSubjectOutcome, AnchorSubjectReport, Anch
|
|
|
10
12
|
export type { InspectRuntimeMethodDisclosure, InspectScoringProjectionDisclosure, } from "./profile/inspect-disclosure.js";
|
|
11
13
|
export { ANCHORED_PRE_REGISTRATION, ANCHORED_TRUST_ROOT, ClaimAnchorProjectionError, ClaimAnchorSchema, SELF_RUN_TRUST_ROOT, STRUCTURAL_PRE_REGISTRATION, additionalLockAnchorLine, anchoredPreRegistration, anchoredPreRegistrationSentence, anchoredTrustRoot, anchoredVenueLimits, carriedMatrixAnchors, deriveClaimAnchors, governingLockAnchors, matrixAnchorLine, } from "./profile/anchor-claims.js";
|
|
12
14
|
export type { CarriedAnchorRecord, ClaimAnchor, ClaimAnchorFacts, ClaimAnchorSubject, DeriveClaimAnchorsInput, OpenTimestampsClaimAnchorFacts, Rfc3161ClaimAnchorFacts, } from "./profile/anchor-claims.js";
|
|
13
|
-
export { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, SUPPORTED_BUNDLE_FORMATS, } from "./manifest.js";
|
|
15
|
+
export { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, BUNDLE_V7_FORMAT, BUNDLE_V8_FORMAT, SUPPORTED_BUNDLE_FORMATS, } from "./manifest.js";
|
|
16
|
+
export { ClaimDisclosureSectionSchema, DISCLOSURE_ROLE_BINDING, DISCLOSURE_SPECIFICATION_BUNDLE_ROLE, DisclosureProjectionError, assertDisclosureSpecification, deriveDisclosureSpecification, } from "./profile/disclosure.js";
|
|
17
|
+
export type { AssertDisclosureSpecificationInput, ClaimDisclosureSection, DisclosureSpecificationReport, } from "./profile/disclosure.js";
|
|
14
18
|
export type { BundleManifest, VerifiedBundleSnapshot } from "./manifest.js";
|
|
15
19
|
export * from "./admission/index.js";
|
|
16
20
|
export * from "./schema.js";
|
|
17
21
|
export * from "./profile/binary-judge-manifest.js";
|
|
18
22
|
export * from "./profile/binary-qualification.js";
|
|
19
|
-
export { ClaimPackageSchema } from "./profile/claim.js";
|
|
23
|
+
export { ClaimPackageSchema, DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID } from "./profile/claim.js";
|
|
20
24
|
export type { ClaimPackage } from "./profile/claim.js";
|
|
25
|
+
export { firstDifference } from "./profile/claim-consistency.js";
|
|
26
|
+
export { NOT_FETCHED_CHECK, summarizeVerificationOutcome } from "./outcome.js";
|
|
27
|
+
export type { VerificationCheckOutcome, VerificationCheckState, VerificationOutcome, } from "./outcome.js";
|
|
21
28
|
export { VERIFIER_VERSION, renderVerifiedBundle, runVerifierCli } from "./cli.js";
|
|
22
29
|
export type { VerifierCliDeps, VerifierCliResult } from "./cli.js";
|
|
23
|
-
export { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS, PUBLIC_BUNDLE_VERIFIER_MAJOR, PUBLIC_BUNDLE_V4_VERIFIER_MAJOR, } from "./reader-instructions.js";
|
|
30
|
+
export { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_CHECKS, PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V8_CHECKS, PUBLIC_BUNDLE_V8_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V8_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS, PUBLIC_BUNDLE_VERIFIER_MAJOR, PUBLIC_BUNDLE_V4_VERIFIER_MAJOR, } from "./reader-instructions.js";
|
|
31
|
+
export { BEACON_BINDING_PROCEDURE, BEACON_SOURCES, BEACON_SOURCE_IDS, MAX_BEACON_ROUND, BeaconReferenceSchema, RunBindingError, RunBindingSchema, beaconRoundInstant, computeBeaconOrder, requiredBeaconRound, verifyRunBinding, } from "./binding/beacon-binding.js";
|
|
32
|
+
export type { BeaconOrderParams, BeaconOrderResult, BeaconPostSealBasis, BeaconReference, BeaconRoundBasis, BeaconSourceDefinition, BeaconSourceId, BeaconSourceTimeBasis, RequiredBeaconRound, RunBinding, VerifiedRunBinding, } from "./binding/beacon-binding.js";
|
|
33
|
+
export { runBindingClass, runBindingSentence, runBoundVenueLimits } from "./binding/report-face.js";
|
|
34
|
+
export type { RunBindingClass } from "./binding/report-face.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { verifyPublicBundle, verifyPublicBundleSnapshot } from "./verify.js";
|
|
2
2
|
export { derivePublicComparison } from "./comparison.js";
|
|
3
3
|
export { buildPublicAssets } from "./assets.js";
|
|
4
|
+
export { assertTaskSelectionConsistency, taskSelectionContradiction } from "./profile/task-selection.js";
|
|
4
5
|
// The three node:crypto ports the RFC 3161 anchor rule engine injects
|
|
5
6
|
// (anchor-evidence design §6.1 "Placement"). They live here, in the standalone
|
|
6
7
|
// verifier, and are reused by the product core -- which already depends on this
|
|
@@ -13,11 +14,23 @@ export { evaluateIntegrityAnchors } from "./anchor/check.js";
|
|
|
13
14
|
// than mirrored into the product core, so the producer's claim section and the verifier's rebuild
|
|
14
15
|
// of it cannot drift -- the byte-compare depends on them being one function.
|
|
15
16
|
export { ANCHORED_PRE_REGISTRATION, ANCHORED_TRUST_ROOT, ClaimAnchorProjectionError, ClaimAnchorSchema, SELF_RUN_TRUST_ROOT, STRUCTURAL_PRE_REGISTRATION, additionalLockAnchorLine, anchoredPreRegistration, anchoredPreRegistrationSentence, anchoredTrustRoot, anchoredVenueLimits, carriedMatrixAnchors, deriveClaimAnchors, governingLockAnchors, matrixAnchorLine, } from "./profile/anchor-claims.js";
|
|
16
|
-
export { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, SUPPORTED_BUNDLE_FORMATS, } from "./manifest.js";
|
|
17
|
+
export { BUNDLE_FORMAT, BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, BUNDLE_V7_FORMAT, BUNDLE_V8_FORMAT, SUPPORTED_BUNDLE_FORMATS, } from "./manifest.js";
|
|
18
|
+
// The disclosed-closure projection and check (disclosure-specification-record design §6.4/§6.6/§7,
|
|
19
|
+
// issue #2839). Single-sourced here for exactly the reason the anchored projection above is: the
|
|
20
|
+
// product core imports this package, so the producer's claim section and the verifier's rebuild of
|
|
21
|
+
// it are one function, and the byte-compare is a comparison of outputs rather than of guesses.
|
|
22
|
+
export { ClaimDisclosureSectionSchema, DISCLOSURE_ROLE_BINDING, DISCLOSURE_SPECIFICATION_BUNDLE_ROLE, DisclosureProjectionError, assertDisclosureSpecification, deriveDisclosureSpecification, } from "./profile/disclosure.js";
|
|
17
23
|
export * from "./admission/index.js";
|
|
18
24
|
export * from "./schema.js";
|
|
19
25
|
export * from "./profile/binary-judge-manifest.js";
|
|
20
26
|
export * from "./profile/binary-qualification.js";
|
|
21
|
-
export { ClaimPackageSchema } from "./profile/claim.js";
|
|
27
|
+
export { ClaimPackageSchema, DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID } from "./profile/claim.js";
|
|
28
|
+
export { firstDifference } from "./profile/claim-consistency.js";
|
|
29
|
+
export { NOT_FETCHED_CHECK, summarizeVerificationOutcome } from "./outcome.js";
|
|
22
30
|
export { VERIFIER_VERSION, renderVerifiedBundle, runVerifierCli } from "./cli.js";
|
|
23
|
-
export { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS, PUBLIC_BUNDLE_VERIFIER_MAJOR, PUBLIC_BUNDLE_V4_VERIFIER_MAJOR, } from "./reader-instructions.js";
|
|
31
|
+
export { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V4_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V5_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_CHECKS, PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V8_CHECKS, PUBLIC_BUNDLE_V8_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V8_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_INSTRUCTIONS, PUBLIC_BUNDLE_VERIFIER_MAJOR, PUBLIC_BUNDLE_V4_VERIFIER_MAJOR, } from "./reader-instructions.js";
|
|
32
|
+
// `beacon-binding/1` (issue #2976): the post-seal public-randomness binding, and the report face
|
|
33
|
+
// that states which binding a run carries. Single-sourced here for the same reason the anchored
|
|
34
|
+
// projection is -- the product core imports this package, so producer and reader run one function.
|
|
35
|
+
export { BEACON_BINDING_PROCEDURE, BEACON_SOURCES, BEACON_SOURCE_IDS, MAX_BEACON_ROUND, BeaconReferenceSchema, RunBindingError, RunBindingSchema, beaconRoundInstant, computeBeaconOrder, requiredBeaconRound, verifyRunBinding, } from "./binding/beacon-binding.js";
|
|
36
|
+
export { runBindingClass, runBindingSentence, runBoundVenueLimits } from "./binding/report-face.js";
|
package/dist/manifest.d.ts
CHANGED
|
@@ -6,7 +6,33 @@ export declare const BUNDLE_V5_FORMAT: "benchmark-product-public-bundle/5";
|
|
|
6
6
|
* lists, byte shapes, and values; the `anchors/` member and the `integrity-anchors` check exist
|
|
7
7
|
* only here. */
|
|
8
8
|
export declare const BUNDLE_V6_FORMAT: "benchmark-product-public-bundle/6";
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The anchored binary-qualification closure (issue #3205): v4's member list — `qualification.json`,
|
|
11
|
+
* the v4 evidence catalog, the v4 trust document — plus v6's `anchors/` member and its
|
|
12
|
+
* `integrity-anchors` check. Additive in exactly the same way v6 was: v2, v4, v5, and v6 keep their
|
|
13
|
+
* member lists, check lists, and bytes, and only a run that is BOTH anchored and
|
|
14
|
+
* qualification-projecting emits this one.
|
|
15
|
+
*/
|
|
16
|
+
export declare const BUNDLE_V7_FORMAT: "benchmark-product-public-bundle/7";
|
|
17
|
+
/**
|
|
18
|
+
* The disclosed anchored binary-qualification closure (issue #2839, disclosure-specification-record
|
|
19
|
+
* design §6.5): v7's complete member list plus one `records/<sha256>.bin` member carrying the sealed
|
|
20
|
+
* disclosure-specification record, and the `disclosure-specification` check.
|
|
21
|
+
*
|
|
22
|
+
* **Why it stacks on v7 rather than on v4.** The design reserved this closure for the UNANCHORED
|
|
23
|
+
* qualified branch, on the premise (its §12.2) that anchoring and qualification could never
|
|
24
|
+
* combine. Issue #3205 dissolved that premise: the published official bundle IS anchored and
|
|
25
|
+
* qualified, on v7. Allocating disclosure on the unanchored branch would have forced the flagship to
|
|
26
|
+
* choose between its anchor and its disclosure record, so the allocation follows the real material.
|
|
27
|
+
* Anything narrower — a second, unanchored disclosed cell — would double the enumeration that
|
|
28
|
+
* #2889 exists to kill, and is deliberately not built.
|
|
29
|
+
*
|
|
30
|
+
* Additive in exactly the way v6 and v7 were: v2, v4, v5, v6, and v7 keep their member lists, check
|
|
31
|
+
* lists, and bytes, and only a run that is anchored AND qualification-projecting AND carrying a
|
|
32
|
+
* sealed disclosure declaration emits this one.
|
|
33
|
+
*/
|
|
34
|
+
export declare const BUNDLE_V8_FORMAT: "benchmark-product-public-bundle/8";
|
|
35
|
+
export declare const SUPPORTED_BUNDLE_FORMATS: readonly ["benchmark-product-public-bundle/2", "benchmark-product-public-bundle/4", "benchmark-product-public-bundle/5", "benchmark-product-public-bundle/6", "benchmark-product-public-bundle/7", "benchmark-product-public-bundle/8"];
|
|
10
36
|
export declare const BUNDLE_MANIFEST_FILENAME: "bundle.json";
|
|
11
37
|
export declare const BundleManifestFileSchema: z.ZodObject<{
|
|
12
38
|
path: z.ZodString;
|
|
@@ -14,7 +40,7 @@ export declare const BundleManifestFileSchema: z.ZodObject<{
|
|
|
14
40
|
bytes: z.ZodNumber;
|
|
15
41
|
}, z.core.$strip>;
|
|
16
42
|
export declare const BundleManifestSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
17
|
-
format: z.ZodUnion<readonly [z.ZodLiteral<"benchmark-product-public-bundle/2">, z.ZodLiteral<"benchmark-product-public-bundle/4">, z.ZodLiteral<"benchmark-product-public-bundle/6">]>;
|
|
43
|
+
format: z.ZodUnion<readonly [z.ZodLiteral<"benchmark-product-public-bundle/2">, z.ZodLiteral<"benchmark-product-public-bundle/4">, z.ZodLiteral<"benchmark-product-public-bundle/6">, z.ZodLiteral<"benchmark-product-public-bundle/7">, z.ZodLiteral<"benchmark-product-public-bundle/8">]>;
|
|
18
44
|
files: z.ZodArray<z.ZodObject<{
|
|
19
45
|
path: z.ZodString;
|
|
20
46
|
sha256: z.ZodString;
|
|
@@ -22,7 +48,7 @@ export declare const BundleManifestSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
22
48
|
}, z.core.$strip>>;
|
|
23
49
|
}, z.core.$strip>, z.ZodObject<{
|
|
24
50
|
format: z.ZodLiteral<"benchmark-product-public-bundle/5">;
|
|
25
|
-
profile: z.ZodLiteral<"https://spec.jinn.network/profiles/benchmark-product-public-bundle/5">;
|
|
51
|
+
profile: z.ZodUnion<readonly [z.ZodLiteral<"https://spec.jinn.network/profiles/benchmark-product-public-bundle/5">, z.ZodLiteral<"https://spec.jinn.network/profiles/benchmark-product-public-bundle/5/metadata-first">]>;
|
|
26
52
|
files: z.ZodArray<z.ZodObject<{
|
|
27
53
|
path: z.ZodString;
|
|
28
54
|
sha256: z.ZodString;
|
|
@@ -45,7 +71,7 @@ export interface VerifyBundleSnapshotDeps {
|
|
|
45
71
|
}
|
|
46
72
|
export interface BuildBundleManifestOptions {
|
|
47
73
|
/** Defaults to v2 so existing producer and golden bytes remain immutable. */
|
|
48
|
-
readonly format?: typeof BUNDLE_FORMAT | typeof BUNDLE_V4_FORMAT | typeof BUNDLE_V6_FORMAT;
|
|
74
|
+
readonly format?: typeof BUNDLE_FORMAT | typeof BUNDLE_V4_FORMAT | typeof BUNDLE_V6_FORMAT | typeof BUNDLE_V7_FORMAT | typeof BUNDLE_V8_FORMAT;
|
|
49
75
|
}
|
|
50
76
|
export declare function buildBundleManifest(bundleDir: string, filePaths: readonly string[], options?: BuildBundleManifestOptions): BuiltBundleManifest;
|
|
51
77
|
export declare function verifyBundleManifest(bundleDir: string): BuiltBundleManifest;
|
package/dist/manifest.js
CHANGED
|
@@ -12,11 +12,39 @@ export const BUNDLE_V5_FORMAT = "benchmark-product-public-bundle/5";
|
|
|
12
12
|
* lists, byte shapes, and values; the `anchors/` member and the `integrity-anchors` check exist
|
|
13
13
|
* only here. */
|
|
14
14
|
export const BUNDLE_V6_FORMAT = "benchmark-product-public-bundle/6";
|
|
15
|
+
/**
|
|
16
|
+
* The anchored binary-qualification closure (issue #3205): v4's member list — `qualification.json`,
|
|
17
|
+
* the v4 evidence catalog, the v4 trust document — plus v6's `anchors/` member and its
|
|
18
|
+
* `integrity-anchors` check. Additive in exactly the same way v6 was: v2, v4, v5, and v6 keep their
|
|
19
|
+
* member lists, check lists, and bytes, and only a run that is BOTH anchored and
|
|
20
|
+
* qualification-projecting emits this one.
|
|
21
|
+
*/
|
|
22
|
+
export const BUNDLE_V7_FORMAT = "benchmark-product-public-bundle/7";
|
|
23
|
+
/**
|
|
24
|
+
* The disclosed anchored binary-qualification closure (issue #2839, disclosure-specification-record
|
|
25
|
+
* design §6.5): v7's complete member list plus one `records/<sha256>.bin` member carrying the sealed
|
|
26
|
+
* disclosure-specification record, and the `disclosure-specification` check.
|
|
27
|
+
*
|
|
28
|
+
* **Why it stacks on v7 rather than on v4.** The design reserved this closure for the UNANCHORED
|
|
29
|
+
* qualified branch, on the premise (its §12.2) that anchoring and qualification could never
|
|
30
|
+
* combine. Issue #3205 dissolved that premise: the published official bundle IS anchored and
|
|
31
|
+
* qualified, on v7. Allocating disclosure on the unanchored branch would have forced the flagship to
|
|
32
|
+
* choose between its anchor and its disclosure record, so the allocation follows the real material.
|
|
33
|
+
* Anything narrower — a second, unanchored disclosed cell — would double the enumeration that
|
|
34
|
+
* #2889 exists to kill, and is deliberately not built.
|
|
35
|
+
*
|
|
36
|
+
* Additive in exactly the way v6 and v7 were: v2, v4, v5, v6, and v7 keep their member lists, check
|
|
37
|
+
* lists, and bytes, and only a run that is anchored AND qualification-projecting AND carrying a
|
|
38
|
+
* sealed disclosure declaration emits this one.
|
|
39
|
+
*/
|
|
40
|
+
export const BUNDLE_V8_FORMAT = "benchmark-product-public-bundle/8";
|
|
15
41
|
export const SUPPORTED_BUNDLE_FORMATS = [
|
|
16
42
|
BUNDLE_FORMAT,
|
|
17
43
|
BUNDLE_V4_FORMAT,
|
|
18
44
|
BUNDLE_V5_FORMAT,
|
|
19
45
|
BUNDLE_V6_FORMAT,
|
|
46
|
+
BUNDLE_V7_FORMAT,
|
|
47
|
+
BUNDLE_V8_FORMAT,
|
|
20
48
|
];
|
|
21
49
|
export const BUNDLE_MANIFEST_FILENAME = "bundle.json";
|
|
22
50
|
const SHA256_HEX = /^[a-f0-9]{64}$/;
|
|
@@ -30,6 +58,8 @@ const LegacyBundleManifestSchema = z.object({
|
|
|
30
58
|
z.literal(BUNDLE_FORMAT),
|
|
31
59
|
z.literal(BUNDLE_V4_FORMAT),
|
|
32
60
|
z.literal(BUNDLE_V6_FORMAT),
|
|
61
|
+
z.literal(BUNDLE_V7_FORMAT),
|
|
62
|
+
z.literal(BUNDLE_V8_FORMAT),
|
|
33
63
|
]),
|
|
34
64
|
files: z.array(BundleManifestFileSchema).min(1),
|
|
35
65
|
});
|
package/dist/materialize.d.ts
CHANGED
|
@@ -2,3 +2,10 @@
|
|
|
2
2
|
export declare const PUBLIC_BUNDLE_FILES: readonly ["static-bundle.json", "benchmark.json", "run.json", "matrix.json", "report.json", "report-envelope.json", "claim-package.json", "verdicts.json", "evidence.json", "verification/assembly.jsonl", "trust/public-keys.json", "index.html", "badge.svg", "social-card.svg", "README.md", "share.txt"];
|
|
3
3
|
/** V4 is the fixed v2 graph with exactly one canonical qualification projection added. */
|
|
4
4
|
export declare const PUBLIC_BUNDLE_V4_FILES: readonly ("benchmark.json" | "run.json" | "matrix.json" | "report.json" | "report-envelope.json" | "claim-package.json" | "qualification.json" | "static-bundle.json" | "evidence.json" | "verdicts.json" | "verification/assembly.jsonl" | "trust/public-keys.json" | "index.html" | "badge.svg" | "social-card.svg" | "README.md" | "share.txt")[];
|
|
5
|
+
/**
|
|
6
|
+
* V8 (issue #2839) adds no mandatory MEMBER. The disclosure-specification record travels at the
|
|
7
|
+
* already-allowlisted `records/<sha256>.bin` path, driven by the evidence catalog exactly like every
|
|
8
|
+
* other sealed record, so v8's mandatory list is v7's — which is v4's. The alias exists so the
|
|
9
|
+
* equality is stated in the file that owns member lists rather than inferred at the call site.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PUBLIC_BUNDLE_V8_FILES: readonly ("benchmark.json" | "run.json" | "matrix.json" | "report.json" | "report-envelope.json" | "claim-package.json" | "qualification.json" | "static-bundle.json" | "evidence.json" | "verdicts.json" | "verification/assembly.jsonl" | "trust/public-keys.json" | "index.html" | "badge.svg" | "social-card.svg" | "README.md" | "share.txt")[];
|
package/dist/materialize.js
CHANGED
|
@@ -11,3 +11,10 @@ export const PUBLIC_BUNDLE_V4_FILES = [
|
|
|
11
11
|
"qualification.json",
|
|
12
12
|
...PUBLIC_BUNDLE_FILES.slice(7),
|
|
13
13
|
];
|
|
14
|
+
/**
|
|
15
|
+
* V8 (issue #2839) adds no mandatory MEMBER. The disclosure-specification record travels at the
|
|
16
|
+
* already-allowlisted `records/<sha256>.bin` path, driven by the evidence catalog exactly like every
|
|
17
|
+
* other sealed record, so v8's mandatory list is v7's — which is v4's. The alias exists so the
|
|
18
|
+
* equality is stated in the file that owns member lists rather than inferred at the call site.
|
|
19
|
+
*/
|
|
20
|
+
export const PUBLIC_BUNDLE_V8_FILES = PUBLIC_BUNDLE_V4_FILES;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PublicBundleVerificationResult } from "./verify.js";
|
|
2
|
+
/**
|
|
3
|
+
* The one check a metadata-first `benchmark-product-public-bundle/5` defers (issue #2986): its
|
|
4
|
+
* artifact digests are carried, its artifact bodies are not.
|
|
5
|
+
*/
|
|
6
|
+
export declare const NOT_FETCHED_CHECK: "artifact-integrity";
|
|
7
|
+
export type VerificationCheckState = "passed" | "not fetched";
|
|
8
|
+
export interface VerificationCheckOutcome {
|
|
9
|
+
readonly check: string;
|
|
10
|
+
readonly state: VerificationCheckState;
|
|
11
|
+
}
|
|
12
|
+
export interface VerificationOutcome {
|
|
13
|
+
readonly outcomes: readonly VerificationCheckOutcome[];
|
|
14
|
+
/** Checks that actually passed. A deferred check is never counted here. */
|
|
15
|
+
readonly passed: number;
|
|
16
|
+
readonly notFetched: number;
|
|
17
|
+
/** The check count the bundle's declared format promises. */
|
|
18
|
+
readonly total: number;
|
|
19
|
+
/** Present exactly when the bundle deferred artifact content. */
|
|
20
|
+
readonly artifactContent?: {
|
|
21
|
+
readonly notFetched: number;
|
|
22
|
+
readonly notFetchedDigests: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The single derivation of what a verification result may be said to have proved. Every reader
|
|
27
|
+
* surface -- the standalone CLI, the product CLI, the local viewer, the web action -- reads this
|
|
28
|
+
* rather than counting `checks` itself, because a surface that counts for itself is a surface that
|
|
29
|
+
* can print a pass over bytes nobody read (issue #2986).
|
|
30
|
+
*/
|
|
31
|
+
export declare function summarizeVerificationOutcome(result: PublicBundleVerificationResult): VerificationOutcome;
|
package/dist/outcome.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { EVIDENCE_NATIVE_BUNDLE_V5_CHECKS } from "@jinn-network/benchmarking-evidence";
|
|
2
|
+
import { PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V6_CHECKS, PUBLIC_BUNDLE_V7_CHECKS, PUBLIC_BUNDLE_V8_CHECKS, } from "./reader-instructions.js";
|
|
3
|
+
/**
|
|
4
|
+
* The one check a metadata-first `benchmark-product-public-bundle/5` defers (issue #2986): its
|
|
5
|
+
* artifact digests are carried, its artifact bodies are not.
|
|
6
|
+
*/
|
|
7
|
+
export const NOT_FETCHED_CHECK = "artifact-integrity";
|
|
8
|
+
/**
|
|
9
|
+
* The single derivation of what a verification result may be said to have proved. Every reader
|
|
10
|
+
* surface -- the standalone CLI, the product CLI, the local viewer, the web action -- reads this
|
|
11
|
+
* rather than counting `checks` itself, because a surface that counts for itself is a surface that
|
|
12
|
+
* can print a pass over bytes nobody read (issue #2986).
|
|
13
|
+
*/
|
|
14
|
+
export function summarizeVerificationOutcome(result) {
|
|
15
|
+
const total = result.format === "benchmark-product-public-bundle/5"
|
|
16
|
+
? EVIDENCE_NATIVE_BUNDLE_V5_CHECKS.length
|
|
17
|
+
: result.format === "benchmark-product-public-bundle/6"
|
|
18
|
+
? PUBLIC_BUNDLE_V6_CHECKS.length
|
|
19
|
+
: result.format === "benchmark-product-public-bundle/7"
|
|
20
|
+
? PUBLIC_BUNDLE_V7_CHECKS.length
|
|
21
|
+
: result.format === "benchmark-product-public-bundle/8"
|
|
22
|
+
? PUBLIC_BUNDLE_V8_CHECKS.length
|
|
23
|
+
: PUBLIC_BUNDLE_VERIFICATION_CHECKS.length;
|
|
24
|
+
const deferred = result.format === "benchmark-product-public-bundle/5"
|
|
25
|
+
&& result.artifactContent.status === "not-fetched"
|
|
26
|
+
? result.artifactContent
|
|
27
|
+
: undefined;
|
|
28
|
+
const outcomes = result.checks.map((check) => ({
|
|
29
|
+
check,
|
|
30
|
+
state: (deferred !== undefined && check === NOT_FETCHED_CHECK ? "not fetched" : "passed"),
|
|
31
|
+
}));
|
|
32
|
+
const notFetched = outcomes.filter((outcome) => outcome.state === "not fetched").length;
|
|
33
|
+
return {
|
|
34
|
+
outcomes,
|
|
35
|
+
passed: outcomes.length - notFetched,
|
|
36
|
+
notFetched,
|
|
37
|
+
total,
|
|
38
|
+
...(deferred === undefined ? {} : {
|
|
39
|
+
artifactContent: {
|
|
40
|
+
notFetched: deferred.notFetched,
|
|
41
|
+
notFetchedDigests: deferred.notFetchedDigests,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validateBinaryInstrumentParameters } from "@jinn-network/benchmarking-aggregate";
|
|
2
|
+
import { PROMPTED_SCREENING_LIMITATIONS, PROMPTED_SCREENING_PROFILE, } from "../admission/contracts.js";
|
|
2
3
|
export const BINARY_INSTRUMENT_REPORT_LIMITATIONS = {
|
|
3
4
|
mutableModelAlias: "The gpt-5.6-luna identifier is a mutable provider alias; this evidence does not prove invariant model weights across calls.",
|
|
4
5
|
reviewerKeyPerson: "Distinct reviewer signing keys prove key control, not that the controllers are distinct people.",
|
|
@@ -48,5 +49,10 @@ export function binaryInstrumentReportLimitations(parameters) {
|
|
|
48
49
|
...(parameters["truthAdmission"] === "screened-operator-sampled"
|
|
49
50
|
? [BINARY_INSTRUMENT_REPORT_LIMITATIONS.screenedNotIndependentlyLabeled]
|
|
50
51
|
: []),
|
|
52
|
+
// Appended only for an authenticated screening-table/v2 closure. Legacy parameter sets omit
|
|
53
|
+
// the profile and therefore retain their exact limitation arrays and sealed Report bytes.
|
|
54
|
+
...(parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE
|
|
55
|
+
? PROMPTED_SCREENING_LIMITATIONS
|
|
56
|
+
: []),
|
|
51
57
|
];
|
|
52
58
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type BenchmarkRecord, type MatrixRecord, type ReportRecord, type RunRecord } from "@jinn-network/benchmarking-records";
|
|
2
2
|
import { type ClaimPackage } from "./claim.js";
|
|
3
3
|
import type { ClaimAnchor } from "./anchor-claims.js";
|
|
4
|
+
import type { ClaimDisclosureSection } from "./disclosure.js";
|
|
4
5
|
export interface ClaimRecordIdentities {
|
|
5
6
|
readonly benchmarkSha256: string;
|
|
6
7
|
readonly runSha256: string;
|
|
@@ -8,6 +9,11 @@ export interface ClaimRecordIdentities {
|
|
|
8
9
|
readonly reportSha256: string | undefined;
|
|
9
10
|
readonly reportEnvelopeSha256: string;
|
|
10
11
|
}
|
|
12
|
+
/** The path of the first field that actually differs, or `undefined` when the two values are
|
|
13
|
+
* equal — equal leaves must report NO difference, or the object branch returns on its first key
|
|
14
|
+
* and every mismatch names the first key in sorted order instead of the edited field. Single
|
|
15
|
+
* implementation: product core imports this helper rather than keeping a second copy. */
|
|
16
|
+
export declare function firstDifference(actual: unknown, expected: unknown, path?: string): string | undefined;
|
|
11
17
|
export declare function assertClaimConsistency(input: {
|
|
12
18
|
readonly claim: ClaimPackage;
|
|
13
19
|
readonly identities: ClaimRecordIdentities;
|
|
@@ -22,5 +28,6 @@ export declare function assertClaimConsistency(input: {
|
|
|
22
28
|
readonly previewCount: number;
|
|
23
29
|
readonly timestamps: readonly string[];
|
|
24
30
|
}; /** anchor-evidence §7.4: the anchors section re-derived from the carried AnchorEvidence bytes, never read from the claim under test. */
|
|
25
|
-
readonly anchors?: readonly ClaimAnchor[];
|
|
31
|
+
readonly anchors?: readonly ClaimAnchor[]; /** disclosure-specification-record design §7 step 10: the disclosure section re-derived from the carried record's own bytes, never read from the claim under test. */
|
|
32
|
+
readonly disclosure?: ClaimDisclosureSection;
|
|
26
33
|
}): void;
|