@colophon-claims/verify 0.1.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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Verify a public Colophon claim bundle without the Colophon app or any execution runtime:
4
4
 
5
5
  ```sh
6
- npx @colophon-claims/verify@0.1 ./bundle
6
+ npx @colophon-claims/verify@0.2 ./bundle
7
7
  ```
8
8
 
9
9
  Use `--json` for machine-readable output. The reader runs the checks declared by the
@@ -11,11 +11,15 @@ bundle format, covering its manifest, evidence closure, calculations, report, an
11
11
  consistency. Exit status is `0` when every check passes, `1` for an invalid bundle, and
12
12
  `2` for usage or operational failures.
13
13
 
14
- This 0.1 reader supports public bundle formats v2, v4, v5, and v6. It intentionally
14
+ This 0.2 reader supports public bundle formats v2, v4, v5, and v6. It intentionally
15
15
  rejects the unrelated accounting bundle v3. Formats v2 and v4 run six checks; the
16
16
  evidence-native v5 and anchored v6 formats run seven.
17
- New claims stamp `npx @colophon-claims/verify@0.1.0` and the compatible
18
- `@0.1` line.
17
+ Existing claim bundles retain their recorded verifier pins. Use this 0.2 reader
18
+ for prompted-screening v2 support and the compatible `@0.2` line for this
19
+ release.
20
+ For this one-time prompted-screening v2 release, `@jinn-network/*` is pinned to
21
+ the exact `0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50` receipt.
22
+ It is not a floating `@canary` dependency and is not a stable stack release.
19
23
 
20
24
  Verification opens no network connection, reads no account or API credential, and uploads
21
25
  nothing. It checks the bundle's integrity, evidence closure, calculations, report, and claim
@@ -8,6 +8,10 @@ export declare const HUMAN_REVIEW_REPLACEMENT_LEDGER_PROTOCOL: "https://spec.jin
8
8
  export declare const HUMAN_REVIEW_OPERATOR_ASSERTION_PROTOCOL: "https://spec.jinn.network/binary-judgment/operator-truth-assertion/v1";
9
9
  export declare const BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL: "https://spec.jinn.network/binary-judgment/admission-manifest/v1";
10
10
  export declare const SCREENING_TABLE_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-table/v1";
11
+ export declare const PROMPTED_SCREENING_PROCEDURE_PROTOCOL: "https://spec.jinn.network/binary-judgment/prompted-screening-procedure/v1";
12
+ export declare const SCREENING_POOL_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-pool/v1";
13
+ export declare const SCREENING_SAMPLE_COMMITMENT_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1";
14
+ export declare const SCREENING_TABLE_V2_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-table/v2";
11
15
  export declare const SCREENING_REVEAL_RECEIPT_PROTOCOL: "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
12
16
  export declare const HUMAN_REVIEW_PACKET_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
13
17
  export declare const HUMAN_REVIEW_RESPONSE_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.human-review-response.v1+json";
@@ -16,6 +20,7 @@ export declare const HUMAN_REVIEW_ROSTER_MEDIA_TYPE: "application/vnd.jinn.binar
16
20
  export declare const HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.reveal-receipt.v1+json";
17
21
  export declare const HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.operator-truth-assertion.v1+json";
18
22
  export declare const SCREENING_TABLE_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.screening-table.v1+json";
23
+ export declare const SCREENING_TABLE_V2_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.screening-table.v2+json";
19
24
  export declare const SCREENING_REVEAL_RECEIPT_MEDIA_TYPE: "application/vnd.jinn.binary-judgment.screening-reveal-receipt.v1+json";
20
25
  export declare const HUMAN_REVIEW_OMITTED_FIELDS: readonly ["instrumentIdentity", "candidateClass", "stratum", "otherReview", "postRunOutcomes"];
