@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
|
@@ -13,9 +13,9 @@ const PAIRED_ESTIMATE_LIMITATION = "This method estimates an effect; it does not
|
|
|
13
13
|
const equal = (left, right) => left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
14
14
|
/** The path of the first field that actually differs, or `undefined` when the two values are
|
|
15
15
|
* equal — equal leaves must report NO difference, or the object branch returns on its first key
|
|
16
|
-
* and every mismatch names the first key in sorted order instead of the edited field.
|
|
17
|
-
*
|
|
18
|
-
function firstDifference(actual, expected, path = "claim") {
|
|
16
|
+
* and every mismatch names the first key in sorted order instead of the edited field. Single
|
|
17
|
+
* implementation: product core imports this helper rather than keeping a second copy. */
|
|
18
|
+
export function firstDifference(actual, expected, path = "claim") {
|
|
19
19
|
// Never hand `undefined` to canonicalJsonBytes: it is deliberately not a JSON value, and a
|
|
20
20
|
// field carried by one side alone is itself the first difference.
|
|
21
21
|
if (actual === undefined || expected === undefined)
|
|
@@ -54,7 +54,7 @@ export function assertClaimConsistency(input) {
|
|
|
54
54
|
// Presence, not emptiness: an empty section belongs to the anchored closure's declared-but-absent
|
|
55
55
|
// bundle, and an omitted one to every unanchored bundle.
|
|
56
56
|
const anchors = input.anchors;
|
|
57
|
-
const expected = buildClaimPackage({ draftId: input.draftId, benchmarkSha256: identities.benchmarkSha256, runRecord, runSha256: identities.runSha256, matrixRecord, matrixSha256: identities.matrixSha256, reportRecord, reportSha256: identities.reportSha256, reportEnvelopeSha256: identities.reportEnvelopeSha256, venueHonesty: buildLocalVenueHonesty(matrixRecord.cells, runRecord, anchors ?? []), verificationCommandVerb: "bundle verify", assurance: { preset: input.assurancePreset, resolved: { independence: runRecord.policy.independence, minVerdicts, distinctEvaluator, verdictRule } }, ...(input.rehearsal === undefined ? {} : { previewDisclosure: input.rehearsal }), ...(anchors === undefined ? {} : { anchors }) });
|
|
57
|
+
const expected = buildClaimPackage({ draftId: input.draftId, benchmarkSha256: identities.benchmarkSha256, runRecord, runSha256: identities.runSha256, matrixRecord, matrixSha256: identities.matrixSha256, reportRecord, reportSha256: identities.reportSha256, reportEnvelopeSha256: identities.reportEnvelopeSha256, venueHonesty: buildLocalVenueHonesty(matrixRecord.cells, runRecord, anchors ?? []), verificationCommandVerb: "bundle verify", assurance: { preset: input.assurancePreset, resolved: { independence: runRecord.policy.independence, minVerdicts, distinctEvaluator, verdictRule } }, ...(input.rehearsal === undefined ? {} : { previewDisclosure: input.rehearsal }), ...(anchors === undefined ? {} : { anchors }), ...(input.disclosure === undefined ? {} : { disclosure: input.disclosure }) });
|
|
58
58
|
if (!equal(canonicalJsonBytes(claim), canonicalJsonBytes(expected)))
|
|
59
59
|
refuse("record-integrity", "claim-consistency", `claim package ${firstDifference(claim, expected) ?? "claim"} is not the exact projection of verified facts`);
|
|
60
60
|
const rehearsalLine = input.rehearsal === undefined ? undefined : previewDisclosureSummaryLine(input.rehearsal);
|
package/dist/profile/claim.d.ts
CHANGED
|
@@ -27,9 +27,15 @@
|
|
|
27
27
|
* disclosure. The one deliberate exception to "never cross-check here": `buildClaimPackage`
|
|
28
28
|
* THROWS when the stated primitives disagree with what the sealed Run record's own policy
|
|
29
29
|
* carries — a claim stating primitives the sealed Run does not carry would be dishonest.
|
|
30
|
+
*
|
|
31
|
+
* Issue #3205: the claim id is chosen on TWO independent axes — anchored or not, and
|
|
32
|
+
* qualification-projecting or not — which is four allocations, not three. `claim-package/5` is
|
|
33
|
+
* the fourth cell; before it existed an anchored binary-instrument run could not produce a
|
|
34
|
+
* claim at all, which made anchoring and binary-instrument benchmarking mutually exclusive.
|
|
30
35
|
*/
|
|
31
36
|
import { z } from "zod";
|
|
32
37
|
import type { MatrixRecord, ReportRecord, RunRecord } from "@jinn-network/benchmarking-records";
|
|
38
|
+
import type { ClaimDisclosureSection } from "./disclosure.js";
|
|
33
39
|
import { SELF_RUN_TRUST_ROOT } from "./anchor-claims.js";
|
|
34
40
|
import type { ClaimAnchor } from "./anchor-claims.js";
|
|
35
41
|
type VenueHonesty = unknown;
|
|
@@ -42,13 +48,40 @@ export declare const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-p
|
|
|
42
48
|
* own later allocation.
|
|
43
49
|
*/
|
|
44
50
|
export declare const ANCHORED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/4";
|
|
51
|
+
/**
|
|
52
|
+
* The anchored binary-qualification claim package (issue #3205): claim-package/2's exact
|
|
53
|
+
* qualification projection plus claim-package/4's `anchors` section, carried by
|
|
54
|
+
* `benchmark-product-public-bundle/7`. This is the "later allocation" both earlier guards named:
|
|
55
|
+
* /2 has no anchors slot and /4 has no qualification slot, so before this number existed an
|
|
56
|
+
* anchored run of a binary-instrument benchmark could not produce a claim at all. The allocation is
|
|
57
|
+
* an ADDITION — /1, /2, /3, and /4 keep their meanings and their bytes.
|
|
58
|
+
*/
|
|
59
|
+
export declare const ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/5";
|
|
60
|
+
/**
|
|
61
|
+
* The disclosed anchored binary-qualification claim package (issue #2839,
|
|
62
|
+
* disclosure-specification-record design §6.5/§6.6): claim-package/5 exactly, plus the
|
|
63
|
+
* `disclosure` section, carried by `benchmark-product-public-bundle/8`.
|
|
64
|
+
*
|
|
65
|
+
* The design reserved `/5` for its own disclosure allocation on the UNANCHORED qualified branch, on
|
|
66
|
+
* the premise (its §12.2) that anchoring and qualification could never combine. Issue #3205 both
|
|
67
|
+
* took `/5` and dissolved that premise, so per the design's own §6.5 rule — the implementation
|
|
68
|
+
* packet takes the then-next free numbers if a line has advanced — this is `/6`, and it stacks on
|
|
69
|
+
* the ANCHORED branch so the real flagship bundle can carry its disclosure record without giving up
|
|
70
|
+
* its anchor. The allocation is an ADDITION: /1, /2, /3, /4, and /5 keep their meanings and bytes.
|
|
71
|
+
*/
|
|
72
|
+
export declare const DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/6";
|
|
45
73
|
export declare const BINARY_QUALIFICATION_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
|
|
46
74
|
export declare const BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.1 <bundle-dir>";
|
|
75
|
+
/** Prompted-screening v2 claims require the verifier release that carries that admission surface. */
|
|
76
|
+
export declare const PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
77
|
+
/** Previously materialized prompted bundles remain valid under their immutable 0.2.0 claim. */
|
|
78
|
+
export declare const LEGACY_PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2.0 <bundle-dir>";
|
|
79
|
+
export declare const PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
47
80
|
/** The fixed sentence every claim package's assurance block carries (BP-21, spec §6/§7.1): what
|
|
48
81
|
* distinct evaluator identities on this venue actually prove. Never softened per-claim. */
|
|
49
82
|
export declare const ASSURANCE_DISCLOSURE: string;
|
|
50
83
|
export declare const ClaimPackageSchema: z.ZodPreprocess<z.ZodObject<{
|
|
51
|
-
claimSchema: z.ZodUnion<readonly [z.ZodLiteral<"benchmark-product.claim-package/1">, z.ZodLiteral<"benchmark-product.claim-package/2">, z.ZodLiteral<"benchmark-product.claim-package/4">]>;
|
|
84
|
+
claimSchema: z.ZodUnion<readonly [z.ZodLiteral<"benchmark-product.claim-package/1">, z.ZodLiteral<"benchmark-product.claim-package/2">, z.ZodLiteral<"benchmark-product.claim-package/4">, z.ZodLiteral<"benchmark-product.claim-package/5">, z.ZodLiteral<"benchmark-product.claim-package/6">]>;
|
|
52
85
|
scope: z.ZodObject<{
|
|
53
86
|
draftId: z.ZodString;
|
|
54
87
|
benchmarkSha256: z.ZodString;
|
|
@@ -269,6 +302,169 @@ export declare const ClaimPackageSchema: z.ZodPreprocess<z.ZodObject<{
|
|
|
269
302
|
pending: z.ZodLiteral<true>;
|
|
270
303
|
}, z.core.$strict>]>]>;
|
|
271
304
|
}, z.core.$strict>>>;
|
|
305
|
+
disclosure: z.ZodOptional<z.ZodObject<{
|
|
306
|
+
recordSha256: z.ZodString;
|
|
307
|
+
specification: z.ZodLiteral<"https://spec.jinn.network/disclosure/six-variable/v1">;
|
|
308
|
+
subjectSha256: z.ZodString;
|
|
309
|
+
variables: z.ZodObject<{
|
|
310
|
+
"ingestion-model": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
311
|
+
status: z.ZodLiteral<"measured-here">;
|
|
312
|
+
statement: z.ZodString;
|
|
313
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
314
|
+
role: z.ZodEnum<{
|
|
315
|
+
"pinned-configuration": "pinned-configuration";
|
|
316
|
+
"execution-observation": "execution-observation";
|
|
317
|
+
}>;
|
|
318
|
+
digest: z.ZodObject<{
|
|
319
|
+
sha256: z.ZodString;
|
|
320
|
+
}, z.core.$strict>;
|
|
321
|
+
}, z.core.$strict>>;
|
|
322
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
323
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
324
|
+
statement: z.ZodString;
|
|
325
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
326
|
+
uri: z.ZodString;
|
|
327
|
+
}, z.core.$strict>>>;
|
|
328
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
329
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
330
|
+
reason: z.ZodEnum<{
|
|
331
|
+
"not-stated": "not-stated";
|
|
332
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
333
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
334
|
+
}>;
|
|
335
|
+
}, z.core.$strict>], "status">;
|
|
336
|
+
"retrieval-config": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
337
|
+
status: z.ZodLiteral<"measured-here">;
|
|
338
|
+
statement: z.ZodString;
|
|
339
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
340
|
+
role: z.ZodEnum<{
|
|
341
|
+
"pinned-configuration": "pinned-configuration";
|
|
342
|
+
"execution-observation": "execution-observation";
|
|
343
|
+
}>;
|
|
344
|
+
digest: z.ZodObject<{
|
|
345
|
+
sha256: z.ZodString;
|
|
346
|
+
}, z.core.$strict>;
|
|
347
|
+
}, z.core.$strict>>;
|
|
348
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
349
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
350
|
+
statement: z.ZodString;
|
|
351
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
352
|
+
uri: z.ZodString;
|
|
353
|
+
}, z.core.$strict>>>;
|
|
354
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
355
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
356
|
+
reason: z.ZodEnum<{
|
|
357
|
+
"not-stated": "not-stated";
|
|
358
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
359
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
360
|
+
}>;
|
|
361
|
+
}, z.core.$strict>], "status">;
|
|
362
|
+
"answer-model": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
363
|
+
status: z.ZodLiteral<"measured-here">;
|
|
364
|
+
statement: z.ZodString;
|
|
365
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
366
|
+
role: z.ZodEnum<{
|
|
367
|
+
"pinned-configuration": "pinned-configuration";
|
|
368
|
+
"execution-observation": "execution-observation";
|
|
369
|
+
}>;
|
|
370
|
+
digest: z.ZodObject<{
|
|
371
|
+
sha256: z.ZodString;
|
|
372
|
+
}, z.core.$strict>;
|
|
373
|
+
}, z.core.$strict>>;
|
|
374
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
375
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
376
|
+
statement: z.ZodString;
|
|
377
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
378
|
+
uri: z.ZodString;
|
|
379
|
+
}, z.core.$strict>>>;
|
|
380
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
381
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
382
|
+
reason: z.ZodEnum<{
|
|
383
|
+
"not-stated": "not-stated";
|
|
384
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
385
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
386
|
+
}>;
|
|
387
|
+
}, z.core.$strict>], "status">;
|
|
388
|
+
"answer-prompt": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
389
|
+
status: z.ZodLiteral<"measured-here">;
|
|
390
|
+
statement: z.ZodString;
|
|
391
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
392
|
+
role: z.ZodEnum<{
|
|
393
|
+
"pinned-configuration": "pinned-configuration";
|
|
394
|
+
"execution-observation": "execution-observation";
|
|
395
|
+
}>;
|
|
396
|
+
digest: z.ZodObject<{
|
|
397
|
+
sha256: z.ZodString;
|
|
398
|
+
}, z.core.$strict>;
|
|
399
|
+
}, z.core.$strict>>;
|
|
400
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
401
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
402
|
+
statement: z.ZodString;
|
|
403
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
404
|
+
uri: z.ZodString;
|
|
405
|
+
}, z.core.$strict>>>;
|
|
406
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
407
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
408
|
+
reason: z.ZodEnum<{
|
|
409
|
+
"not-stated": "not-stated";
|
|
410
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
411
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
412
|
+
}>;
|
|
413
|
+
}, z.core.$strict>], "status">;
|
|
414
|
+
"judge-model": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
415
|
+
status: z.ZodLiteral<"measured-here">;
|
|
416
|
+
statement: z.ZodString;
|
|
417
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
418
|
+
role: z.ZodEnum<{
|
|
419
|
+
"pinned-configuration": "pinned-configuration";
|
|
420
|
+
"execution-observation": "execution-observation";
|
|
421
|
+
}>;
|
|
422
|
+
digest: z.ZodObject<{
|
|
423
|
+
sha256: z.ZodString;
|
|
424
|
+
}, z.core.$strict>;
|
|
425
|
+
}, z.core.$strict>>;
|
|
426
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
427
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
428
|
+
statement: z.ZodString;
|
|
429
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
430
|
+
uri: z.ZodString;
|
|
431
|
+
}, z.core.$strict>>>;
|
|
432
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
433
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
434
|
+
reason: z.ZodEnum<{
|
|
435
|
+
"not-stated": "not-stated";
|
|
436
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
437
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
438
|
+
}>;
|
|
439
|
+
}, z.core.$strict>], "status">;
|
|
440
|
+
"judge-prompt": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
441
|
+
status: z.ZodLiteral<"measured-here">;
|
|
442
|
+
statement: z.ZodString;
|
|
443
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
444
|
+
role: z.ZodEnum<{
|
|
445
|
+
"pinned-configuration": "pinned-configuration";
|
|
446
|
+
"execution-observation": "execution-observation";
|
|
447
|
+
}>;
|
|
448
|
+
digest: z.ZodObject<{
|
|
449
|
+
sha256: z.ZodString;
|
|
450
|
+
}, z.core.$strict>;
|
|
451
|
+
}, z.core.$strict>>;
|
|
452
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
453
|
+
status: z.ZodLiteral<"disclosed-by-publisher">;
|
|
454
|
+
statement: z.ZodString;
|
|
455
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
456
|
+
uri: z.ZodString;
|
|
457
|
+
}, z.core.$strict>>>;
|
|
458
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
459
|
+
status: z.ZodLiteral<"undisclosed">;
|
|
460
|
+
reason: z.ZodEnum<{
|
|
461
|
+
"not-stated": "not-stated";
|
|
462
|
+
"stated-without-identifiers": "stated-without-identifiers";
|
|
463
|
+
"outside-this-experiment": "outside-this-experiment";
|
|
464
|
+
}>;
|
|
465
|
+
}, z.core.$strict>], "status">;
|
|
466
|
+
}, z.core.$strict>;
|
|
467
|
+
}, z.core.$strict>>;
|
|
272
468
|
}, z.core.$strip>>;
|
|
273
469
|
export type ClaimPackage = z.infer<typeof ClaimPackageSchema>;
|
|
274
470
|
export interface BuildClaimPackageInput {
|
|
@@ -310,10 +506,16 @@ export interface BuildClaimPackageInput {
|
|
|
310
506
|
* here: this builder is pure, and the derivation needs the record bytes the caller already
|
|
311
507
|
* authenticated. */
|
|
312
508
|
readonly anchors?: readonly ClaimAnchor[];
|
|
509
|
+
/** disclosure-specification-record design §6.6: the projected disclosure section, already derived
|
|
510
|
+
* from the sealed record's exact bytes by the shared `deriveDisclosureSpecification`. Absent for
|
|
511
|
+
* every run with no declaration, which is what keeps every existing claim byte-identical. */
|
|
512
|
+
readonly disclosure?: ClaimDisclosureSection;
|
|
313
513
|
}
|
|
314
514
|
export declare const CLAIM_VERIFICATION_CHECKS: readonly string[];
|
|
315
515
|
/** The anchored closure's list: the six frozen checks plus `integrity-anchors` (§8). */
|
|
316
516
|
export declare const ANCHORED_CLAIM_VERIFICATION_CHECKS: readonly string[];
|
|
517
|
+
/** The disclosed closure's list: the anchored seven plus `disclosure-specification` (design §7). */
|
|
518
|
+
export declare const DISCLOSED_CLAIM_VERIFICATION_CHECKS: readonly string[];
|
|
317
519
|
export declare const PUBLIC_BUNDLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
|
|
318
520
|
/** The unconditional trust-root sentence, re-exported unchanged. It is DEFINED once beside its
|
|
319
521
|
* anchored replacement in `anchor-claims.ts`: one sentence written out twice, in two mirrored
|
package/dist/profile/claim.js
CHANGED
|
@@ -27,13 +27,20 @@
|
|
|
27
27
|
* disclosure. The one deliberate exception to "never cross-check here": `buildClaimPackage`
|
|
28
28
|
* THROWS when the stated primitives disagree with what the sealed Run record's own policy
|
|
29
29
|
* carries — a claim stating primitives the sealed Run does not carry would be dishonest.
|
|
30
|
+
*
|
|
31
|
+
* Issue #3205: the claim id is chosen on TWO independent axes — anchored or not, and
|
|
32
|
+
* qualification-projecting or not — which is four allocations, not three. `claim-package/5` is
|
|
33
|
+
* the fourth cell; before it existed an anchored binary-instrument run could not produce a
|
|
34
|
+
* claim at all, which made anchoring and binary-instrument benchmarking mutually exclusive.
|
|
30
35
|
*/
|
|
31
36
|
import { z } from "zod";
|
|
32
37
|
import { Buffer } from "node:buffer";
|
|
33
38
|
import { validateBinaryInstrumentQualificationProjection } from "@jinn-network/benchmarking-aggregate";
|
|
34
39
|
import { BENCHMARKING_METHOD_IDS, BENCHMARKING_METHOD_VERSION } from "@jinn-network/benchmarking-records";
|
|
35
40
|
import { canonicalJsonBytes } from "@jinn-network/trust-core";
|
|
36
|
-
import { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS as READER_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND as READER_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS as READER_ANCHORED_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, } from "../reader-instructions.js";
|
|
41
|
+
import { PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_VERIFICATION_CHECKS as READER_VERIFICATION_CHECKS, PUBLIC_BUNDLE_VERIFICATION_COMMAND as READER_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_CHECKS as READER_ANCHORED_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_CHECKS as READER_ANCHORED_QUALIFICATION_VERIFICATION_CHECKS, PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND, PUBLIC_BUNDLE_V8_CHECKS as READER_DISCLOSED_VERIFICATION_CHECKS, } from "../reader-instructions.js";
|
|
42
|
+
import { ClaimDisclosureSectionSchema } from "./disclosure.js";
|
|
43
|
+
import { PROMPTED_SCREENING_PROFILE } from "../admission/contracts.js";
|
|
37
44
|
import { ClaimAnchorSchema, SELF_RUN_TRUST_ROOT, anchoredTrustRoot } from "./anchor-claims.js";
|
|
38
45
|
export const CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/1";
|
|
39
46
|
export const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/2";
|
|
@@ -44,8 +51,35 @@ export const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.c
|
|
|
44
51
|
* own later allocation.
|
|
45
52
|
*/
|
|
46
53
|
export const ANCHORED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/4";
|
|
54
|
+
/**
|
|
55
|
+
* The anchored binary-qualification claim package (issue #3205): claim-package/2's exact
|
|
56
|
+
* qualification projection plus claim-package/4's `anchors` section, carried by
|
|
57
|
+
* `benchmark-product-public-bundle/7`. This is the "later allocation" both earlier guards named:
|
|
58
|
+
* /2 has no anchors slot and /4 has no qualification slot, so before this number existed an
|
|
59
|
+
* anchored run of a binary-instrument benchmark could not produce a claim at all. The allocation is
|
|
60
|
+
* an ADDITION — /1, /2, /3, and /4 keep their meanings and their bytes.
|
|
61
|
+
*/
|
|
62
|
+
export const ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/5";
|
|
63
|
+
/**
|
|
64
|
+
* The disclosed anchored binary-qualification claim package (issue #2839,
|
|
65
|
+
* disclosure-specification-record design §6.5/§6.6): claim-package/5 exactly, plus the
|
|
66
|
+
* `disclosure` section, carried by `benchmark-product-public-bundle/8`.
|
|
67
|
+
*
|
|
68
|
+
* The design reserved `/5` for its own disclosure allocation on the UNANCHORED qualified branch, on
|
|
69
|
+
* the premise (its §12.2) that anchoring and qualification could never combine. Issue #3205 both
|
|
70
|
+
* took `/5` and dissolved that premise, so per the design's own §6.5 rule — the implementation
|
|
71
|
+
* packet takes the then-next free numbers if a line has advanced — this is `/6`, and it stacks on
|
|
72
|
+
* the ANCHORED branch so the real flagship bundle can carry its disclosure record without giving up
|
|
73
|
+
* its anchor. The allocation is an ADDITION: /1, /2, /3, /4, and /5 keep their meanings and bytes.
|
|
74
|
+
*/
|
|
75
|
+
export const DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/6";
|
|
47
76
|
export const BINARY_QUALIFICATION_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
|
|
48
77
|
export const BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.1 <bundle-dir>";
|
|
78
|
+
/** Prompted-screening v2 claims require the verifier release that carries that admission surface. */
|
|
79
|
+
export const PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2.1 <bundle-dir>";
|
|
80
|
+
/** Previously materialized prompted bundles remain valid under their immutable 0.2.0 claim. */
|
|
81
|
+
export const LEGACY_PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2.0 <bundle-dir>";
|
|
82
|
+
export const PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2 <bundle-dir>";
|
|
49
83
|
const Sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, "must be a lowercase sha256 hex digest");
|
|
50
84
|
/** Mirrors `../run/preview-log.ts`'s own (unexported) `Rfc3339Schema` — restated here rather than
|
|
51
85
|
* reached across the module boundary for one regex. */
|
|
@@ -185,6 +219,8 @@ const ClaimPackageWireSchema = z.object({
|
|
|
185
219
|
z.literal(CLAIM_PACKAGE_SCHEMA_ID),
|
|
186
220
|
z.literal(BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID),
|
|
187
221
|
z.literal(ANCHORED_CLAIM_PACKAGE_SCHEMA_ID),
|
|
222
|
+
z.literal(ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID),
|
|
223
|
+
z.literal(DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID),
|
|
188
224
|
]),
|
|
189
225
|
scope: z.object({
|
|
190
226
|
draftId: z.string().min(1),
|
|
@@ -244,35 +280,70 @@ const ClaimPackageWireSchema = z.object({
|
|
|
244
280
|
* headline, comparison, threshold, selection, or ranking projection. */
|
|
245
281
|
qualification: z.unknown().optional(),
|
|
246
282
|
/** anchor-evidence §7.4: one entry per AnchorEvidence record the bundle carries, in record-digest
|
|
247
|
-
* order, each carrying only the facts embedded in the proof's own bytes. Present exactly on
|
|
248
|
-
* claim-package/4 — the schema-level refine below
|
|
249
|
-
*
|
|
283
|
+
* order, each carrying only the facts embedded in the proof's own bytes. Present exactly on the
|
|
284
|
+
* two anchored allocations, claim-package/4 and claim-package/5 — the schema-level refine below
|
|
285
|
+
* refuses it on /1 and /2, so an unanchored claim cannot grow an anchors section and an anchored
|
|
286
|
+
* one cannot be published without it. */
|
|
250
287
|
anchors: z.array(ClaimAnchorSchema).optional(),
|
|
288
|
+
/** disclosure-specification-record design §6.6: the sealed record's digest plus the facts embedded
|
|
289
|
+
* in its own bytes, each variable entry VERBATIM. Nothing here is summarized, counted, ranked, or
|
|
290
|
+
* reworded, and nothing here is derived from anything but the record. Present exactly on
|
|
291
|
+
* claim-package/6 — the refine below refuses it on every earlier allocation, so a claim cannot
|
|
292
|
+
* grow a disclosure section without moving to the closure whose check reads it. */
|
|
293
|
+
disclosure: ClaimDisclosureSectionSchema.optional(),
|
|
251
294
|
}).superRefine((claim, ctx) => {
|
|
252
|
-
|
|
295
|
+
// The two anchored allocations differ only in which method projection they carry: /4 takes the
|
|
296
|
+
// headline/comparison family, /5 (issue #3205) the binary qualification. Both carry the section.
|
|
297
|
+
// The disclosed allocation is the anchored binary one plus a section, so it inherits BOTH parents'
|
|
298
|
+
// rules by falling through every branch below that /5 falls through (issue #2839).
|
|
299
|
+
const disclosedClosure = claim.claimSchema === DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID;
|
|
300
|
+
if (!disclosedClosure && claim.disclosure !== undefined) {
|
|
301
|
+
ctx.addIssue({
|
|
302
|
+
code: "custom",
|
|
303
|
+
message: `only ${DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID} carries a disclosure section`,
|
|
304
|
+
path: ["disclosure"],
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (disclosedClosure && claim.disclosure === undefined) {
|
|
308
|
+
// Unlike `anchors`, this section has no legal EMPTY form: all six variables are structurally
|
|
309
|
+
// required, so a disclosed bundle with nothing to disclose is not a thing that exists. Omitting
|
|
310
|
+
// the section while claiming the closure would leave the check reading a record that no reader
|
|
311
|
+
// of the claim alone can see.
|
|
312
|
+
ctx.addIssue({
|
|
313
|
+
code: "custom",
|
|
314
|
+
message: `${DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID} must carry its disclosure section`,
|
|
315
|
+
path: ["disclosure"],
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
const anchoredClosure = claim.claimSchema === ANCHORED_CLAIM_PACKAGE_SCHEMA_ID
|
|
319
|
+
|| claim.claimSchema === ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID
|
|
320
|
+
// /6 is /5 plus a disclosure section, so it is anchored by inheritance: it carries the anchors
|
|
321
|
+
// section under the same presence rule, and an omitted one refuses identically.
|
|
322
|
+
|| disclosedClosure;
|
|
323
|
+
if (!anchoredClosure && claim.anchors !== undefined) {
|
|
253
324
|
ctx.addIssue({
|
|
254
325
|
code: "custom",
|
|
255
|
-
message: `only ${ANCHORED_CLAIM_PACKAGE_SCHEMA_ID}
|
|
326
|
+
message: `only ${ANCHORED_CLAIM_PACKAGE_SCHEMA_ID} and ${ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID} carry an anchors section`,
|
|
327
|
+
path: ["anchors"],
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (anchoredClosure && claim.anchors === undefined) {
|
|
331
|
+
// Present, not necessarily non-empty. An empty section is legal on exactly one bundle: one
|
|
332
|
+
// whose sealed Run declared anchoring intent that no carried anchor satisfies (§7.3). That
|
|
333
|
+
// bundle must still be on the anchored closure so the check that reports the absence runs,
|
|
334
|
+
// and its claim must therefore still state the closure's seven checks. What no claim may do
|
|
335
|
+
// is omit the section while claiming the closure, or carry one while claiming an earlier one.
|
|
336
|
+
ctx.addIssue({
|
|
337
|
+
code: "custom",
|
|
338
|
+
message: `${claim.claimSchema} must carry its anchors section, even when the section is empty`,
|
|
256
339
|
path: ["anchors"],
|
|
257
340
|
});
|
|
258
341
|
}
|
|
259
342
|
if (claim.claimSchema === ANCHORED_CLAIM_PACKAGE_SCHEMA_ID) {
|
|
260
|
-
if (claim.anchors === undefined) {
|
|
261
|
-
// Present, not necessarily non-empty. An empty section is legal on exactly one bundle: one
|
|
262
|
-
// whose sealed Run declared anchoring intent that no carried anchor satisfies (§7.3). That
|
|
263
|
-
// bundle must still be on the anchored closure so the check that reports the absence runs,
|
|
264
|
-
// and its claim must therefore still state the closure's seven checks. What no claim may do
|
|
265
|
-
// is omit the section while claiming the closure, or carry one while claiming an earlier one.
|
|
266
|
-
ctx.addIssue({
|
|
267
|
-
code: "custom",
|
|
268
|
-
message: `${ANCHORED_CLAIM_PACKAGE_SCHEMA_ID} must carry its anchors section, even when the section is empty`,
|
|
269
|
-
path: ["anchors"],
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
343
|
if (claim.qualification !== undefined) {
|
|
273
344
|
ctx.addIssue({
|
|
274
345
|
code: "custom",
|
|
275
|
-
message:
|
|
346
|
+
message: `the anchored binary-qualification closure is ${ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID}, not claim-package/4`,
|
|
276
347
|
path: ["qualification"],
|
|
277
348
|
});
|
|
278
349
|
}
|
|
@@ -361,9 +432,43 @@ const ClaimPackageWireSchema = z.object({
|
|
|
361
432
|
if (!exactResult) {
|
|
362
433
|
ctx.addIssue({ code: "custom", message: "qualification must exactly equal the Report's one F6 per-subject result", path: ["qualification"] });
|
|
363
434
|
}
|
|
364
|
-
if (claim.
|
|
365
|
-
||
|
|
366
|
-
|
|
435
|
+
if (claim.claimSchema === ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID
|
|
436
|
+
|| disclosedClosure) {
|
|
437
|
+
// No released reader before 0.2.1 understands `benchmark-product-public-bundle/7` or `/8`, so
|
|
438
|
+
// both allocations pin that line unconditionally rather than inheriting /2's prompted/unprompted
|
|
439
|
+
// split — a claim naming an older reader would be an instruction to fail.
|
|
440
|
+
const expectedChecks = disclosedClosure
|
|
441
|
+
? READER_DISCLOSED_VERIFICATION_CHECKS
|
|
442
|
+
: READER_ANCHORED_QUALIFICATION_VERIFICATION_CHECKS;
|
|
443
|
+
if (claim.verification.command !== PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND
|
|
444
|
+
|| claim.verification.compatibleCommand !== PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND) {
|
|
445
|
+
ctx.addIssue({ code: "custom", message: "anchored binary claim package must pin verifier 0.2.1/@0.2", path: ["verification"] });
|
|
446
|
+
}
|
|
447
|
+
if (claim.verification.checks.length !== expectedChecks.length
|
|
448
|
+
|| claim.verification.checks.some((check, index) => check !== expectedChecks[index])) {
|
|
449
|
+
ctx.addIssue({
|
|
450
|
+
code: "custom",
|
|
451
|
+
message: disclosedClosure
|
|
452
|
+
? "disclosed claim package must retain the seven anchored verification checks plus disclosure-specification, in order"
|
|
453
|
+
: "anchored binary claim package must retain the six frozen verification checks plus integrity-anchors, in order",
|
|
454
|
+
path: ["verification", "checks"],
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const prompted = claim.method.parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE;
|
|
460
|
+
const command = prompted
|
|
461
|
+
? PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND
|
|
462
|
+
: BINARY_QUALIFICATION_VERIFICATION_COMMAND;
|
|
463
|
+
const compatibleCommand = prompted
|
|
464
|
+
? PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND
|
|
465
|
+
: BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND;
|
|
466
|
+
const promptedCommandAccepted = prompted
|
|
467
|
+
&& (claim.verification.command === PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND
|
|
468
|
+
|| claim.verification.command === LEGACY_PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND);
|
|
469
|
+
if ((prompted ? !promptedCommandAccepted : claim.verification.command !== command)
|
|
470
|
+
|| claim.verification.compatibleCommand !== compatibleCommand) {
|
|
471
|
+
ctx.addIssue({ code: "custom", message: `binary claim package must pin verifier ${prompted ? "0.2.1 (or historical 0.2.0)/@0.2" : "0.1.0/@0.1"}`, path: ["verification"] });
|
|
367
472
|
}
|
|
368
473
|
if (claim.verification.checks.length !== READER_VERIFICATION_CHECKS.length
|
|
369
474
|
|| claim.verification.checks.some((check, index) => check !== READER_VERIFICATION_CHECKS[index])) {
|
|
@@ -390,7 +495,7 @@ function exactBinaryClaimControls(input) {
|
|
|
390
495
|
// control-shape failure. Neither judge field is ever set on an actual binary-instrument claim
|
|
391
496
|
// (`methodProjection`'s dispatch is exclusive), so admitting them here is defense in depth, not
|
|
392
497
|
// a widening any real claim exercises.
|
|
393
|
-
return exactKeys(input, ["claimSchema", "scope", "records", "method", "results", "completeness", "attrition", "conflicted", "assurance", "disclosures", "limitations", "venueHonesty", "verification", "rehearsal", "qualification", "anchors", "pairwiseDisagreement", "pairedMajorityDelta"])
|
|
498
|
+
return exactKeys(input, ["claimSchema", "scope", "records", "method", "results", "completeness", "attrition", "conflicted", "assurance", "disclosures", "limitations", "venueHonesty", "verification", "rehearsal", "qualification", "anchors", "disclosure", "pairwiseDisagreement", "pairedMajorityDelta"])
|
|
394
499
|
&& exactKeys(scope, ["draftId", "benchmarkSha256", "taskCount", "arms", "replicates", "venue"])
|
|
395
500
|
&& Array.isArray(scope.arms)
|
|
396
501
|
&& (scope.arms).every((arm) => exactKeys(arm, ["armId", "pinning"]))
|
|
@@ -405,9 +510,17 @@ function exactBinaryClaimControls(input) {
|
|
|
405
510
|
&& exactKeys(verification, ["command", "compatibleCommand", "checks", "trustRoot"])
|
|
406
511
|
&& (input.rehearsal === undefined || exactKeys(input.rehearsal, ["previewCount", "timestamps"]));
|
|
407
512
|
}
|
|
513
|
+
/** Both binary allocations pass through the same anti-conclusion control-shape gate: /5 is /2's
|
|
514
|
+
* projection plus an anchors section, so smuggling a ranking into it must fail identically. */
|
|
515
|
+
const BINARY_CLAIM_PACKAGE_SCHEMA_IDS = [
|
|
516
|
+
BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID,
|
|
517
|
+
ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID,
|
|
518
|
+
// /6 is /5 plus a section, so a ranking smuggled into it must fail identically (issue #2839).
|
|
519
|
+
DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID,
|
|
520
|
+
];
|
|
408
521
|
export const ClaimPackageSchema = z.preprocess((input) => {
|
|
409
522
|
if (typeof input === "object" && input !== null && !Array.isArray(input)
|
|
410
|
-
&& input.claimSchema
|
|
523
|
+
&& BINARY_CLAIM_PACKAGE_SCHEMA_IDS.includes(input.claimSchema)
|
|
411
524
|
&& !exactBinaryClaimControls(input)) {
|
|
412
525
|
return { claimSchema: "invalid-binary-claim-control-shape" };
|
|
413
526
|
}
|
|
@@ -609,6 +722,8 @@ function summedPinningUnverifiableCounts(perSubject) {
|
|
|
609
722
|
export const CLAIM_VERIFICATION_CHECKS = READER_VERIFICATION_CHECKS;
|
|
610
723
|
/** The anchored closure's list: the six frozen checks plus `integrity-anchors` (§8). */
|
|
611
724
|
export const ANCHORED_CLAIM_VERIFICATION_CHECKS = READER_ANCHORED_VERIFICATION_CHECKS;
|
|
725
|
+
/** The disclosed closure's list: the anchored seven plus `disclosure-specification` (design §7). */
|
|
726
|
+
export const DISCLOSED_CLAIM_VERIFICATION_CHECKS = READER_DISCLOSED_VERIFICATION_CHECKS;
|
|
612
727
|
export const PUBLIC_BUNDLE_VERIFICATION_COMMAND = READER_VERIFICATION_COMMAND;
|
|
613
728
|
/** The unconditional trust-root sentence, re-exported unchanged. It is DEFINED once beside its
|
|
614
729
|
* anchored replacement in `anchor-claims.ts`: one sentence written out twice, in two mirrored
|
|
@@ -635,6 +750,10 @@ export function buildClaimPackage(input) {
|
|
|
635
750
|
+ " — a claim stating primitives the sealed Run does not carry would be dishonest");
|
|
636
751
|
}
|
|
637
752
|
const projection = methodProjection(reportRecord);
|
|
753
|
+
// Prompted screening is an authenticated Run-level admission fact. Every report/claim emitted
|
|
754
|
+
// from that Run uses the v2 reader, including its companion method claims; the binary claim's
|
|
755
|
+
// own schema separately binds the same exact profile in its method parameters.
|
|
756
|
+
const promptedScreening = input.runRecord.analysisPlan?.some((entry) => entry.parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE) === true;
|
|
638
757
|
const disclosuresPerSubject = (reportRecord.disclosures?.perSubject ?? []);
|
|
639
758
|
const taskCount = new Set(input.matrixRecord.cells.map((cell) => cell.taskDigest)).size;
|
|
640
759
|
// anchor-evidence §7.4: the anchored closure is entered by the CALLER, by supplying the section
|
|
@@ -643,16 +762,32 @@ export function buildClaimPackage(input) {
|
|
|
643
762
|
// this builder produced before the feature existed.
|
|
644
763
|
const anchors = input.anchors ?? [];
|
|
645
764
|
const anchored = input.anchors !== undefined;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
765
|
+
// Strictly opt-in, exactly like `anchors`: a run with no sealed disclosure declaration produces
|
|
766
|
+
// the claim this builder produced before the feature existed, byte for byte (issue #2839).
|
|
767
|
+
const disclosure = input.disclosure;
|
|
768
|
+
// Four allocations across two independent axes (anchored yes/no × qualification yes/no). The
|
|
769
|
+
// fourth cell, anchored+qualification, is claim-package/5 (issue #3205); before it existed this
|
|
770
|
+
// pairing threw, which made anchoring and binary-instrument benchmarking mutually exclusive.
|
|
771
|
+
const anchoredQualification = anchored && projection.qualification !== undefined;
|
|
772
|
+
// The disclosed allocation is the anchored QUALIFICATION cell plus a section, and there is no
|
|
773
|
+
// other disclosed cell (issue #2839). A run publishes one bundle per analysis, and its sibling
|
|
774
|
+
// headline/comparison analyses project no qualification, so they have nowhere to put the section.
|
|
775
|
+
// Refusing here rather than dropping it silently is what makes the caller state which entry the
|
|
776
|
+
// record belongs to instead of discovering later that one bundle quietly lost it.
|
|
777
|
+
if (disclosure !== undefined && !anchoredQualification) {
|
|
778
|
+
throw new Error("claim package: only the anchored binary-qualification closure carries a disclosure section"
|
|
779
|
+
+ " — this projection has no qualification, and no other closure version expresses one");
|
|
649
780
|
}
|
|
650
781
|
return {
|
|
651
|
-
claimSchema:
|
|
652
|
-
?
|
|
653
|
-
:
|
|
654
|
-
?
|
|
655
|
-
:
|
|
782
|
+
claimSchema: anchoredQualification && disclosure !== undefined
|
|
783
|
+
? DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID
|
|
784
|
+
: anchoredQualification
|
|
785
|
+
? ANCHORED_BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID
|
|
786
|
+
: anchored
|
|
787
|
+
? ANCHORED_CLAIM_PACKAGE_SCHEMA_ID
|
|
788
|
+
: projection.qualification === undefined
|
|
789
|
+
? CLAIM_PACKAGE_SCHEMA_ID
|
|
790
|
+
: BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID,
|
|
656
791
|
scope: {
|
|
657
792
|
draftId: input.draftId,
|
|
658
793
|
benchmarkSha256: input.benchmarkSha256,
|
|
@@ -693,22 +828,36 @@ export function buildClaimPackage(input) {
|
|
|
693
828
|
limitations: [...(reportRecord.limitations ?? [])],
|
|
694
829
|
venueHonesty: input.venueHonesty,
|
|
695
830
|
verification: {
|
|
696
|
-
command:
|
|
697
|
-
?
|
|
698
|
-
:
|
|
699
|
-
?
|
|
700
|
-
:
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
831
|
+
command: anchoredQualification
|
|
832
|
+
? PUBLIC_BUNDLE_V7_VERIFICATION_COMMAND
|
|
833
|
+
: anchored
|
|
834
|
+
? PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND
|
|
835
|
+
: promptedScreening
|
|
836
|
+
? PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND
|
|
837
|
+
: projection.qualification === undefined
|
|
838
|
+
? PUBLIC_BUNDLE_VERIFICATION_COMMAND
|
|
839
|
+
: BINARY_QUALIFICATION_VERIFICATION_COMMAND,
|
|
840
|
+
compatibleCommand: anchoredQualification
|
|
841
|
+
? PUBLIC_BUNDLE_V7_COMPATIBLE_VERIFICATION_COMMAND
|
|
842
|
+
: anchored
|
|
843
|
+
? PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND
|
|
844
|
+
: promptedScreening
|
|
845
|
+
? PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND
|
|
846
|
+
: projection.qualification === undefined
|
|
847
|
+
? PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND
|
|
848
|
+
: BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND,
|
|
849
|
+
checks: anchoredQualification && disclosure !== undefined
|
|
850
|
+
? [...DISCLOSED_CLAIM_VERIFICATION_CHECKS]
|
|
851
|
+
: anchored ? [...ANCHORED_CLAIM_VERIFICATION_CHECKS] : [...CLAIM_VERIFICATION_CHECKS],
|
|
707
852
|
// §9.2: the trust-root sentence is replaced only by a governing lock anchor. A bundle whose
|
|
708
853
|
// only anchors are pending, or cover the Matrix alone, keeps the unconditional sentence.
|
|
709
854
|
trustRoot: anchoredTrustRoot(anchors),
|
|
710
855
|
},
|
|
711
856
|
...(anchored ? { anchors: anchors.map((anchor) => ({ ...anchor })) } : {}),
|
|
857
|
+
// Copied through, never rebuilt here: the section is `deriveDisclosureSpecification`'s output
|
|
858
|
+
// over the sealed record's exact bytes, and this builder is not entitled to a second opinion
|
|
859
|
+
// about what that record says (issue #2839, design §6.6).
|
|
860
|
+
...(disclosure === undefined ? {} : { disclosure }),
|
|
712
861
|
...(input.previewDisclosure !== undefined
|
|
713
862
|
? {
|
|
714
863
|
rehearsal: {
|