@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.
Files changed (96) hide show
  1. package/README.md +39 -0
  2. package/dist/admission/application.d.ts +18 -0
  3. package/dist/admission/application.js +53 -0
  4. package/dist/admission/contracts.d.ts +506 -0
  5. package/dist/admission/contracts.js +459 -0
  6. package/dist/admission/index.d.ts +5 -0
  7. package/dist/admission/index.js +5 -0
  8. package/dist/admission/intake.d.ts +75 -0
  9. package/dist/admission/intake.js +70 -0
  10. package/dist/admission/result-evaluation.d.ts +18 -0
  11. package/dist/admission/result-evaluation.js +71 -0
  12. package/dist/admission/screening-sample.d.ts +56 -0
  13. package/dist/admission/screening-sample.js +126 -0
  14. package/dist/admission/verification.d.ts +102 -0
  15. package/dist/admission/verification.js +844 -0
  16. package/dist/anchor/check.d.ts +95 -0
  17. package/dist/anchor/check.js +146 -0
  18. package/dist/anchor/ports.d.ts +6 -0
  19. package/dist/anchor/ports.js +354 -0
  20. package/dist/assets.d.ts +33 -0
  21. package/dist/assets.js +885 -0
  22. package/dist/bin.d.ts +2 -0
  23. package/dist/bin.js +20 -0
  24. package/dist/cli.d.ts +14 -0
  25. package/dist/cli.js +205 -0
  26. package/dist/comparison.d.ts +64 -0
  27. package/dist/comparison.js +235 -0
  28. package/dist/index.d.ts +23 -0
  29. package/dist/index.js +23 -0
  30. package/dist/manifest.d.ts +54 -0
  31. package/dist/manifest.js +240 -0
  32. package/dist/materialize.d.ts +4 -0
  33. package/dist/materialize.js +13 -0
  34. package/dist/profile/admission-receipts.d.ts +11 -0
  35. package/dist/profile/admission-receipts.js +24 -0
  36. package/dist/profile/anchor-claims.d.ts +157 -0
  37. package/dist/profile/anchor-claims.js +330 -0
  38. package/dist/profile/artifacts.d.ts +261 -0
  39. package/dist/profile/artifacts.js +139 -0
  40. package/dist/profile/assembly-ports.d.ts +19 -0
  41. package/dist/profile/assembly-ports.js +42 -0
  42. package/dist/profile/binary-judge-manifest.d.ts +121 -0
  43. package/dist/profile/binary-judge-manifest.js +106 -0
  44. package/dist/profile/binary-qualification.d.ts +9 -0
  45. package/dist/profile/binary-qualification.js +58 -0
  46. package/dist/profile/branding-assets.d.ts +5 -0
  47. package/dist/profile/branding-assets.js +5 -0
  48. package/dist/profile/branding.d.ts +24 -0
  49. package/dist/profile/branding.js +14 -0
  50. package/dist/profile/claim-consistency.d.ts +26 -0
  51. package/dist/profile/claim-consistency.js +91 -0
  52. package/dist/profile/claim.d.ts +327 -0
  53. package/dist/profile/claim.js +742 -0
  54. package/dist/profile/errors.d.ts +49 -0
  55. package/dist/profile/errors.js +78 -0
  56. package/dist/profile/inspect-assurance.d.ts +16 -0
  57. package/dist/profile/inspect-assurance.js +30 -0
  58. package/dist/profile/inspect-disclosure.d.ts +28 -0
  59. package/dist/profile/inspect-disclosure.js +54 -0
  60. package/dist/profile/inspect-manifest.d.ts +706 -0
  61. package/dist/profile/inspect-manifest.js +397 -0
  62. package/dist/profile/isolation.d.ts +21 -0
  63. package/dist/profile/isolation.js +31 -0
  64. package/dist/profile/pinning-evidence.d.ts +41 -0
  65. package/dist/profile/pinning-evidence.js +43 -0
  66. package/dist/profile/ports.d.ts +3 -0
  67. package/dist/profile/ports.js +11 -0
  68. package/dist/profile/preview-log.d.ts +4 -0
  69. package/dist/profile/preview-log.js +3 -0
  70. package/dist/profile/run-results.d.ts +17 -0
  71. package/dist/profile/run-results.js +23 -0
  72. package/dist/profile/signing.d.ts +10 -0
  73. package/dist/profile/signing.js +46 -0
  74. package/dist/profile/trust.d.ts +13 -0
  75. package/dist/profile/trust.js +35 -0
  76. package/dist/profile/venue.d.ts +2 -0
  77. package/dist/profile/venue.js +2 -0
  78. package/dist/profile/verdict.d.ts +28 -0
  79. package/dist/profile/verdict.js +51 -0
  80. package/dist/reader-instructions.d.ts +41 -0
  81. package/dist/reader-instructions.js +52 -0
  82. package/dist/schema.d.ts +380 -0
  83. package/dist/schema.js +498 -0
  84. package/dist/verify.d.ts +72 -0
  85. package/dist/verify.js +1573 -0
  86. package/dist/version.d.ts +2 -0
  87. package/dist/version.js +2 -0
  88. package/package.json +63 -3
  89. package/schemas/assembly-row.schema.json +194 -0
  90. package/schemas/bundle-manifest.schema.json +23 -0
  91. package/schemas/claim-package.schema.json +279 -0
  92. package/schemas/dsse-envelope.schema.json +25 -0
  93. package/schemas/evidence-catalog.schema.json +43 -0
  94. package/schemas/public-trust.schema.json +44 -0
  95. package/schemas/verdict-catalog.schema.json +27 -0
  96. package/scripts/external-verify.py +238 -0