21
26
  export declare const HumanReviewPacketSchema: z.ZodObject<{
@@ -186,6 +191,243 @@ export declare const ScreeningTableSchema: z.ZodObject<{
186
191
  sealedAt: z.ZodString;
187
192
  }, z.core.$strict>;
188
193
  export type ScreeningTable = z.infer<typeof ScreeningTableSchema>;
194
+ export declare const PROMPTED_SCREENING_PROFILE: "prompted-codex-screening/v1";
195
+ export declare const PROMPTED_SCREENING_LIMITATIONS: readonly ["prompt-compliance-not-machine-verified", "provider-execution-not-machine-verified", "transcript-provenance-not-machine-verified", "mutable-model-alias-weights-not-machine-verified"];
196
+ /** Closed, machine-checkable orchestration metadata. Prompt and transcript bytes stay opaque. */
197
+ export declare const PromptedScreeningProcedureV1Schema: z.ZodObject<{
198
+ protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/prompted-screening-procedure/v1">;
199
+ procedureId: z.ZodLiteral<"prompted-codex-screening/v1">;
200
+ coordinatorPromptSha256: z.ZodString;
201
+ coordinator: z.ZodObject<{
202
+ alias: z.ZodLiteral<"Sol">;
203
+ model: z.ZodLiteral<"gpt-5.6-sol">;
204
+ reasoningEffort: z.ZodLiteral<"high">;
205
+ mayOrchestrate: z.ZodLiteral<true>;
206
+ }, z.core.$strict>;
207
+ judgmentAgents: z.ZodTuple<[z.ZodObject<{
208
+ alias: z.ZodLiteral<"Luna">;
209
+ model: z.ZodLiteral<"gpt-5.6-luna">;
210
+ reasoningEffort: z.ZodLiteral<"medium" | "high">;
211
+ maxBatchSize: z.ZodLiteral<32>;
212
+ }, z.core.$strict>, z.ZodObject<{
213
+ alias: z.ZodLiteral<"Terra">;
214
+ model: z.ZodLiteral<"gpt-5.6-terra">;
215
+ reasoningEffort: z.ZodLiteral<"medium" | "high">;
216
+ maxBatchSize: z.ZodLiteral<16>;
217
+ }, z.core.$strict>, z.ZodObject<{
218
+ alias: z.ZodLiteral<"Sol">;
219
+ model: z.ZodLiteral<"gpt-5.6-sol">;
220
+ reasoningEffort: z.ZodLiteral<"medium" | "high">;
221
+ maxBatchSize: z.ZodLiteral<8>;
222
+ }, z.core.$strict>], null>;
223
+ toolPolicy: z.ZodObject<{
224
+ coordinator: z.ZodLiteral<"orchestration-only">;
225
+ judgmentAgents: z.ZodObject<{
226
+ web: z.ZodLiteral<false>;
227
+ shell: z.ZodLiteral<false>;
228
+ repository: z.ZodLiteral<false>;
229
+ search: z.ZodLiteral<false>;
230
+ }, z.core.$strict>;
231
+ }, z.core.$strict>;
232
+ output: z.ZodObject<{
233
+ alphabet: z.ZodTuple<[z.ZodLiteral<"CORRECT">, z.ZodLiteral<"WRONG">, z.ZodLiteral<"UNSURE">], null>;
234
+ invalidOutputDecision: z.ZodLiteral<"UNSURE">;
235
+ }, z.core.$strict>;
236
+ retry: z.ZodObject<{
237
+ maxRetries: z.ZodLiteral<1>;
238
+ onlyWhen: z.ZodLiteral<"infrastructure-failure-with-no-model-output">;
239
+ prompt: z.ZodLiteral<"identical">;
240
+ }, z.core.$strict>;
241
+ transcriptSha256: z.ZodString;
242
+ sealedAt: z.ZodString;
243
+ }, z.core.$strict>;
244
+ export type PromptedScreeningProcedureV1 = z.infer<typeof PromptedScreeningProcedureV1Schema>;
245
+ export declare const SCREENING_POOL_CANDIDATE_CLASSES: readonly ["correct", "specific-wrong", "vague-topical-wrong"];
246
+ export declare const SCREENING_POOL_STRATA: readonly ["category-1", "category-2", "category-3", "category-4"];
247
+ export declare const ScreeningPoolItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
248
+ itemSha256: z.ZodString;
249
+ intendedLabel: z.ZodEnum<{
250
+ CORRECT: "CORRECT";
251
+ WRONG: "WRONG";
252
+ }>;
253
+ candidateClass: z.ZodEnum<{
254
+ correct: "correct";
255
+ "specific-wrong": "specific-wrong";
256
+ "vague-topical-wrong": "vague-topical-wrong";
257
+ }>;
258
+ stratum: z.ZodEnum<{
259
+ "category-1": "category-1";
260
+ "category-2": "category-2";
261
+ "category-3": "category-3";
262
+ "category-4": "category-4";
263
+ }>;
264
+ poolPosition: z.ZodNumber;
265
+ slotId: z.ZodString;
266
+ poolKind: z.ZodLiteral<"main">;
267
+ }, z.core.$strict>, z.ZodObject<{
268
+ itemSha256: z.ZodString;
269
+ intendedLabel: z.ZodEnum<{
270
+ CORRECT: "CORRECT";
271
+ WRONG: "WRONG";
272
+ }>;
273
+ candidateClass: z.ZodEnum<{
274
+ correct: "correct";
275
+ "specific-wrong": "specific-wrong";
276
+ "vague-topical-wrong": "vague-topical-wrong";
277
+ }>;
278
+ stratum: z.ZodEnum<{
279
+ "category-1": "category-1";
280
+ "category-2": "category-2";
281
+ "category-3": "category-3";
282
+ "category-4": "category-4";
283
+ }>;
284
+ poolPosition: z.ZodNumber;
285
+ slotId: z.ZodString;
286
+ poolKind: z.ZodLiteral<"reserve">;
287
+ reserveOrder: z.ZodNumber;
288
+ }, z.core.$strict>], "poolKind">;
289
+ export type ScreeningPoolItem = z.infer<typeof ScreeningPoolItemSchema>;
290
+ /** The complete, ordered 240-main plus 424-reserve candidate universe. */
291
+ export declare const ScreeningPoolV1Schema: z.ZodObject<{
292
+ protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-pool/v1">;
293
+ draftId: z.ZodString;
294
+ identityCommitmentSha256: z.ZodString;
295
+ items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
296
+ itemSha256: z.ZodString;
297
+ intendedLabel: z.ZodEnum<{
298
+ CORRECT: "CORRECT";
299
+ WRONG: "WRONG";
300
+ }>;
301
+ candidateClass: z.ZodEnum<{
302
+ correct: "correct";
303
+ "specific-wrong": "specific-wrong";
304
+ "vague-topical-wrong": "vague-topical-wrong";
305
+ }>;
306
+ stratum: z.ZodEnum<{
307
+ "category-1": "category-1";
308
+ "category-2": "category-2";
309
+ "category-3": "category-3";
310
+ "category-4": "category-4";
311
+ }>;
312
+ poolPosition: z.ZodNumber;
313
+ slotId: z.ZodString;
314
+ poolKind: z.ZodLiteral<"main">;
315
+ }, z.core.$strict>, z.ZodObject<{
316
+ itemSha256: z.ZodString;
317
+ intendedLabel: z.ZodEnum<{
318
+ CORRECT: "CORRECT";
319
+ WRONG: "WRONG";
320
+ }>;
321
+ candidateClass: z.ZodEnum<{
322
+ correct: "correct";
323
+ "specific-wrong": "specific-wrong";
324
+ "vague-topical-wrong": "vague-topical-wrong";
325
+ }>;
326
+ stratum: z.ZodEnum<{
327
+ "category-1": "category-1";
328
+ "category-2": "category-2";
329
+ "category-3": "category-3";
330
+ "category-4": "category-4";
331
+ }>;
332
+ poolPosition: z.ZodNumber;
333
+ slotId: z.ZodString;
334
+ poolKind: z.ZodLiteral<"reserve">;
335
+ reserveOrder: z.ZodNumber;
336
+ }, z.core.$strict>], "poolKind">>;
337
+ sealedAt: z.ZodString;
338
+ }, z.core.$strict>;
339
+ export type ScreeningPoolV1 = z.infer<typeof ScreeningPoolV1Schema>;
340
+ export declare const ScreeningSampleCommitmentV1Schema: z.ZodObject<{
341
+ protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1">;
342
+ draftId: z.ZodString;
343
+ poolSha256: z.ZodString;
344
+ poolIdentityCommitmentSha256: z.ZodString;
345
+ samplingProcedure: z.ZodLiteral<"screening-sample/1">;
346
+ sampleSeed: z.ZodString;
347
+ sampleSize: z.ZodLiteral<72>;
348
+ sampleItemSha256s: z.ZodArray<z.ZodString>;
349
+ committedAt: z.ZodString;
350
+ }, z.core.$strict>;
351
+ export type ScreeningSampleCommitmentV1 = z.infer<typeof ScreeningSampleCommitmentV1Schema>;
352
+ export declare const PromptedScreeningRowV2Schema: z.ZodObject<{
353
+ itemSha256: z.ZodString;
354
+ intendedLabel: z.ZodEnum<{
355
+ CORRECT: "CORRECT";
356
+ WRONG: "WRONG";
357
+ }>;
358
+ screeningVerdict: z.ZodEnum<{
359
+ CORRECT: "CORRECT";
360
+ WRONG: "WRONG";
361
+ UNSURE: "UNSURE";
362
+ }>;
363
+ terraReviewVerdict: z.ZodOptional<z.ZodEnum<{
364
+ CORRECT: "CORRECT";
365
+ WRONG: "WRONG";
366
+ UNSURE: "UNSURE";
367
+ }>>;
368
+ solReviewVerdict: z.ZodOptional<z.ZodEnum<{
369
+ CORRECT: "CORRECT";
370
+ WRONG: "WRONG";
371
+ UNSURE: "UNSURE";
372
+ }>>;
373
+ ritsuDecision: z.ZodDiscriminatedUnion<[z.ZodObject<{
374
+ checked: z.ZodLiteral<false>;
375
+ }, z.core.$strict>, z.ZodObject<{
376
+ checked: z.ZodLiteral<true>;
377
+ verdict: z.ZodEnum<{
378
+ confirm: "confirm";
379
+ exclude: "exclude";
380
+ }>;
381
+ decidedAt: z.ZodString;
382
+ }, z.core.$strict>], "checked">;
383
+ }, z.core.$strict>;
384
+ export type PromptedScreeningRowV2 = z.infer<typeof PromptedScreeningRowV2Schema>;
385
+ /** Signed authority decision table for the prompted Codex procedure. */
386
+ export declare const ScreeningTableV2Schema: z.ZodObject<{
387
+ protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/screening-table/v2">;
388
+ draftId: z.ZodString;
389
+ procedureSha256: z.ZodString;
390
+ coordinatorPromptSha256: z.ZodString;
391
+ poolSha256: z.ZodString;
392
+ sampleCommitmentSha256: z.ZodString;
393
+ samplingScriptSha256: z.ZodString;
394
+ transcriptSha256: z.ZodString;
395
+ operator: z.ZodLiteral<"Ritsu">;
396
+ rows: z.ZodArray<z.ZodObject<{
397
+ itemSha256: z.ZodString;
398
+ intendedLabel: z.ZodEnum<{
399
+ CORRECT: "CORRECT";
400
+ WRONG: "WRONG";
401
+ }>;
402
+ screeningVerdict: z.ZodEnum<{
403
+ CORRECT: "CORRECT";
404
+ WRONG: "WRONG";
405
+ UNSURE: "UNSURE";
406
+ }>;
407
+ terraReviewVerdict: z.ZodOptional<z.ZodEnum<{
408
+ CORRECT: "CORRECT";
409
+ WRONG: "WRONG";
410
+ UNSURE: "UNSURE";
411
+ }>>;
412
+ solReviewVerdict: z.ZodOptional<z.ZodEnum<{
413
+ CORRECT: "CORRECT";
414
+ WRONG: "WRONG";
415
+ UNSURE: "UNSURE";
416
+ }>>;
417
+ ritsuDecision: z.ZodDiscriminatedUnion<[z.ZodObject<{
418
+ checked: z.ZodLiteral<false>;
419
+ }, z.core.$strict>, z.ZodObject<{
420
+ checked: z.ZodLiteral<true>;
421
+ verdict: z.ZodEnum<{
422
+ confirm: "confirm";
423
+ exclude: "exclude";
424
+ }>;
425
+ decidedAt: z.ZodString;
426
+ }, z.core.$strict>], "checked">;
427
+ }, z.core.$strict>>;
428
+ sealedAt: z.ZodString;
429
+ }, z.core.$strict>;
430
+ export type ScreeningTableV2 = z.infer<typeof ScreeningTableV2Schema>;
189
431
  export declare const HumanReviewReplacementLedgerEntrySchema: z.ZodObject<{
190
432
  excludedItemSha256: z.ZodString;
191
433
  replacementItemSha256: z.ZodString;
@@ -11,6 +11,10 @@ export const HUMAN_REVIEW_OPERATOR_ASSERTION_PROTOCOL = "https://spec.jinn.netwo
11
11
  export const BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL = "https://spec.jinn.network/binary-judgment/admission-manifest/v1";
12
12
  // screened-operator-sampled admission branch (spec §6.1, §6.3, §6.6; packet P6).
13
13
  export const SCREENING_TABLE_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-table/v1";
14
+ export const PROMPTED_SCREENING_PROCEDURE_PROTOCOL = "https://spec.jinn.network/binary-judgment/prompted-screening-procedure/v1";
15
+ export const SCREENING_POOL_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-pool/v1";
16
+ export const SCREENING_SAMPLE_COMMITMENT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-sample-commitment/v1";
17
+ export const SCREENING_TABLE_V2_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-table/v2";
14
18
  export const SCREENING_REVEAL_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
15
19
  export const HUMAN_REVIEW_PACKET_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
16
20
  export const HUMAN_REVIEW_RESPONSE_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-response.v1+json";
@@ -20,6 +24,7 @@ export const HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.bina
20
24
  export const HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.operator-truth-assertion.v1+json";
21
25
  // screened-operator-sampled admission branch (spec §6.3, §6.6; packet P6).
22
26
  export const SCREENING_TABLE_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-table.v1+json";
27
+ export const SCREENING_TABLE_V2_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-table.v2+json";
23
28
  export const SCREENING_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-reveal-receipt.v1+json";
24
29
  const DigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/u);
25
30
  const TimestampSchema = z.string().datetime({ offset: true });
@@ -201,6 +206,170 @@ export const ScreeningTableSchema = z.strictObject({
201
206
  }
202
207
  }
203
208
  });
