@colophon-claims/verify 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +39 -0
  2. package/dist/admission/application.d.ts +18 -0
  3. package/dist/admission/application.js +53 -0
  4. package/dist/admission/contracts.d.ts +506 -0
  5. package/dist/admission/contracts.js +459 -0
  6. package/dist/admission/index.d.ts +5 -0
  7. package/dist/admission/index.js +5 -0
  8. package/dist/admission/intake.d.ts +75 -0
  9. package/dist/admission/intake.js +70 -0
  10. package/dist/admission/result-evaluation.d.ts +18 -0
  11. package/dist/admission/result-evaluation.js +71 -0
  12. package/dist/admission/screening-sample.d.ts +56 -0
  13. package/dist/admission/screening-sample.js +126 -0
  14. package/dist/admission/verification.d.ts +102 -0
  15. package/dist/admission/verification.js +844 -0
  16. package/dist/anchor/check.d.ts +95 -0
  17. package/dist/anchor/check.js +146 -0
  18. package/dist/anchor/ports.d.ts +6 -0
  19. package/dist/anchor/ports.js +354 -0
  20. package/dist/assets.d.ts +33 -0
  21. package/dist/assets.js +885 -0
  22. package/dist/bin.d.ts +2 -0
  23. package/dist/bin.js +20 -0
  24. package/dist/cli.d.ts +14 -0
  25. package/dist/cli.js +205 -0
  26. package/dist/comparison.d.ts +64 -0
  27. package/dist/comparison.js +235 -0
  28. package/dist/index.d.ts +23 -0
  29. package/dist/index.js +23 -0
  30. package/dist/manifest.d.ts +54 -0
  31. package/dist/manifest.js +240 -0
  32. package/dist/materialize.d.ts +4 -0
  33. package/dist/materialize.js +13 -0
  34. package/dist/profile/admission-receipts.d.ts +11 -0
  35. package/dist/profile/admission-receipts.js +24 -0
  36. package/dist/profile/anchor-claims.d.ts +157 -0
  37. package/dist/profile/anchor-claims.js +330 -0
  38. package/dist/profile/artifacts.d.ts +261 -0
  39. package/dist/profile/artifacts.js +139 -0
  40. package/dist/profile/assembly-ports.d.ts +19 -0
  41. package/dist/profile/assembly-ports.js +42 -0
  42. package/dist/profile/binary-judge-manifest.d.ts +121 -0
  43. package/dist/profile/binary-judge-manifest.js +106 -0
  44. package/dist/profile/binary-qualification.d.ts +9 -0
  45. package/dist/profile/binary-qualification.js +58 -0
  46. package/dist/profile/branding-assets.d.ts +5 -0
  47. package/dist/profile/branding-assets.js +5 -0
  48. package/dist/profile/branding.d.ts +24 -0
  49. package/dist/profile/branding.js +14 -0
  50. package/dist/profile/claim-consistency.d.ts +26 -0
  51. package/dist/profile/claim-consistency.js +91 -0
  52. package/dist/profile/claim.d.ts +327 -0
  53. package/dist/profile/claim.js +742 -0
  54. package/dist/profile/errors.d.ts +49 -0
  55. package/dist/profile/errors.js +78 -0
  56. package/dist/profile/inspect-assurance.d.ts +16 -0
  57. package/dist/profile/inspect-assurance.js +30 -0
  58. package/dist/profile/inspect-disclosure.d.ts +28 -0
  59. package/dist/profile/inspect-disclosure.js +54 -0
  60. package/dist/profile/inspect-manifest.d.ts +706 -0
  61. package/dist/profile/inspect-manifest.js +397 -0
  62. package/dist/profile/isolation.d.ts +21 -0
  63. package/dist/profile/isolation.js +31 -0
  64. package/dist/profile/pinning-evidence.d.ts +41 -0
  65. package/dist/profile/pinning-evidence.js +43 -0
  66. package/dist/profile/ports.d.ts +3 -0
  67. package/dist/profile/ports.js +11 -0
  68. package/dist/profile/preview-log.d.ts +4 -0
  69. package/dist/profile/preview-log.js +3 -0
  70. package/dist/profile/run-results.d.ts +17 -0
  71. package/dist/profile/run-results.js +23 -0
  72. package/dist/profile/signing.d.ts +10 -0
  73. package/dist/profile/signing.js +46 -0
  74. package/dist/profile/trust.d.ts +13 -0
  75. package/dist/profile/trust.js +35 -0
  76. package/dist/profile/venue.d.ts +2 -0
  77. package/dist/profile/venue.js +2 -0
  78. package/dist/profile/verdict.d.ts +28 -0
  79. package/dist/profile/verdict.js +51 -0
  80. package/dist/reader-instructions.d.ts +41 -0
  81. package/dist/reader-instructions.js +52 -0
  82. package/dist/schema.d.ts +380 -0
  83. package/dist/schema.js +498 -0
  84. package/dist/verify.d.ts +72 -0
  85. package/dist/verify.js +1573 -0
  86. package/dist/version.d.ts +2 -0
  87. package/dist/version.js +2 -0
  88. package/package.json +63 -3
  89. package/schemas/assembly-row.schema.json +194 -0
  90. package/schemas/bundle-manifest.schema.json +23 -0
  91. package/schemas/claim-package.schema.json +279 -0
  92. package/schemas/dsse-envelope.schema.json +25 -0
  93. package/schemas/evidence-catalog.schema.json +43 -0
  94. package/schemas/public-trust.schema.json +44 -0
  95. package/schemas/verdict-catalog.schema.json +27 -0
  96. package/scripts/external-verify.py +238 -0
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ // Keep this check ahead of every package import. A reader on an unsupported
3
+ // machine should get one actionable answer, not a loader failure from the
4
+ // verification dependency graph.
5
+ const nodeMajor = Number(process.versions.node.split(".", 1)[0]);
6
+ if (!Number.isInteger(nodeMajor) || nodeMajor < 22) {
7
+ process.stderr.write(`Colophon Verify requires Node 22 or newer; this machine is running Node ${process.versions.node}.\n`);
8
+ process.stderr.write("Install a current Node 22 LTS release, then run the same command again.\n");
9
+ process.exitCode = 2;
10
+ }
11
+ else {
12
+ const { runVerifierCli } = await import("./cli.js");
13
+ const result = await runVerifierCli(process.argv.slice(2));
14
+ if (result.stdout !== "")
15
+ process.stdout.write(result.stdout);
16
+ if (result.stderr !== "")
17
+ process.stderr.write(result.stderr);
18
+ process.exitCode = result.exitCode;
19
+ }
20
+ export {};
package/dist/cli.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { type PublicBundleVerificationResult, type VerifyPublicBundleDeps } from "./verify.js";
2
+ export { VERIFIER_VERSION } from "./version.js";
3
+ export interface VerifierCliResult {
4
+ readonly exitCode: 0 | 1 | 2;
5
+ readonly stdout: string;
6
+ readonly stderr: string;
7
+ }
8
+ export interface VerifierCliDeps {
9
+ readonly verify?: (bundleDir: string, options?: VerifyPublicBundleDeps) => Promise<PublicBundleVerificationResult>;
10
+ /** Test seam for the trust-material files the flags name. Defaults to the real filesystem. */
11
+ readonly readFile?: (path: string) => Uint8Array;
12
+ }
13
+ export declare function renderVerifiedBundle(result: PublicBundleVerificationResult): string;
14
+ export declare function runVerifierCli(args: readonly string[], deps?: VerifierCliDeps): Promise<VerifierCliResult>;
package/dist/cli.js ADDED
@@ -0,0 +1,205 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { SUPPORTED_BUNDLE_FORMATS } from "./manifest.js";
3
+ import { EVIDENCE_NATIVE_BUNDLE_V5_CHECKS } from "@jinn-network/benchmarking-evidence";
4
+ import { PUBLIC_BUNDLE_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V6_CHECKS } from "./reader-instructions.js";
5
+ import { verifyPublicBundle } from "./verify.js";
6
+ import { VERIFIER_VERSION } from "./version.js";
7
+ export { VERIFIER_VERSION } from "./version.js";
8
+ function usage() {
9
+ return "Usage: colophon-verify <bundle> [--json] [--tsa-root <file>]... [--ots-headers <file>]...\n"
10
+ + " --tsa-root RFC 3161 trust anchor, DER or PEM. Repeatable.\n"
11
+ + " --ots-headers Bitcoin block headers, one \"<height>:<80-byte-hex>\" per line. Repeatable.\n"
12
+ + "Trust material is yours, not the bundle's: with none supplied a well-formed anchor reports\n"
13
+ + "present rather than verified, and none ships with this tool.\n"
14
+ + "Exit 0: valid bundle; 1: invalid bundle; 2: usage or operational failure.\n"
15
+ + "Protocol identifiers name https://spec.jinn.network/…. That origin is not hosted yet. Verification uses exact platform bytes from npm.\n";
16
+ }
17
+ // ---------------------------------------------------------------------------
18
+ // Human rendering
19
+ // ---------------------------------------------------------------------------
20
+ function anchoredValue(entry) {
21
+ const facts = entry.facts;
22
+ if (typeof facts?.genTime === "string")
23
+ return facts.genTime;
24
+ if (typeof facts?.blockHeight === "number")
25
+ return `block ${facts.blockHeight}`;
26
+ return undefined;
27
+ }
28
+ /** What THIS reader did about the time basis, stated separately from what the bytes say. §8: the
29
+ * verifier's own report always adds its evaluation — whose material validated the time basis, or
30
+ * that none was supplied. */
31
+ function evaluationNote(entry) {
32
+ if (entry.status === "verified") {
33
+ // The evaluated instant is reported only where it adds something the head line does not: for a
34
+ // chain-time proof it is the block's own time, which the height alone never gives.
35
+ const evaluated = entry.time !== undefined && entry.time !== anchoredValue(entry)
36
+ ? ` — ${entry.time}`
37
+ : "";
38
+ return `time basis evaluated against trust material you supplied${evaluated}`;
39
+ }
40
+ if (entry.status === "pending")
41
+ return entry.reason ?? "no chain attestation yet";
42
+ if (entry.status === "invalid")
43
+ return entry.reason ?? "the proof does not verify";
44
+ // Exhaustive over the four proof statuses: `present` is the only one left. A fifth member of
45
+ // ANCHOR_PROOF_STATUSES fails here rather than silently inheriting this note.
46
+ entry.status;
47
+ // `present` with material supplied is a different disclosure from `present` with none: this
48
+ // reader did have material for the profile, and it did not carry this anchor to `verified`.
49
+ return entry.trustMaterial === "supplied"
50
+ ? "time basis not evaluated: the trust material you supplied does not verify this anchor"
51
+ : "time basis not evaluated: no trust material supplied";
52
+ }
53
+ function renderAnchor(entry) {
54
+ const value = anchoredValue(entry);
55
+ const head = [
56
+ ` ${entry.subject ?? "unresolved"} anchor`,
57
+ entry.timeBasis ?? "unknown time basis",
58
+ entry.status,
59
+ ...(value === undefined ? [] : [value]),
60
+ ].join(" · ");
61
+ return `${head}\n ${evaluationNote(entry)}\n record ${entry.recordSha256}`;
62
+ }
63
+ function renderSubject(subject) {
64
+ if (subject.outcome === "declared-but-absent") {
65
+ return ` ${subject.subject}: declared-but-absent — this run declared `
66
+ + `${subject.declaredProfiles?.join(", ") ?? "an anchor provider"} and the bundle carries no matching anchor`;
67
+ }
68
+ if (subject.outcome === "absent")
69
+ return ` ${subject.subject}: absent — no anchor was carried and none was declared`;
70
+ return ` ${subject.subject}: anchored`;
71
+ }
72
+ function renderAnchorReport(report) {
73
+ const anchors = report.anchors.length === 0
74
+ ? " no anchor records carried"
75
+ : report.anchors.map(renderAnchor).join("\n");
76
+ return `\nAnchors\n${anchors}\n\nAnchor subjects\n${report.subjects.map(renderSubject).join("\n")}\n`;
77
+ }
78
+ export function renderVerifiedBundle(result) {
79
+ const checks = result.checks.map((check) => `${check.padEnd(24)}passed`).join("\n");
80
+ const totalChecks = result.format === "benchmark-product-public-bundle/5"
81
+ ? EVIDENCE_NATIVE_BUNDLE_V5_CHECKS.length
82
+ : result.format === "benchmark-product-public-bundle/6"
83
+ ? PUBLIC_BUNDLE_V6_CHECKS.length
84
+ : PUBLIC_BUNDLE_VERIFICATION_CHECKS.length;
85
+ const identity = result.identity.startsWith("sha256:") ? result.identity : `sha256:${result.identity}`;
86
+ const anchors = "anchors" in result && result.anchors !== undefined
87
+ ? renderAnchorReport(result.anchors)
88
+ : "";
89
+ const anchorLimits = anchors === ""
90
+ ? ""
91
+ : "\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
+ return `Verified: ${result.checks.length} of ${totalChecks} checks passed
93
+ Bundle: ${identity}
94
+ Format: ${result.format}
95
+
96
+ ${checks}
97
+ ${anchors}
98
+ This checks the bundle's integrity, evidence closure, calculations, report,
99
+ 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}
101
+ No files were uploaded.
102
+ Protocol identifiers name https://spec.jinn.network/…. That origin is not hosted yet.
103
+ Verification uses the exact platform bytes installed from npm.
104
+ `;
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Verifier-side trust material (anchor-evidence design §8 step 3)
108
+ // ---------------------------------------------------------------------------
109
+ const PEM_BLOCK = /-----BEGIN CERTIFICATE-----([A-Za-z0-9+/=\s]+?)-----END CERTIFICATE-----/g;
110
+ /** Accepts a DER file as-is, or one or more PEM blocks. Nothing here validates the certificate;
111
+ * that is the chain verifier's job, and an operator naming a file they chose is not an assertion
112
+ * this tool second-guesses. */
113
+ function readTrustAnchors(bytes) {
114
+ const text = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
115
+ const blocks = [...text.matchAll(PEM_BLOCK)];
116
+ if (blocks.length === 0)
117
+ return [bytes];
118
+ return blocks.map((block) => new Uint8Array(Buffer.from(block[1].replace(/\s+/g, ""), "base64")));
119
+ }
120
+ const HEADER_LINE = /^([0-9]+):([0-9a-fA-F]{160})$/;
121
+ function readBlockHeaders(bytes, path) {
122
+ const lines = new TextDecoder("utf-8", { fatal: true }).decode(bytes)
123
+ .split("\n").map((line) => line.trim()).filter((line) => line !== "" && !line.startsWith("#"));
124
+ return lines.map((line) => {
125
+ const match = HEADER_LINE.exec(line);
126
+ if (match === null) {
127
+ throw new Error(`${path}: expected "<height>:<160 hex characters>" per line, got "${line}"`);
128
+ }
129
+ return {
130
+ height: Number.parseInt(match[1], 10),
131
+ header: new Uint8Array(Buffer.from(match[2].toLowerCase(), "hex")),
132
+ };
133
+ });
134
+ }
135
+ function parseArguments(args) {
136
+ const positional = [];
137
+ const tsaRoots = [];
138
+ const otsHeaders = [];
139
+ let json = false;
140
+ for (let index = 0; index < args.length; index += 1) {
141
+ const arg = args[index];
142
+ if (arg === "--json") {
143
+ json = true;
144
+ }
145
+ else if (arg === "--tsa-root" || arg === "--ots-headers") {
146
+ const value = args[index + 1];
147
+ if (value === undefined || value.startsWith("--"))
148
+ return undefined;
149
+ (arg === "--tsa-root" ? tsaRoots : otsHeaders).push(value);
150
+ index += 1;
151
+ }
152
+ else if (arg.startsWith("--")) {
153
+ return undefined;
154
+ }
155
+ else {
156
+ positional.push(arg);
157
+ }
158
+ }
159
+ if (positional.length !== 1)
160
+ return undefined;
161
+ return { bundleDir: positional[0], json, tsaRoots, otsHeaders };
162
+ }
163
+ function buildAnchorTrust(parsed, readFile) {
164
+ const trustAnchorsDer = parsed.tsaRoots.flatMap((path) => readTrustAnchors(readFile(path)));
165
+ const blockHeaders = parsed.otsHeaders.flatMap((path) => readBlockHeaders(readFile(path), path));
166
+ if (trustAnchorsDer.length === 0 && blockHeaders.length === 0)
167
+ return undefined;
168
+ return {
169
+ ...(trustAnchorsDer.length === 0 ? {} : { rfc3161: { trustAnchorsDer } }),
170
+ ...(blockHeaders.length === 0 ? {} : { opentimestamps: { blockHeaders } }),
171
+ };
172
+ }
173
+ export async function runVerifierCli(args, deps = {}) {
174
+ const parsed = parseArguments(args);
175
+ if (parsed === undefined)
176
+ return { exitCode: 2, stdout: "", stderr: usage() };
177
+ let anchorTrust;
178
+ try {
179
+ anchorTrust = buildAnchorTrust(parsed, deps.readFile ?? ((path) => new Uint8Array(readFileSync(path))));
180
+ }
181
+ catch (cause) {
182
+ return {
183
+ exitCode: 2,
184
+ stdout: "",
185
+ stderr: `colophon-verify: ${cause instanceof Error ? cause.message : String(cause)}\n`,
186
+ };
187
+ }
188
+ try {
189
+ const result = await (deps.verify ?? verifyPublicBundle)(parsed.bundleDir, anchorTrust === undefined ? {} : { anchorTrust });
190
+ const stdout = parsed.json
191
+ ? `${JSON.stringify({ ok: true, verifierVersion: VERIFIER_VERSION, supportedFormats: SUPPORTED_BUNDLE_FORMATS, ...result })}\n`
192
+ : renderVerifiedBundle(result);
193
+ return { exitCode: 0, stdout, stderr: "" };
194
+ }
195
+ catch (cause) {
196
+ const error = cause instanceof Error ? cause : new Error(String(cause));
197
+ const code = (cause !== null && typeof cause === "object" && "code" in cause)
198
+ ? String(cause.code) : "environment";
199
+ const stdout = parsed.json
200
+ ? `${JSON.stringify({ ok: false, verifierVersion: VERIFIER_VERSION, supportedFormats: SUPPORTED_BUNDLE_FORMATS, code, message: error.message })}\n`
201
+ : "";
202
+ const stderr = parsed.json ? "" : `colophon-verify: ${error.message}\n`;
203
+ return { exitCode: code === "record-integrity" ? 1 : 2, stdout, stderr };
204
+ }
205
+ }
@@ -0,0 +1,64 @@
1
+ import { type BenchmarkRecord, type MatrixRecord } from "@jinn-network/benchmarking-records";
2
+ import type { BundleAssemblyCell } from "./schema.js";
3
+ export interface PublicComparisonTask {
4
+ readonly digest: string;
5
+ readonly profileUri: string;
6
+ readonly label: string;
7
+ readonly summary: string;
8
+ readonly evidencePath: string;
9
+ }
10
+ export interface PublicComparisonOutput {
11
+ readonly name: string;
12
+ readonly sha256: string;
13
+ readonly summary: string;
14
+ readonly evidencePath: string;
15
+ }
16
+ export interface PublicComparisonVerdict {
17
+ readonly evaluator: string;
18
+ readonly verdict: "pass" | "fail" | "inconclusive";
19
+ readonly measurements: Readonly<Record<string, string | number | boolean>>;
20
+ readonly evidencePath: string;
21
+ }
22
+ export interface PublicComparisonCell {
23
+ readonly cellKey: string;
24
+ readonly taskDigest: string;
25
+ readonly armId: string;
26
+ readonly replicate: number;
27
+ readonly outcome: MatrixRecord["cells"][number]["outcome"];
28
+ readonly outputSummary: string;
29
+ readonly primaryScore?: {
30
+ readonly name: "solverBrier";
31
+ readonly value: string;
32
+ readonly direction: "lower-is-better";
33
+ };
34
+ readonly outputs: readonly PublicComparisonOutput[];
35
+ readonly verdicts: readonly PublicComparisonVerdict[];
36
+ readonly evidencePaths: readonly string[];
37
+ }
38
+ export interface PublicDescriptiveComparison {
39
+ readonly kind: "paired-measurement";
40
+ readonly measurement: "solverBrier";
41
+ readonly direction: "lower-is-better";
42
+ readonly firstArm: string;
43
+ readonly secondArm: string;
44
+ readonly pairedCells: number;
45
+ readonly lowerByFirst: number;
46
+ readonly lowerBySecond: number;
47
+ readonly ties: number;
48
+ readonly formalWinner: false;
49
+ }
50
+ export interface PublicComparisonView {
51
+ readonly profile: "colophon-public-comparison/1";
52
+ readonly sampleKind?: "bundled-prediction";
53
+ readonly tasks: readonly PublicComparisonTask[];
54
+ readonly arms: readonly string[];
55
+ readonly cells: readonly PublicComparisonCell[];
56
+ readonly descriptiveComparison?: PublicDescriptiveComparison;
57
+ }
58
+ export interface DerivePublicComparisonInput {
59
+ readonly benchmark: BenchmarkRecord;
60
+ readonly matrix: MatrixRecord;
61
+ readonly assemblyCells: readonly BundleAssemblyCell[];
62
+ readonly recordBytes: ReadonlyMap<string, Uint8Array>;
63
+ }
64
+ export declare function derivePublicComparison(input: DerivePublicComparisonInput): PublicComparisonView;
@@ -0,0 +1,235 @@
1
+ import { itemTaskDigest } from "@jinn-network/benchmarking-records";
2
+ import { PREDICTION_FORECAST_PROFILE_URI, REPOSITORY_WORK_PROFILE_URI, } from "@jinn-network/task-execution-profiles";
3
+ import { TaskSpecificationSchema } from "@jinn-network/task-execution-protocol";
4
+ import { INSPECT_TASK_PROFILE_URI } from "./profile/artifacts.js";
5
+ const decoder = new TextDecoder("utf-8", { fatal: true });
6
+ const SHA256 = /^[a-f0-9]{64}$/u;
7
+ const SAMPLE_BENCHMARK_NAME = "bundled-prediction-sample";
8
+ function isObject(value) {
9
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10
+ }
11
+ function bounded(value, maximum = 480) {
12
+ const normalized = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/gu, " ").replace(/\s+/gu, " ").trim();
13
+ const points = Array.from(normalized);
14
+ return points.length <= maximum ? normalized : `${points.slice(0, maximum - 1).join("")}…`;
15
+ }
16
+ function exactJson(bytes, label) {
17
+ try {
18
+ return JSON.parse(decoder.decode(bytes));
19
+ }
20
+ catch {
21
+ throw new TypeError(`${label} is not valid UTF-8 JSON`);
22
+ }
23
+ }
24
+ function requiredRecord(records, sha256, role) {
25
+ if (!SHA256.test(sha256))
26
+ throw new TypeError(`${role} has an invalid digest`);
27
+ const bytes = records.get(sha256);
28
+ if (bytes === undefined)
29
+ throw new TypeError(`${role} ${sha256} is absent from the authenticated record closure`);
30
+ return bytes;
31
+ }
32
+ function percentage(probability) {
33
+ const numeric = Number(probability);
34
+ if (!Number.isFinite(numeric))
35
+ return probability;
36
+ const percent = numeric * 100;
37
+ return `${Number.isInteger(percent) ? String(percent) : percent.toFixed(1)}% Yes`;
38
+ }
39
+ function taskProjection(digest, bytes, bundledPredictionSample) {
40
+ const parsed = TaskSpecificationSchema.parse(exactJson(bytes, `Task ${digest}`));
41
+ const profileUri = parsed.profile.uri ?? "unprofiled";
42
+ const payload = isObject(parsed.payload) ? parsed.payload : {};
43
+ if (profileUri === PREDICTION_FORECAST_PROFILE_URI) {
44
+ const forecast = isObject(payload["forecast"]) ? payload["forecast"] : {};
45
+ const question = typeof forecast["question"] === "string" ? forecast["question"] : `Prediction task ${digest.slice(0, 12)}`;
46
+ const consensus = typeof forecast["consensusProbabilityYes"] === "string" ? forecast["consensusProbabilityYes"] : undefined;
47
+ const syntheticOutcome = bundledPredictionSample && consensus !== undefined
48
+ ? (Number(consensus) >= 0.5 ? "Yes" : "No")
49
+ : undefined;
50
+ const summary = consensus === undefined
51
+ ? "Forecast a probability for the declared outcome."
52
+ : bundledPredictionSample
53
+ ? `Sample consensus input: ${percentage(consensus)}. Synthetic sample resolution: ${syntheticOutcome}.`
54
+ : `Consensus reference at observation: ${percentage(consensus)}.`;
55
+ return {
56
+ task: {
57
+ digest,
58
+ profileUri,
59
+ label: bounded(question, 180),
60
+ summary,
61
+ evidencePath: `records/${digest}.bin`,
62
+ },
63
+ profileUri,
64
+ };
65
+ }
66
+ if (profileUri === REPOSITORY_WORK_PROFILE_URI) {
67
+ const instance = typeof payload["instance_id"] === "string" ? payload["instance_id"] : digest.slice(0, 12);
68
+ const language = typeof payload["language"] === "string" ? payload["language"] : "repository";
69
+ return {
70
+ task: {
71
+ digest,
72
+ profileUri,
73
+ label: bounded(instance, 180),
74
+ summary: bounded(`${language} task — ${parsed.instructions}`, 480),
75
+ evidencePath: `records/${digest}.bin`,
76
+ },
77
+ profileUri,
78
+ };
79
+ }
80
+ if (profileUri === INSPECT_TASK_PROFILE_URI) {
81
+ const selection = typeof payload["selectionManifestSha256"] === "string"
82
+ ? payload["selectionManifestSha256"]
83
+ : undefined;
84
+ return {
85
+ task: {
86
+ digest,
87
+ profileUri,
88
+ label: `Inspect evaluation ${digest.slice(0, 12)}`,
89
+ summary: selection === undefined
90
+ ? "Inspect evaluation with bundle-carried scoring evidence."
91
+ : `Inspect selection ${selection.slice(0, 12)} is sealed into this task.`,
92
+ evidencePath: `records/${digest}.bin`,
93
+ },
94
+ profileUri,
95
+ };
96
+ }
97
+ return {
98
+ task: {
99
+ digest,
100
+ profileUri,
101
+ label: `Task ${digest.slice(0, 12)}`,
102
+ summary: "This task profile has no plain-language Colophon projector; verified identities and measurements remain available below.",
103
+ evidencePath: `records/${digest}.bin`,
104
+ },
105
+ profileUri,
106
+ };
107
+ }
108
+ function outputProjection(profileUri, name, sha256, bytes) {
109
+ let summary = `${name} — ${bytes.length} authenticated bytes`;
110
+ if (profileUri === PREDICTION_FORECAST_PROFILE_URI && name === "prediction") {
111
+ const value = exactJson(bytes, `prediction output ${sha256}`);
112
+ if (isObject(value) && typeof value["probabilityYes"] === "string") {
113
+ summary = `Forecast ${percentage(value["probabilityYes"])}`;
114
+ }
115
+ }
116
+ else if (profileUri === REPOSITORY_WORK_PROFILE_URI && name === "patch") {
117
+ summary = `Unified-diff patch — ${bytes.length} authenticated bytes`;
118
+ }
119
+ else if (profileUri === INSPECT_TASK_PROFILE_URI) {
120
+ summary = `Inspect ${name} — ${bytes.length} authenticated bytes`;
121
+ }
122
+ return { name, sha256, summary, evidencePath: `records/${sha256}.bin` };
123
+ }
124
+ function commonBrier(verdicts) {
125
+ const values = verdicts.map((verdict) => verdict.measurements["solverBrier"]);
126
+ if (values.length === 0 || values.some((value) => typeof value !== "string"))
127
+ return undefined;
128
+ return values.every((value) => value === values[0]) ? values[0] : undefined;
129
+ }
130
+ function descriptiveComparison(arms, cells) {
131
+ if (arms.length !== 2)
132
+ return undefined;
133
+ const [firstArm, secondArm] = arms;
134
+ const first = new Map();
135
+ const second = new Map();
136
+ for (const cell of cells) {
137
+ if (cell.primaryScore?.name !== "solverBrier")
138
+ continue;
139
+ const key = `${cell.taskDigest}\u001f${cell.replicate}`;
140
+ const value = Number(cell.primaryScore.value);
141
+ if (!Number.isFinite(value))
142
+ continue;
143
+ if (cell.armId === firstArm)
144
+ first.set(key, value);
145
+ if (cell.armId === secondArm)
146
+ second.set(key, value);
147
+ }
148
+ let lowerByFirst = 0;
149
+ let lowerBySecond = 0;
150
+ let ties = 0;
151
+ for (const key of [...first.keys()].sort()) {
152
+ const left = first.get(key);
153
+ const right = second.get(key);
154
+ if (right === undefined)
155
+ continue;
156
+ if (left < right)
157
+ lowerByFirst += 1;
158
+ else if (right < left)
159
+ lowerBySecond += 1;
160
+ else
161
+ ties += 1;
162
+ }
163
+ const pairedCells = lowerByFirst + lowerBySecond + ties;
164
+ if (pairedCells === 0)
165
+ return undefined;
166
+ return {
167
+ kind: "paired-measurement",
168
+ measurement: "solverBrier",
169
+ direction: "lower-is-better",
170
+ firstArm,
171
+ secondArm,
172
+ pairedCells,
173
+ lowerByFirst,
174
+ lowerBySecond,
175
+ ties,
176
+ formalWinner: false,
177
+ };
178
+ }
179
+ export function derivePublicComparison(input) {
180
+ const bundledPredictionSample = input.benchmark.name === SAMPLE_BENCHMARK_NAME;
181
+ const taskDigests = [...new Set(input.benchmark.items.map(itemTaskDigest))];
182
+ const taskByDigest = new Map();
183
+ const tasks = taskDigests.map((digest) => {
184
+ const projected = taskProjection(digest, requiredRecord(input.recordBytes, digest, "Task"), bundledPredictionSample);
185
+ taskByDigest.set(digest, projected);
186
+ return projected.task;
187
+ });
188
+ const arms = [...new Set(input.matrix.cells.map((cell) => cell.armId))];
189
+ const assemblyByKey = new Map(input.assemblyCells.map((cell) => [cell.cellKey, cell]));
190
+ const cells = input.matrix.cells.map((matrixCell) => {
191
+ const assembly = assemblyByKey.get(matrixCell.cellKey);
192
+ if (assembly === undefined)
193
+ throw new TypeError(`comparison cell ${matrixCell.cellKey} is absent from the verified assembly`);
194
+ const profileUri = taskByDigest.get(matrixCell.taskDigest)?.profileUri;
195
+ if (profileUri === undefined)
196
+ throw new TypeError(`comparison cell ${matrixCell.cellKey} names an unknown Task`);
197
+ const outputs = (assembly.solveOutputs ?? []).map((output) => outputProjection(profileUri, output.name, output.sha256, requiredRecord(input.recordBytes, output.sha256, "solve output")));
198
+ const verdicts = assembly.verdicts.map((verdict) => ({
199
+ evaluator: verdict.evaluator,
200
+ verdict: verdict.verdict,
201
+ measurements: verdict.measurements,
202
+ evidencePath: `records/${verdict.sha256}.bin`,
203
+ }));
204
+ const brier = commonBrier(verdicts);
205
+ const outputSummary = outputs.length === 0
206
+ ? "No solve output is present for this accounted cell."
207
+ : outputs.map((output) => output.summary).join("; ");
208
+ return {
209
+ cellKey: matrixCell.cellKey,
210
+ taskDigest: matrixCell.taskDigest,
211
+ armId: matrixCell.armId,
212
+ replicate: matrixCell.replicate,
213
+ outcome: matrixCell.outcome,
214
+ outputSummary,
215
+ ...(brier === undefined ? {} : { primaryScore: { name: "solverBrier", value: brier, direction: "lower-is-better" } }),
216
+ outputs,
217
+ verdicts,
218
+ evidencePaths: [
219
+ `records/${matrixCell.taskDigest}.bin`,
220
+ ...(assembly.deliverySha256 === undefined ? [] : [`records/${assembly.deliverySha256}.bin`]),
221
+ ...outputs.map((output) => output.evidencePath),
222
+ ...verdicts.map((verdict) => verdict.evidencePath),
223
+ ],
224
+ };
225
+ });
226
+ const comparison = descriptiveComparison(arms, cells);
227
+ return {
228
+ profile: "colophon-public-comparison/1",
229
+ ...(bundledPredictionSample ? { sampleKind: "bundled-prediction" } : {}),
230
+ tasks,
231
+ arms,
232
+ cells,
233
+ ...(comparison === undefined ? {} : { descriptiveComparison: comparison }),
234
+ };
235
+ }
@@ -0,0 +1,23 @@
1
+ export { verifyPublicBundle, verifyPublicBundleSnapshot } from "./verify.js";
2
+ export type { PublicBundleVerificationCheck, PublicBundleVerificationResult, VerifiedPublicBundleSnapshot, VerifyPublicBundleDeps, } from "./verify.js";
3
+ export { derivePublicComparison } from "./comparison.js";
4
+ export type { DerivePublicComparisonInput, PublicComparisonCell, PublicComparisonOutput, PublicComparisonTask, PublicComparisonVerdict, PublicComparisonView, PublicDescriptiveComparison, } from "./comparison.js";
5
+ export { buildPublicAssets } from "./assets.js";
6
+ export type { PublicAssetInput } from "./assets.js";
7
+ export { anchorCertificateReader, anchorChainVerifier, anchorSignatureVerifier, nodeCryptoAnchorPorts, } from "./anchor/ports.js";
8
+ export { evaluateIntegrityAnchors } from "./anchor/check.js";
9
+ export type { AnchorProofStatus, AnchorSubjectOutcome, AnchorSubjectReport, AnchorVerificationEntry, EvaluateIntegrityAnchorsInput, IntegrityAnchorsReport, PublicBundleAnchorTrustMaterial, } from "./anchor/check.js";
10
+ export type { InspectRuntimeMethodDisclosure, InspectScoringProjectionDisclosure, } from "./profile/inspect-disclosure.js";
11
+ 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
+ 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";
14
+ export type { BundleManifest, VerifiedBundleSnapshot } from "./manifest.js";
15
+ export * from "./admission/index.js";
16
+ export * from "./schema.js";
17
+ export * from "./profile/binary-judge-manifest.js";
18
+ export * from "./profile/binary-qualification.js";
19
+ export { ClaimPackageSchema } from "./profile/claim.js";
20
+ export type { ClaimPackage } from "./profile/claim.js";
21
+ export { VERIFIER_VERSION, renderVerifiedBundle, runVerifierCli } from "./cli.js";
22
+ 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";
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ export { verifyPublicBundle, verifyPublicBundleSnapshot } from "./verify.js";
2
+ export { derivePublicComparison } from "./comparison.js";
3
+ export { buildPublicAssets } from "./assets.js";
4
+ // The three node:crypto ports the RFC 3161 anchor rule engine injects
5
+ // (anchor-evidence design §6.1 "Placement"). They live here, in the standalone
6
+ // verifier, and are reused by the product core -- which already depends on this
7
+ // package, so the split matches the real dependency direction.
8
+ export { anchorCertificateReader, anchorChainVerifier, anchorSignatureVerifier, nodeCryptoAnchorPorts, } from "./anchor/ports.js";
9
+ // The `integrity-anchors` check (anchor-evidence design §8), shared by `bundle verify` and the
10
+ // workspace-side `run.verify` so the two cannot become two implementations.
11
+ export { evaluateIntegrityAnchors } from "./anchor/check.js";
12
+ // The anchored-closure projection (anchor-evidence design §7.4, §9.2). Single-sourced here rather
13
+ // than mirrored into the product core, so the producer's claim section and the verifier's rebuild
14
+ // of it cannot drift -- the byte-compare depends on them being one function.
15
+ 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 * from "./admission/index.js";
18
+ export * from "./schema.js";
19
+ export * from "./profile/binary-judge-manifest.js";
20
+ export * from "./profile/binary-qualification.js";
21
+ export { ClaimPackageSchema } from "./profile/claim.js";
22
+ 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";
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ export declare const BUNDLE_FORMAT: "benchmark-product-public-bundle/2";
3
+ export declare const BUNDLE_V4_FORMAT: "benchmark-product-public-bundle/4";
4
+ export declare const BUNDLE_V5_FORMAT: "benchmark-product-public-bundle/5";
5
+ /** The anchored closure (anchor-evidence design §7.4). Additive: v2, v4, and v5 keep their check
6
+ * lists, byte shapes, and values; the `anchors/` member and the `integrity-anchors` check exist
7
+ * only here. */
8
+ export declare const BUNDLE_V6_FORMAT: "benchmark-product-public-bundle/6";
9
+ 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"];
10
+ export declare const BUNDLE_MANIFEST_FILENAME: "bundle.json";
11
+ export declare const BundleManifestFileSchema: z.ZodObject<{
12
+ path: z.ZodString;
13
+ sha256: z.ZodString;
14
+ bytes: z.ZodNumber;
15
+ }, z.core.$strip>;
16
+ 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">]>;
18
+ files: z.ZodArray<z.ZodObject<{
19
+ path: z.ZodString;
20
+ sha256: z.ZodString;
21
+ bytes: z.ZodNumber;
22
+ }, z.core.$strip>>;
23
+ }, z.core.$strip>, z.ZodObject<{
24
+ format: z.ZodLiteral<"benchmark-product-public-bundle/5">;
25
+ profile: z.ZodLiteral<"https://spec.jinn.network/profiles/benchmark-product-public-bundle/5">;
26
+ files: z.ZodArray<z.ZodObject<{
27
+ path: z.ZodString;
28
+ sha256: z.ZodString;
29
+ bytes: z.ZodNumber;
30
+ }, z.core.$strict>>;
31
+ }, z.core.$strict>]>;
32
+ export type BundleManifest = z.infer<typeof BundleManifestSchema>;
33
+ export interface BuiltBundleManifest {
34
+ readonly manifest: BundleManifest;
35
+ readonly bytes: Uint8Array;
36
+ readonly identity: string;
37
+ }
38
+ export interface VerifiedBundleSnapshot extends BuiltBundleManifest {
39
+ /** Every authenticated file byte string, including bundle.json. Never backed by a pathname. */
40
+ readonly fileBytes: ReadonlyMap<string, Uint8Array>;
41
+ }
42
+ export interface VerifyBundleSnapshotDeps {
43
+ /** Deterministic adversarial boundary: every byte is already authenticated before this runs. */
44
+ readonly afterManifestValidated?: () => void;
45
+ }
46
+ export interface BuildBundleManifestOptions {
47
+ /** 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;
49
+ }
50
+ export declare function buildBundleManifest(bundleDir: string, filePaths: readonly string[], options?: BuildBundleManifestOptions): BuiltBundleManifest;
51
+ export declare function verifyBundleManifest(bundleDir: string): BuiltBundleManifest;
52
+ /** Authenticates the complete tree once and returns the exact immutable byte snapshot used by
53
+ * every semantic verifier. No consumer may reopen a pathname after this boundary. */
54
+ export declare function verifyBundleSnapshot(bundleDir: string, deps?: VerifyBundleSnapshotDeps): VerifiedBundleSnapshot;