@colophon-claims/verify 0.2.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 +18 -8
- package/dist/admission/contracts.d.ts +241 -0
- package/dist/admission/contracts.js +116 -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 +1 -0
- package/dist/admission/verification.js +88 -42
- 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/claim-consistency.d.ts +8 -1
- package/dist/profile/claim-consistency.js +4 -4
- package/dist/profile/claim.d.ts +201 -2
- package/dist/profile/claim.js +178 -47
- package/dist/profile/disclosure.d.ts +273 -0
- package/dist/profile/disclosure.js +240 -0
- 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 +4 -3
- package/dist/schema.js +17 -0
- 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
package/README.md
CHANGED
|
@@ -8,17 +8,27 @@ npx @colophon-claims/verify@0.2 ./bundle
|
|
|
8
8
|
|
|
9
9
|
Use `--json` for machine-readable output. The reader runs the checks declared by the
|
|
10
10
|
bundle format, covering its manifest, evidence closure, calculations, report, and claim
|
|
11
|
-
consistency. Exit status is `0` when
|
|
12
|
-
`2` for usage or operational failures.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
consistency. Exit status is `0` when the bundle is valid for the format and profile it
|
|
12
|
+
declares, `1` for an invalid bundle, and `2` for usage or operational failures. A check a
|
|
13
|
+
profile defers is reported as deferred, never as passed, and never as a failure.
|
|
14
|
+
|
|
15
|
+
This 0.2 reader supports public bundle formats v2, v4, v5, v6, v7, and v8. It
|
|
16
|
+
intentionally rejects the unrelated accounting bundle v3. Formats v2 and v4 run six
|
|
17
|
+
checks; the evidence-native v5 and the two anchored formats, v6 and v7, run seven; the
|
|
18
|
+
disclosed v8 runs eight. The v7 format is the anchored binary-qualification closure —
|
|
19
|
+
v4's members plus v6's anchors — and v8 is v7 plus a sealed six-variable
|
|
20
|
+
disclosure-specification record and the `disclosure-specification` check. Both exist
|
|
21
|
+
only from this 0.2.1 release, so their bundles pin `@0.2.1` rather than the `@0.1` line
|
|
22
|
+
every earlier closure stamps.
|
|
23
|
+
The evidence-native v5 has two declared profiles, full-evidence and metadata-first;
|
|
24
|
+
this reader supports both. A metadata-first bundle carries the artifact digests without
|
|
25
|
+
the artifact bodies, so `artifact-integrity` reports `not fetched` rather than passing,
|
|
26
|
+
and the verdict line counts it out of the passed total. Every other check is complete.
|
|
17
27
|
Existing claim bundles retain their recorded verifier pins. Use this 0.2 reader
|
|
18
28
|
for prompted-screening v2 support and the compatible `@0.2` line for this
|
|
19
29
|
release.
|
|
20
|
-
For this
|
|
21
|
-
|
|
30
|
+
For this release, `@jinn-network/*` is pinned to the exact
|
|
31
|
+
`0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62` receipt.
|
|
22
32
|
It is not a floating `@canary` dependency and is not a stable stack release.
|
|
23
33
|
|
|
24
34
|
Verification opens no network connection, reads no account or API credential, and uploads
|
|
@@ -10,7 +10,10 @@ export declare const BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL: "https://spec.
|
|
|
10
10
|
export declare const SCREENING_TABLE_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-table/v1";
|
|
11
11
|
export declare const PROMPTED_SCREENING_PROCEDURE_PROTOCOL: "https://spec.jinn.network/binary-judgment/prompted-screening-procedure/v1";
|
|
12
12
|
export declare const SCREENING_POOL_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-pool/v1";
|
|
13
|
+
export declare const SCREENING_POOL_V2_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-pool/v2";
|
|
14
|
+
export declare const SCREENING_POOL_V2_RESERVE_SELECTION_PROTOCOL: "shared-slice-first-admissible/1";
|
|
13
15
|
export declare const SCREENING_SAMPLE_COMMITMENT_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1";
|
|
16
|
+
export declare const REGISTERED_SCREENING_SAMPLE_COMMITMENT_V1_SCHEMA: "https://colophon-claims.github.io/locomo-judge-report/sampling-commitment/v1";
|
|
14
17
|
export declare const SCREENING_TABLE_V2_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-table/v2";
|
|
15
18
|
export declare const SCREENING_REVEAL_RECEIPT_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
|
|
16
19
|
export declare const HUMAN_REVIEW_PACKET_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
|
|
@@ -337,6 +340,206 @@ export declare const ScreeningPoolV1Schema: z.ZodObject<{
|
|
|
337
340
|
sealedAt: z.ZodString;
|
|
338
341
|
}, z.core.$strict>;
|
|
339
342
|
export type ScreeningPoolV1 = z.infer<typeof ScreeningPoolV1Schema>;
|
|
343
|
+
export declare const ScreeningPoolV2ItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
344
|
+
screeningIdentitySha256: z.ZodString;
|
|
345
|
+
itemSha256: z.ZodString;
|
|
346
|
+
intendedLabel: z.ZodEnum<{
|
|
347
|
+
CORRECT: "CORRECT";
|
|
348
|
+
WRONG: "WRONG";
|
|
349
|
+
}>;
|
|
350
|
+
candidateClass: z.ZodEnum<{
|
|
351
|
+
correct: "correct";
|
|
352
|
+
"specific-wrong": "specific-wrong";
|
|
353
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
354
|
+
}>;
|
|
355
|
+
stratum: z.ZodEnum<{
|
|
356
|
+
"category-1": "category-1";
|
|
357
|
+
"category-2": "category-2";
|
|
358
|
+
"category-3": "category-3";
|
|
359
|
+
"category-4": "category-4";
|
|
360
|
+
}>;
|
|
361
|
+
poolPosition: z.ZodNumber;
|
|
362
|
+
sourceQuestionLineageId: z.ZodString;
|
|
363
|
+
poolKind: z.ZodLiteral<"main">;
|
|
364
|
+
slotId: z.ZodString;
|
|
365
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
366
|
+
screeningIdentitySha256: z.ZodString;
|
|
367
|
+
itemSha256: z.ZodString;
|
|
368
|
+
intendedLabel: z.ZodEnum<{
|
|
369
|
+
CORRECT: "CORRECT";
|
|
370
|
+
WRONG: "WRONG";
|
|
371
|
+
}>;
|
|
372
|
+
candidateClass: z.ZodEnum<{
|
|
373
|
+
correct: "correct";
|
|
374
|
+
"specific-wrong": "specific-wrong";
|
|
375
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
376
|
+
}>;
|
|
377
|
+
stratum: z.ZodEnum<{
|
|
378
|
+
"category-1": "category-1";
|
|
379
|
+
"category-2": "category-2";
|
|
380
|
+
"category-3": "category-3";
|
|
381
|
+
"category-4": "category-4";
|
|
382
|
+
}>;
|
|
383
|
+
poolPosition: z.ZodNumber;
|
|
384
|
+
sourceQuestionLineageId: z.ZodString;
|
|
385
|
+
poolKind: z.ZodLiteral<"reserve">;
|
|
386
|
+
reserveOrder: z.ZodNumber;
|
|
387
|
+
}, z.core.$strict>], "poolKind">;
|
|
388
|
+
export type ScreeningPoolV2Item = z.infer<typeof ScreeningPoolV2ItemSchema>;
|
|
389
|
+
/** A 240-main pool whose reserves are ordered shared slices within each class/stratum cell. */
|
|
390
|
+
export declare const ScreeningPoolV2Schema: z.ZodObject<{
|
|
391
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-pool/v2">;
|
|
392
|
+
reserveSelectionProtocol: z.ZodLiteral<"shared-slice-first-admissible/1">;
|
|
393
|
+
draftId: z.ZodString;
|
|
394
|
+
identityCommitmentSha256: z.ZodString;
|
|
395
|
+
items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
396
|
+
screeningIdentitySha256: z.ZodString;
|
|
397
|
+
itemSha256: z.ZodString;
|
|
398
|
+
intendedLabel: z.ZodEnum<{
|
|
399
|
+
CORRECT: "CORRECT";
|
|
400
|
+
WRONG: "WRONG";
|
|
401
|
+
}>;
|
|
402
|
+
candidateClass: z.ZodEnum<{
|
|
403
|
+
correct: "correct";
|
|
404
|
+
"specific-wrong": "specific-wrong";
|
|
405
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
406
|
+
}>;
|
|
407
|
+
stratum: z.ZodEnum<{
|
|
408
|
+
"category-1": "category-1";
|
|
409
|
+
"category-2": "category-2";
|
|
410
|
+
"category-3": "category-3";
|
|
411
|
+
"category-4": "category-4";
|
|
412
|
+
}>;
|
|
413
|
+
poolPosition: z.ZodNumber;
|
|
414
|
+
sourceQuestionLineageId: z.ZodString;
|
|
415
|
+
poolKind: z.ZodLiteral<"main">;
|
|
416
|
+
slotId: z.ZodString;
|
|
417
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
418
|
+
screeningIdentitySha256: z.ZodString;
|
|
419
|
+
itemSha256: z.ZodString;
|
|
420
|
+
intendedLabel: z.ZodEnum<{
|
|
421
|
+
CORRECT: "CORRECT";
|
|
422
|
+
WRONG: "WRONG";
|
|
423
|
+
}>;
|
|
424
|
+
candidateClass: z.ZodEnum<{
|
|
425
|
+
correct: "correct";
|
|
426
|
+
"specific-wrong": "specific-wrong";
|
|
427
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
428
|
+
}>;
|
|
429
|
+
stratum: z.ZodEnum<{
|
|
430
|
+
"category-1": "category-1";
|
|
431
|
+
"category-2": "category-2";
|
|
432
|
+
"category-3": "category-3";
|
|
433
|
+
"category-4": "category-4";
|
|
434
|
+
}>;
|
|
435
|
+
poolPosition: z.ZodNumber;
|
|
436
|
+
sourceQuestionLineageId: z.ZodString;
|
|
437
|
+
poolKind: z.ZodLiteral<"reserve">;
|
|
438
|
+
reserveOrder: z.ZodNumber;
|
|
439
|
+
}, z.core.$strict>], "poolKind">>;
|
|
440
|
+
sealedAt: z.ZodString;
|
|
441
|
+
}, z.core.$strict>;
|
|
442
|
+
export type ScreeningPoolV2 = z.infer<typeof ScreeningPoolV2Schema>;
|
|
443
|
+
export declare const ScreeningPoolSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
444
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-pool/v1">;
|
|
445
|
+
draftId: z.ZodString;
|
|
446
|
+
identityCommitmentSha256: z.ZodString;
|
|
447
|
+
items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
448
|
+
itemSha256: z.ZodString;
|
|
449
|
+
intendedLabel: z.ZodEnum<{
|
|
450
|
+
CORRECT: "CORRECT";
|
|
451
|
+
WRONG: "WRONG";
|
|
452
|
+
}>;
|
|
453
|
+
candidateClass: z.ZodEnum<{
|
|
454
|
+
correct: "correct";
|
|
455
|
+
"specific-wrong": "specific-wrong";
|
|
456
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
457
|
+
}>;
|
|
458
|
+
stratum: z.ZodEnum<{
|
|
459
|
+
"category-1": "category-1";
|
|
460
|
+
"category-2": "category-2";
|
|
461
|
+
"category-3": "category-3";
|
|
462
|
+
"category-4": "category-4";
|
|
463
|
+
}>;
|
|
464
|
+
poolPosition: z.ZodNumber;
|
|
465
|
+
slotId: z.ZodString;
|
|
466
|
+
poolKind: z.ZodLiteral<"main">;
|
|
467
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
468
|
+
itemSha256: z.ZodString;
|
|
469
|
+
intendedLabel: z.ZodEnum<{
|
|
470
|
+
CORRECT: "CORRECT";
|
|
471
|
+
WRONG: "WRONG";
|
|
472
|
+
}>;
|
|
473
|
+
candidateClass: z.ZodEnum<{
|
|
474
|
+
correct: "correct";
|
|
475
|
+
"specific-wrong": "specific-wrong";
|
|
476
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
477
|
+
}>;
|
|
478
|
+
stratum: z.ZodEnum<{
|
|
479
|
+
"category-1": "category-1";
|
|
480
|
+
"category-2": "category-2";
|
|
481
|
+
"category-3": "category-3";
|
|
482
|
+
"category-4": "category-4";
|
|
483
|
+
}>;
|
|
484
|
+
poolPosition: z.ZodNumber;
|
|
485
|
+
slotId: z.ZodString;
|
|
486
|
+
poolKind: z.ZodLiteral<"reserve">;
|
|
487
|
+
reserveOrder: z.ZodNumber;
|
|
488
|
+
}, z.core.$strict>], "poolKind">>;
|
|
489
|
+
sealedAt: z.ZodString;
|
|
490
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
491
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-pool/v2">;
|
|
492
|
+
reserveSelectionProtocol: z.ZodLiteral<"shared-slice-first-admissible/1">;
|
|
493
|
+
draftId: z.ZodString;
|
|
494
|
+
identityCommitmentSha256: z.ZodString;
|
|
495
|
+
items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
496
|
+
screeningIdentitySha256: z.ZodString;
|
|
497
|
+
itemSha256: z.ZodString;
|
|
498
|
+
intendedLabel: z.ZodEnum<{
|
|
499
|
+
CORRECT: "CORRECT";
|
|
500
|
+
WRONG: "WRONG";
|
|
501
|
+
}>;
|
|
502
|
+
candidateClass: z.ZodEnum<{
|
|
503
|
+
correct: "correct";
|
|
504
|
+
"specific-wrong": "specific-wrong";
|
|
505
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
506
|
+
}>;
|
|
507
|
+
stratum: z.ZodEnum<{
|
|
508
|
+
"category-1": "category-1";
|
|
509
|
+
"category-2": "category-2";
|
|
510
|
+
"category-3": "category-3";
|
|
511
|
+
"category-4": "category-4";
|
|
512
|
+
}>;
|
|
513
|
+
poolPosition: z.ZodNumber;
|
|
514
|
+
sourceQuestionLineageId: z.ZodString;
|
|
515
|
+
poolKind: z.ZodLiteral<"main">;
|
|
516
|
+
slotId: z.ZodString;
|
|
517
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
518
|
+
screeningIdentitySha256: z.ZodString;
|
|
519
|
+
itemSha256: z.ZodString;
|
|
520
|
+
intendedLabel: z.ZodEnum<{
|
|
521
|
+
CORRECT: "CORRECT";
|
|
522
|
+
WRONG: "WRONG";
|
|
523
|
+
}>;
|
|
524
|
+
candidateClass: z.ZodEnum<{
|
|
525
|
+
correct: "correct";
|
|
526
|
+
"specific-wrong": "specific-wrong";
|
|
527
|
+
"vague-topical-wrong": "vague-topical-wrong";
|
|
528
|
+
}>;
|
|
529
|
+
stratum: z.ZodEnum<{
|
|
530
|
+
"category-1": "category-1";
|
|
531
|
+
"category-2": "category-2";
|
|
532
|
+
"category-3": "category-3";
|
|
533
|
+
"category-4": "category-4";
|
|
534
|
+
}>;
|
|
535
|
+
poolPosition: z.ZodNumber;
|
|
536
|
+
sourceQuestionLineageId: z.ZodString;
|
|
537
|
+
poolKind: z.ZodLiteral<"reserve">;
|
|
538
|
+
reserveOrder: z.ZodNumber;
|
|
539
|
+
}, z.core.$strict>], "poolKind">>;
|
|
540
|
+
sealedAt: z.ZodString;
|
|
541
|
+
}, z.core.$strict>], "protocol">;
|
|
542
|
+
export type ScreeningPool = z.infer<typeof ScreeningPoolSchema>;
|
|
340
543
|
export declare const ScreeningSampleCommitmentV1Schema: z.ZodObject<{
|
|
341
544
|
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1">;
|
|
342
545
|
draftId: z.ZodString;
|
|
@@ -349,6 +552,42 @@ export declare const ScreeningSampleCommitmentV1Schema: z.ZodObject<{
|
|
|
349
552
|
committedAt: z.ZodString;
|
|
350
553
|
}, z.core.$strict>;
|
|
351
554
|
export type ScreeningSampleCommitmentV1 = z.infer<typeof ScreeningSampleCommitmentV1Schema>;
|
|
555
|
+
/**
|
|
556
|
+
* Exact public identity-only commitments made by an external registration repository. Unlike the
|
|
557
|
+
* internal v1 envelope, this record deliberately does not claim that the later label-bearing pool
|
|
558
|
+
* bridge existed at registration time. Its sorted identities, product-defined pool digest, seed,
|
|
559
|
+
* sample size, script digest, and timestamp are sufficient to replay the committed sample.
|
|
560
|
+
*/
|
|
561
|
+
export declare const RegisteredScreeningSampleCommitmentV1Schema: z.ZodObject<{
|
|
562
|
+
schema: z.ZodLiteral<"https://colophon-claims.github.io/locomo-judge-report/sampling-commitment/v1">;
|
|
563
|
+
candidateItemDigests: z.ZodArray<z.ZodString>;
|
|
564
|
+
committedAt: z.ZodString;
|
|
565
|
+
poolDigest: z.ZodString;
|
|
566
|
+
sampleSeed: z.ZodString;
|
|
567
|
+
sampleSize: z.ZodLiteral<72>;
|
|
568
|
+
samplingScriptSha256: z.ZodString;
|
|
569
|
+
}, z.core.$strict>;
|
|
570
|
+
export type RegisteredScreeningSampleCommitmentV1 = z.infer<typeof RegisteredScreeningSampleCommitmentV1Schema>;
|
|
571
|
+
export declare const ScreeningSampleCommitmentSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
572
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1">;
|
|
573
|
+
draftId: z.ZodString;
|
|
574
|
+
poolSha256: z.ZodString;
|
|
575
|
+
poolIdentityCommitmentSha256: z.ZodString;
|
|
576
|
+
samplingProcedure: z.ZodLiteral<"screening-sample/1">;
|
|
577
|
+
sampleSeed: z.ZodString;
|
|
578
|
+
sampleSize: z.ZodLiteral<72>;
|
|
579
|
+
sampleItemSha256s: z.ZodArray<z.ZodString>;
|
|
580
|
+
committedAt: z.ZodString;
|
|
581
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
582
|
+
schema: z.ZodLiteral<"https://colophon-claims.github.io/locomo-judge-report/sampling-commitment/v1">;
|
|
583
|
+
candidateItemDigests: z.ZodArray<z.ZodString>;
|
|
584
|
+
committedAt: z.ZodString;
|
|
585
|
+
poolDigest: z.ZodString;
|
|
586
|
+
sampleSeed: z.ZodString;
|
|
587
|
+
sampleSize: z.ZodLiteral<72>;
|
|
588
|
+
samplingScriptSha256: z.ZodString;
|
|
589
|
+
}, z.core.$strict>]>;
|
|
590
|
+
export type ScreeningSampleCommitment = z.infer<typeof ScreeningSampleCommitmentSchema>;
|
|
352
591
|
export declare const PromptedScreeningRowV2Schema: z.ZodObject<{
|
|
353
592
|
itemSha256: z.ZodString;
|
|
354
593
|
intendedLabel: z.ZodEnum<{
|
|
@@ -443,6 +682,7 @@ export declare const HumanReviewReplacementLedgerEntrySchema: z.ZodObject<{
|
|
|
443
682
|
"screening-indeterminate": "screening-indeterminate";
|
|
444
683
|
"screening-hand-excluded": "screening-hand-excluded";
|
|
445
684
|
}>;
|
|
685
|
+
receivingSlotId: z.ZodOptional<z.ZodString>;
|
|
446
686
|
reviewVerdictSha256s: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodString], null>>;
|
|
447
687
|
visibilityReceiptSha256s: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodString], null>>;
|
|
448
688
|
reviewerRosterSha256: z.ZodOptional<z.ZodString>;
|
|
@@ -466,6 +706,7 @@ export declare const HumanReviewReplacementLedgerSchema: z.ZodObject<{
|
|
|
466
706
|
"screening-indeterminate": "screening-indeterminate";
|
|
467
707
|
"screening-hand-excluded": "screening-hand-excluded";
|
|
468
708
|
}>;
|
|
709
|
+
receivingSlotId: z.ZodOptional<z.ZodString>;
|
|
469
710
|
reviewVerdictSha256s: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodString], null>>;
|
|
470
711
|
visibilityReceiptSha256s: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodString], null>>;
|
|
471
712
|
reviewerRosterSha256: z.ZodOptional<z.ZodString>;
|
|
@@ -13,7 +13,10 @@ export const BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL = "https://spec.jinn.ne
|
|
|
13
13
|
export const SCREENING_TABLE_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-table/v1";
|
|
14
14
|
export const PROMPTED_SCREENING_PROCEDURE_PROTOCOL = "https://spec.jinn.network/binary-judgment/prompted-screening-procedure/v1";
|
|
15
15
|
export const SCREENING_POOL_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-pool/v1";
|
|
16
|
+
export const SCREENING_POOL_V2_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-pool/v2";
|
|
17
|
+
export const SCREENING_POOL_V2_RESERVE_SELECTION_PROTOCOL = "shared-slice-first-admissible/1";
|
|
16
18
|
export const SCREENING_SAMPLE_COMMITMENT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1";
|
|
19
|
+
export const REGISTERED_SCREENING_SAMPLE_COMMITMENT_V1_SCHEMA = "https://colophon-claims.github.io/locomo-judge-report/sampling-commitment/v1";
|
|
17
20
|
export const SCREENING_TABLE_V2_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-table/v2";
|
|
18
21
|
export const SCREENING_REVEAL_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
|
|
19
22
|
export const HUMAN_REVIEW_PACKET_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
|
|
@@ -320,6 +323,90 @@ export const ScreeningPoolV1Schema = z.strictObject({
|
|
|
320
323
|
ctx.addIssue({ code: "custom", path: ["items"], message: `main pool must contain 20 ${candidateClass}/${stratum} items` });
|
|
321
324
|
}
|
|
322
325
|
});
|
|
326
|
+
const ScreeningPoolV2CommonItemSchema = z.strictObject({
|
|
327
|
+
/** Privacy-preserving identity committed before screening outcomes were observed. */
|
|
328
|
+
screeningIdentitySha256: DigestSchema,
|
|
329
|
+
/** Digest of the exact later Colophon F0 item bytes. */
|
|
330
|
+
itemSha256: DigestSchema,
|
|
331
|
+
intendedLabel: BinaryJudgmentTruthLabelSchema,
|
|
332
|
+
candidateClass: z.enum(SCREENING_POOL_CANDIDATE_CLASSES),
|
|
333
|
+
stratum: z.enum(SCREENING_POOL_STRATA),
|
|
334
|
+
poolPosition: z.number().int().positive(),
|
|
335
|
+
sourceQuestionLineageId: IdentitySchema,
|
|
336
|
+
});
|
|
337
|
+
export const ScreeningPoolV2ItemSchema = z.discriminatedUnion("poolKind", [
|
|
338
|
+
ScreeningPoolV2CommonItemSchema.extend({
|
|
339
|
+
poolKind: z.literal("main"),
|
|
340
|
+
slotId: z.string().regex(/^slot-[0-9]{3}$/u),
|
|
341
|
+
}),
|
|
342
|
+
ScreeningPoolV2CommonItemSchema.extend({
|
|
343
|
+
poolKind: z.literal("reserve"),
|
|
344
|
+
reserveOrder: z.number().int().positive(),
|
|
345
|
+
}),
|
|
346
|
+
]);
|
|
347
|
+
/** A 240-main pool whose reserves are ordered shared slices within each class/stratum cell. */
|
|
348
|
+
export const ScreeningPoolV2Schema = z.strictObject({
|
|
349
|
+
protocol: z.literal(SCREENING_POOL_V2_PROTOCOL),
|
|
350
|
+
reserveSelectionProtocol: z.literal(SCREENING_POOL_V2_RESERVE_SELECTION_PROTOCOL),
|
|
351
|
+
draftId: IdentitySchema,
|
|
352
|
+
identityCommitmentSha256: DigestSchema,
|
|
353
|
+
items: z.array(ScreeningPoolV2ItemSchema).length(664),
|
|
354
|
+
sealedAt: TimestampSchema,
|
|
355
|
+
}).superRefine((pool, ctx) => {
|
|
356
|
+
const identities = new Set();
|
|
357
|
+
const itemDigests = new Set();
|
|
358
|
+
const mains = pool.items.filter((item) => item.poolKind === "main");
|
|
359
|
+
const mainSlots = new Set();
|
|
360
|
+
const mainLineages = new Set();
|
|
361
|
+
for (const [index, item] of pool.items.entries()) {
|
|
362
|
+
if (item.poolPosition !== index + 1)
|
|
363
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "poolPosition"], message: "poolPosition must be contiguous and match array order" });
|
|
364
|
+
if (identities.has(item.screeningIdentitySha256))
|
|
365
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "screeningIdentitySha256"], message: "screeningIdentitySha256 must be unique" });
|
|
366
|
+
identities.add(item.screeningIdentitySha256);
|
|
367
|
+
if (itemDigests.has(item.itemSha256))
|
|
368
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "itemSha256"], message: "itemSha256 must be unique" });
|
|
369
|
+
itemDigests.add(item.itemSha256);
|
|
370
|
+
const expectedLabel = item.candidateClass === "correct" ? "CORRECT" : "WRONG";
|
|
371
|
+
if (item.intendedLabel !== expectedLabel)
|
|
372
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "intendedLabel"], message: "intendedLabel does not derive from candidateClass" });
|
|
373
|
+
if (item.poolKind === "main") {
|
|
374
|
+
if (mainSlots.has(item.slotId))
|
|
375
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "slotId"], message: "main slotId must be unique" });
|
|
376
|
+
mainSlots.add(item.slotId);
|
|
377
|
+
if (mainLineages.has(item.sourceQuestionLineageId))
|
|
378
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "sourceQuestionLineageId"], message: "main sourceQuestionLineageId must be unique" });
|
|
379
|
+
mainLineages.add(item.sourceQuestionLineageId);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (mains.length !== 240)
|
|
383
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: "pool must contain exactly 240 main items" });
|
|
384
|
+
const lastMainPosition = Math.max(...mains.map((item) => item.poolPosition));
|
|
385
|
+
for (const [index, item] of pool.items.entries()) {
|
|
386
|
+
if (item.poolKind === "reserve" && item.poolPosition <= lastMainPosition)
|
|
387
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "poolPosition"], message: "all shared reserves must follow all main items in pool order" });
|
|
388
|
+
}
|
|
389
|
+
const expectedSlotIds = Array.from({ length: 240 }, (_, index) => `slot-${(index + 1).toString().padStart(3, "0")}`);
|
|
390
|
+
const actualSlotIds = [...mainSlots].sort(compareCodeUnitStrings);
|
|
391
|
+
if (actualSlotIds.length !== expectedSlotIds.length || actualSlotIds.some((value, index) => value !== expectedSlotIds[index]))
|
|
392
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: "main slots must be exactly slot-001 through slot-240" });
|
|
393
|
+
for (const candidateClass of SCREENING_POOL_CANDIDATE_CLASSES)
|
|
394
|
+
for (const stratum of SCREENING_POOL_STRATA) {
|
|
395
|
+
if (mains.filter((item) => item.candidateClass === candidateClass && item.stratum === stratum).length !== 20)
|
|
396
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `main pool must contain 20 ${candidateClass}/${stratum} items` });
|
|
397
|
+
const reserves = pool.items
|
|
398
|
+
.filter((item) => item.poolKind === "reserve" && item.candidateClass === candidateClass && item.stratum === stratum)
|
|
399
|
+
.sort((left, right) => left.reserveOrder - right.reserveOrder);
|
|
400
|
+
for (const [index, reserve] of reserves.entries()) {
|
|
401
|
+
if (reserve.reserveOrder !== index + 1)
|
|
402
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `${candidateClass}/${stratum} reserveOrder must be contiguous and unique` });
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
export const ScreeningPoolSchema = z.discriminatedUnion("protocol", [
|
|
407
|
+
ScreeningPoolV1Schema,
|
|
408
|
+
ScreeningPoolV2Schema,
|
|
409
|
+
]);
|
|
323
410
|
export const ScreeningSampleCommitmentV1Schema = z.strictObject({
|
|
324
411
|
protocol: z.literal(SCREENING_SAMPLE_COMMITMENT_PROTOCOL),
|
|
325
412
|
draftId: IdentitySchema,
|
|
@@ -336,6 +423,32 @@ export const ScreeningSampleCommitmentV1Schema = z.strictObject({
|
|
|
336
423
|
}),
|
|
337
424
|
committedAt: TimestampSchema,
|
|
338
425
|
});
|
|
426
|
+
/**
|
|
427
|
+
* Exact public identity-only commitments made by an external registration repository. Unlike the
|
|
428
|
+
* internal v1 envelope, this record deliberately does not claim that the later label-bearing pool
|
|
429
|
+
* bridge existed at registration time. Its sorted identities, product-defined pool digest, seed,
|
|
430
|
+
* sample size, script digest, and timestamp are sufficient to replay the committed sample.
|
|
431
|
+
*/
|
|
432
|
+
export const RegisteredScreeningSampleCommitmentV1Schema = z.strictObject({
|
|
433
|
+
schema: z.literal(REGISTERED_SCREENING_SAMPLE_COMMITMENT_V1_SCHEMA),
|
|
434
|
+
candidateItemDigests: z.array(DigestSchema).length(664),
|
|
435
|
+
committedAt: TimestampSchema,
|
|
436
|
+
poolDigest: DigestSchema,
|
|
437
|
+
sampleSeed: z.string().min(1),
|
|
438
|
+
sampleSize: z.literal(72),
|
|
439
|
+
samplingScriptSha256: DigestSchema,
|
|
440
|
+
}).superRefine((commitment, ctx) => {
|
|
441
|
+
for (let index = 1; index < commitment.candidateItemDigests.length; index += 1) {
|
|
442
|
+
if (compareCodeUnitStrings(commitment.candidateItemDigests[index - 1], commitment.candidateItemDigests[index]) >= 0) {
|
|
443
|
+
ctx.addIssue({ code: "custom", path: ["candidateItemDigests"], message: "registered identities must be sorted and unique" });
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
export const ScreeningSampleCommitmentSchema = z.union([
|
|
449
|
+
ScreeningSampleCommitmentV1Schema,
|
|
450
|
+
RegisteredScreeningSampleCommitmentV1Schema,
|
|
451
|
+
]);
|
|
339
452
|
const ScreeningDecisionSchema = z.enum(["CORRECT", "WRONG", "UNSURE"]);
|
|
340
453
|
const RitsuScreeningDecisionSchema = z.discriminatedUnion("checked", [
|
|
341
454
|
z.strictObject({ checked: z.literal(false) }),
|
|
@@ -396,6 +509,9 @@ export const HumanReviewReplacementLedgerEntrySchema = z.strictObject({
|
|
|
396
509
|
excludedPoolPosition: z.number().int().positive(),
|
|
397
510
|
replacementPoolPosition: z.number().int().positive(),
|
|
398
511
|
reason: z.enum([...HUMAN_REVIEW_LEDGER_REASONS, ...SCREENING_LEDGER_REASONS]),
|
|
512
|
+
// Required by closure replay for shared-slice pool/v2 replacements. It names the main slot that
|
|
513
|
+
// receives the reserve; the reserve itself carries no static slot ownership.
|
|
514
|
+
receivingSlotId: z.string().regex(/^slot-[0-9]{3}$/u).optional(),
|
|
399
515
|
// Per-item two-human apparatus (spec §6.9 deliberately drops it for the screened branch):
|
|
400
516
|
// present if and only if `reason` is one of the three two-human reasons above.
|
|
401
517
|
reviewVerdictSha256s: SortedUniqueDigestPairSchema.optional(),
|
package/dist/admission/index.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ScreeningSampleCommitment } from "./contracts.js";
|
|
2
|
+
export interface PromptedScreeningCommitmentView {
|
|
3
|
+
readonly committedAt: string;
|
|
4
|
+
readonly poolIdentityCommitmentSha256: string;
|
|
5
|
+
readonly sampleSeed: string;
|
|
6
|
+
readonly sampleSize: 72;
|
|
7
|
+
readonly registeredIdentitySha256s?: readonly string[];
|
|
8
|
+
readonly samplingScriptSha256?: string;
|
|
9
|
+
readonly sampleItemSha256s?: readonly string[];
|
|
10
|
+
readonly draftId?: string;
|
|
11
|
+
readonly poolSha256?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse the two exact wire encodings. Internal Colophon envelopes use bare canonical JSON;
|
|
15
|
+
* external registration files use the canonical one-record JSONL form with exactly one final LF.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseScreeningSampleCommitmentBytes(bytes: Uint8Array): ScreeningSampleCommitment;
|
|
18
|
+
/** Normalize the original internal envelope and exact external registration shape for replay. */
|
|
19
|
+
export declare function promptedScreeningCommitmentView(commitment: ScreeningSampleCommitment): PromptedScreeningCommitmentView;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { canonicalJsonBytes } from "@jinn-network/task-execution-profiles";
|
|
3
|
+
import { ScreeningSampleCommitmentSchema, } from "./contracts.js";
|
|
4
|
+
function sameBytes(left, right) {
|
|
5
|
+
return left.byteLength === right.byteLength && left.every((byte, index) => byte === right[index]);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse the two exact wire encodings. Internal Colophon envelopes use bare canonical JSON;
|
|
9
|
+
* external registration files use the canonical one-record JSONL form with exactly one final LF.
|
|
10
|
+
*/
|
|
11
|
+
export function parseScreeningSampleCommitmentBytes(bytes) {
|
|
12
|
+
let input;
|
|
13
|
+
try {
|
|
14
|
+
input = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
throw new TypeError("screening sample commitment is not UTF-8 JSON");
|
|
18
|
+
}
|
|
19
|
+
const parsed = ScreeningSampleCommitmentSchema.safeParse(input);
|
|
20
|
+
if (!parsed.success)
|
|
21
|
+
throw new TypeError(`screening sample commitment failed its closed schema: ${parsed.error.message}`);
|
|
22
|
+
const canonical = canonicalJsonBytes(parsed.data);
|
|
23
|
+
const expected = "candidateItemDigests" in parsed.data
|
|
24
|
+
? new Uint8Array([...canonical, 0x0a])
|
|
25
|
+
: canonical;
|
|
26
|
+
if (!sameBytes(bytes, expected)) {
|
|
27
|
+
throw new TypeError("screening sample commitment is not in its exact canonical wire encoding");
|
|
28
|
+
}
|
|
29
|
+
return parsed.data;
|
|
30
|
+
}
|
|
31
|
+
/** Normalize the original internal envelope and exact external registration shape for replay. */
|
|
32
|
+
export function promptedScreeningCommitmentView(commitment) {
|
|
33
|
+
if (!("candidateItemDigests" in commitment)) {
|
|
34
|
+
return {
|
|
35
|
+
committedAt: commitment.committedAt,
|
|
36
|
+
poolIdentityCommitmentSha256: commitment.poolIdentityCommitmentSha256,
|
|
37
|
+
sampleSeed: commitment.sampleSeed,
|
|
38
|
+
sampleSize: commitment.sampleSize,
|
|
39
|
+
sampleItemSha256s: commitment.sampleItemSha256s,
|
|
40
|
+
draftId: commitment.draftId,
|
|
41
|
+
poolSha256: commitment.poolSha256,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
committedAt: commitment.committedAt,
|
|
46
|
+
poolIdentityCommitmentSha256: commitment.poolDigest,
|
|
47
|
+
sampleSeed: commitment.sampleSeed,
|
|
48
|
+
sampleSize: commitment.sampleSize,
|
|
49
|
+
registeredIdentitySha256s: commitment.candidateItemDigests,
|
|
50
|
+
samplingScriptSha256: commitment.samplingScriptSha256,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type PromptedScreeningRowV2, type ScreeningPool } from "./contracts.js";
|
|
2
|
+
type PoolItem = ScreeningPool["items"][number];
|
|
3
|
+
type MainItem = Extract<PoolItem, {
|
|
4
|
+
poolKind: "main";
|
|
5
|
+
}>;
|
|
6
|
+
type ReserveItem = Extract<PoolItem, {
|
|
7
|
+
poolKind: "reserve";
|
|
8
|
+
}>;
|
|
9
|
+
export interface PromptedScreeningReplacement {
|
|
10
|
+
readonly excludedMain: MainItem;
|
|
11
|
+
readonly replacement: ReserveItem;
|
|
12
|
+
readonly receivingSlotId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PromptedScreeningSelection {
|
|
15
|
+
readonly winners: readonly PoolItem[];
|
|
16
|
+
readonly replacements: readonly PromptedScreeningReplacement[];
|
|
17
|
+
readonly participatingItemSha256s: ReadonlySet<string>;
|
|
18
|
+
}
|
|
19
|
+
export declare class PromptedScreeningSelectionError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
/** Deterministic prompted-screening winner selection shared by the producer and portable replay. */
|
|
23
|
+
export declare function selectPromptedScreeningPool(pool: ScreeningPool, rows: ReadonlyMap<string, PromptedScreeningRowV2>): PromptedScreeningSelection;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { compareCodeUnitStrings } from "@jinn-network/task-execution-profiles";
|
|
3
|
+
import { SCREENING_POOL_V2_PROTOCOL, } from "./contracts.js";
|
|
4
|
+
export class PromptedScreeningSelectionError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "PromptedScreeningSelectionError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function admitted(row) {
|
|
11
|
+
const agreed = row.screeningVerdict !== "UNSURE" && row.screeningVerdict === row.intendedLabel;
|
|
12
|
+
return row.ritsuDecision.checked ? row.ritsuDecision.verdict === "confirm" : agreed;
|
|
13
|
+
}
|
|
14
|
+
function v1Selection(pool, rows) {
|
|
15
|
+
const winners = [];
|
|
16
|
+
const replacements = [];
|
|
17
|
+
const participating = new Set();
|
|
18
|
+
const slotIds = [...new Set(pool.items.map((item) => item.slotId))].sort(compareCodeUnitStrings);
|
|
19
|
+
for (const slotId of slotIds) {
|
|
20
|
+
const slotItems = pool.items.filter((item) => item.slotId === slotId);
|
|
21
|
+
const main = slotItems.find((item) => item.poolKind === "main");
|
|
22
|
+
const reserves = slotItems
|
|
23
|
+
.filter((item) => item.poolKind === "reserve")
|
|
24
|
+
.sort((left, right) => left.reserveOrder - right.reserveOrder);
|
|
25
|
+
const winner = [main, ...reserves].find((item) => admitted(rows.get(item.itemSha256)));
|
|
26
|
+
if (winner === undefined)
|
|
27
|
+
throw new PromptedScreeningSelectionError(`${slotId} has no admissible main or reserve candidate`);
|
|
28
|
+
winners.push(winner);
|
|
29
|
+
participating.add(winner.itemSha256);
|
|
30
|
+
if (winner.poolKind === "reserve") {
|
|
31
|
+
participating.add(main.itemSha256);
|
|
32
|
+
replacements.push({ excludedMain: main, replacement: winner, receivingSlotId: slotId });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { winners, replacements, participatingItemSha256s: participating };
|
|
36
|
+
}
|
|
37
|
+
function v2Selection(pool, rows) {
|
|
38
|
+
const mains = pool.items
|
|
39
|
+
.filter((item) => item.poolKind === "main")
|
|
40
|
+
.sort((left, right) => compareCodeUnitStrings(left.slotId, right.slotId));
|
|
41
|
+
const winners = [];
|
|
42
|
+
const replacements = [];
|
|
43
|
+
const participating = new Set();
|
|
44
|
+
const activeLineages = new Set();
|
|
45
|
+
for (const main of mains) {
|
|
46
|
+
if (!admitted(rows.get(main.itemSha256)))
|
|
47
|
+
continue;
|
|
48
|
+
if (activeLineages.has(main.sourceQuestionLineageId)) {
|
|
49
|
+
throw new PromptedScreeningSelectionError(`admitted mains duplicate source-question lineage ${main.sourceQuestionLineageId}`);
|
|
50
|
+
}
|
|
51
|
+
activeLineages.add(main.sourceQuestionLineageId);
|
|
52
|
+
winners.push(main);
|
|
53
|
+
participating.add(main.itemSha256);
|
|
54
|
+
}
|
|
55
|
+
for (const main of mains) {
|
|
56
|
+
if (admitted(rows.get(main.itemSha256)))
|
|
57
|
+
continue;
|
|
58
|
+
const reserves = pool.items
|
|
59
|
+
.filter((item) => item.poolKind === "reserve"
|
|
60
|
+
&& item.candidateClass === main.candidateClass
|
|
61
|
+
&& item.stratum === main.stratum)
|
|
62
|
+
.sort((left, right) => left.reserveOrder - right.reserveOrder);
|
|
63
|
+
const replacement = reserves.find((reserve) => admitted(rows.get(reserve.itemSha256))
|
|
64
|
+
&& !activeLineages.has(reserve.sourceQuestionLineageId));
|
|
65
|
+
if (replacement === undefined) {
|
|
66
|
+
throw new PromptedScreeningSelectionError(`${main.slotId} has no admissible unused-lineage reserve in ${main.candidateClass}/${main.stratum}`);
|
|
67
|
+
}
|
|
68
|
+
activeLineages.add(replacement.sourceQuestionLineageId);
|
|
69
|
+
winners.push(replacement);
|
|
70
|
+
participating.add(main.itemSha256);
|
|
71
|
+
participating.add(replacement.itemSha256);
|
|
72
|
+
replacements.push({ excludedMain: main, replacement, receivingSlotId: main.slotId });
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
winners: winners.sort((left, right) => left.poolPosition - right.poolPosition),
|
|
76
|
+
replacements,
|
|
77
|
+
participatingItemSha256s: participating,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** Deterministic prompted-screening winner selection shared by the producer and portable replay. */
|
|
81
|
+
export function selectPromptedScreeningPool(pool, rows) {
|
|
82
|
+
return pool.protocol === SCREENING_POOL_V2_PROTOCOL
|
|
83
|
+
? v2Selection(pool, rows)
|
|
84
|
+
: v1Selection(pool, rows);
|
|
85
|
+
}
|