209
+ export const PROMPTED_SCREENING_PROFILE = "prompted-codex-screening/v1";
210
+ export const PROMPTED_SCREENING_LIMITATIONS = [
211
+ "prompt-compliance-not-machine-verified",
212
+ "provider-execution-not-machine-verified",
213
+ "transcript-provenance-not-machine-verified",
214
+ "mutable-model-alias-weights-not-machine-verified",
215
+ ];
216
+ const PromptedAgentSchema = (alias, model, reasoningEffort, maxBatchSize) => z.strictObject({
217
+ alias: z.literal(alias),
218
+ model: z.literal(model),
219
+ reasoningEffort: z.literal(reasoningEffort),
220
+ maxBatchSize: z.literal(maxBatchSize),
221
+ });
222
+ /** Closed, machine-checkable orchestration metadata. Prompt and transcript bytes stay opaque. */
223
+ export const PromptedScreeningProcedureV1Schema = z.strictObject({
224
+ protocol: z.literal(PROMPTED_SCREENING_PROCEDURE_PROTOCOL),
225
+ procedureId: z.literal(PROMPTED_SCREENING_PROFILE),
226
+ coordinatorPromptSha256: DigestSchema,
227
+ coordinator: z.strictObject({
228
+ alias: z.literal("Sol"),
229
+ model: z.literal("gpt-5.6-sol"),
230
+ reasoningEffort: z.literal("high"),
231
+ mayOrchestrate: z.literal(true),
232
+ }),
233
+ judgmentAgents: z.tuple([
234
+ PromptedAgentSchema("Luna", "gpt-5.6-luna", "medium", 32),
235
+ PromptedAgentSchema("Terra", "gpt-5.6-terra", "high", 16),
236
+ PromptedAgentSchema("Sol", "gpt-5.6-sol", "high", 8),
237
+ ]),
238
+ toolPolicy: z.strictObject({
239
+ coordinator: z.literal("orchestration-only"),
240
+ judgmentAgents: z.strictObject({
241
+ web: z.literal(false),
242
+ shell: z.literal(false),
243
+ repository: z.literal(false),
244
+ search: z.literal(false),
245
+ }),
246
+ }),
247
+ output: z.strictObject({
248
+ alphabet: z.tuple([z.literal("CORRECT"), z.literal("WRONG"), z.literal("UNSURE")]),
249
+ invalidOutputDecision: z.literal("UNSURE"),
250
+ }),
251
+ retry: z.strictObject({
252
+ maxRetries: z.literal(1),
253
+ onlyWhen: z.literal("infrastructure-failure-with-no-model-output"),
254
+ prompt: z.literal("identical"),
255
+ }),
256
+ transcriptSha256: DigestSchema,
257
+ sealedAt: TimestampSchema,
258
+ });
259
+ export const SCREENING_POOL_CANDIDATE_CLASSES = ["correct", "specific-wrong", "vague-topical-wrong"];
260
+ export const SCREENING_POOL_STRATA = ["category-1", "category-2", "category-3", "category-4"];
261
+ const ScreeningPoolCommonItemSchema = z.strictObject({
262
+ itemSha256: DigestSchema,
263
+ intendedLabel: BinaryJudgmentTruthLabelSchema,
264
+ candidateClass: z.enum(SCREENING_POOL_CANDIDATE_CLASSES),
265
+ stratum: z.enum(SCREENING_POOL_STRATA),
266
+ poolPosition: z.number().int().positive(),
267
+ slotId: z.string().regex(/^slot-[0-9]{3}$/u),
268
+ });
269
+ export const ScreeningPoolItemSchema = z.discriminatedUnion("poolKind", [
270
+ ScreeningPoolCommonItemSchema.extend({ poolKind: z.literal("main") }),
271
+ ScreeningPoolCommonItemSchema.extend({ poolKind: z.literal("reserve"), reserveOrder: z.number().int().positive() }),
272
+ ]);
273
+ /** The complete, ordered 240-main plus 424-reserve candidate universe. */
274
+ export const ScreeningPoolV1Schema = z.strictObject({
275
+ protocol: z.literal(SCREENING_POOL_PROTOCOL),
276
+ draftId: IdentitySchema,
277
+ identityCommitmentSha256: DigestSchema,
278
+ items: z.array(ScreeningPoolItemSchema).length(664),
279
+ sealedAt: TimestampSchema,
280
+ }).superRefine((pool, ctx) => {
281
+ const slots = new Map();
282
+ const identities = new Set();
283
+ for (const [index, item] of pool.items.entries()) {
284
+ if (item.poolPosition !== index + 1)
285
+ ctx.addIssue({ code: "custom", path: ["items", index, "poolPosition"], message: "poolPosition must be contiguous and match array order" });
286
+ if (identities.has(item.itemSha256))
287
+ ctx.addIssue({ code: "custom", path: ["items", index, "itemSha256"], message: "itemSha256 must be unique" });
288
+ identities.add(item.itemSha256);
289
+ const expectedLabel = item.candidateClass === "correct" ? "CORRECT" : "WRONG";
290
+ if (item.intendedLabel !== expectedLabel)
291
+ ctx.addIssue({ code: "custom", path: ["items", index, "intendedLabel"], message: "intendedLabel does not derive from candidateClass" });
292
+ slots.set(item.slotId, [...(slots.get(item.slotId) ?? []), item]);
293
+ }
294
+ const mains = pool.items.filter((item) => item.poolKind === "main");
295
+ if (mains.length !== 240 || slots.size !== 240)
296
+ ctx.addIssue({ code: "custom", path: ["items"], message: "pool must contain exactly 240 main slots" });
297
+ const expectedSlotIds = Array.from({ length: 240 }, (_, index) => `slot-${(index + 1).toString().padStart(3, "0")}`);
298
+ const actualSlotIds = [...slots.keys()].sort(compareCodeUnitStrings);
299
+ if (actualSlotIds.length !== expectedSlotIds.length || actualSlotIds.some((value, index) => value !== expectedSlotIds[index]))
300
+ ctx.addIssue({ code: "custom", path: ["items"], message: "slot lineage must be exactly slot-001 through slot-240" });
301
+ for (const [slotId, items] of slots) {
302
+ const main = items.filter((item) => item.poolKind === "main");
303
+ if (main.length !== 1) {
304
+ ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} must contain exactly one main item` });
305
+ continue;
306
+ }
307
+ const reserves = items.filter((item) => item.poolKind === "reserve").sort((a, b) => a.reserveOrder - b.reserveOrder);
308
+ for (const [index, reserve] of reserves.entries()) {
309
+ if (reserve.reserveOrder !== index + 1)
310
+ ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserveOrder must be contiguous` });
311
+ if (reserve.poolPosition <= main[0].poolPosition)
312
+ ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserves must follow their main item in pool order` });
313
+ if (reserve.candidateClass !== main[0].candidateClass || reserve.stratum !== main[0].stratum || reserve.intendedLabel !== main[0].intendedLabel)
314
+ ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserves must preserve class, stratum, and intended label` });
315
+ }
316
+ }
317
+ for (const candidateClass of SCREENING_POOL_CANDIDATE_CLASSES)
318
+ for (const stratum of SCREENING_POOL_STRATA) {
319
+ if (mains.filter((item) => item.candidateClass === candidateClass && item.stratum === stratum).length !== 20)
320
+ ctx.addIssue({ code: "custom", path: ["items"], message: `main pool must contain 20 ${candidateClass}/${stratum} items` });
321
+ }
322
+ });
323
+ export const ScreeningSampleCommitmentV1Schema = z.strictObject({
324
+ protocol: z.literal(SCREENING_SAMPLE_COMMITMENT_PROTOCOL),
325
+ draftId: IdentitySchema,
326
+ poolSha256: DigestSchema,
327
+ poolIdentityCommitmentSha256: DigestSchema,
328
+ samplingProcedure: z.literal("screening-sample/1"),
329
+ sampleSeed: z.string().min(1),
330
+ sampleSize: z.literal(72),
331
+ sampleItemSha256s: z.array(DigestSchema).length(72).superRefine((values, ctx) => {
332
+ for (let index = 1; index < values.length; index += 1) {
333
+ if (compareCodeUnitStrings(values[index - 1], values[index]) >= 0)
334
+ ctx.addIssue({ code: "custom", message: "sample identities must be sorted and unique" });
335
+ }
336
+ }),
337
+ committedAt: TimestampSchema,
338
+ });
339
+ const ScreeningDecisionSchema = z.enum(["CORRECT", "WRONG", "UNSURE"]);
340
+ const RitsuScreeningDecisionSchema = z.discriminatedUnion("checked", [
341
+ z.strictObject({ checked: z.literal(false) }),
342
+ z.strictObject({ checked: z.literal(true), verdict: z.enum(["confirm", "exclude"]), decidedAt: TimestampSchema }),
343
+ ]);
344
+ export const PromptedScreeningRowV2Schema = z.strictObject({
345
+ itemSha256: DigestSchema,
346
+ intendedLabel: BinaryJudgmentTruthLabelSchema,
347
+ screeningVerdict: ScreeningDecisionSchema,
348
+ terraReviewVerdict: ScreeningDecisionSchema.optional(),
349
+ solReviewVerdict: ScreeningDecisionSchema.optional(),
350
+ ritsuDecision: RitsuScreeningDecisionSchema,
351
+ });
352
+ /** Signed authority decision table for the prompted Codex procedure. */
353
+ export const ScreeningTableV2Schema = z.strictObject({
354
+ protocol: z.literal(SCREENING_TABLE_V2_PROTOCOL),
355
+ draftId: IdentitySchema,
356
+ procedureSha256: DigestSchema,
357
+ coordinatorPromptSha256: DigestSchema,
358
+ poolSha256: DigestSchema,
359
+ sampleCommitmentSha256: DigestSchema,
360
+ samplingScriptSha256: DigestSchema,
361
+ transcriptSha256: DigestSchema,
362
+ operator: z.literal("Ritsu"),
363
+ rows: z.array(PromptedScreeningRowV2Schema).length(664),
364
+ sealedAt: TimestampSchema,
365
+ }).superRefine((table, ctx) => {
366
+ for (let index = 1; index < table.rows.length; index += 1) {
367
+ if (compareCodeUnitStrings(table.rows[index - 1].itemSha256, table.rows[index].itemSha256) >= 0) {
368
+ ctx.addIssue({ code: "custom", path: ["rows"], message: "rows must be sorted by itemSha256 and unique" });
369
+ return;
370
+ }
371
+ }
372
+ });
204
373
  // The two-human-review reasons (unchanged) and the screened-branch reasons this packet adds
205
374
  // (spec §6.4; packet P6). This is one of four widened copies of the closed reason vocabulary
206
375
  // (the other three: verify/src/schema.ts's exclusions[].reason, verify/src/admission/
@@ -1,6 +1,6 @@
1
- import { type BinaryJudgmentAdmissionManifest, type HumanReviewReplacementLedger } from "./contracts.js";
1
+ import { PROMPTED_SCREENING_PROFILE, type BinaryJudgmentAdmissionManifest, type HumanReviewReplacementLedger } from "./contracts.js";
2
2
  export type AdmissionSha256 = `sha256:${string}`;
3
- export declare const BINARY_JUDGMENT_ADMISSION_RECORD_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs"];
3
+ export declare const BINARY_JUDGMENT_ADMISSION_RECORD_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs", "screening-prompt", "screening-procedure", "screening-pool", "screening-sample-commitment", "screening-transcript"];
4
4
  export type BinaryJudgmentAdmissionRecordRole = (typeof BINARY_JUDGMENT_ADMISSION_RECORD_ROLES)[number];
5
5
  export type AdmissionAuthorityRole = "roster-attestor" | "truth-reveal-attestor" | "operator-truth-attestor";