@@ -0,0 +1,330 @@
1
+ /**
2
+ * The anchored-closure projection (anchor-evidence design §7.4 and §9.2): the pure function that
3
+ * turns a bundle's carried AnchorEvidence bytes into the claim package's `anchors` section, and
4
+ * the conditional honesty copy that section gates.
5
+ *
6
+ * This module is **single-sourced, not mirrored**. `@colophon-claims/core` already depends on this
7
+ * package (it takes `nodeCryptoAnchorPorts` and the reader instructions from here), so producer and
8
+ * verifier import the same function rather than two copies of it. §7.4 requires that "producer and
9
+ * verifier derive the section from the same bundle bytes by the same pure function, so
10
+ * claim-consistency remains an exact byte-compare" — one function is the strongest available form
11
+ * of that requirement, since two mirrored copies can drift and this one cannot.
12
+ *
13
+ * Four disciplines are load-bearing:
14
+ *
15
+ * - **Records are read only through `parseExactAnchorEvidence`, proof content only through
16
+ * `decodeAnchorProofContent`.** Conformance is shape-level and admits alternate JSON spellings;
17
+ * identity is byte-exactness. A record selected through the laxer door would have a digest other
18
+ * than the one it is filed under.
19
+ * - **Subject selectors are digest-keyed.** The lock anchor is any carried anchor whose
20
+ * `subject.digest` equals the digest of the bundle's exact `run.json` bytes; the matrix anchor is
21
+ * any whose digest equals `matrix.json`'s. `subject.kind` is then required to equal the resolved
22
+ * record's actual kind — it is checked, never used to route (§8 step 2). A digest that names no
23
+ * bundle record, or a kind that misdescribes the one it names, is `invalid`: affirmative evidence
24
+ * of substitution, reported louder than absence.
25
+ * - **Byte-embedded facts only.** `genTime`, `policyOid`, `serialNumber`,
26
+ * `signerCertificateSha256` for RFC 3161; the attested block height (or `pending`) for
27
+ * OpenTimestamps. Facts that need external data (block time) or lack a canonical rendering
28
+ * (issuer distinguished names, accuracy intervals) never enter this section — they are
29
+ * verifier-report and presentation content (§7.4).
30
+ * - **No trust material is supplied here.** This projection is a function of the bundle's bytes,
31
+ * never of a verifier's configured roots, because the sealed claim text must be identical for
32
+ * every reader (§8, "The honesty text keys on byte-facts"). Trust evaluation lives in the
33
+ * `integrity-anchors` check's own report.
34
+ */
35
+ import { z } from "zod";
36
+ import { MATRIX_RECORD_KIND, RUN_RECORD_KIND, compareCalendarStrictRfc3339Instants, } from "@jinn-network/benchmarking-records";
37
+ import { OPENTIMESTAMPS_ANCHOR_PROFILE, RFC3161_TSA_ANCHOR_PROFILE, createOpenTimestampsProofVerifier, createRfc3161AnchorProofVerifier, decodeAnchorProofContent, parseExactAnchorEvidence, } from "@jinn-network/trust-core";
38
+ import { nodeCryptoAnchorPorts } from "../anchor/ports.js";
39
+ // ---------------------------------------------------------------------------
40
+ // The wire schema. Defined once here and imported by both claim-package modules,
41
+ // for the same drift reason the derivation is single-sourced.
42
+ // ---------------------------------------------------------------------------
43
+ const Sha256HexSchema = z.string().regex(/^[a-f0-9]{64}$/, "must be a lowercase sha256 hex digest");
44
+ /** RFC 3161's four byte-embedded facts, strictly — an extra key here would be a fact this section
45
+ * is not allowed to carry. */
46
+ const Rfc3161ClaimAnchorFactsSchema = z.strictObject({
47
+ genTime: z.string().min(1),
48
+ policyOid: z.string().min(1),
49
+ serialNumber: z.string().regex(/^[a-f0-9]+$/, "must be lowercase hex of the DER INTEGER content octets"),
50
+ signerCertificateSha256: Sha256HexSchema,
51
+ });
52
+ /** OpenTimestamps' two disjoint shapes: an attested height, or the calendar-only promise. */
53
+ const OpenTimestampsClaimAnchorFactsSchema = z.union([
54
+ z.strictObject({ blockHeight: z.number().int().nonnegative() }),
55
+ z.strictObject({ pending: z.literal(true) }),
56
+ ]);
57
+ export const ClaimAnchorSchema = z.strictObject({
58
+ subject: z.enum(["lock", "matrix"]),
59
+ kind: z.string().min(1),
60
+ provider: z.string().min(1),
61
+ recordSha256: Sha256HexSchema,
62
+ upgradesRecordSha256: Sha256HexSchema.optional(),
63
+ facts: z.union([Rfc3161ClaimAnchorFactsSchema, OpenTimestampsClaimAnchorFactsSchema]),
64
+ });
65
+ /** A record this projection refuses. Every caller converts it into its own typed refusal
66
+ * (`record-integrity` on the producer side, an `invalid` anchor outcome on the verifier side), so
67
+ * the failure is never swallowed and never crosses a package boundary as an untyped throw. */
68
+ export class ClaimAnchorProjectionError extends Error {
69
+ name = "ClaimAnchorProjectionError";
70
+ recordSha256;
71
+ constructor(recordSha256, message) {
72
+ super(message);
73
+ this.recordSha256 = recordSha256;
74
+ }
75
+ }
76
+ function compareCodeUnits(left, right) {
77
+ return left < right ? -1 : left > right ? 1 : 0;
78
+ }
79
+ function isRfc3161Facts(facts) {
80
+ return "genTime" in facts;
81
+ }
82
+ function isPending(facts) {
83
+ return "pending" in facts;
84
+ }
85
+ /**
86
+ * The proof outcome, computed with **no trust material** — the only outcome shape this projection
87
+ * may key on. A verifier's configured roots change `present` into `verified`; they must never
88
+ * change one byte of the sealed claim (§8).
89
+ */
90
+ function verifyCarriedProof(provider, subjectSha256, proofBytes) {
91
+ return provider === RFC3161_TSA_ANCHOR_PROFILE
92
+ ? createRfc3161AnchorProofVerifier(nodeCryptoAnchorPorts).verifyProof({ subjectSha256, proofBytes })
93
+ : createOpenTimestampsProofVerifier().verifyProof({ subjectSha256, proofBytes });
94
+ }
95
+ function factsFor(recordSha256, provider, result) {
96
+ if (result.status === "invalid") {
97
+ throw new ClaimAnchorProjectionError(recordSha256, `the carried proof does not verify: ${result.reason}`);
98
+ }
99
+ // Exhaustive over the four proof statuses: everything below reads one of these three shapes. A
100
+ // fifth member of ANCHOR_PROOF_STATUSES fails here rather than being projected as a fact.
101
+ result.status;
102
+ if (provider === RFC3161_TSA_ANCHOR_PROFILE) {
103
+ if (result.status === "pending") {
104
+ // Structurally unreachable: an RFC 3161 token is complete when it is issued. Refusing rather
105
+ // than inventing a `pending` RFC 3161 fact shape keeps the two profiles' fact grammars
106
+ // disjoint by construction.
107
+ throw new ClaimAnchorProjectionError(recordSha256, "an RFC 3161 token has no pending form");
108
+ }
109
+ const facts = result.facts;
110
+ return {
111
+ genTime: facts.genTime,
112
+ policyOid: facts.policyOid,
113
+ serialNumber: facts.serialNumber,
114
+ signerCertificateSha256: facts.signerCertificateSha256,
115
+ };
116
+ }
117
+ if (result.status === "pending")
118
+ return { pending: true };
119
+ return { blockHeight: result.facts.blockHeight };
120
+ }
121
+ /**
122
+ * §6.2's upgrade edge, derived from the carried bytes rather than read from producer bookkeeping.
123
+ *
124
+ * The AnchorEvidence record has no field naming the record it supersedes (§5 rule 3 keeps nothing
125
+ * derivable in the record), so the edge must come out of the set itself or not appear at all. It is
126
+ * emitted exactly when one `(subject-digest, provider)` group carries precisely one pending proof
127
+ * and one completed proof — the shape the design calls "the write-once exception admits exactly
128
+ * this pair" (§11 family 9). Any other group shape leaves the field absent on every member: an
129
+ * ambiguous chain is not an edge this function is willing to assert, and both sides compute the
130
+ * same absence, so the byte-compare holds either way.
131
+ *
132
+ * Recorded as a finding for the design owner: §7.4 does not enumerate this field, and RunState's
133
+ * own `upgradesRecordSha256` admits longer chains than a bundle can express.
134
+ */
135
+ function upgradeEdges(entries, subjectDigests) {
136
+ const edges = new Map();
137
+ const groups = new Map();
138
+ for (const entry of entries) {
139
+ const key = `${subjectDigests.get(entry.subject)}${entry.provider}`;
140
+ groups.set(key, [...(groups.get(key) ?? []), entry]);
141
+ }
142
+ for (const group of groups.values()) {
143
+ const pending = group.filter((entry) => isPending(entry.facts));
144
+ const complete = group.filter((entry) => !isPending(entry.facts));
145
+ if (pending.length === 1 && complete.length === 1) {
146
+ edges.set(complete[0].recordSha256, pending[0].recordSha256);
147
+ }
148
+ }
149
+ return edges;
150
+ }
151
+ /**
152
+ * Projects the carried AnchorEvidence records into the claim package's `anchors` section.
153
+ *
154
+ * Ordered by record digest so the section has exactly one spelling for one carried set. Throws
155
+ * `ClaimAnchorProjectionError` on a record that is not exactly-sealed, does not parse, names a
156
+ * digest no bundle record has, misdescribes the kind of the record it does name, carries a provider
157
+ * profile no verifier implements, or carries a proof the rules reject.
158
+ */
159
+ export function deriveClaimAnchors(input) {
160
+ const subjectDigests = new Map([
161
+ ["lock", input.runSha256],
162
+ ["matrix", input.matrixSha256],
163
+ ]);
164
+ const kindsBySubject = new Map([
165
+ ["lock", RUN_RECORD_KIND],
166
+ ["matrix", MATRIX_RECORD_KIND],
167
+ ]);
168
+ const partial = [...input.records]
169
+ .sort((left, right) => compareCodeUnits(left.recordSha256, right.recordSha256))
170
+ .map((carried) => {
171
+ let record;
172
+ let proofBytes;
173
+ try {
174
+ record = parseExactAnchorEvidence(carried.bytes);
175
+ proofBytes = decodeAnchorProofContent(record.proof.content);
176
+ }
177
+ catch (cause) {
178
+ throw new ClaimAnchorProjectionError(carried.recordSha256, `anchor record is not the exact sealed encoding of a conforming AnchorEvidence: ${cause instanceof Error ? cause.message : String(cause)}`);
179
+ }
180
+ // Digest-keyed selection. Nothing routes on `subject.kind`; a kind label can never move an
181
+ // anchor onto a claim its digest does not back.
182
+ const subject = [...subjectDigests].find(([, digest]) => digest === record.subject.digest.sha256)?.[0];
183
+ if (subject === undefined) {
184
+ throw new ClaimAnchorProjectionError(carried.recordSha256, `anchor covers ${record.subject.digest.sha256}, which is neither this bundle's sealed Run nor its sealed Matrix`);
185
+ }
186
+ const resolvedKind = kindsBySubject.get(subject);
187
+ if (record.subject.kind !== resolvedKind) {
188
+ throw new ClaimAnchorProjectionError(carried.recordSha256, `anchor names subject kind ${record.subject.kind}, but the record its digest resolves to is ${resolvedKind}`);
189
+ }
190
+ if (record.provider !== RFC3161_TSA_ANCHOR_PROFILE
191
+ && record.provider !== OPENTIMESTAMPS_ANCHOR_PROFILE) {
192
+ throw new ClaimAnchorProjectionError(carried.recordSha256, `no proof verifier implements the anchor profile ${record.provider}`);
193
+ }
194
+ return {
195
+ subject,
196
+ kind: resolvedKind,
197
+ provider: record.provider,
198
+ recordSha256: carried.recordSha256,
199
+ facts: factsFor(carried.recordSha256, record.provider, verifyCarriedProof(record.provider, record.subject.digest.sha256, proofBytes)),
200
+ };
201
+ });
202
+ const edges = upgradeEdges(partial, subjectDigests);
203
+ return partial.map((entry) => {
204
+ const upgrades = edges.get(entry.recordSha256);
205
+ return upgrades === undefined ? entry : { ...entry, upgradesRecordSha256: upgrades };
206
+ });
207
+ }
208
+ // ---------------------------------------------------------------------------
209
+ // The honesty mapping (§9.2). Every sentence below is the design's own text.
210
+ // ---------------------------------------------------------------------------
211
+ /** The historical value every unanchored bundle keeps (§9.2, "Additive"). */
212
+ export const STRUCTURAL_PRE_REGISTRATION = "structural-and-append-order-only";
213
+ /** The widened value an anchored bundle carries. */
214
+ export const ANCHORED_PRE_REGISTRATION = "structural-append-order-and-anchored-time";
215
+ export const SELF_RUN_TRUST_ROOT = "Signatures verify against the bundle-carried public keys minted by this workspace; there is no third-party trust anchor on the self-run venue.";
216
+ export const ANCHORED_TRUST_ROOT = "Signatures verify against the bundle-carried public keys minted by this workspace. The lock digest "
217
+ + "additionally carries a third-party time anchor, checked against trust material supplied on the "
218
+ + "verifier's side — never against roots carried in this bundle.";
219
+ /**
220
+ * A lock anchor gates copy only when it is carried, structurally complete for its class, and
221
+ * digest- and kind-matching (§9.2). The first and last are guaranteed by `deriveClaimAnchors`,
222
+ * which refuses everything else; completeness is the one condition readable off the section: a
223
+ * `pending`-only proof is not structurally complete and gates nothing.
224
+ */
225
+ export function governingLockAnchors(anchors) {
226
+ const complete = anchors.filter((anchor) => anchor.subject === "lock" && !isPending(anchor.facts));
227
+ // §4.2's earliest-wins, made total: anchors whose time is byte-embedded order by that time, and
228
+ // they precede the time-less chain-time anchors, which can never be shown to be earlier. Record
229
+ // digest is the deterministic tiebreak, and the sole order among the time-less ones.
230
+ return [...complete].sort((left, right) => {
231
+ const leftTime = isRfc3161Facts(left.facts) ? left.facts.genTime : undefined;
232
+ const rightTime = isRfc3161Facts(right.facts) ? right.facts.genTime : undefined;
233
+ if (leftTime !== undefined && rightTime !== undefined) {
234
+ const compared = compareCalendarStrictRfc3339Instants(leftTime, rightTime);
235
+ if (compared !== undefined && compared !== 0)
236
+ return compared;
237
+ }
238
+ else if (leftTime !== undefined) {
239
+ return -1;
240
+ }
241
+ else if (rightTime !== undefined) {
242
+ return 1;
243
+ }
244
+ return compareCodeUnits(left.recordSha256, right.recordSha256);
245
+ });
246
+ }
247
+ /** Complete matrix anchors, in record-digest order. A matrix anchor upgrades nothing (§9.2). */
248
+ export function carriedMatrixAnchors(anchors) {
249
+ return anchors
250
+ .filter((anchor) => anchor.subject === "matrix" && !isPending(anchor.facts))
251
+ .sort((left, right) => compareCodeUnits(left.recordSha256, right.recordSha256));
252
+ }
253
+ /** `<genTime|height>` — the one rendering both the replacement sentence and the neutral lines use. */
254
+ function anchoredTimeOrHeight(anchor) {
255
+ return isRfc3161Facts(anchor.facts)
256
+ ? anchor.facts.genTime
257
+ : String(anchor.facts.blockHeight);
258
+ }
259
+ /** The time basis a profile rests on (§4.1), as the `<class>` the neutral line names. */
260
+ function anchorClass(anchor) {
261
+ return isRfc3161Facts(anchor.facts) ? "authority-time" : "chain-time";
262
+ }
263
+ /**
264
+ * The replacement for limitation sentence 2, rendered once from the governing anchor.
265
+ *
266
+ * The `authority-time` form asserts, because its cryptography is fully carried and the verifier
267
+ * re-verifies it unconditionally and fails loud on `invalid`. The `chain-time` form is attributive
268
+ * — it says what the proof asserts and what checking it requires — because structural completeness
269
+ * is not chain evaluation; the assertive chain-time statement lives only in the report of a
270
+ * verifier that evaluated headers (§8, §9.2).
271
+ */
272
+ export function anchoredPreRegistrationSentence(governing) {
273
+ return isRfc3161Facts(governing.facts)
274
+ ? "Pre-registration here is anchored: an external timestamp authority asserts this run's sealed "
275
+ + `design digest existed no later than ${governing.facts.genTime}. That assertion proves the `
276
+ + "design's existence by that time and nothing else about the run — in particular, not that "
277
+ + "results were produced after it — and it is only as good as the authority behind the signing "
278
+ + "key named in the token."
279
+ : "Pre-registration here carries an anchor: an OpenTimestamps proof asserting a Bitcoin "
280
+ + `commitment at block height ${anchoredTimeOrHeight(governing)} covers this run's sealed design `
281
+ + "digest. Checking that commitment requires Bitcoin block headers on the verifier's side; if "
282
+ + "it holds, it shows the design existed no later than that block — and nothing else about the "
283
+ + "run.";
284
+ }
285
+ /** One neutral line per additional lock anchor (§9.2). It upgrades nothing; it reports. */
286
+ export function additionalLockAnchorLine(anchor) {
287
+ return `The lock digest carries an additional ${anchorClass(anchor)} anchor of ${anchoredTimeOrHeight(anchor)}.`;
288
+ }
289
+ /** One neutral line per carried matrix anchor (§9.2). It upgrades no claim. */
290
+ export function matrixAnchorLine(anchor) {
291
+ return `The terminal results digest carries a third-party time anchor of ${anchoredTimeOrHeight(anchor)}.`;
292
+ }
293
+ /**
294
+ * The complete venue-limits list for one anchor section: the unconditional list with sentence 2
295
+ * replaced by the governing anchor's form, followed by the neutral lines. Sentences 1, 3/3', 4, and
296
+ * 5 are untouched — anchors have nothing to say about operator control, pinning axes, self-reported
297
+ * cost, or agent distinctness (§9.2).
298
+ *
299
+ * With no governing lock anchor the unconditional list is returned unchanged, including when the
300
+ * bundle carries only pending or only matrix anchors: absent, pending, or invalid anchors change
301
+ * nothing.
302
+ */
303
+ export function anchoredVenueLimits(unconditional, anchors) {
304
+ const lock = governingLockAnchors(anchors);
305
+ const matrix = carriedMatrixAnchors(anchors);
306
+ const governing = lock[0];
307
+ if (governing === undefined) {
308
+ return matrix.length === 0 ? unconditional : [...unconditional, ...matrix.map(matrixAnchorLine)];
309
+ }
310
+ const additional = [...lock.slice(1)]
311
+ .sort((left, right) => compareCodeUnits(left.recordSha256, right.recordSha256))
312
+ .map(additionalLockAnchorLine);
313
+ return [
314
+ unconditional[0],
315
+ anchoredPreRegistrationSentence(governing),
316
+ ...unconditional.slice(2),
317
+ ...additional,
318
+ ...matrix.map(matrixAnchorLine),
319
+ ];
320
+ }
321
+ /** `venueHonesty.preRegistration` for one anchor section (§9.2). */
322
+ export function anchoredPreRegistration(anchors) {
323
+ return governingLockAnchors(anchors).length === 0
324
+ ? STRUCTURAL_PRE_REGISTRATION
325
+ : ANCHORED_PRE_REGISTRATION;
326
+ }
327
+ /** `claim.verification.trustRoot` for one anchor section (§9.2). */
328
+ export function anchoredTrustRoot(anchors) {
329
+ return governingLockAnchors(anchors).length === 0 ? SELF_RUN_TRUST_ROOT : ANCHORED_TRUST_ROOT;
330
+ }
@@ -0,0 +1,261 @@
1
+ import { z } from "zod";
2
+ import { type InspectSelectionManifest } from "./inspect-manifest.js";
3
+ export declare const INSPECT_TASK_PROFILE_URI = "https://product.jinn.network/profiles/inspect-evaluation/1";
4
+ export declare const INSPECT_EMBEDDED_EVALUATOR_ID = "urn:jinn:benchmark-product:inspect-runtime:same-execution-scorer";
5
+ export declare const InspectCellSummaryV1Schema: z.ZodObject<{
6
+ schema: z.ZodLiteral<"jinn.network/benchmark-product/inspect-cell-summary/1">;
7
+ terminal: z.ZodEnum<{
8
+ unscorable: "unscorable";
9
+ scored: "scored";
10
+ }>;
11
+ inspectStatus: z.ZodEnum<{
12
+ error: "error";
13
+ success: "success";
14
+ cancelled: "cancelled";
15
+ started: "started";
16
+ }>;
17
+ expectedSamples: z.ZodNullable<z.ZodNumber>;
18
+ observedSamples: z.ZodNumber;
19
+ erroredSamples: z.ZodNumber;
20
+ missingScoreSamples: z.ZodNumber;
21
+ invalidated: z.ZodBoolean;
22
+ scorer: z.ZodString;
23
+ verdict: z.ZodNullable<z.ZodEnum<{
24
+ pass: "pass";
25
+ fail: "fail";
26
+ }>>;
27
+ measurement: z.ZodNullable<z.ZodBoolean>;
28
+ evaluatedAt: z.ZodString;
29
+ nativeLogSha256: z.ZodString;
30
+ nativeLogBytes: z.ZodNumber;
31
+ provider: z.ZodOptional<z.ZodObject<{
32
+ surface: z.ZodLiteral<"openai-responses">;
33
+ resolvedModel: z.ZodNullable<z.ZodString>;
34
+ callCount: z.ZodNumber;
35
+ usage: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
36
+ terminalStatus: z.ZodEnum<{
37
+ completed: "completed";
38
+ "authentication-failure": "authentication-failure";
39
+ "rate-limited": "rate-limited";
40
+ timeout: "timeout";
41
+ "broker-loss": "broker-loss";
42
+ "provider-5xx": "provider-5xx";
43
+ "provider-failure": "provider-failure";
44
+ "budget-rejected": "budget-rejected";
45
+ "method-conflict": "method-conflict";
46
+ "capability-rejected": "capability-rejected";
47
+ "malformed-request": "malformed-request";
48
+ "no-call": "no-call";
49
+ }>;
50
+ eventDigest: z.ZodNullable<z.ZodString>;
51
+ brokerProtocol: z.ZodLiteral<"jinn.network/model-broker/1">;
52
+ brokerSourceSha256: z.ZodString;
53
+ }, z.core.$strict>>;
54
+ }, z.core.$strip>;
55
+ export declare const InspectCellSummaryV2Schema: z.ZodObject<{
56
+ schema: z.ZodLiteral<"jinn.network/benchmark-product/inspect-cell-summary/2">;
57
+ terminal: z.ZodEnum<{
58
+ unscorable: "unscorable";
59
+ scored: "scored";
60
+ }>;
61
+ inspectStatus: z.ZodEnum<{
62
+ error: "error";
63
+ success: "success";
64
+ cancelled: "cancelled";
65
+ started: "started";
66
+ }>;
67
+ expectedSamples: z.ZodNullable<z.ZodNumber>;
68
+ observedSamples: z.ZodNumber;
69
+ erroredSamples: z.ZodNumber;
70
+ invalidated: z.ZodBoolean;
71
+ scorers: z.ZodArray<z.ZodObject<{
72
+ name: z.ZodString;
73
+ presentSamples: z.ZodNumber;
74
+ missingSamples: z.ZodNumber;
75
+ valueShapes: z.ZodArray<z.ZodEnum<{
76
+ string: "string";
77
+ number: "number";
78
+ boolean: "boolean";
79
+ object: "object";
80
+ null: "null";
81
+ list: "list";
82
+ }>>;
83
+ }, z.core.$strict>>;
84
+ measurements: z.ZodArray<z.ZodObject<{
85
+ measurementName: z.ZodString;
86
+ scorerName: z.ZodString;
87
+ subScoreKey: z.ZodOptional<z.ZodString>;
88
+ missingSamples: z.ZodNumber;
89
+ invalidValueSamples: z.ZodNumber;
90
+ value: z.ZodNullable<z.ZodBoolean>;
91
+ }, z.core.$strict>>;
92
+ verdict: z.ZodNullable<z.ZodEnum<{
93
+ pass: "pass";
94
+ fail: "fail";
95
+ inconclusive: "inconclusive";
96
+ }>>;
97
+ evaluatedAt: z.ZodString;
98
+ nativeLogSha256: z.ZodString;
99
+ nativeLogBytes: z.ZodNumber;
100
+ provider: z.ZodOptional<z.ZodObject<{
101
+ surface: z.ZodLiteral<"openai-responses">;
102
+ resolvedModel: z.ZodNullable<z.ZodString>;
103
+ callCount: z.ZodNumber;
104
+ usage: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
105
+ terminalStatus: z.ZodEnum<{
106
+ completed: "completed";
107
+ "authentication-failure": "authentication-failure";
108
+ "rate-limited": "rate-limited";
109
+ timeout: "timeout";
110
+ "broker-loss": "broker-loss";
111
+ "provider-5xx": "provider-5xx";
112
+ "provider-failure": "provider-failure";
113
+ "budget-rejected": "budget-rejected";
114
+ "method-conflict": "method-conflict";
115
+ "capability-rejected": "capability-rejected";
116
+ "malformed-request": "malformed-request";
117
+ "no-call": "no-call";
118
+ }>;
119
+ eventDigest: z.ZodNullable<z.ZodString>;
120
+ brokerProtocol: z.ZodLiteral<"jinn.network/model-broker/1">;
121
+ brokerSourceSha256: z.ZodString;
122
+ }, z.core.$strict>>;
123
+ sandbox: z.ZodOptional<z.ZodObject<{
124
+ provider: z.ZodLiteral<"jinn-oci">;
125
+ protocol: z.ZodLiteral<"jinn.network/inspect-sandbox-host/1">;
126
+ imageDigest: z.ZodString;
127
+ environmentCount: z.ZodNumber;
128
+ operationCount: z.ZodNumber;
129
+ eventDigest: z.ZodString;
130
+ }, z.core.$strict>>;
131
+ }, z.core.$strict>;
132
+ export declare const InspectCellSummarySchema: z.ZodUnion<readonly [z.ZodObject<{
133
+ schema: z.ZodLiteral<"jinn.network/benchmark-product/inspect-cell-summary/1">;
134
+ terminal: z.ZodEnum<{
135
+ unscorable: "unscorable";
136
+ scored: "scored";
137
+ }>;
138
+ inspectStatus: z.ZodEnum<{
139
+ error: "error";
140
+ success: "success";
141
+ cancelled: "cancelled";
142
+ started: "started";
143
+ }>;
144
+ expectedSamples: z.ZodNullable<z.ZodNumber>;
145
+ observedSamples: z.ZodNumber;
146
+ erroredSamples: z.ZodNumber;
147
+ missingScoreSamples: z.ZodNumber;
148
+ invalidated: z.ZodBoolean;
149
+ scorer: z.ZodString;
150
+ verdict: z.ZodNullable<z.ZodEnum<{
151
+ pass: "pass";
152
+ fail: "fail";
153
+ }>>;
154
+ measurement: z.ZodNullable<z.ZodBoolean>;
155
+ evaluatedAt: z.ZodString;
156
+ nativeLogSha256: z.ZodString;
157
+ nativeLogBytes: z.ZodNumber;
158
+ provider: z.ZodOptional<z.ZodObject<{
159
+ surface: z.ZodLiteral<"openai-responses">;
160
+ resolvedModel: z.ZodNullable<z.ZodString>;
161
+ callCount: z.ZodNumber;
162
+ usage: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
163
+ terminalStatus: z.ZodEnum<{
164
+ completed: "completed";
165
+ "authentication-failure": "authentication-failure";
166
+ "rate-limited": "rate-limited";
167
+ timeout: "timeout";
168
+ "broker-loss": "broker-loss";
169
+ "provider-5xx": "provider-5xx";
170
+ "provider-failure": "provider-failure";
171
+ "budget-rejected": "budget-rejected";
172
+ "method-conflict": "method-conflict";
173
+ "capability-rejected": "capability-rejected";
174
+ "malformed-request": "malformed-request";
175
+ "no-call": "no-call";
176
+ }>;
177
+ eventDigest: z.ZodNullable<z.ZodString>;
178
+ brokerProtocol: z.ZodLiteral<"jinn.network/model-broker/1">;
179
+ brokerSourceSha256: z.ZodString;
180
+ }, z.core.$strict>>;
181
+ }, z.core.$strip>, z.ZodObject<{
182
+ schema: z.ZodLiteral<"jinn.network/benchmark-product/inspect-cell-summary/2">;
183
+ terminal: z.ZodEnum<{
184
+ unscorable: "unscorable";
185
+ scored: "scored";
186
+ }>;
187
+ inspectStatus: z.ZodEnum<{
188
+ error: "error";
189
+ success: "success";
190
+ cancelled: "cancelled";
191
+ started: "started";
192
+ }>;
193
+ expectedSamples: z.ZodNullable<z.ZodNumber>;
194
+ observedSamples: z.ZodNumber;
195
+ erroredSamples: z.ZodNumber;
196
+ invalidated: z.ZodBoolean;
197
+ scorers: z.ZodArray<z.ZodObject<{
198
+ name: z.ZodString;
199
+ presentSamples: z.ZodNumber;
200
+ missingSamples: z.ZodNumber;
201
+ valueShapes: z.ZodArray<z.ZodEnum<{
202
+ string: "string";
203
+ number: "number";
204
+ boolean: "boolean";
205
+ object: "object";
206
+ null: "null";
207
+ list: "list";
208
+ }>>;
209
+ }, z.core.$strict>>;
210
+ measurements: z.ZodArray<z.ZodObject<{
211
+ measurementName: z.ZodString;
212
+ scorerName: z.ZodString;
213
+ subScoreKey: z.ZodOptional<z.ZodString>;
214
+ missingSamples: z.ZodNumber;
215
+ invalidValueSamples: z.ZodNumber;
216
+ value: z.ZodNullable<z.ZodBoolean>;
217
+ }, z.core.$strict>>;
218
+ verdict: z.ZodNullable<z.ZodEnum<{
219
+ pass: "pass";
220
+ fail: "fail";
221
+ inconclusive: "inconclusive";
222
+ }>>;
223
+ evaluatedAt: z.ZodString;
224
+ nativeLogSha256: z.ZodString;
225
+ nativeLogBytes: z.ZodNumber;
226
+ provider: z.ZodOptional<z.ZodObject<{
227
+ surface: z.ZodLiteral<"openai-responses">;
228
+ resolvedModel: z.ZodNullable<z.ZodString>;
229
+ callCount: z.ZodNumber;
230
+ usage: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
231
+ terminalStatus: z.ZodEnum<{
232
+ completed: "completed";
233
+ "authentication-failure": "authentication-failure";
234
+ "rate-limited": "rate-limited";
235
+ timeout: "timeout";
236
+ "broker-loss": "broker-loss";
237
+ "provider-5xx": "provider-5xx";
238
+ "provider-failure": "provider-failure";
239
+ "budget-rejected": "budget-rejected";
240
+ "method-conflict": "method-conflict";
241
+ "capability-rejected": "capability-rejected";
242
+ "malformed-request": "malformed-request";
243
+ "no-call": "no-call";
244
+ }>;
245
+ eventDigest: z.ZodNullable<z.ZodString>;
246
+ brokerProtocol: z.ZodLiteral<"jinn.network/model-broker/1">;
247
+ brokerSourceSha256: z.ZodString;
248
+ }, z.core.$strict>>;
249
+ sandbox: z.ZodOptional<z.ZodObject<{
250
+ provider: z.ZodLiteral<"jinn-oci">;
251
+ protocol: z.ZodLiteral<"jinn.network/inspect-sandbox-host/1">;
252
+ imageDigest: z.ZodString;
253
+ environmentCount: z.ZodNumber;
254
+ operationCount: z.ZodNumber;
255
+ eventDigest: z.ZodString;
256
+ }, z.core.$strict>>;
257
+ }, z.core.$strict>]>;
258
+ export type InspectCellSummary = z.infer<typeof InspectCellSummarySchema>;
259
+ export type InspectCellSummaryV2 = z.infer<typeof InspectCellSummaryV2Schema>;
260
+ /** Validate the product projection and return the only verdict authorized by its sealed rule. */
261
+ export declare function projectInspectCellVerdict(summary: InspectCellSummaryV2, manifest: InspectSelectionManifest): "pass" | "fail" | "inconclusive" | null;