@colophon-claims/verify 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/admission/application.d.ts +18 -0
- package/dist/admission/application.js +53 -0
- package/dist/admission/contracts.d.ts +506 -0
- package/dist/admission/contracts.js +459 -0
- package/dist/admission/index.d.ts +5 -0
- package/dist/admission/index.js +5 -0
- package/dist/admission/intake.d.ts +75 -0
- package/dist/admission/intake.js +70 -0
- package/dist/admission/result-evaluation.d.ts +18 -0
- package/dist/admission/result-evaluation.js +71 -0
- package/dist/admission/screening-sample.d.ts +56 -0
- package/dist/admission/screening-sample.js +126 -0
- package/dist/admission/verification.d.ts +102 -0
- package/dist/admission/verification.js +844 -0
- package/dist/anchor/check.d.ts +95 -0
- package/dist/anchor/check.js +146 -0
- package/dist/anchor/ports.d.ts +6 -0
- package/dist/anchor/ports.js +354 -0
- package/dist/assets.d.ts +33 -0
- package/dist/assets.js +885 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +20 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +205 -0
- package/dist/comparison.d.ts +64 -0
- package/dist/comparison.js +235 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/manifest.d.ts +54 -0
- package/dist/manifest.js +240 -0
- package/dist/materialize.d.ts +4 -0
- package/dist/materialize.js +13 -0
- package/dist/profile/admission-receipts.d.ts +11 -0
- package/dist/profile/admission-receipts.js +24 -0
- package/dist/profile/anchor-claims.d.ts +157 -0
- package/dist/profile/anchor-claims.js +330 -0
- package/dist/profile/artifacts.d.ts +261 -0
- package/dist/profile/artifacts.js +139 -0
- package/dist/profile/assembly-ports.d.ts +19 -0
- package/dist/profile/assembly-ports.js +42 -0
- package/dist/profile/binary-judge-manifest.d.ts +121 -0
- package/dist/profile/binary-judge-manifest.js +106 -0
- package/dist/profile/binary-qualification.d.ts +9 -0
- package/dist/profile/binary-qualification.js +58 -0
- package/dist/profile/branding-assets.d.ts +5 -0
- package/dist/profile/branding-assets.js +5 -0
- package/dist/profile/branding.d.ts +24 -0
- package/dist/profile/branding.js +14 -0
- package/dist/profile/claim-consistency.d.ts +26 -0
- package/dist/profile/claim-consistency.js +91 -0
- package/dist/profile/claim.d.ts +327 -0
- package/dist/profile/claim.js +742 -0
- package/dist/profile/errors.d.ts +49 -0
- package/dist/profile/errors.js +78 -0
- package/dist/profile/inspect-assurance.d.ts +16 -0
- package/dist/profile/inspect-assurance.js +30 -0
- package/dist/profile/inspect-disclosure.d.ts +28 -0
- package/dist/profile/inspect-disclosure.js +54 -0
- package/dist/profile/inspect-manifest.d.ts +706 -0
- package/dist/profile/inspect-manifest.js +397 -0
- package/dist/profile/isolation.d.ts +21 -0
- package/dist/profile/isolation.js +31 -0
- package/dist/profile/pinning-evidence.d.ts +41 -0
- package/dist/profile/pinning-evidence.js +43 -0
- package/dist/profile/ports.d.ts +3 -0
- package/dist/profile/ports.js +11 -0
- package/dist/profile/preview-log.d.ts +4 -0
- package/dist/profile/preview-log.js +3 -0
- package/dist/profile/run-results.d.ts +17 -0
- package/dist/profile/run-results.js +23 -0
- package/dist/profile/signing.d.ts +10 -0
- package/dist/profile/signing.js +46 -0
- package/dist/profile/trust.d.ts +13 -0
- package/dist/profile/trust.js +35 -0
- package/dist/profile/venue.d.ts +2 -0
- package/dist/profile/venue.js +2 -0
- package/dist/profile/verdict.d.ts +28 -0
- package/dist/profile/verdict.js +51 -0
- package/dist/reader-instructions.d.ts +41 -0
- package/dist/reader-instructions.js +52 -0
- package/dist/schema.d.ts +380 -0
- package/dist/schema.js +498 -0
- package/dist/verify.d.ts +72 -0
- package/dist/verify.js +1573 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +63 -3
- package/schemas/assembly-row.schema.json +194 -0
- package/schemas/bundle-manifest.schema.json +23 -0
- package/schemas/claim-package.schema.json +279 -0
- package/schemas/dsse-envelope.schema.json +25 -0
- package/schemas/evidence-catalog.schema.json +43 -0
- package/schemas/public-trust.schema.json +44 -0
- package/schemas/verdict-catalog.schema.json +27 -0
- package/scripts/external-verify.py +238 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { BINARY_JUDGMENT_TIMESTAMP_PATTERN, compareCodeUnitStrings, } from "@jinn-network/task-execution-profiles";
|
|
4
|
+
export const HUMAN_REVIEW_PACKET_PROTOCOL = "https://spec.jinn.network/binary-judgment/human-review-packet/v1";
|
|
5
|
+
export const HUMAN_REVIEW_RESPONSE_PROTOCOL = "https://spec.jinn.network/binary-judgment/human-review-response/v1";
|
|
6
|
+
export const HUMAN_REVIEW_VISIBILITY_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/visibility-receipt/v1";
|
|
7
|
+
export const HUMAN_REVIEW_ROSTER_PROTOCOL = "https://spec.jinn.network/binary-judgment/reviewer-roster/v1";
|
|
8
|
+
export const HUMAN_REVIEW_REVEAL_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/reveal-receipt/v1";
|
|
9
|
+
export const HUMAN_REVIEW_REPLACEMENT_LEDGER_PROTOCOL = "https://spec.jinn.network/binary-judgment/replacement-ledger/v1";
|
|
10
|
+
export const HUMAN_REVIEW_OPERATOR_ASSERTION_PROTOCOL = "https://spec.jinn.network/binary-judgment/operator-truth-assertion/v1";
|
|
11
|
+
export const BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL = "https://spec.jinn.network/binary-judgment/admission-manifest/v1";
|
|
12
|
+
// screened-operator-sampled admission branch (spec §6.1, §6.3, §6.6; packet P6).
|
|
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";
|
|
18
|
+
export const SCREENING_REVEAL_RECEIPT_PROTOCOL = "https://spec.jinn.network/binary-judgment/screening-reveal-receipt/v1";
|
|
19
|
+
export const HUMAN_REVIEW_PACKET_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-packet.v1+json";
|
|
20
|
+
export const HUMAN_REVIEW_RESPONSE_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.human-review-response.v1+json";
|
|
21
|
+
export const HUMAN_REVIEW_VISIBILITY_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.visibility-receipt.v1+json";
|
|
22
|
+
export const HUMAN_REVIEW_ROSTER_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.reviewer-roster.v1+json";
|
|
23
|
+
export const HUMAN_REVIEW_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.reveal-receipt.v1+json";
|
|
24
|
+
export const HUMAN_REVIEW_OPERATOR_ASSERTION_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.operator-truth-assertion.v1+json";
|
|
25
|
+
// screened-operator-sampled admission branch (spec §6.3, §6.6; packet P6).
|
|
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";
|
|
28
|
+
export const SCREENING_REVEAL_RECEIPT_MEDIA_TYPE = "application/vnd.jinn.binary-judgment.screening-reveal-receipt.v1+json";
|
|
29
|
+
const DigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/u);
|
|
30
|
+
const TimestampSchema = z.string().datetime({ offset: true });
|
|
31
|
+
const IdentitySchema = z.string().min(1).max(256);
|
|
32
|
+
const EvaluatorIdentitySchema = IdentitySchema.regex(/^(?:https?:\/\/|urn:)[^\s]+$/u);
|
|
33
|
+
// §3.1 rule 1: one identifier dialect, not two. Shared shape with `candidateClass`.
|
|
34
|
+
const IDENTIFIER_NAME = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/u;
|
|
35
|
+
const CandidateClassSchema = z.string().regex(IDENTIFIER_NAME);
|
|
36
|
+
const BinaryJudgmentTruthLabelSchema = z.enum(["CORRECT", "WRONG"]);
|
|
37
|
+
const BinaryJudgmentStratumSchema = z.string().regex(IDENTIFIER_NAME);
|
|
38
|
+
/**
|
|
39
|
+
* RFC 3339 instant SHAPE, seconds precision, no fractional part. The pattern is imported from the
|
|
40
|
+
* profiles package rather than restated, so this mirrored payload copy cannot drift from the
|
|
41
|
+
* canonical one it mirrors.
|
|
42
|
+
*/
|
|
43
|
+
const BinaryJudgmentTimestampShapeSchema = z.string().regex(new RegExp(BINARY_JUDGMENT_TIMESTAMP_PATTERN, "u"));
|
|
44
|
+
const BinaryJudgmentPayloadSchema = z.strictObject({
|
|
45
|
+
itemId: z.string().regex(/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u),
|
|
46
|
+
question: z.string(),
|
|
47
|
+
referenceAnswer: z.string(),
|
|
48
|
+
candidateAnswer: z.string(),
|
|
49
|
+
evidence: z.string().optional(),
|
|
50
|
+
provenance: z.strictObject({
|
|
51
|
+
sourceCommitment: DigestSchema,
|
|
52
|
+
timestamp: BinaryJudgmentTimestampShapeSchema,
|
|
53
|
+
}),
|
|
54
|
+
sources: z.array(z.strictObject({
|
|
55
|
+
digest: z.strictObject({ sha256: z.string().regex(/^[0-9a-f]{64}$/u) }),
|
|
56
|
+
})).min(1),
|
|
57
|
+
});
|
|
58
|
+
const ConflictListSchema = z.array(z.string().min(1)).superRefine((values, ctx) => {
|
|
59
|
+
for (let index = 1; index < values.length; index += 1) {
|
|
60
|
+
if (compareCodeUnitStrings(values[index - 1], values[index]) >= 0) {
|
|
61
|
+
ctx.addIssue({ code: "custom", message: "conflicts must be sorted and unique" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const SortedUniqueDigestListSchema = z.array(DigestSchema).superRefine((values, ctx) => {
|
|
67
|
+
for (let index = 1; index < values.length; index += 1) {
|
|
68
|
+
if (compareCodeUnitStrings(values[index - 1], values[index]) >= 0) {
|
|
69
|
+
ctx.addIssue({ code: "custom", message: "digest references must be sorted and unique" });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const SortedUniqueDigestPairSchema = z.tuple([DigestSchema, DigestSchema]).superRefine((values, ctx) => {
|
|
75
|
+
if (compareCodeUnitStrings(values[0], values[1]) >= 0)
|
|
76
|
+
ctx.addIssue({ code: "custom", message: "digest references must be sorted and unique" });
|
|
77
|
+
});
|
|
78
|
+
export const HUMAN_REVIEW_OMITTED_FIELDS = [
|
|
79
|
+
"instrumentIdentity", "candidateClass", "stratum", "otherReview", "postRunOutcomes",
|
|
80
|
+
];
|
|
81
|
+
export const HumanReviewPacketSchema = z.strictObject({
|
|
82
|
+
protocol: z.literal(HUMAN_REVIEW_PACKET_PROTOCOL),
|
|
83
|
+
itemSha256: DigestSchema,
|
|
84
|
+
item: BinaryJudgmentPayloadSchema,
|
|
85
|
+
evaluationSpecSha256: DigestSchema,
|
|
86
|
+
reviewerId: EvaluatorIdentitySchema,
|
|
87
|
+
form: z.strictObject({
|
|
88
|
+
question: z.literal("Is the candidate answer correct relative to the question and reference answer?"),
|
|
89
|
+
labels: z.tuple([z.literal("CORRECT"), z.literal("WRONG"), z.literal("indeterminate")]),
|
|
90
|
+
completeReviewRequired: z.literal(true),
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
export const HumanReviewVisibilityReceiptSchema = z.strictObject({
|
|
94
|
+
protocol: z.literal(HUMAN_REVIEW_VISIBILITY_RECEIPT_PROTOCOL),
|
|
95
|
+
packetSha256: DigestSchema,
|
|
96
|
+
itemSha256: DigestSchema,
|
|
97
|
+
reviewerId: EvaluatorIdentitySchema,
|
|
98
|
+
omittedFields: z.tuple(HUMAN_REVIEW_OMITTED_FIELDS.map((value) => z.literal(value))),
|
|
99
|
+
issuedAt: TimestampSchema,
|
|
100
|
+
});
|
|
101
|
+
export const HumanReviewResponseSchema = z.strictObject({
|
|
102
|
+
protocol: z.literal(HUMAN_REVIEW_RESPONSE_PROTOCOL),
|
|
103
|
+
packetSha256: DigestSchema,
|
|
104
|
+
visibilityReceiptSha256: DigestSchema,
|
|
105
|
+
itemSha256: DigestSchema,
|
|
106
|
+
evaluatorId: EvaluatorIdentitySchema,
|
|
107
|
+
label: z.union([BinaryJudgmentTruthLabelSchema, z.literal("indeterminate")]),
|
|
108
|
+
complete: z.boolean(),
|
|
109
|
+
completedAt: TimestampSchema,
|
|
110
|
+
});
|
|
111
|
+
export const ReviewerDeclarationSchema = z.strictObject({
|
|
112
|
+
evaluatorId: EvaluatorIdentitySchema,
|
|
113
|
+
keyId: IdentitySchema,
|
|
114
|
+
personId: IdentitySchema,
|
|
115
|
+
role: IdentitySchema,
|
|
116
|
+
conflicts: ConflictListSchema,
|
|
117
|
+
});
|
|
118
|
+
export const HumanReviewRosterSchema = z.strictObject({
|
|
119
|
+
protocol: z.literal(HUMAN_REVIEW_ROSTER_PROTOCOL),
|
|
120
|
+
itemSha256: DigestSchema,
|
|
121
|
+
reviewers: z.tuple([ReviewerDeclarationSchema, ReviewerDeclarationSchema]),
|
|
122
|
+
attestedBy: IdentitySchema,
|
|
123
|
+
attestorKeyId: IdentitySchema,
|
|
124
|
+
attestorRole: z.literal("roster-attestor"),
|
|
125
|
+
attestedAt: TimestampSchema,
|
|
126
|
+
});
|
|
127
|
+
export const HumanReviewRevealReceiptSchema = z.strictObject({
|
|
128
|
+
protocol: z.literal(HUMAN_REVIEW_REVEAL_RECEIPT_PROTOCOL),
|
|
129
|
+
draftId: IdentitySchema,
|
|
130
|
+
itemSha256: DigestSchema,
|
|
131
|
+
truthFrozenAt: TimestampSchema,
|
|
132
|
+
judgeExecutionState: z.literal("not-started"),
|
|
133
|
+
attestedBy: IdentitySchema,
|
|
134
|
+
attestorKeyId: IdentitySchema,
|
|
135
|
+
attestorRole: z.literal("truth-reveal-attestor"),
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* `screening-reveal-receipt/v1` (spec §6.6): a bank-scoped sibling of `HumanReviewRevealReceiptSchema`
|
|
139
|
+
* above. Same ordering primitive, same attestor role, same `judgeExecutionState: "not-started"`
|
|
140
|
+
* gate — differing only in subject: the bank (`screeningTableSha256`), not an item (`itemSha256`).
|
|
141
|
+
* `AdmissionAuthorityRole` (`verify/src/admission/verification.ts`) is deliberately unchanged: this
|
|
142
|
+
* reuses `truth-reveal-attestor` rather than minting a new role.
|
|
143
|
+
*/
|
|
144
|
+
export const ScreeningRevealReceiptSchema = z.strictObject({
|
|
145
|
+
protocol: z.literal(SCREENING_REVEAL_RECEIPT_PROTOCOL),
|
|
146
|
+
draftId: IdentitySchema,
|
|
147
|
+
screeningTableSha256: DigestSchema,
|
|
148
|
+
truthFrozenAt: TimestampSchema,
|
|
149
|
+
judgeExecutionState: z.literal("not-started"),
|
|
150
|
+
attestedBy: IdentitySchema,
|
|
151
|
+
attestorKeyId: IdentitySchema,
|
|
152
|
+
attestorRole: z.literal("truth-reveal-attestor"),
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* One row of the `screening-table/v1` record (spec §6.3). `handVerdict` is present if and only if
|
|
156
|
+
* `handChecked === true`; both directions refuse. `handVerdict` deliberately does not reuse
|
|
157
|
+
* `BinaryJudgmentTruthLabelSchema` — the hand-check outcome space is confirm-or-exclude only, with
|
|
158
|
+
* no label corrections.
|
|
159
|
+
*/
|
|
160
|
+
export const ScreeningRowSchema = z.strictObject({
|
|
161
|
+
itemSha256: DigestSchema,
|
|
162
|
+
intendedLabel: BinaryJudgmentTruthLabelSchema,
|
|
163
|
+
screeningVerdict: z.union([BinaryJudgmentTruthLabelSchema, z.literal("indeterminate")]),
|
|
164
|
+
handChecked: z.boolean(),
|
|
165
|
+
handVerdict: z.enum(["confirm", "exclude"]).optional(),
|
|
166
|
+
}).superRefine((row, ctx) => {
|
|
167
|
+
if (row.handChecked && row.handVerdict === undefined) {
|
|
168
|
+
ctx.addIssue({ code: "custom", path: ["handVerdict"], message: "handVerdict is required when handChecked is true" });
|
|
169
|
+
}
|
|
170
|
+
if (!row.handChecked && row.handVerdict !== undefined) {
|
|
171
|
+
ctx.addIssue({ code: "custom", path: ["handVerdict"], message: "handVerdict must be absent when handChecked is false" });
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
/**
|
|
175
|
+
* `screening-table/v1` (spec §6.3): one signed record per bank. Every derived quantity (the
|
|
176
|
+
* flagged set, the sample, the exclusions, the agreement rate) is a *view* of this table, never a
|
|
177
|
+
* stored field that can disagree with it — those recomputations live in `screening-sample.ts` and
|
|
178
|
+
* its siblings, not here. `screeningModel` is deliberately absent: it is derivable from
|
|
179
|
+
* `screeningInstrumentSha256`, and a second copy is a second thing to drift. The table is signed
|
|
180
|
+
* once, over the whole record, on the existing DSSE signing path used by the other admission
|
|
181
|
+
* records (`sealRoleEvidence`), not the ledger's non-DSSE path.
|
|
182
|
+
*/
|
|
183
|
+
export const ScreeningTableSchema = z.strictObject({
|
|
184
|
+
protocol: z.literal(SCREENING_TABLE_PROTOCOL),
|
|
185
|
+
draftId: IdentitySchema,
|
|
186
|
+
screeningInstrumentSha256: DigestSchema,
|
|
187
|
+
sampleSeed: z.string().min(1),
|
|
188
|
+
// Positive integer, `1 <= sampleSize`. The `<= rows.length` half is a verifier recomputation
|
|
189
|
+
// (spec §6.5 check (0)) owned elsewhere; this schema owns only the positivity.
|
|
190
|
+
sampleSize: z.number().int().positive(),
|
|
191
|
+
samplingScriptSha256: DigestSchema,
|
|
192
|
+
// Digest-bound opaque sidecar; the verifier resolves and hashes its exact bytes but never parses
|
|
193
|
+
// or interprets their content (spec §6.5).
|
|
194
|
+
rawOutputsSha256: DigestSchema,
|
|
195
|
+
rows: z.array(ScreeningRowSchema),
|
|
196
|
+
sealedAt: TimestampSchema,
|
|
197
|
+
}).superRefine((table, ctx) => {
|
|
198
|
+
if (table.rows.length === 0) {
|
|
199
|
+
ctx.addIssue({ code: "custom", path: ["rows"], message: "rows must be non-empty" });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
for (let index = 1; index < table.rows.length; index += 1) {
|
|
203
|
+
if (compareCodeUnitStrings(table.rows[index - 1].itemSha256, table.rows[index].itemSha256) >= 0) {
|
|
204
|
+
ctx.addIssue({ code: "custom", path: ["rows"], message: "rows must be sorted by itemSha256 and unique" });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
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
|
+
});
|
|
373
|
+
// The two-human-review reasons (unchanged) and the screened-branch reasons this packet adds
|
|
374
|
+
// (spec §6.4; packet P6). This is one of four widened copies of the closed reason vocabulary
|
|
375
|
+
// (the other three: verify/src/schema.ts's exclusions[].reason, verify/src/admission/
|
|
376
|
+
// verification.ts's VerifiedBinaryJudgmentAdmissionExclusion.reason, and
|
|
377
|
+
// core/src/operations/human-review.ts's HumanAdmissionExclusionSummary.reason) — duplicated
|
|
378
|
+
// with a comment at each site rather than imported, matching this package's existing pattern for
|
|
379
|
+
// shared closed vocabularies (e.g. IDENTIFIER_NAME above) and its standalone-verifier posture.
|
|
380
|
+
// Two further sites carry the vocabulary but are deliberately left narrow: human-review.ts's
|
|
381
|
+
// exclusion-reason derivation ternary and its downstream type guard structurally cannot produce
|
|
382
|
+
// a screening-* value without the screened branch's own construction logic (out of scope, see
|
|
383
|
+
// this packet's report), so widening their literal sets would be inert. A seventh site,
|
|
384
|
+
// verification.ts's `expectedExclusionReason` (recomputation logic, S3's), is out of scope too.
|
|
385
|
+
const HUMAN_REVIEW_LEDGER_REASONS = ["review-disagreement", "review-indeterminate", "review-incomplete"];
|
|
386
|
+
// Derived from §6.4's admission rule (`admitted := handChecked ? (handVerdict === "confirm") :
|
|
387
|
+
// agreed`): a row is excluded because the screen disagreed with the intended label, because the
|
|
388
|
+
// screen's verdict was indeterminate, or because the operator's hand check excluded it (including
|
|
389
|
+
// the R-3 tie-break: a screen-agreed row the hand check overrode).
|
|
390
|
+
const SCREENING_LEDGER_REASONS = ["screening-disagreement", "screening-indeterminate", "screening-hand-excluded"];
|
|
391
|
+
export const HumanReviewReplacementLedgerEntrySchema = z.strictObject({
|
|
392
|
+
excludedItemSha256: DigestSchema,
|
|
393
|
+
replacementItemSha256: DigestSchema,
|
|
394
|
+
candidateClass: CandidateClassSchema,
|
|
395
|
+
stratum: BinaryJudgmentStratumSchema,
|
|
396
|
+
excludedPoolPosition: z.number().int().positive(),
|
|
397
|
+
replacementPoolPosition: z.number().int().positive(),
|
|
398
|
+
reason: z.enum([...HUMAN_REVIEW_LEDGER_REASONS, ...SCREENING_LEDGER_REASONS]),
|
|
399
|
+
// Per-item two-human apparatus (spec §6.9 deliberately drops it for the screened branch):
|
|
400
|
+
// present if and only if `reason` is one of the three two-human reasons above.
|
|
401
|
+
reviewVerdictSha256s: SortedUniqueDigestPairSchema.optional(),
|
|
402
|
+
visibilityReceiptSha256s: SortedUniqueDigestPairSchema.optional(),
|
|
403
|
+
reviewerRosterSha256: DigestSchema.optional(),
|
|
404
|
+
revealReceiptSha256: DigestSchema.optional(),
|
|
405
|
+
}).superRefine((entry, ctx) => {
|
|
406
|
+
const isTwoHuman = HUMAN_REVIEW_LEDGER_REASONS.includes(entry.reason);
|
|
407
|
+
const twoHumanFields = [
|
|
408
|
+
["reviewVerdictSha256s", entry.reviewVerdictSha256s],
|
|
409
|
+
["visibilityReceiptSha256s", entry.visibilityReceiptSha256s],
|
|
410
|
+
["reviewerRosterSha256", entry.reviewerRosterSha256],
|
|
411
|
+
["revealReceiptSha256", entry.revealReceiptSha256],
|
|
412
|
+
];
|
|
413
|
+
for (const [field, value] of twoHumanFields) {
|
|
414
|
+
if (isTwoHuman && value === undefined) {
|
|
415
|
+
ctx.addIssue({ code: "custom", path: [field], message: `${field} is required for a two-human-review reason` });
|
|
416
|
+
}
|
|
417
|
+
if (!isTwoHuman && value !== undefined) {
|
|
418
|
+
ctx.addIssue({ code: "custom", path: [field], message: `${field} must be absent for a screening reason` });
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
export const HumanReviewReplacementLedgerSchema = z.strictObject({
|
|
423
|
+
protocol: z.literal(HUMAN_REVIEW_REPLACEMENT_LEDGER_PROTOCOL),
|
|
424
|
+
draftId: IdentitySchema,
|
|
425
|
+
entries: z.array(HumanReviewReplacementLedgerEntrySchema),
|
|
426
|
+
sealedAt: TimestampSchema,
|
|
427
|
+
});
|
|
428
|
+
export const HumanReviewOperatorAssertionSchema = z.strictObject({
|
|
429
|
+
protocol: z.literal(HUMAN_REVIEW_OPERATOR_ASSERTION_PROTOCOL),
|
|
430
|
+
itemSha256: DigestSchema,
|
|
431
|
+
truthLabel: BinaryJudgmentTruthLabelSchema,
|
|
432
|
+
assertedBy: IdentitySchema,
|
|
433
|
+
assertedAt: TimestampSchema,
|
|
434
|
+
attestorKeyId: IdentitySchema,
|
|
435
|
+
attestorRole: z.literal("operator-truth-attestor"),
|
|
436
|
+
limitation: z.literal("operator-only-not-publication-grade"),
|
|
437
|
+
});
|
|
438
|
+
export const BinaryJudgmentAdmissionManifestSchema = z.strictObject({
|
|
439
|
+
protocol: z.literal(BINARY_JUDGMENT_ADMISSION_MANIFEST_PROTOCOL),
|
|
440
|
+
draftId: IdentitySchema,
|
|
441
|
+
truthAdmission: z.enum(["two-human-unanimous", "operator-only", "screened-operator-sampled"]),
|
|
442
|
+
labelResolutionSha256s: SortedUniqueDigestListSchema,
|
|
443
|
+
analysisContextSha256s: SortedUniqueDigestListSchema,
|
|
444
|
+
excludedItemSha256s: SortedUniqueDigestListSchema,
|
|
445
|
+
replacementLedgerSha256: DigestSchema,
|
|
446
|
+
// Present if and only if truthAdmission === "screened-operator-sampled" (spec §6.8). Existing
|
|
447
|
+
// two-human-unanimous and operator-only manifests stay byte-identical: this key is absent for
|
|
448
|
+
// both, exactly as it is today.
|
|
449
|
+
screeningTableSha256: DigestSchema.optional(),
|
|
450
|
+
admittedAt: TimestampSchema,
|
|
451
|
+
}).superRefine((manifest, ctx) => {
|
|
452
|
+
const isScreened = manifest.truthAdmission === "screened-operator-sampled";
|
|
453
|
+
if (isScreened && manifest.screeningTableSha256 === undefined) {
|
|
454
|
+
ctx.addIssue({ code: "custom", path: ["screeningTableSha256"], message: "screeningTableSha256 is required for screened-operator-sampled admission" });
|
|
455
|
+
}
|
|
456
|
+
if (!isScreened && manifest.screeningTableSha256 !== undefined) {
|
|
457
|
+
ctx.addIssue({ code: "custom", path: ["screeningTableSha256"], message: "screeningTableSha256 must be absent outside screened-operator-sampled admission" });
|
|
458
|
+
}
|
|
459
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const BINARY_ITEM_BANK_ENTRY_PROTOCOL: "https://spec.jinn.network/binary-judgment/item-bank-entry/v1";
|
|
3
|
+
export declare const BINARY_SOURCE_MANIFEST_ENTRY_PROTOCOL: "https://spec.jinn.network/binary-judgment/source-manifest-entry/v1";
|
|
4
|
+
export declare const BINARY_ADMISSION_INDEX_ENTRY_PROTOCOL: "https://spec.jinn.network/binary-judgment/admission-index-entry/v1";
|
|
5
|
+
export declare const BINARY_ITEM_BANK_INTAKE_EXTENSION: "https://product.jinn.network/extensions/binary-judgment-intake/v1";
|
|
6
|
+
export declare const BinaryItemBankEntrySchema: z.ZodObject<{
|
|
7
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/item-bank-entry/v1">;
|
|
8
|
+
item: z.ZodObject<{
|
|
9
|
+
itemId: z.ZodString;
|
|
10
|
+
question: z.ZodString;
|
|
11
|
+
referenceAnswer: z.ZodString;
|
|
12
|
+
candidateAnswer: z.ZodString;
|
|
13
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
14
|
+
provenance: z.ZodObject<{
|
|
15
|
+
sourceCommitment: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
16
|
+
timestamp: z.ZodString;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
19
|
+
digest: z.ZodObject<{
|
|
20
|
+
sha256: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
}, z.core.$strict>>;
|
|
23
|
+
}, z.core.$strict>;
|
|
24
|
+
}, z.core.$strict>;
|
|
25
|
+
export type BinaryItemBankEntry = z.infer<typeof BinaryItemBankEntrySchema>;
|
|
26
|
+
export declare const BinarySourceManifestEntrySchema: z.ZodObject<{
|
|
27
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/source-manifest-entry/v1">;
|
|
28
|
+
provenanceSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
29
|
+
source: z.ZodObject<{
|
|
30
|
+
name: z.ZodOptional<z.ZodString>;
|
|
31
|
+
uri: z.ZodString;
|
|
32
|
+
digest: z.ZodObject<{
|
|
33
|
+
sha256: z.ZodString;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
mediaType: z.ZodOptional<z.ZodString>;
|
|
36
|
+
downloadLocation: z.ZodOptional<z.ZodString>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
license: z.ZodObject<{
|
|
39
|
+
name: z.ZodOptional<z.ZodString>;
|
|
40
|
+
uri: z.ZodString;
|
|
41
|
+
digest: z.ZodObject<{
|
|
42
|
+
sha256: z.ZodString;
|
|
43
|
+
}, z.core.$strict>;
|
|
44
|
+
mediaType: z.ZodOptional<z.ZodString>;
|
|
45
|
+
downloadLocation: z.ZodOptional<z.ZodString>;
|
|
46
|
+
}, z.core.$strict>;
|
|
47
|
+
attribution: z.ZodObject<{
|
|
48
|
+
name: z.ZodOptional<z.ZodString>;
|
|
49
|
+
uri: z.ZodString;
|
|
50
|
+
digest: z.ZodObject<{
|
|
51
|
+
sha256: z.ZodString;
|
|
52
|
+
}, z.core.$strict>;
|
|
53
|
+
mediaType: z.ZodOptional<z.ZodString>;
|
|
54
|
+
downloadLocation: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, z.core.$strict>;
|
|
56
|
+
publishedAt: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
57
|
+
}, z.core.$strict>;
|
|
58
|
+
export type BinarySourceManifestEntry = z.infer<typeof BinarySourceManifestEntrySchema>;
|
|
59
|
+
export declare const BinaryAdmissionIndexEntrySchema: z.ZodObject<{
|
|
60
|
+
protocol: z.ZodLiteral<"https://spec.jinn.network/binary-judgment/admission-index-entry/v1">;
|
|
61
|
+
admissionManifestSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
62
|
+
itemSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
63
|
+
labelResolutionSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
64
|
+
analysisContextSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
65
|
+
}, z.core.$strict>;
|
|
66
|
+
export type BinaryAdmissionIndexEntry = z.infer<typeof BinaryAdmissionIndexEntrySchema>;
|
|
67
|
+
export declare const BinaryItemBankIntakeExtensionSchema: z.ZodObject<{
|
|
68
|
+
profile: z.ZodLiteral<"https://spec.jinn.network/task-profiles/binary-judgment/2.0">;
|
|
69
|
+
itemBankSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
70
|
+
sourceManifestSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
71
|
+
admissionIndexSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
72
|
+
admissionManifestSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
73
|
+
replacementLedgerSha256: z.ZodPipe<z.ZodString, z.ZodTransform<`sha256:${string}`, string>>;
|
|
74
|
+
}, z.core.$strict>;
|
|
75
|
+
export type BinaryItemBankIntakeExtension = z.infer<typeof BinaryItemBankIntakeExtensionSchema>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isCalendarStrictRfc3339 } from "@jinn-network/benchmarking-records";
|
|
4
|
+
import { BINARY_JUDGMENT_TIMESTAMP_PATTERN } from "@jinn-network/task-execution-profiles";
|
|
5
|
+
export const BINARY_ITEM_BANK_ENTRY_PROTOCOL = "https://spec.jinn.network/binary-judgment/item-bank-entry/v1";
|
|
6
|
+
export const BINARY_SOURCE_MANIFEST_ENTRY_PROTOCOL = "https://spec.jinn.network/binary-judgment/source-manifest-entry/v1";
|
|
7
|
+
export const BINARY_ADMISSION_INDEX_ENTRY_PROTOCOL = "https://spec.jinn.network/binary-judgment/admission-index-entry/v1";
|
|
8
|
+
export const BINARY_ITEM_BANK_INTAKE_EXTENSION = "https://product.jinn.network/extensions/binary-judgment-intake/v1";
|
|
9
|
+
const DigestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/u).transform((value) => value);
|
|
10
|
+
const Sha256HexSchema = z.string().regex(/^[0-9a-f]{64}$/u);
|
|
11
|
+
/**
|
|
12
|
+
* RFC 3339 instant SHAPE, seconds precision, no fractional part. The pattern itself is imported
|
|
13
|
+
* from the profiles package rather than restated, so the payload contract and this manifest row
|
|
14
|
+
* cannot drift apart. Shape only: calendar strictness is the `publishedAt` refinement below.
|
|
15
|
+
*/
|
|
16
|
+
const BinaryJudgmentTimestampShapeSchema = z.string().regex(new RegExp(BINARY_JUDGMENT_TIMESTAMP_PATTERN, "u"));
|
|
17
|
+
const ItemPayloadSchema = z.strictObject({
|
|
18
|
+
itemId: z.string().regex(/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u),
|
|
19
|
+
question: z.string(),
|
|
20
|
+
referenceAnswer: z.string(),
|
|
21
|
+
candidateAnswer: z.string(),
|
|
22
|
+
evidence: z.string().optional(),
|
|
23
|
+
provenance: z.strictObject({
|
|
24
|
+
sourceCommitment: DigestSchema,
|
|
25
|
+
timestamp: BinaryJudgmentTimestampShapeSchema,
|
|
26
|
+
}),
|
|
27
|
+
sources: z.array(z.strictObject({ digest: z.strictObject({ sha256: Sha256HexSchema }) })).min(1),
|
|
28
|
+
});
|
|
29
|
+
const SourceDescriptorSchema = z.strictObject({
|
|
30
|
+
name: z.string().min(1).optional(),
|
|
31
|
+
uri: z.string().min(1),
|
|
32
|
+
digest: z.strictObject({ sha256: Sha256HexSchema }),
|
|
33
|
+
mediaType: z.string().min(1).optional(),
|
|
34
|
+
downloadLocation: z.string().min(1).optional(),
|
|
35
|
+
});
|
|
36
|
+
export const BinaryItemBankEntrySchema = z.strictObject({
|
|
37
|
+
protocol: z.literal(BINARY_ITEM_BANK_ENTRY_PROTOCOL),
|
|
38
|
+
item: ItemPayloadSchema,
|
|
39
|
+
});
|
|
40
|
+
export const BinarySourceManifestEntrySchema = z.strictObject({
|
|
41
|
+
protocol: z.literal(BINARY_SOURCE_MANIFEST_ENTRY_PROTOCOL),
|
|
42
|
+
provenanceSha256: DigestSchema,
|
|
43
|
+
source: SourceDescriptorSchema,
|
|
44
|
+
license: SourceDescriptorSchema,
|
|
45
|
+
attribution: SourceDescriptorSchema,
|
|
46
|
+
// The source publication instant lives on the source row, not the item: two items drawn from
|
|
47
|
+
// one source then structurally carry the same cluster key (provenanceSha256) and the same
|
|
48
|
+
// publishedAt, instead of a rule someone has to check by hand. A per-item timestamp would let a
|
|
49
|
+
// bank author encode an ordering that correlates with the label.
|
|
50
|
+
publishedAt: BinaryJudgmentTimestampShapeSchema.refine(isCalendarStrictRfc3339, "publishedAt must be a calendar-strict RFC 3339 instant at seconds precision"),
|
|
51
|
+
}).superRefine((entry, ctx) => {
|
|
52
|
+
if (`sha256:${entry.source.digest.sha256}` !== entry.provenanceSha256) {
|
|
53
|
+
ctx.addIssue({ code: "custom", path: ["source", "digest", "sha256"], message: "source digest must equal provenanceSha256" });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
export const BinaryAdmissionIndexEntrySchema = z.strictObject({
|
|
57
|
+
protocol: z.literal(BINARY_ADMISSION_INDEX_ENTRY_PROTOCOL),
|
|
58
|
+
admissionManifestSha256: DigestSchema,
|
|
59
|
+
itemSha256: DigestSchema,
|
|
60
|
+
labelResolutionSha256: DigestSchema,
|
|
61
|
+
analysisContextSha256: DigestSchema,
|
|
62
|
+
});
|
|
63
|
+
export const BinaryItemBankIntakeExtensionSchema = z.strictObject({
|
|
64
|
+
profile: z.literal("https://spec.jinn.network/task-profiles/binary-judgment/2.0"),
|
|
65
|
+
itemBankSha256: DigestSchema,
|
|
66
|
+
sourceManifestSha256: DigestSchema,
|
|
67
|
+
admissionIndexSha256: DigestSchema,
|
|
68
|
+
admissionManifestSha256: DigestSchema,
|
|
69
|
+
replacementLedgerSha256: DigestSchema,
|
|
70
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface AdmissionVerdictStatementView {
|
|
2
|
+
readonly evaluatorId: string;
|
|
3
|
+
readonly verdict: "pass" | "fail" | "inconclusive";
|
|
4
|
+
readonly evaluationSpecificationSha256: string;
|
|
5
|
+
readonly measurements: Readonly<Record<string, boolean | number | string>>;
|
|
6
|
+
readonly evaluatedAt: string;
|
|
7
|
+
readonly evidence?: readonly {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly sha256: string;
|
|
10
|
+
readonly mediaType?: string;
|
|
11
|
+
}[];
|
|
12
|
+
readonly limitations?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function readAdmissionVerdictEnvelope(envelopeBytes: Uint8Array): AdmissionVerdictStatementView;
|
|
15
|
+
export declare function readOrderedAdmissionVerdictMeasurements(envelopeBytes: Uint8Array): readonly {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly value: boolean | number | string;
|
|
18
|
+
}[];
|