6
6
  export interface BinaryJudgmentAdmissionClosurePorts {
@@ -57,12 +57,25 @@ export interface VerifiedBinaryJudgmentAdmissionClosure {
57
57
  readonly sha256: AdmissionSha256;
58
58
  readonly roles: readonly BinaryJudgmentAdmissionRecordRole[];
59
59
  }[];
60
- /** Present iff `manifest.truthAdmission === "screened-operator-sampled"` (spec §6.5 check (3)). */
60
+ /** Present for the legacy screening-table/v1 method (spec §6.5 check (3)). */
61
61
  readonly screening?: {
62
62
  readonly sampleAgreementRate: number;
63
63
  readonly instrumentSha256: AdmissionSha256;
64
64
  };
65
+ /** Present for screening-table/v2; kept separate so the legacy v1 result shape stays source-compatible. */
66
+ readonly promptedScreening?: {
67
+ readonly sampleAgreementRate: number;
68
+ readonly procedureSha256: AdmissionSha256;
69
+ readonly profile: typeof PROMPTED_SCREENING_PROFILE;
70
+ readonly capabilityBoundary: PromptedScreeningCapabilityBoundary;
71
+ };
65
72
  }
73
+ export declare const PROMPTED_SCREENING_CAPABILITY_BOUNDARY: {
74
+ readonly status: "not-machine-verified";
75
+ readonly machineVerified: readonly ["sealed-pool", "sealed-sample", "signed-table", "operator-decisions", "artifact-integrity"];
76
+ readonly notMachineVerified: readonly ["prompt-compliance-not-machine-verified", "provider-execution-not-machine-verified", "transcript-provenance-not-machine-verified", "mutable-model-alias-weights-not-machine-verified"];
77
+ };
78
+ export type PromptedScreeningCapabilityBoundary = typeof PROMPTED_SCREENING_CAPABILITY_BOUNDARY;
66
79
  export declare class BinaryJudgmentAdmissionClosureError extends Error {
67
80
  readonly path: string;
68
81
  constructor(path: string, detail: string, options?: ErrorOptions);
@@ -3,9 +3,9 @@ import { z } from "zod";
3
3
  import { VERDICT_DSSE_PAYLOAD_TYPE, canonicalJsonBytes, compareCodeUnitStrings, parseBinaryJudgmentAnalysisContext, parseBinaryJudgmentInstrument, parseBinaryJudgmentLabelResolution, parseBinaryJudgmentPayload, recordDigest, sealBinaryJudgmentInstrument, } from "@jinn-network/task-execution-profiles";
4
4
  import { parseExactDsseEnvelope } from "@jinn-network/trust-core";
5
5
  import { BINARY_JUDGMENT_HUMAN_REVIEW_EVALUATION_SPEC_SEALED, HUMAN_REVIEW_FORM_SEALED, } from "./application.js";
6
- import { BinaryJudgmentAdmissionManifestSchema, HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE, HUMAN_REVIEW_PACKET_MEDIA_TYPE, HUMAN_REVIEW_RESPONSE_MEDIA_TYPE, HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE, HUMAN_REVIEW_ROSTER_MEDIA_TYPE, HUMAN_REVIEW_VISIBILITY_RECEIPT_MEDIA_TYPE, SCREENING_REVEAL_RECEIPT_MEDIA_TYPE, SCREENING_TABLE_MEDIA_TYPE, HumanReviewOperatorAssertionSchema, HumanReviewPacketSchema, HumanReviewReplacementLedgerSchema, HumanReviewResponseSchema, HumanReviewRevealReceiptSchema, HumanReviewRosterSchema, HumanReviewVisibilityReceiptSchema, ScreeningRevealReceiptSchema, ScreeningTableSchema, } from "./contracts.js";
6
+ import { BinaryJudgmentAdmissionManifestSchema, HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE, HUMAN_REVIEW_PACKET_MEDIA_TYPE, HUMAN_REVIEW_RESPONSE_MEDIA_TYPE, HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE, HUMAN_REVIEW_ROSTER_MEDIA_TYPE, HUMAN_REVIEW_VISIBILITY_RECEIPT_MEDIA_TYPE, SCREENING_REVEAL_RECEIPT_MEDIA_TYPE, SCREENING_TABLE_MEDIA_TYPE, SCREENING_TABLE_V2_MEDIA_TYPE, HumanReviewOperatorAssertionSchema, HumanReviewPacketSchema, HumanReviewReplacementLedgerSchema, HumanReviewResponseSchema, HumanReviewRevealReceiptSchema, HumanReviewRosterSchema, HumanReviewVisibilityReceiptSchema, ScreeningRevealReceiptSchema, ScreeningTableSchema, ScreeningTableV2Schema, PromptedScreeningProcedureV1Schema, ScreeningPoolV1Schema, ScreeningSampleCommitmentV1Schema, PROMPTED_SCREENING_LIMITATIONS, PROMPTED_SCREENING_PROFILE, } from "./contracts.js";
7
7
  import { readOrderedAdmissionVerdictMeasurements, readAdmissionVerdictEnvelope } from "./result-evaluation.js";
8
- import { computeScreeningSample, ScreeningSampleError } from "./screening-sample.js";
8
+ import { computeScreeningPoolDigest, computeScreeningSample, ScreeningSampleError } from "./screening-sample.js";
9
9
  // Verbatim duplicate of `schema.ts`'s `BUNDLE_V4_ADMISSION_EVIDENCE_ROLES`, hand-kept in sync
10
10
  // (spec §6.8a Group C).
11
11
  export const BINARY_JUDGMENT_ADMISSION_RECORD_ROLES = [
@@ -21,7 +21,17 @@ export const BINARY_JUDGMENT_ADMISSION_RECORD_ROLES = [
21
21
  "screening-instrument",
22
22
  "screening-sampling-script",
23
23
  "screening-raw-outputs",
24
+ "screening-prompt",
25
+ "screening-procedure",
26
+ "screening-pool",
27
+ "screening-sample-commitment",
28
+ "screening-transcript",
24
29
  ];
30
+ export const PROMPTED_SCREENING_CAPABILITY_BOUNDARY = {
31
+ status: "not-machine-verified",
32
+ machineVerified: ["sealed-pool", "sealed-sample", "signed-table", "operator-decisions", "artifact-integrity"],
33
+ notMachineVerified: PROMPTED_SCREENING_LIMITATIONS,
34
+ };
25
35
  export class BinaryJudgmentAdmissionClosureError extends Error {
26
36
  path;
27
37
  constructor(path, detail, options) {
@@ -244,14 +254,15 @@ function authorityPayload(state, options) {
244
254
  catch (cause) {
245
255
  fail(path, "authority evidence is not an exact compact DSSE envelope", cause);
246
256
  }
247
- if (envelope.payloadType !== mediaType || envelope.signatures.length !== 1)
257
+ const allowedMediaTypes = typeof mediaType === "string" ? [mediaType] : mediaType;
258
+ if (!allowedMediaTypes.includes(envelope.payloadType) || envelope.signatures.length !== 1)
248
259
  fail(path, "authority evidence has the wrong payload type or signature count");
249
260
  const signature = envelope.signatures[0];
250
261
  const signatureKeyId = signature.keyid;
251
262
  if (typeof signatureKeyId !== "string" || !state.ports.verifyAuthoritySignature({ envelopeBytes, keyId: signatureKeyId, role })) {
252
263
  fail(path, `authority signature is invalid for role ${role}`);
253
264
  }
254
- return { value: exactCanonical(schema, envelope.payloadBytes, `${path}.payload`), keyId: signatureKeyId };
265
+ return { value: exactCanonical(schema, envelope.payloadBytes, `${path}.payload`), keyId: signatureKeyId, mediaType: envelope.payloadType };
255
266
  }
256
267
  function verifyHumanEvidence(state, refs, expectedItemSha256, expectedDraftId, admittedAt, path) {
257
268
  const reviews = refs.reviewVerdictSha256s.map((digest, index) => verifyReview(state, digest, expectedItemSha256, `${path}.reviews.${index}`));
@@ -314,27 +325,29 @@ function expectedExclusionReason(reviews) {
314
325
  return "review-disagreement";
315
326
  return undefined;
316
327
  }
317
- /**
318
- * The screened branch's sibling of `expectedExclusionReason` above, derived from §6.4's admission
319
- * rule instead of two signed reviews (spec §6.4, §6.5 check (4)). The seventh copy of the
320
- * replacement-ledger reason vocabulary this file carries (contracts.ts's own comment names the
321
- * other six and defers this one to S3, "recomputation logic").
322
- *
323
- * A row this file already knows is admitted returns `undefined` (no exclusion). Among excluded
324
- * rows: a FLAGGED row (`screeningVerdict !== intendedLabel`) is always hand-checked in a passing
325
- * closure (check (2) requires it), so its reason names the screen's own finding regardless of
326
- * that hand check having run -- `screening-indeterminate` when the screen itself was
327
- * indeterminate, `screening-disagreement` for a definite-label disagreement. `screening-hand-
328
- * excluded` is reserved for the one case a flagged-first read would miss: R-3's tie-break, a row
329
- * the screen AGREED with that the hand check overrode to exclude.
330
- */
328
+ function screeningRowAgreed(row) {
329
+ return row.screeningVerdict !== "UNSURE"
330
+ && row.screeningVerdict !== "indeterminate"
331
+ && row.screeningVerdict === row.intendedLabel;
332
+ }
333
+ function screeningRowChecked(row) {
334
+ return "ritsuDecision" in row ? row.ritsuDecision.checked : row.handChecked;
335
+ }
336
+ function screeningRowHandVerdict(row) {
337
+ if ("ritsuDecision" in row)
338
+ return row.ritsuDecision.checked ? row.ritsuDecision.verdict : undefined;
339
+ return row.handVerdict;
340
+ }
341
+ function screeningRowAdmitted(row) {
342
+ return screeningRowChecked(row) ? screeningRowHandVerdict(row) === "confirm" : screeningRowAgreed(row);
343
+ }
331
344
  function expectedScreeningExclusionReason(row) {
332
- const agreed = row.screeningVerdict === row.intendedLabel;
333
- const admitted = row.handChecked ? row.handVerdict === "confirm" : agreed;
345
+ const agreed = screeningRowAgreed(row);
346
+ const admitted = screeningRowAdmitted(row);
334
347
  if (admitted)
335
348
  return undefined;
336
349
  if (!agreed)
337
- return row.screeningVerdict === "indeterminate" ? "screening-indeterminate" : "screening-disagreement";
350
+ return row.screeningVerdict === "indeterminate" || row.screeningVerdict === "UNSURE" ? "screening-indeterminate" : "screening-disagreement";
338
351
  return "screening-hand-excluded";
339
352
  }
340
353
  /** The reviewer Result Evaluation verifier shared by admission construction and closure replay. */
@@ -365,6 +378,10 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
365
378
  let screeningSample = new Set();
366
379
  let screeningSampleAgreementRate;
367
380
  let screeningInstrumentSha256;
381
+ let promptedScreeningProcedureSha256;
382
+ let promptedScreeningPool;
383
+ let promptedCommittedSample;
384
+ let screeningTableAuthorityKeyId;
368
385
  if (manifest.truthAdmission === "screened-operator-sampled") {
369
386
  if (manifest.screeningTableSha256 === undefined) {
370
387
  fail("admissionManifest.screeningTableSha256", "screened admission manifest carries no screening table reference");
@@ -380,28 +397,86 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
380
397
  // branch's sole legal authority set is `["truth-reveal-attestor"]` alone (§6.8a Group C), so
381
398
  // that is the one key that signs both the bank-scoped table and the bank-scoped reveal
382
399
  // receipt: "signed once per bank" as D1 describes.
383
- screeningTable = authorityPayload(state, {
400
+ const tableEvidence = authorityPayload(state, {
384
401
  digest: manifest.screeningTableSha256,
385
- mediaType: SCREENING_TABLE_MEDIA_TYPE,
402
+ mediaType: [SCREENING_TABLE_MEDIA_TYPE, SCREENING_TABLE_V2_MEDIA_TYPE],
386
403
  role: "truth-reveal-attestor",
387
404
  evidenceRole: "screening-table",
388
- schema: ScreeningTableSchema,
405
+ schema: z.union([ScreeningTableSchema, ScreeningTableV2Schema]),
389
406
  path: "admissionManifest.screeningTableSha256",
390
- }).value;
407
+ });
408
+ screeningTable = tableEvidence.value;
409
+ screeningTableAuthorityKeyId = tableEvidence.keyId;
391
410
  if (screeningTable.draftId !== input.expectedDraftId || screeningTable.sealedAt !== manifest.admittedAt) {
392
411
  fail("screeningTable", "table draft/time does not bind the manifest");
393
412
  }
394
- const screeningInstrument = parseProfileRecord(state, screeningTable.screeningInstrumentSha256, "screeningTable.screeningInstrumentSha256", parseBinaryJudgmentInstrument, "screening-instrument");
395
- const resealedScreeningInstrument = sealBinaryJudgmentInstrument(screeningInstrument.value);
396
- if (resealedScreeningInstrument.digest !== screeningTable.screeningInstrumentSha256
397
- || !bytesEqual(resealedScreeningInstrument.bytes, screeningInstrument.bytes)) {
398
- fail("screeningTable.screeningInstrumentSha256", "instrument does not reseal to its table commitment");
413
+ let sampleSeed;
414
+ let sampleSize;
415
+ let sampleIdentities;
416
+ if (screeningTable.protocol === "https://spec.jinn.network/binary-judgment/screening-table/v1") {
417
+ if (tableEvidence.mediaType !== SCREENING_TABLE_MEDIA_TYPE)
418
+ fail("screeningTable", "v1 table protocol must use the v1 media type");
419
+ const screeningInstrument = parseProfileRecord(state, screeningTable.screeningInstrumentSha256, "screeningTable.screeningInstrumentSha256", parseBinaryJudgmentInstrument, "screening-instrument");
420
+ const resealedScreeningInstrument = sealBinaryJudgmentInstrument(screeningInstrument.value);
421
+ if (resealedScreeningInstrument.digest !== screeningTable.screeningInstrumentSha256 || !bytesEqual(resealedScreeningInstrument.bytes, screeningInstrument.bytes)) {
422
+ fail("screeningTable.screeningInstrumentSha256", "instrument does not reseal to its table commitment");
423
+ }
424
+ screeningInstrumentSha256 = screeningTable.screeningInstrumentSha256;
425
+ resolve(state, screeningTable.samplingScriptSha256, "screeningTable.samplingScriptSha256", "screening-sampling-script");
426
+ resolve(state, screeningTable.rawOutputsSha256, "screeningTable.rawOutputsSha256", "screening-raw-outputs");
427
+ sampleSeed = screeningTable.sampleSeed;
428
+ sampleSize = screeningTable.sampleSize;
429
+ sampleIdentities = screeningTable.rows.map((row) => row.itemSha256);
430
+ }
431
+ else {
432
+ if (tableEvidence.mediaType !== SCREENING_TABLE_V2_MEDIA_TYPE)
433
+ fail("screeningTable", "v2 table protocol must use the v2 media type");
434
+ const procedure = exactCanonical(PromptedScreeningProcedureV1Schema, resolve(state, screeningTable.procedureSha256, "screeningTable.procedureSha256", "screening-procedure"), "screeningProcedure");
435
+ const pool = exactCanonical(ScreeningPoolV1Schema, resolve(state, screeningTable.poolSha256, "screeningTable.poolSha256", "screening-pool"), "screeningPool");
436
+ const commitment = exactCanonical(ScreeningSampleCommitmentV1Schema, resolve(state, screeningTable.sampleCommitmentSha256, "screeningTable.sampleCommitmentSha256", "screening-sample-commitment"), "screeningSampleCommitment");
437
+ resolve(state, screeningTable.coordinatorPromptSha256, "screeningTable.coordinatorPromptSha256", "screening-prompt");
438
+ resolve(state, screeningTable.samplingScriptSha256, "screeningTable.samplingScriptSha256", "screening-sampling-script");
439
+ resolve(state, screeningTable.transcriptSha256, "screeningTable.transcriptSha256", "screening-transcript");
440
+ if (procedure.coordinatorPromptSha256 !== screeningTable.coordinatorPromptSha256
441
+ || procedure.transcriptSha256 !== screeningTable.transcriptSha256
442
+ || pool.draftId !== input.expectedDraftId
443
+ || commitment.draftId !== input.expectedDraftId
444
+ || commitment.poolSha256 !== screeningTable.poolSha256
445
+ || commitment.poolIdentityCommitmentSha256 !== pool.identityCommitmentSha256
446
+ || Date.parse(procedure.sealedAt) > Date.parse(screeningTable.sealedAt)
447
+ || Date.parse(pool.sealedAt) > Date.parse(commitment.committedAt)
448
+ || Date.parse(commitment.committedAt) > Date.parse(screeningTable.sealedAt))
449
+ fail("screeningTable", "prompted procedure, prompt, transcript, pool, commitment, draft, or timestamps do not join");
450
+ const poolIdentities = pool.items.map((item) => item.itemSha256);
451
+ if (computeScreeningPoolDigest(poolIdentities) !== pool.identityCommitmentSha256)
452
+ fail("screeningPool.identityCommitmentSha256", "identity commitment does not match the sorted unique pool identities");
453
+ const itemIds = new Set();
454
+ for (const [index, poolItem] of pool.items.entries()) {
455
+ const item = parseProfileRecord(state, poolItem.itemSha256, `screeningPool.items.${index}.itemSha256`, (bytes) => parseBinaryJudgmentPayload(bytes), "source-item").value;
456
+ if (itemIds.has(item.itemId))
457
+ fail("screeningPool.items", `duplicate source itemId ${item.itemId}`);
458
+ itemIds.add(item.itemId);
459
+ }
460
+ const rowIdentities = screeningTable.rows.map((row) => row.itemSha256);
461
+ const sortedPoolIdentities = [...poolIdentities].sort(compareCodeUnitStrings);
462
+ if (!sameStrings(rowIdentities, sortedPoolIdentities))
463
+ fail("screeningTable.rows", "v2 table must cover all 664 pool identities in sorted order");
464
+ const poolByItem = new Map(pool.items.map((item) => [item.itemSha256, item]));
465
+ for (const row of screeningTable.rows) {
466
+ const poolItem = poolByItem.get(row.itemSha256);
467
+ if (row.intendedLabel !== poolItem.intendedLabel)
468
+ fail("screeningTable.rows", `row ${row.itemSha256} intended label differs from the sealed pool`);
469
+ if (row.ritsuDecision.checked && (Date.parse(row.ritsuDecision.decidedAt) < Date.parse(commitment.committedAt)
470
+ || Date.parse(row.ritsuDecision.decidedAt) > Date.parse(screeningTable.sealedAt)))
471
+ fail("screeningTable.rows", `row ${row.itemSha256} has a Ritsu decision outside the committed-sample-to-table interval`);
472
+ }
473
+ sampleSeed = commitment.sampleSeed;
474
+ sampleSize = commitment.sampleSize;
475
+ sampleIdentities = poolIdentities;
476
+ promptedScreeningProcedureSha256 = screeningTable.procedureSha256;
477
+ promptedScreeningPool = pool;
478
+ promptedCommittedSample = commitment.sampleItemSha256s;
399
479
  }
400
- screeningInstrumentSha256 = screeningTable.screeningInstrumentSha256;
401
- // These two sidecars are intentionally opaque. Resolving them is sufficient to prove exact
402
- // digest-bound reachability; screening-sample/1 remains the independent sampling authority.
403
- resolve(state, screeningTable.samplingScriptSha256, "screeningTable.samplingScriptSha256", "screening-sampling-script");
404
- resolve(state, screeningTable.rawOutputsSha256, "screeningTable.rawOutputsSha256", "screening-raw-outputs");
405
480
  screeningRowsByItem = new Map(screeningTable.rows.map((row) => [row.itemSha256, row]));
406
481
  // (1) Sample membership: recomputed by screening-sample/1, never by executing the sealed
407
482
  // script (R-4). The recomputation is authoritative for checks (2) and (3) below -- there is
@@ -409,9 +484,9 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
409
484
  let sampleResult;
410
485
  try {
411
486
  sampleResult = computeScreeningSample({
412
- itemSha256s: screeningTable.rows.map((row) => row.itemSha256),
413
- sampleSeed: screeningTable.sampleSeed,
414
- sampleSize: screeningTable.sampleSize,
487
+ itemSha256s: sampleIdentities,
488
+ sampleSeed,
489
+ sampleSize,
415
490
  });
416
491
  }
417
492
  catch (cause) {
@@ -420,11 +495,13 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
420
495
  : "sample recomputation (screening-sample/1) failed", cause);
421
496
  }
422
497
  screeningSample = new Set(sampleResult.sample);
498
+ if (promptedCommittedSample !== undefined && !sameStrings([...sampleResult.sample].sort(compareCodeUnitStrings), promptedCommittedSample))
499
+ fail("screeningSampleCommitment.sampleItemSha256s", "public sample membership differs from screening-sample/1 recomputation");
423
500
  // (2) Required hand checks: flagged := rows where NOT agreed. Every row in flagged ∪ sample
424
501
  // must carry handChecked === true.
425
502
  for (const row of screeningTable.rows) {
426
- const flagged = row.screeningVerdict !== row.intendedLabel;
427
- if ((flagged || screeningSample.has(row.itemSha256)) && !row.handChecked) {
503
+ const flagged = !screeningRowAgreed(row);
504
+ if ((flagged || screeningSample.has(row.itemSha256)) && !screeningRowChecked(row)) {
428
505
  fail("screeningTable.rows", `row ${row.itemSha256} is flagged or sampled but was never hand-checked`);
429
506
  }
430
507
  }
@@ -432,7 +509,7 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
432
509
  // row in `screeningSample` is hand-checked by check (2) above, so `handVerdict` is defined.
433
510
  const sampleMatches = [...screeningSample].filter((sampledItemSha256) => {
434
511
  const row = screeningRowsByItem.get(sampledItemSha256);
435
- return (row.screeningVerdict === row.intendedLabel) === (row.handVerdict === "confirm");
512
+ return screeningRowAgreed(row) === (screeningRowHandVerdict(row) === "confirm");
436
513
  }).length;
437
514
  screeningSampleAgreementRate = sampleMatches / screeningSample.size;
438
515
  }
@@ -528,6 +605,7 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
528
605
  const reveal = revealEvidence.value;
529
606
  if (reveal.attestorRole !== "truth-reveal-attestor"
530
607
  || reveal.attestorKeyId !== revealEvidence.keyId
608
+ || revealEvidence.keyId !== screeningTableAuthorityKeyId
531
609
  || reveal.draftId !== input.expectedDraftId
532
610
  || reveal.screeningTableSha256 !== resolution.screeningTableSha256
533
611
  || reveal.judgeExecutionState !== "not-started"
@@ -539,12 +617,13 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
539
617
  const row = screeningRowsByItem.get(resolution.itemSha256);
540
618
  if (row === undefined)
541
619
  fail(path, "accepted screened item has no covering screening-table row");
542
- const agreed = row.screeningVerdict === row.intendedLabel;
543
- const admitted = row.handChecked ? row.handVerdict === "confirm" : agreed;
544
- if (!admitted)
545
- fail(path, "admitted screened item's table row is not itself admitted per §6.4's admission rule");
620
+ if (!screeningRowAdmitted(row))
621
+ fail(path, "admitted screened item's table row is not itself admitted per the sealed admission rule");
546
622
  if (row.intendedLabel !== resolution.truthLabel)
547
623
  fail(path, "resolution truth label differs from the screening table's intended label");
624
+ const poolItem = promptedScreeningPool?.items.find((item) => item.itemSha256 === resolution.itemSha256);
625
+ if (poolItem !== undefined && (poolItem.candidateClass !== resolution.candidateClass || poolItem.stratum !== resolution.stratum))
626
+ fail(path, "resolution class or stratum differs from the prompted screening pool");
548
627
  break;
549
628
  }
550
629
  default: {
@@ -566,6 +645,37 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
566
645
  if (contextByResolution.size !== resolutions.length || contexts.some((entry) => !manifest.labelResolutionSha256s.includes(entry.value.labelResolutionSha256))) {
567
646
  fail("admissionManifest.analysisContextSha256s", "analysis-context coverage has an orphan or omission");
568
647
  }
648
+ const promptedExpectedReplacements = new Map();
649
+ if (promptedScreeningPool !== undefined) {
650
+ const slotIds = [...new Set(promptedScreeningPool.items.map((item) => item.slotId))].sort(compareCodeUnitStrings);
651
+ const expectedAccepted = new Set();
652
+ for (const slotId of slotIds) {
653
+ const slotItems = promptedScreeningPool.items.filter((item) => item.slotId === slotId);
654
+ const main = slotItems.find((item) => item.poolKind === "main");
655
+ const reserves = slotItems
656
+ .filter((item) => item.poolKind === "reserve")
657
+ .sort((left, right) => left.reserveOrder - right.reserveOrder);
658
+ const winner = [main, ...reserves].find((item) => screeningRowAdmitted(screeningRowsByItem.get(item.itemSha256)));
659
+ if (winner === undefined)
660
+ fail("screeningPool.items", `${slotId} has no admissible main or reserve candidate`);
661
+ expectedAccepted.add(winner.itemSha256);
662
+ if (winner.itemSha256 !== main.itemSha256)
663
+ promptedExpectedReplacements.set(main.itemSha256, winner.itemSha256);
664
+ }
665
+ const actualAccepted = [...acceptedItems].sort(compareCodeUnitStrings);
666
+ if (!sameStrings(actualAccepted, [...expectedAccepted].sort(compareCodeUnitStrings)))
667
+ fail("admissionManifest.labelResolutionSha256s", "accepted items are not the first admissible candidate in every sealed slot");
668
+ if (accepted.length !== 240)
669
+ fail("admissionManifest.labelResolutionSha256s", "prompted screening must admit exactly 240 items");
670
+ for (const candidateClass of ["correct", "specific-wrong", "vague-topical-wrong"]) {
671
+ if (accepted.filter((item) => item.candidateClass === candidateClass).length !== 80)
672
+ fail("admissionManifest.labelResolutionSha256s", `final bank must contain exactly 80 ${candidateClass} items`);
673
+ for (const stratum of ["category-1", "category-2", "category-3", "category-4"]) {
674
+ if (accepted.filter((item) => item.candidateClass === candidateClass && item.stratum === stratum).length !== 20)
675
+ fail("admissionManifest.labelResolutionSha256s", `final bank must contain exactly 20 ${candidateClass}/${stratum} items`);
676
+ }
677
+ }
678
+ }
569
679
  const excludedDigests = ledger.entries.map((entry) => entry.excludedItemSha256).sort(compareCodeUnitStrings);
570
680
  if (!sameStrings(excludedDigests, manifest.excludedItemSha256s))
571
681
  fail("replacementLedger.entries", "ledger exclusion coverage differs from manifest");
@@ -593,6 +703,17 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
593
703
  || replacement.candidateClass !== entry.candidateClass
594
704
  || replacement.stratum !== entry.stratum)
595
705
  fail(path, "replacement is not a later admitted reserve in the same class and stratum");
706
+ if (promptedScreeningPool !== undefined) {
707
+ const excludedPoolItem = promptedScreeningPool.items.find((item) => item.itemSha256 === entry.excludedItemSha256);
708
+ const replacementPoolItem = promptedScreeningPool.items.find((item) => item.itemSha256 === entry.replacementItemSha256);
709
+ if (excludedPoolItem?.poolKind !== "main"
710
+ || replacementPoolItem?.poolKind !== "reserve"
711
+ || excludedPoolItem.slotId !== replacementPoolItem.slotId
712
+ || entry.excludedPoolPosition !== excludedPoolItem.poolPosition
713
+ || entry.replacementPoolPosition !== replacementPoolItem.poolPosition
714
+ || promptedExpectedReplacements.get(entry.excludedItemSha256) !== entry.replacementItemSha256)
715
+ fail(path, "ledger does not name the deterministic first-admissible reserve for the exact sealed slot positions");
716
+ }
596
717
  // Branches on admission mode (spec §6.4, §6.5 check (4); ratified resolution to G-1): a
597
718
  // screened exclusion is verified against the screening table's own per-row admission rule
598
719
  // rather than against two signed reviews. §6.9 deliberately DROPS the four per-item two-human
@@ -652,6 +773,12 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
652
773
  replacementItemSha256: prefixed(entry.replacementItemSha256),
653
774
  });
654
775
  }
776
+ if (promptedScreeningPool !== undefined) {
777
+ const ledgerReplacements = new Map(ledger.entries.map((entry) => [entry.excludedItemSha256, entry.replacementItemSha256]));
778
+ if (ledgerReplacements.size !== promptedExpectedReplacements.size || [...promptedExpectedReplacements].some(([excludedItem, replacementItem]) => ledgerReplacements.get(excludedItem) !== replacementItem)) {
779
+ fail("replacementLedger.entries", "ledger does not exactly cover every prompted main-slot replacement");
780
+ }
781
+ }
655
782
  // (0) Coverage, the other half (spec §6.5 check (0)): the table's rows must cover the frozen
656
783
  // bank's candidate pool EXACTLY. The pool itself is not a separate input to this function --
657
784
  // it is reconstructed as accepted ∪ excluded, the closure's own admission decision, which by
@@ -659,7 +786,7 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
659
786
  // with a same-class same-stratum replacement, and every replacement is itself an admitted pool
660
787
  // member). `sampleSize <= rows.length` (check (0)'s other clause) is enforced transitively:
661
788
  // `computeScreeningSample` above refuses a `sampleSize` exceeding the pool size on its own.
662
- if (manifest.truthAdmission === "screened-operator-sampled") {
789
+ if (manifest.truthAdmission === "screened-operator-sampled" && promptedScreeningPool === undefined) {
663
790
  if (screeningTable === undefined) {
664
791
  // Unreachable today: the screened arm resolves the table before any row is admitted and fails
665
792
  // closed when it is absent. Written as a refusal anyway, because the `&& screeningTable !==
@@ -705,5 +832,13 @@ export function verifyBinaryJudgmentAdmissionClosure(input, ports) {
705
832
  instrumentSha256: screeningInstrumentSha256,
706
833
  },
707
834
  }),
835
+ ...(screeningSampleAgreementRate === undefined || promptedScreeningProcedureSha256 === undefined ? {} : {
836
+ promptedScreening: {
837
+ sampleAgreementRate: screeningSampleAgreementRate,
838
+ procedureSha256: promptedScreeningProcedureSha256,
839
+ profile: PROMPTED_SCREENING_PROFILE,
840
+ capabilityBoundary: PROMPTED_SCREENING_CAPABILITY_BOUNDARY,
841
+ },
842
+ }),
708
843
  };
709
844
  }
@@ -1,4 +1,5 @@
1
1
  import { validateBinaryInstrumentParameters } from "@jinn-network/benchmarking-aggregate";
2
+ import { PROMPTED_SCREENING_LIMITATIONS, PROMPTED_SCREENING_PROFILE, } from "../admission/contracts.js";
2
3
  export const BINARY_INSTRUMENT_REPORT_LIMITATIONS = {
3
4
  mutableModelAlias: "The gpt-5.6-luna identifier is a mutable provider alias; this evidence does not prove invariant model weights across calls.",
4
5
  reviewerKeyPerson: "Distinct reviewer signing keys prove key control, not that the controllers are distinct people.",
@@ -48,5 +49,10 @@ export function binaryInstrumentReportLimitations(parameters) {
48
49
  ...(parameters["truthAdmission"] === "screened-operator-sampled"
49
50
  ? [BINARY_INSTRUMENT_REPORT_LIMITATIONS.screenedNotIndependentlyLabeled]
50
51
  : []),
52
+ // Appended only for an authenticated screening-table/v2 closure. Legacy parameter sets omit
53
+ // the profile and therefore retain their exact limitation arrays and sealed Report bytes.
54
+ ...(parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE
55
+ ? PROMPTED_SCREENING_LIMITATIONS
56
+ : []),
51
57
  ];
52
58
  }
@@ -44,6 +44,9 @@ export declare const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-p
44
44
  export declare const ANCHORED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/4";
45
45
  export declare const BINARY_QUALIFICATION_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
46
46
  export declare const BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.1 <bundle-dir>";
47
+ /** Prompted-screening v2 claims require the verifier release that carries that admission surface. */
48
+ export declare const PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2.0 <bundle-dir>";
49
+ export declare const PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND: "npx @colophon-claims/verify@0.2 <bundle-dir>";
47
50
  /** The fixed sentence every claim package's assurance block carries (BP-21, spec §6/§7.1): what
48
51
  * distinct evaluator identities on this venue actually prove. Never softened per-claim. */
49
52
  export declare const ASSURANCE_DISCLOSURE: string;
@@ -34,6 +34,7 @@ import { validateBinaryInstrumentQualificationProjection } from "@jinn-network/b
34
34
  import { BENCHMARKING_METHOD_IDS, BENCHMARKING_METHOD_VERSION } from "@jinn-network/benchmarking-records";
35
35
  import { canonicalJsonBytes } from "@jinn-network/trust-core";
36
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";
37
+ import { PROMPTED_SCREENING_PROFILE } from "../admission/contracts.js";
37
38
  import { ClaimAnchorSchema, SELF_RUN_TRUST_ROOT, anchoredTrustRoot } from "./anchor-claims.js";
38
39
  export const CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/1";
39
40
  export const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/2";
@@ -46,6 +47,9 @@ export const BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.c
46
47
  export const ANCHORED_CLAIM_PACKAGE_SCHEMA_ID = "benchmark-product.claim-package/4";
47
48
  export const BINARY_QUALIFICATION_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.1.0 <bundle-dir>";
48
49
  export const BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.1 <bundle-dir>";
50
+ /** Prompted-screening v2 claims require the verifier release that carries that admission surface. */
51
+ export const PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2.0 <bundle-dir>";
52
+ export const PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND = "npx @colophon-claims/verify@0.2 <bundle-dir>";
49
53
  const Sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, "must be a lowercase sha256 hex digest");
50
54
  /** Mirrors `../run/preview-log.ts`'s own (unexported) `Rfc3339Schema` — restated here rather than
51
55
  * reached across the module boundary for one regex. */
@@ -361,9 +365,15 @@ const ClaimPackageWireSchema = z.object({
361
365
  if (!exactResult) {
362
366
  ctx.addIssue({ code: "custom", message: "qualification must exactly equal the Report's one F6 per-subject result", path: ["qualification"] });
363
367
  }
364
- if (claim.verification.command !== BINARY_QUALIFICATION_VERIFICATION_COMMAND
365
- || claim.verification.compatibleCommand !== BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND) {
366
- ctx.addIssue({ code: "custom", message: "binary claim package must pin verifier 0.1.0/@0.1", path: ["verification"] });
368
+ const prompted = claim.method.parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE;
369
+ const command = prompted
370
+ ? PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND
371
+ : BINARY_QUALIFICATION_VERIFICATION_COMMAND;
372
+ const compatibleCommand = prompted
373
+ ? PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND
374
+ : BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND;
375
+ if (claim.verification.command !== command || claim.verification.compatibleCommand !== compatibleCommand) {
376
+ ctx.addIssue({ code: "custom", message: `binary claim package must pin verifier ${prompted ? "0.2.0/@0.2" : "0.1.0/@0.1"}`, path: ["verification"] });
367
377
  }
368
378
  if (claim.verification.checks.length !== READER_VERIFICATION_CHECKS.length
369
379
  || claim.verification.checks.some((check, index) => check !== READER_VERIFICATION_CHECKS[index])) {
@@ -635,6 +645,10 @@ export function buildClaimPackage(input) {
635
645
  + " — a claim stating primitives the sealed Run does not carry would be dishonest");
636
646
  }
637
647
  const projection = methodProjection(reportRecord);
648
+ // Prompted screening is an authenticated Run-level admission fact. Every report/claim emitted
649
+ // from that Run uses the v2 reader, including its companion method claims; the binary claim's
650
+ // own schema separately binds the same exact profile in its method parameters.
651
+ const promptedScreening = input.runRecord.analysisPlan?.some((entry) => entry.parameters["promptedScreeningProfile"] === PROMPTED_SCREENING_PROFILE) === true;
638
652
  const disclosuresPerSubject = (reportRecord.disclosures?.perSubject ?? []);
639
653
  const taskCount = new Set(input.matrixRecord.cells.map((cell) => cell.taskDigest)).size;
640
654
  // anchor-evidence §7.4: the anchored closure is entered by the CALLER, by supplying the section
@@ -695,14 +709,18 @@ export function buildClaimPackage(input) {
695
709
  verification: {
696
710
  command: anchored
697
711
  ? PUBLIC_BUNDLE_V6_VERIFICATION_COMMAND
698
- : projection.qualification === undefined
699
- ? PUBLIC_BUNDLE_VERIFICATION_COMMAND
700
- : BINARY_QUALIFICATION_VERIFICATION_COMMAND,
712
+ : promptedScreening
713
+ ? PROMPTED_BINARY_QUALIFICATION_VERIFICATION_COMMAND
714
+ : projection.qualification === undefined
715
+ ? PUBLIC_BUNDLE_VERIFICATION_COMMAND
716
+ : BINARY_QUALIFICATION_VERIFICATION_COMMAND,
701
717
  compatibleCommand: anchored
702
718
  ? PUBLIC_BUNDLE_V6_COMPATIBLE_VERIFICATION_COMMAND
703
- : projection.qualification === undefined
704
- ? PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND
705
- : BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND,
719
+ : promptedScreening
720
+ ? PROMPTED_BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND
721
+ : projection.qualification === undefined
722
+ ? PUBLIC_BUNDLE_COMPATIBLE_VERIFICATION_COMMAND
723
+ : BINARY_QUALIFICATION_COMPATIBLE_VERIFICATION_COMMAND,
706
724
  checks: anchored ? [...ANCHORED_CLAIM_VERIFICATION_CHECKS] : [...CLAIM_VERIFICATION_CHECKS],
707
725
  // §9.2: the trust-root sentence is replaced only by a governing lock anchor. A bundle whose
708
726
  // only anchors are pending, or cover the Matrix alone, keeps the unconditional sentence.
@@ -16,8 +16,8 @@ export declare const RunPinningEvidenceSchema: z.ZodObject<{
16
16
  }, z.core.$strict>>;
17
17
  observations: z.ZodOptional<z.ZodArray<z.ZodObject<{
18
18
  axis: z.ZodEnum<{
19
- harness: "harness";
20
19
  model: "model";
20
+ harness: "harness";
21
21
  loadout: "loadout";
22
22
  isolation: "isolation";
23
23
  }>;
package/dist/schema.d.ts CHANGED
@@ -6,9 +6,9 @@ export declare const BUNDLE_ASSEMBLY_FORMAT: "benchmark-product-assembly/2";
6
6
  export declare const BUNDLE_V4_TRUST_FORMAT: "benchmark-product-public-trust/4";
7
7
  export declare const BUNDLE_V4_EVIDENCE_FORMAT: "benchmark-product-evidence-catalog/4";
8
8
  export declare const BUNDLE_QUALIFICATION_FORMAT: "benchmark-product-binary-qualification/1";
9
- export declare const BUNDLE_V4_EVIDENCE_ROLES: readonly ["task", "runtime-selection", "evaluation-spec", "admission-receipt", "solve-submission", "run-pinning-evidence", "evaluation-submission", "solve-delivery", "solve-output", "evaluation-task", "evaluation-delivery", "verdict", "item-bank", "source-manifest", "admission-index", "admission-manifest", "replacement-ledger", "source-item", "judge-instrument", "analysis-context", "label-resolution", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "snapshot-probe", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs"];
9
+ export declare const BUNDLE_V4_EVIDENCE_ROLES: readonly ["task", "runtime-selection", "evaluation-spec", "admission-receipt", "solve-submission", "run-pinning-evidence", "evaluation-submission", "solve-delivery", "solve-output", "evaluation-task", "evaluation-delivery", "verdict", "item-bank", "source-manifest", "admission-index", "admission-manifest", "replacement-ledger", "source-item", "judge-instrument", "analysis-context", "label-resolution", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "snapshot-probe", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs", "screening-prompt", "screening-procedure", "screening-pool", "screening-sample-commitment", "screening-transcript"];
10
10
  export type BundleV4EvidenceRole = (typeof BUNDLE_V4_EVIDENCE_ROLES)[number];
11
- export declare const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs"];
11
+ export declare const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES: readonly ["admission-manifest", "replacement-ledger", "source-item", "label-resolution", "analysis-context", "human-review-evaluation-spec", "human-review-form", "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster", "review-visibility-receipt", "review-reveal-receipt", "operator-assertion", "screening-table", "screening-reveal-receipt", "screening-instrument", "screening-sampling-script", "screening-raw-outputs", "screening-prompt", "screening-procedure", "screening-pool", "screening-sample-commitment", "screening-transcript"];
12
12
  export declare const BundleTrustSchema: z.ZodObject<{
13
13
  format: z.ZodLiteral<"benchmark-product-public-trust/2">;
14
14
  selfRun: z.ZodObject<{
@@ -76,6 +76,7 @@ export declare const BundleEvidenceCatalogSchema: z.ZodObject<{
76
76
  records: z.ZodArray<z.ZodObject<{
77
77
  sha256: z.ZodString;
78
78
  roles: z.ZodArray<z.ZodEnum<{
79
+ verdict: "verdict";
79
80
  task: "task";
80
81
  "runtime-selection": "runtime-selection";
81
82
  "evaluation-spec": "evaluation-spec";
@@ -87,7 +88,6 @@ export declare const BundleEvidenceCatalogSchema: z.ZodObject<{
87
88
  "solve-output": "solve-output";
88
89
  "evaluation-task": "evaluation-task";
89
90
  "evaluation-delivery": "evaluation-delivery";
90
- verdict: "verdict";
91
91
  "judge-instrument": "judge-instrument";
92
92
  "analysis-context": "analysis-context";
93
93
  "label-resolution": "label-resolution";
@@ -100,6 +100,7 @@ export declare const BundleV4EvidenceCatalogSchema: z.ZodObject<{
100
100
  records: z.ZodArray<z.ZodObject<{
101
101
  sha256: z.ZodString;
102
102
  roles: z.ZodArray<z.ZodEnum<{
103
+ verdict: "verdict";
103
104
  task: "task";
104
105
  "runtime-selection": "runtime-selection";
105
106
  "evaluation-spec": "evaluation-spec";
@@ -111,7 +112,6 @@ export declare const BundleV4EvidenceCatalogSchema: z.ZodObject<{
111
112
  "solve-output": "solve-output";
112
113
  "evaluation-task": "evaluation-task";
113
114
  "evaluation-delivery": "evaluation-delivery";
114
- verdict: "verdict";
115
115
  "item-bank": "item-bank";
116
116
  "source-manifest": "source-manifest";
117
117
  "admission-index": "admission-index";
@@ -136,6 +136,11 @@ export declare const BundleV4EvidenceCatalogSchema: z.ZodObject<{
136
136
  "screening-instrument": "screening-instrument";
137
137
  "screening-sampling-script": "screening-sampling-script";
138
138
  "screening-raw-outputs": "screening-raw-outputs";
139
+ "screening-prompt": "screening-prompt";
140
+ "screening-procedure": "screening-procedure";
141
+ "screening-pool": "screening-pool";
142
+ "screening-sample-commitment": "screening-sample-commitment";
143
+ "screening-transcript": "screening-transcript";
139
144
  }>>;
140
145
  }, z.core.$strict>>;
141
146
  }, z.core.$strict>;
@@ -197,6 +202,11 @@ export declare const BundleQualificationSchema: z.ZodObject<{
197
202
  "screening-instrument": "screening-instrument";
198
203
  "screening-sampling-script": "screening-sampling-script";
199
204
  "screening-raw-outputs": "screening-raw-outputs";
205
+ "screening-prompt": "screening-prompt";
206
+ "screening-procedure": "screening-procedure";
207
+ "screening-pool": "screening-pool";
208
+ "screening-sample-commitment": "screening-sample-commitment";
209
+ "screening-transcript": "screening-transcript";
200
210
  }>>;
201
211
  }, z.core.$strict>>;
202
212
  reachableSha256s: z.ZodArray<z.ZodString>;
package/dist/schema.js CHANGED
@@ -52,6 +52,11 @@ export const BUNDLE_V4_EVIDENCE_ROLES = [
52
52
  "screening-instrument",
53
53
  "screening-sampling-script",
54
54
  "screening-raw-outputs",
55
+ "screening-prompt",
56
+ "screening-procedure",
57
+ "screening-pool",
58
+ "screening-sample-commitment",
59
+ "screening-transcript",
55
60
  ];
56
61
  export const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES = [
57
62
  "admission-manifest", "replacement-ledger", "source-item", "label-resolution",
@@ -68,6 +73,11 @@ export const BUNDLE_V4_ADMISSION_EVIDENCE_ROLES = [
68
73
  "screening-instrument",
69
74
  "screening-sampling-script",
70
75
  "screening-raw-outputs",
76
+ "screening-prompt",
77
+ "screening-procedure",
78
+ "screening-pool",
79
+ "screening-sample-commitment",
80
+ "screening-transcript",
71
81
  ];
72
82
  const PublicKeySchema = z.object({
73
83
  keyId: z.string().min(1),
@@ -317,12 +327,11 @@ export const BundleQualificationSchema = z.strictObject({
317
327
  "human-review-packet", "human-review-response", "human-review-verdict", "reviewer-roster",
318
328
  "review-visibility-receipt", "review-reveal-receipt",
319
329
  ];
320
- const screeningEvidenceRoles = [
321
- "screening-table",
322
- "screening-reveal-receipt",
323
- "screening-instrument",
324
- "screening-sampling-script",
325
- "screening-raw-outputs",
330
+ const commonScreeningEvidenceRoles = ["screening-table", "screening-reveal-receipt", "screening-sampling-script"];
331
+ const legacyScreeningEvidenceRoles = ["screening-instrument", "screening-raw-outputs"];
332
+ const promptedScreeningEvidenceRoles = [
333
+ "screening-prompt", "screening-procedure", "screening-pool",
334
+ "screening-sample-commitment", "screening-transcript",
326
335
  ];
327
336
  if (qualification.truthAdmission === "two-human-unanimous") {
328
337
  if (humanEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) === 0)
@@ -340,10 +349,15 @@ export const BundleQualificationSchema = z.strictObject({
340
349
  // silently inheriting the screened one's evidence rules.
341
350
  }
342
351
  else if (qualification.truthAdmission === "screened-operator-sampled") {
343
- if (screeningEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) !== 1)
352
+ const legacyRoleSet = legacyScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 1)
353
+ && promptedScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 0);
354
+ const promptedRoleSet = promptedScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 1)
355
+ && legacyScreeningEvidenceRoles.every((role) => roleCounts.get(role) === 0);
356
+ if (commonScreeningEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) !== 1)
357
+ || (!legacyRoleSet && !promptedRoleSet)
344
358
  || humanEvidenceRoles.some((role) => (roleCounts.get(role) ?? 0) !== 0)
345
359
  || (roleCounts.get("operator-assertion") ?? 0) !== 0) {
346
- ctx.addIssue({ code: "custom", path: ["admissionRecords"], message: "screened admission must carry exactly one of every screening record and no human-review evidence or operator assertion" });
360
+ ctx.addIssue({ code: "custom", path: ["admissionRecords"], message: "screened admission must carry exactly one complete legacy-v1 or prompted-v2 screening record set and no human-review evidence or operator assertion" });
347
361
  }
348
362
  const screeningInstrument = qualification.admissionRecords.find((entry) => (entry.roles.includes("screening-instrument")));
349
363
  if (screeningInstrument !== undefined
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Public verifier release line. Kept in one module for output and bundle instructions. */
2
- export declare const VERIFIER_VERSION: "0.1.0";
2
+ export declare const VERIFIER_VERSION: "0.2.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Public verifier release line. Kept in one module for output and bundle instructions. */
2
- export const VERIFIER_VERSION = "0.1.0";
2
+ export const VERIFIER_VERSION = "0.2.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colophon-claims/verify",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Standalone public-bundle verifier for Colophon claims.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -47,28 +47,28 @@
47
47
  "@fontsource-variable/newsreader": "5.3.0",
48
48
  "@fontsource-variable/public-sans": "5.3.0",
49
49
  "@fontsource/ibm-plex-mono": "5.3.0",
50
- "@jinn-network/benchmarking-aggregate": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
51
- "@jinn-network/benchmarking-evidence": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
52
- "@jinn-network/benchmarking-interop": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
53
- "@jinn-network/benchmarking-local": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
54
- "@jinn-network/benchmarking-protocol": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
55
- "@jinn-network/benchmarking-records": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
56
- "@jinn-network/benchmarking-run": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
57
- "@jinn-network/task-admission": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
58
- "@jinn-network/task-execution-profiles": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
59
- "@jinn-network/task-execution-protocol": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
60
- "@jinn-network/trust-core": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
50
+ "@jinn-network/benchmarking-aggregate": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
51
+ "@jinn-network/benchmarking-evidence": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
52
+ "@jinn-network/benchmarking-interop": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
53
+ "@jinn-network/benchmarking-local": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
54
+ "@jinn-network/benchmarking-protocol": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
55
+ "@jinn-network/benchmarking-records": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
56
+ "@jinn-network/benchmarking-run": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
57
+ "@jinn-network/task-admission": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
58
+ "@jinn-network/task-execution-profiles": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
59
+ "@jinn-network/task-execution-protocol": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
60
+ "@jinn-network/trust-core": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
61
61
  "zod": "4.4.3"
62
62
  },
63
63
  "resolutions": {
64
64
  "@noble/hashes": "2.2.0"
65
65
  },
66
66
  "devDependencies": {
67
- "@jinn-network/trust-testing": "0.1.0-canary.sha.1ed36166faf16ea4b96b021ceff0397f83a0a80c",
67
+ "@jinn-network/trust-testing": "0.1.0-canary.sha.e00b2fc47fc5635b007eb349fb1e41aa81bb3c50",
68
68
  "@types/node": "^22.0.0",
69
69
  "ajv": "8.17.1",
70
70
  "typescript": "^5.9.3",
71
71
  "vitest": "^4.1.8"
72
72
  },
73
- "gitHead": "2f249073718111afd810127ff7bbbc19b206dc93"
73
+ "gitHead": "892a10067cc653d4971b22d77aea716b617ef2d6"
74
74
  }