@colophon-claims/verify 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/dist/admission/contracts.d.ts +483 -0
- package/dist/admission/contracts.js +285 -0
- package/dist/admission/index.d.ts +2 -0
- package/dist/admission/index.js +2 -0
- package/dist/admission/prompted-commitment.d.ts +19 -0
- package/dist/admission/prompted-commitment.js +52 -0
- package/dist/admission/prompted-selection.d.ts +24 -0
- package/dist/admission/prompted-selection.js +85 -0
- package/dist/admission/verification.d.ts +17 -3
- package/dist/admission/verification.js +230 -49
- package/dist/assets.d.ts +21 -1
- package/dist/assets.js +60 -3
- package/dist/binding/beacon-binding.d.ts +230 -0
- package/dist/binding/beacon-binding.js +325 -0
- package/dist/binding/report-face.d.ts +45 -0
- package/dist/binding/report-face.js +153 -0
- package/dist/cli.js +74 -12
- package/dist/index.d.ts +14 -3
- package/dist/index.js +16 -3
- package/dist/manifest.d.ts +30 -4
- package/dist/manifest.js +30 -0
- package/dist/materialize.d.ts +7 -0
- package/dist/materialize.js +7 -0
- package/dist/outcome.d.ts +31 -0
- package/dist/outcome.js +45 -0
- package/dist/profile/binary-qualification.js +6 -0
- package/dist/profile/claim-consistency.d.ts +8 -1
- package/dist/profile/claim-consistency.js +4 -4
- package/dist/profile/claim.d.ts +203 -1
- package/dist/profile/claim.js +192 -43
- package/dist/profile/disclosure.d.ts +273 -0
- package/dist/profile/disclosure.js +240 -0
- package/dist/profile/pinning-evidence.d.ts +1 -1
- package/dist/profile/run-results.d.ts +8 -2
- package/dist/profile/run-results.js +9 -3
- package/dist/profile/task-selection.d.ts +69 -0
- package/dist/profile/task-selection.js +140 -0
- package/dist/reader-instructions.d.ts +38 -1
- package/dist/reader-instructions.js +42 -2
- package/dist/schema.d.ts +13 -2
- package/dist/schema.js +39 -8
- package/dist/signers.d.ts +48 -0
- package/dist/signers.js +77 -0
- package/dist/verify.d.ts +20 -6
- package/dist/verify.js +156 -31
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -14
|
@@ -11,6 +11,13 @@ 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_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";
|
|
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";
|
|
20
|
+
export const SCREENING_TABLE_V2_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-table/v2";
|
|
14
21
|
export const SCREENING_REVEAL_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
|
|
15
22
|
export const HUMAN_REVIEW_PACKET_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
|
|
16
23
|
export const HUMAN_REVIEW_RESPONSE_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-response.v1+json";
|
|
@@ -20,6 +27,7 @@ export const HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.bina
|
|
|
20
27
|
export const HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.operator-truth-assertion.v1+json";
|
|
21
28
|
// screened-operator-sampled admission branch (spec §6.3, §6.6; packet P6).
|
|
22
29
|
export const SCREENING_TABLE_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-table.v1+json";
|
|
30
|
+
export const SCREENING_TABLE_V2_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-table.v2+json";
|
|
23
31
|
export const SCREENING_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-reveal-receipt.v1+json";
|
|
24
32
|
const DigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/u);
|
|
25
33
|
const TimestampSchema = z.string().datetime({ offset: true });
|
|
@@ -201,6 +209,280 @@ export const ScreeningTableSchema = z.strictObject({
|
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
211
|
});
|
|
212
|
+
export const PROMPTED_SCREENING_PROFILE = "prompted-codex-screening/v1";
|
|
213
|
+
export const PROMPTED_SCREENING_LIMITATIONS = [
|
|
214
|
+
"prompt-compliance-not-machine-verified",
|
|
215
|
+
"provider-execution-not-machine-verified",
|
|
216
|
+
"transcript-provenance-not-machine-verified",
|
|
217
|
+
"mutable-model-alias-weights-not-machine-verified",
|
|
218
|
+
];
|
|
219
|
+
const PromptedAgentSchema = (alias, model, reasoningEffort, maxBatchSize) => z.strictObject({
|
|
220
|
+
alias: z.literal(alias),
|
|
221
|
+
model: z.literal(model),
|
|
222
|
+
reasoningEffort: z.literal(reasoningEffort),
|
|
223
|
+
maxBatchSize: z.literal(maxBatchSize),
|
|
224
|
+
});
|
|
225
|
+
/** Closed, machine-checkable orchestration metadata. Prompt and transcript bytes stay opaque. */
|
|
226
|
+
export const PromptedScreeningProcedureV1Schema = z.strictObject({
|
|
227
|
+
protocol: z.literal(PROMPTED_SCREENING_PROCEDURE_PROTOCOL),
|
|
228
|
+
procedureId: z.literal(PROMPTED_SCREENING_PROFILE),
|
|
229
|
+
coordinatorPromptSha256: DigestSchema,
|
|
230
|
+
coordinator: z.strictObject({
|
|
231
|
+
alias: z.literal("Sol"),
|
|
232
|
+
model: z.literal("gpt-5.6-sol"),
|
|
233
|
+
reasoningEffort: z.literal("high"),
|
|
234
|
+
mayOrchestrate: z.literal(true),
|
|
235
|
+
}),
|
|
236
|
+
judgmentAgents: z.tuple([
|
|
237
|
+
PromptedAgentSchema("Luna", "gpt-5.6-luna", "medium", 32),
|
|
238
|
+
PromptedAgentSchema("Terra", "gpt-5.6-terra", "high", 16),
|
|
239
|
+
PromptedAgentSchema("Sol", "gpt-5.6-sol", "high", 8),
|
|
240
|
+
]),
|
|
241
|
+
toolPolicy: z.strictObject({
|
|
242
|
+
coordinator: z.literal("orchestration-only"),
|
|
243
|
+
judgmentAgents: z.strictObject({
|
|
244
|
+
web: z.literal(false),
|
|
245
|
+
shell: z.literal(false),
|
|
246
|
+
repository: z.literal(false),
|
|
247
|
+
search: z.literal(false),
|
|
248
|
+
}),
|
|
249
|
+
}),
|
|
250
|
+
output: z.strictObject({
|
|
251
|
+
alphabet: z.tuple([z.literal("CORRECT"), z.literal("WRONG"), z.literal("UNSURE")]),
|
|
252
|
+
invalidOutputDecision: z.literal("UNSURE"),
|
|
253
|
+
}),
|
|
254
|
+
retry: z.strictObject({
|
|
255
|
+
maxRetries: z.literal(1),
|
|
256
|
+
onlyWhen: z.literal("infrastructure-failure-with-no-model-output"),
|
|
257
|
+
prompt: z.literal("identical"),
|
|
258
|
+
}),
|
|
259
|
+
transcriptSha256: DigestSchema,
|
|
260
|
+
sealedAt: TimestampSchema,
|
|
261
|
+
});
|
|
262
|
+
export const SCREENING_POOL_CANDIDATE_CLASSES = ["correct", "specific-wrong", "vague-topical-wrong"];
|
|
263
|
+
export const SCREENING_POOL_STRATA = ["category-1", "category-2", "category-3", "category-4"];
|
|
264
|
+
const ScreeningPoolCommonItemSchema = z.strictObject({
|
|
265
|
+
itemSha256: DigestSchema,
|
|
266
|
+
intendedLabel: BinaryJudgmentTruthLabelSchema,
|
|
267
|
+
candidateClass: z.enum(SCREENING_POOL_CANDIDATE_CLASSES),
|
|
268
|
+
stratum: z.enum(SCREENING_POOL_STRATA),
|
|
269
|
+
poolPosition: z.number().int().positive(),
|
|
270
|
+
slotId: z.string().regex(/^slot-[0-9]{3}$/u),
|
|
271
|
+
});
|
|
272
|
+
export const ScreeningPoolItemSchema = z.discriminatedUnion("poolKind", [
|
|
273
|
+
ScreeningPoolCommonItemSchema.extend({ poolKind: z.literal("main") }),
|
|
274
|
+
ScreeningPoolCommonItemSchema.extend({ poolKind: z.literal("reserve"), reserveOrder: z.number().int().positive() }),
|
|
275
|
+
]);
|
|
276
|
+
/** The complete, ordered 240-main plus 424-reserve candidate universe. */
|
|
277
|
+
export const ScreeningPoolV1Schema = z.strictObject({
|
|
278
|
+
protocol: z.literal(SCREENING_POOL_PROTOCOL),
|
|
279
|
+
draftId: IdentitySchema,
|
|
280
|
+
identityCommitmentSha256: DigestSchema,
|
|
281
|
+
items: z.array(ScreeningPoolItemSchema).length(664),
|
|
282
|
+
sealedAt: TimestampSchema,
|
|
283
|
+
}).superRefine((pool, ctx) => {
|
|
284
|
+
const slots = new Map();
|
|
285
|
+
const identities = new Set();
|
|
286
|
+
for (const [index, item] of pool.items.entries()) {
|
|
287
|
+
if (item.poolPosition !== index + 1)
|
|
288
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "poolPosition"], message: "poolPosition must be contiguous and match array order" });
|
|
289
|
+
if (identities.has(item.itemSha256))
|
|
290
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "itemSha256"], message: "itemSha256 must be unique" });
|
|
291
|
+
identities.add(item.itemSha256);
|
|
292
|
+
const expectedLabel = item.candidateClass === "correct" ? "CORRECT" : "WRONG";
|
|
293
|
+
if (item.intendedLabel !== expectedLabel)
|
|
294
|
+
ctx.addIssue({ code: "custom", path: ["items", index, "intendedLabel"], message: "intendedLabel does not derive from candidateClass" });
|
|
295
|
+
slots.set(item.slotId, [...(slots.get(item.slotId) ?? []), item]);
|
|
296
|
+
}
|
|
297
|
+
const mains = pool.items.filter((item) => item.poolKind === "main");
|
|
298
|
+
if (mains.length !== 240 || slots.size !== 240)
|
|
299
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: "pool must contain exactly 240 main slots" });
|
|
300
|
+
const expectedSlotIds = Array.from({ length: 240 }, (_, index) => `slot-${(index + 1).toString().padStart(3, "0")}`);
|
|
301
|
+
const actualSlotIds = [...slots.keys()].sort(compareCodeUnitStrings);
|
|
302
|
+
if (actualSlotIds.length !== expectedSlotIds.length || actualSlotIds.some((value, index) => value !== expectedSlotIds[index]))
|
|
303
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: "slot lineage must be exactly slot-001 through slot-240" });
|
|
304
|
+
for (const [slotId, items] of slots) {
|
|
305
|
+
const main = items.filter((item) => item.poolKind === "main");
|
|
306
|
+
if (main.length !== 1) {
|
|
307
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} must contain exactly one main item` });
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const reserves = items.filter((item) => item.poolKind === "reserve").sort((a, b) => a.reserveOrder - b.reserveOrder);
|
|
311
|
+
for (const [index, reserve] of reserves.entries()) {
|
|
312
|
+
if (reserve.reserveOrder !== index + 1)
|
|
313
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserveOrder must be contiguous` });
|
|
314
|
+
if (reserve.poolPosition <= main[0].poolPosition)
|
|
315
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserves must follow their main item in pool order` });
|
|
316
|
+
if (reserve.candidateClass !== main[0].candidateClass || reserve.stratum !== main[0].stratum || reserve.intendedLabel !== main[0].intendedLabel)
|
|
317
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `${slotId} reserves must preserve class, stratum, and intended label` });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
for (const candidateClass of SCREENING_POOL_CANDIDATE_CLASSES)
|
|
321
|
+
for (const stratum of SCREENING_POOL_STRATA) {
|
|
322
|
+
if (mains.filter((item) => item.candidateClass === candidateClass && item.stratum === stratum).length !== 20)
|
|
323
|
+
ctx.addIssue({ code: "custom", path: ["items"], message: `main pool must contain 20 ${candidateClass}/${stratum} items` });
|
|
324
|
+
}
|
|
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
|
+
]);
|
|
410
|
+
export const ScreeningSampleCommitmentV1Schema = z.strictObject({
|
|
411
|
+
protocol: z.literal(SCREENING_SAMPLE_COMMITMENT_PROTOCOL),
|
|
412
|
+
draftId: IdentitySchema,
|
|
413
|
+
poolSha256: DigestSchema,
|
|
414
|
+
poolIdentityCommitmentSha256: DigestSchema,
|
|
415
|
+
samplingProcedure: z.literal("screening-sample/1"),
|
|
416
|
+
sampleSeed: z.string().min(1),
|
|
417
|
+
sampleSize: z.literal(72),
|
|
418
|
+
sampleItemSha256s: z.array(DigestSchema).length(72).superRefine((values, ctx) => {
|
|
419
|
+
for (let index = 1; index < values.length; index += 1) {
|
|
420
|
+
if (compareCodeUnitStrings(values[index - 1], values[index]) >= 0)
|
|
421
|
+
ctx.addIssue({ code: "custom", message: "sample identities must be sorted and unique" });
|
|
422
|
+
}
|
|
423
|
+
}),
|
|
424
|
+
committedAt: TimestampSchema,
|
|
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
|
+
]);
|
|
452
|
+
const ScreeningDecisionSchema = z.enum(["CORRECT", "WRONG", "UNSURE"]);
|
|
453
|
+
const RitsuScreeningDecisionSchema = z.discriminatedUnion("checked", [
|
|
454
|
+
z.strictObject({ checked: z.literal(false) }),
|
|
455
|
+
z.strictObject({ checked: z.literal(true), verdict: z.enum(["confirm", "exclude"]), decidedAt: TimestampSchema }),
|
|
456
|
+
]);
|
|
457
|
+
export const PromptedScreeningRowV2Schema = z.strictObject({
|
|
458
|
+
itemSha256: DigestSchema,
|
|
459
|
+
intendedLabel: BinaryJudgmentTruthLabelSchema,
|
|
460
|
+
screeningVerdict: ScreeningDecisionSchema,
|
|
461
|
+
terraReviewVerdict: ScreeningDecisionSchema.optional(),
|
|
462
|
+
solReviewVerdict: ScreeningDecisionSchema.optional(),
|
|
463
|
+
ritsuDecision: RitsuScreeningDecisionSchema,
|
|
464
|
+
});
|
|
465
|
+
/** Signed authority decision table for the prompted Codex procedure. */
|
|
466
|
+
export const ScreeningTableV2Schema = z.strictObject({
|
|
467
|
+
protocol: z.literal(SCREENING_TABLE_V2_PROTOCOL),
|
|
468
|
+
draftId: IdentitySchema,
|
|
469
|
+
procedureSha256: DigestSchema,
|
|
470
|
+
coordinatorPromptSha256: DigestSchema,
|
|
471
|
+
poolSha256: DigestSchema,
|
|
472
|
+
sampleCommitmentSha256: DigestSchema,
|
|
473
|
+
samplingScriptSha256: DigestSchema,
|
|
474
|
+
transcriptSha256: DigestSchema,
|
|
475
|
+
operator: z.literal("Ritsu"),
|
|
476
|
+
rows: z.array(PromptedScreeningRowV2Schema).length(664),
|
|
477
|
+
sealedAt: TimestampSchema,
|
|
478
|
+
}).superRefine((table, ctx) => {
|
|
479
|
+
for (let index = 1; index < table.rows.length; index += 1) {
|
|
480
|
+
if (compareCodeUnitStrings(table.rows[index - 1].itemSha256, table.rows[index].itemSha256) >= 0) {
|
|
481
|
+
ctx.addIssue({ code: "custom", path: ["rows"], message: "rows must be sorted by itemSha256 and unique" });
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
});
|
|
204
486
|
// The two-human-review reasons (unchanged) and the screened-branch reasons this packet adds
|
|
205
487
|
// (spec §6.4; packet P6). This is one of four widened copies of the closed reason vocabulary
|
|
206
488
|
// (the other three: verify/src/schema.ts's exclusions[].reason, verify/src/admission/
|
|
@@ -227,6 +509,9 @@ export const HumanReviewReplacementLedgerEntrySchema = z.strictObject({
|
|
|
227
509
|
excludedPoolPosition: z.number().int().positive(),
|
|
228
510
|
replacementPoolPosition: z.number().int().positive(),
|
|
229
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(),
|
|
230
515
|
// Per-item two-human apparatus (spec §6.9 deliberately drops it for the screened branch):
|
|
231
516
|
// present if and only if `reason` is one of the three two-human reasons above.
|
|
232
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
|
+
}
|
|
@@ -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 {
|
|
@@ -40,6 +40,7 @@ export interface VerifiedBinaryJudgmentAdmissionExclusion {
|
|
|
40
40
|
readonly stratum: string;
|
|
41
41
|
readonly reason: "review-disagreement" | "review-indeterminate" | "review-incomplete" | "screening-disagreement" | "screening-indeterminate" | "screening-hand-excluded";
|
|
42
42
|
readonly replacementItemSha256: AdmissionSha256;
|
|
43
|
+
readonly receivingSlotId?: string;
|
|
43
44
|
}
|
|
44
45
|
export interface VerifiedBinaryJudgmentAdmissionClosure {
|
|
45
46
|
readonly manifestSha256: AdmissionSha256;
|
|
@@ -57,12 +58,25 @@ export interface VerifiedBinaryJudgmentAdmissionClosure {
|
|
|
57
58
|
readonly sha256: AdmissionSha256;
|
|
58
59
|
readonly roles: readonly BinaryJudgmentAdmissionRecordRole[];
|
|
59
60
|
}[];
|
|
60
|
-
/** Present
|
|
61
|
+
/** Present for the legacy screening-table/v1 method (spec §6.5 check (3)). */
|
|
61
62
|
readonly screening?: {
|
|
62
63
|
readonly sampleAgreementRate: number;
|
|
63
64
|
readonly instrumentSha256: AdmissionSha256;
|
|
64
65
|
};
|
|
66
|
+
/** Present for screening-table/v2; kept separate so the legacy v1 result shape stays source-compatible. */
|
|
67
|
+
readonly promptedScreening?: {
|
|
68
|
+
readonly sampleAgreementRate: number;
|
|
69
|
+
readonly procedureSha256: AdmissionSha256;
|
|
70
|
+
readonly profile: typeof PROMPTED_SCREENING_PROFILE;
|
|
71
|
+
readonly capabilityBoundary: PromptedScreeningCapabilityBoundary;
|
|
72
|
+
};
|
|
65
73
|
}
|
|
74
|
+
export declare const PROMPTED_SCREENING_CAPABILITY_BOUNDARY: {
|
|
75
|
+
readonly status: "not-machine-verified";
|
|
76
|
+
readonly machineVerified: readonly ["sealed-pool", "sealed-sample", "signed-table", "operator-decisions", "artifact-integrity"];
|
|
77
|
+
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"];
|
|
78
|
+
};
|
|
79
|
+
export type PromptedScreeningCapabilityBoundary = typeof PROMPTED_SCREENING_CAPABILITY_BOUNDARY;
|
|
66
80
|
export declare class BinaryJudgmentAdmissionClosureError extends Error {
|
|
67
81
|
readonly path: string;
|
|
68
82
|
constructor(path: string, detail: string, options?: ErrorOptions);
|