@riddledc/riddle-proof 0.8.84 → 0.8.85

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 (67) hide show
  1. package/README.md +193 -0
  2. package/capabilities.json +17 -0
  3. package/dist/advanced/engine-harness.js +2 -2
  4. package/dist/advanced/index.js +4 -4
  5. package/dist/advanced/runner.js +2 -2
  6. package/dist/change-proof.cjs +22 -260
  7. package/dist/change-proof.d.cts +1 -1
  8. package/dist/change-proof.d.ts +1 -1
  9. package/dist/change-proof.js +2 -2
  10. package/dist/checked-meaning.cjs +67 -0
  11. package/dist/checked-meaning.d.cts +2 -0
  12. package/dist/checked-meaning.d.ts +2 -0
  13. package/dist/checked-meaning.js +41 -0
  14. package/dist/{chunk-QYZ3GKCP.js → chunk-AFARUBE4.js} +12 -11
  15. package/dist/chunk-J2SIQGQI.js +71 -0
  16. package/dist/{chunk-7OAETQU3.js → chunk-JZKLCY5G.js} +1 -1
  17. package/dist/chunk-KB7FYRBG.js +46 -0
  18. package/dist/chunk-NWLKJ2WI.js +31 -0
  19. package/dist/{chunk-LR4UYJDY.js → chunk-O2AO726C.js} +1 -1
  20. package/dist/chunk-ODLGSEP2.js +43 -0
  21. package/dist/chunk-OHDNCXRM.js +17 -0
  22. package/dist/cli/index.js +7 -7
  23. package/dist/cli.cjs +265 -1122
  24. package/dist/cli.d.cts +0 -1
  25. package/dist/cli.d.ts +0 -1
  26. package/dist/cli.js +7 -7
  27. package/dist/engine-harness.js +2 -2
  28. package/dist/grounded-evidence.cjs +95 -0
  29. package/dist/grounded-evidence.d.cts +2 -0
  30. package/dist/grounded-evidence.d.ts +2 -0
  31. package/dist/grounded-evidence.js +69 -0
  32. package/dist/index.cjs +314 -2042
  33. package/dist/index.d.cts +9 -3
  34. package/dist/index.d.ts +9 -3
  35. package/dist/index.js +126 -18
  36. package/dist/pr-comment.cjs +17 -107
  37. package/dist/pr-comment.d.cts +1 -1
  38. package/dist/pr-comment.d.ts +1 -1
  39. package/dist/pr-comment.js +3 -3
  40. package/dist/receipts.cjs +10 -255
  41. package/dist/receipts.d.cts +7 -115
  42. package/dist/receipts.d.ts +7 -115
  43. package/dist/receipts.js +1 -1
  44. package/dist/riddle-client.cjs +23 -695
  45. package/dist/riddle-client.d.cts +1 -188
  46. package/dist/riddle-client.d.ts +1 -188
  47. package/dist/riddle-client.js +5 -2
  48. package/dist/runner.js +2 -2
  49. package/dist/runtime/index.cjs +23 -695
  50. package/dist/runtime/index.d.cts +1 -5
  51. package/dist/runtime/index.d.ts +1 -5
  52. package/dist/runtime/index.js +5 -2
  53. package/dist/runtime/riddle-client.cjs +23 -695
  54. package/dist/runtime/riddle-client.d.cts +1 -5
  55. package/dist/runtime/riddle-client.d.ts +1 -5
  56. package/dist/runtime/riddle-client.js +5 -2
  57. package/dist/semantic-certificate.cjs +17 -1083
  58. package/dist/semantic-certificate.d.cts +2 -310
  59. package/dist/semantic-certificate.d.ts +2 -310
  60. package/dist/semantic-certificate.js +1 -1
  61. package/package.json +28 -5
  62. package/runtime/lib/riddle_core_call.mjs +3 -806
  63. package/dist/chunk-5IFZSUPF.js +0 -644
  64. package/dist/chunk-AQTCU6W5.js +0 -1086
  65. package/dist/chunk-MEVVL4TI.js +0 -258
  66. package/dist/{chunk-WLUMLHII.js → chunk-BID7CKMM.js} +9 -9
  67. package/dist/{chunk-YH7ADFY4.js → chunk-IVSP24XI.js} +3 -3
package/README.md CHANGED
@@ -203,6 +203,199 @@ truth. Contract/rule IDs remain declared data, so consumers that care which
203
203
  models were used should apply their own allowlist or authenticated issuer
204
204
  policy in addition to anchoring the expected root ID.
205
205
 
206
+ ### Experimental Grounded Evidence
207
+
208
+ The grounded-evidence layer extends Semantic certificates with a replayable
209
+ path back to the exact captured bytes:
210
+
211
+ 1. `createRiddleProofSignedCaptureBundle` canonicalizes an artifact manifest,
212
+ binds it to a complete Semantic scope, a 32-byte challenge nonce, capture
213
+ time, collector, sensor, and verifier identity, and signs the protected
214
+ header plus statement with Ed25519.
215
+ 2. `verifyRiddleProofSignedCaptureBundle` independently checks the policy,
216
+ freshness window, trusted public-key fingerprint, signature, manifest, and
217
+ every inline artifact's length and SHA-256 digest. The callback registry path
218
+ runs a verifier twice on fresh byte copies and accepts only one identical
219
+ canonical JSON observation; the callback-free declarative path runs the
220
+ package's fixed, data-only JSON interpreter.
221
+ 3. `createRiddleProofGroundedSemanticCertificate` applies the registered
222
+ contract to that verifier-derived observation. It emits a content-addressed
223
+ grounded receipt and a contract-derived Semantic certificate whose evidence
224
+ begins with that exact receipt and then names every captured artifact.
225
+ 4. Atomic grounded closures can be composed. Validation or matching structurally
226
+ validates the complete Semantic closure, requires exactly one grounding for
227
+ every contract leaf and none for composition nodes, then replays every leaf
228
+ against independently supplied signer, verifier, contract, nonce, scope, and
229
+ time policy. Shared leaves are deduplicated, and a composition certificate
230
+ cannot predate any direct premise.
231
+
232
+ The public surface is available from both the package root and
233
+ `@riddledc/riddle-proof/grounded-evidence`. This example issues one grounded
234
+ leaf, wraps it as a closure, and replays the complete handoff. The omitted
235
+ values (`scope`, key material, artifacts, and identity objects) come from the
236
+ collector and trust setup. In particular, policy and replay expectations must
237
+ be independently configured rather than copied out of an untrusted bundle:
238
+
239
+ ```ts
240
+ import {
241
+ type RiddleProofGroundedCaptureVerificationPolicy,
242
+ type RiddleProofGroundedReplayConfiguration,
243
+ createRiddleProofGroundedDeclarativeJsonContract,
244
+ createRiddleProofGroundedDeclarativeJsonVerifier,
245
+ createRiddleProofGroundedSemanticAtomicCertificateClosure,
246
+ createRiddleProofGroundedSemanticCertificate,
247
+ createRiddleProofSignedCaptureBundle,
248
+ matchRiddleProofGroundedSemanticCertificateClosure,
249
+ } from "@riddledc/riddle-proof/grounded-evidence";
250
+
251
+ const declarativeVerifier = createRiddleProofGroundedDeclarativeJsonVerifier({
252
+ verifier_id: "riddle-proof.profile-evidence-json",
253
+ verifier_version: "1",
254
+ program: {
255
+ artifact: {
256
+ artifact_id: "profile-evidence.json",
257
+ role: "profile_evidence",
258
+ media_type: "application/json",
259
+ },
260
+ pointer: "", // RFC 6901: select the parsed document root
261
+ },
262
+ });
263
+ if (!declarativeVerifier.ok) throw new Error(declarativeVerifier.error.message);
264
+
265
+ const declarativeContract = createRiddleProofGroundedDeclarativeJsonContract({
266
+ contract_id: "riddle-proof.profile-passed",
267
+ contract_version: "1",
268
+ label: "The captured profile passed",
269
+ claim: passedProfileClaim,
270
+ program: {
271
+ all: [
272
+ { op: "type_is", source: "observation", pointer: "", type: "object" },
273
+ { op: "equals", source: "observation", pointer: "/status", value: "passed" },
274
+ { op: "equals", source: "scope", pointer: "/revision", value: scope.revision },
275
+ ],
276
+ },
277
+ });
278
+ if (!declarativeContract.ok) throw new Error(declarativeContract.error.message);
279
+
280
+ const createdBundle = createRiddleProofSignedCaptureBundle({
281
+ scope,
282
+ nonce, // canonical base64url encoding of an independently issued 32-byte value
283
+ captured_at: "2026-07-19T14:30:00.000Z",
284
+ collector,
285
+ sensor,
286
+ verifier: declarativeVerifier.verifier_ref,
287
+ artifacts,
288
+ signing_key: {
289
+ key_id: "local-playwright-key",
290
+ private_key_pkcs8_base64: privateKeyPkcs8Base64,
291
+ },
292
+ });
293
+ if (!createdBundle.ok) throw new Error(createdBundle.error.message);
294
+
295
+ const policy: RiddleProofGroundedCaptureVerificationPolicy = {
296
+ expected_scope: scope,
297
+ expected_nonce: nonce,
298
+ expected_collector: collector,
299
+ expected_sensor: sensor,
300
+ expected_verifier: declarativeVerifier.verifier_ref,
301
+ expected_signer: {
302
+ key_id: "local-playwright-key",
303
+ public_key_spki_sha256: trustedPublicKeySpkiSha256,
304
+ },
305
+ verification_time: "2026-07-19T14:30:01.000Z",
306
+ max_capture_age_ms: 60_000,
307
+ max_future_skew_ms: 1_000,
308
+ required_artifact_roles: ["profile_evidence"],
309
+ };
310
+
311
+ const configuration: RiddleProofGroundedReplayConfiguration = {
312
+ policy,
313
+ trusted_signers: [{
314
+ key_id: "local-playwright-key",
315
+ public_key_spki_base64: trustedPublicKeySpkiBase64,
316
+ }],
317
+ verifier_registry: [declarativeVerifier.registration],
318
+ contract_registry: [declarativeContract.registration],
319
+ expected_contract: declarativeContract.contract_ref,
320
+ };
321
+
322
+ const issued = createRiddleProofGroundedSemanticCertificate({
323
+ bundle: createdBundle.bundle,
324
+ ...configuration,
325
+ // Grounded leaf chronology is the independent verification time, not caller drift.
326
+ issued_at: policy.verification_time,
327
+ });
328
+ if (!issued.ok) throw new Error(issued.error.message);
329
+
330
+ const atomic = createRiddleProofGroundedSemanticAtomicCertificateClosure({
331
+ certificate: issued.certificate,
332
+ grounding: issued.grounding,
333
+ configuration,
334
+ });
335
+ if (!atomic.ok) throw new Error(atomic.error.message);
336
+
337
+ const checked = matchRiddleProofGroundedSemanticCertificateClosure({
338
+ grounded_closure: JSON.parse(JSON.stringify(atomic.grounded_closure)),
339
+ replay_contexts: [{
340
+ certificate_id: issued.certificate.certificate_id,
341
+ ...configuration,
342
+ }],
343
+ expected_root_certificate_id: trustedHandoffCertificateId,
344
+ expected_scope: scope,
345
+ expected_claim: passedProfileClaim,
346
+ expected_assurance: "runtime_contract_accepted",
347
+ });
348
+ if (!checked.ok) throw new Error(checked.error.message);
349
+ ```
350
+
351
+ Use `composeRiddleProofGroundedSemanticCertificateClosures` for higher claims.
352
+ It takes a normal Semantic `rule`, one grounded closure per premise,
353
+ `replay_contexts` for every distinct leaf, and an `issued_at` no earlier than
354
+ the latest input root. `validateRiddleProofGroundedSemanticCertificateClosure`
355
+ performs the same full leaf replay without applying trusted root expectations;
356
+ `matchRiddleProofGroundedSemanticCertificateClosure` adds those expectations.
357
+
358
+ The declarative builders above are the narrower primary path. They canonicalize
359
+ the data-only program, domain-separate and SHA-256 hash the complete definition,
360
+ set `trust_basis.kind` to `builtin_declarative_json`, and return a registration
361
+ with no callback. During every issuance and replay, Riddle Proof recomputes that
362
+ digest and uses only its fixed v0 interpreter. The verifier selects one exact
363
+ `application/json` artifact by ID, role, and media type, parses strict UTF-8 JSON,
364
+ and projects an RFC 6901 JSON Pointer. The contract supports a bounded `all`
365
+ list of `exists`, exact `equals`, and `type_is` assertions over the observation
366
+ or the five-field scope.
367
+
368
+ The custom callback trust boundary remains deliberately visible. A verifier or
369
+ contract reference with `trust_basis: { kind: "external_registry" }` means an
370
+ independent registry selected that callback and vouches for its
371
+ `implementation_digest`. Riddle Proof does not derive callback identity from
372
+ `Function#toString` or prove that arbitrary JavaScript bytes correspond to the
373
+ declared digest. Registry callbacks are invoked from snapshots without a
374
+ receiver and with cloned inputs, but the registry remains part of the trusted
375
+ computing base.
376
+
377
+ Parsing is fail-closed for extra/hidden/accessor fields, sparse structural
378
+ arrays, noncanonical base64, noncanonical timestamps, and noncanonical DER.
379
+ The exported limits bound a capture to 64 artifacts, 16 MiB per artifact,
380
+ 64 MiB total decoded artifact bytes, and a 1 MiB canonical observation. A
381
+ grounded closure additionally has 256 MiB aggregate replay-work and 64 MiB
382
+ canonical metadata limits, plus aggregate replay-configuration, registry, and
383
+ trusted-key limits. Declarative definitions are limited to 64 KiB, 64 contract
384
+ assertions, and bounded JSON Pointer sizes and depth. These limits are
385
+ denial-of-service boundaries; they do not make the evidence empirically true.
386
+
387
+ The remaining outside-world boundary is also explicit. The signature proves
388
+ that the trusted key signed this exact capture statement, and replay proves that
389
+ the registered verifier and contract deterministically produce this exact leaf
390
+ from the included bytes. It does not prove that the key was well kept, the
391
+ collector's clock or nonce source was honest, the browser rendered the claimed
392
+ URL faithfully, the sensor was well calibrated, or the included screenshot
393
+ matches photons a human would have seen. The Playwright runner reduces that gap
394
+ by signing the exact files it persisted and recording browser provenance, but
395
+ its signer, browser process, machine, and capture policy still require trust.
396
+ Lean proves the framework invariants that connect these stages; it does not
397
+ turn those empirical assumptions into theorems.
398
+
206
399
  Persist a deploy result and its immutable receipt for later Change Proof input:
207
400
 
208
401
  ```sh
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "riddle-proof.package-capabilities.v1",
3
+ "package": "@riddledc/riddle-proof",
4
+ "capabilities": {
5
+ "network": true,
6
+ "filesystem": true,
7
+ "browser": true,
8
+ "subprocess": true,
9
+ "hosted_riddle": true,
10
+ "cryptography": true,
11
+ "ambient_clock": true
12
+ },
13
+ "notes": [
14
+ "This pre-1.0 package is the compatibility facade and intentionally exposes the union of core, local engine, and hosted-client capabilities.",
15
+ "Security-sensitive local consumers should install @riddledc/riddle-proof-core and a specific adapter instead."
16
+ ]
17
+ }
@@ -2,10 +2,10 @@ import {
2
2
  createDisabledRiddleProofAgentAdapter,
3
3
  readRiddleProofRunStatus,
4
4
  runRiddleProofEngineHarness
5
- } from "../chunk-WLUMLHII.js";
5
+ } from "../chunk-BID7CKMM.js";
6
+ import "../chunk-EKZXU6MU.js";
6
7
  import "../chunk-CGJX7LJO.js";
7
8
  import "../chunk-UTCL7FEZ.js";
8
- import "../chunk-EKZXU6MU.js";
9
9
  import "../chunk-DYE3URAQ.js";
10
10
  import "../chunk-NKHZASNQ.js";
11
11
  import "../chunk-ZAR7BWMN.js";
@@ -3,15 +3,15 @@ import {
3
3
  } from "../chunk-VYJD6XYF.js";
4
4
  import {
5
5
  runner_exports
6
- } from "../chunk-YH7ADFY4.js";
6
+ } from "../chunk-IVSP24XI.js";
7
7
  import {
8
8
  engine_harness_exports
9
- } from "../chunk-WLUMLHII.js";
10
- import "../chunk-CGJX7LJO.js";
11
- import "../chunk-UTCL7FEZ.js";
9
+ } from "../chunk-BID7CKMM.js";
12
10
  import {
13
11
  proof_run_core_exports
14
12
  } from "../chunk-EKZXU6MU.js";
13
+ import "../chunk-CGJX7LJO.js";
14
+ import "../chunk-UTCL7FEZ.js";
15
15
  import "../chunk-DYE3URAQ.js";
16
16
  import "../chunk-NKHZASNQ.js";
17
17
  import "../chunk-ZAR7BWMN.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runRiddleProof
3
- } from "../chunk-YH7ADFY4.js";
3
+ } from "../chunk-IVSP24XI.js";
4
+ import "../chunk-EKZXU6MU.js";
4
5
  import "../chunk-CGJX7LJO.js";
5
6
  import "../chunk-UTCL7FEZ.js";
6
- import "../chunk-EKZXU6MU.js";
7
7
  import "../chunk-DYE3URAQ.js";
8
8
  import "../chunk-NKHZASNQ.js";
9
9
  import "../chunk-ZAR7BWMN.js";
@@ -15,6 +15,7 @@ var __copyProps = (to, from, except, desc) => {
15
15
  }
16
16
  return to;
17
17
  };
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
20
 
20
21
  // src/change-proof.ts
@@ -47,255 +48,16 @@ var RIDDLE_PROOF_PROFILE_STATUSES = [
47
48
  ];
48
49
 
49
50
  // src/receipts.ts
50
- var RIDDLE_PREVIEW_RECEIPT_VERSION = "riddle.preview-receipt.v1";
51
- var RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION = "riddle-proof.observation-receipt.v1";
52
- function isRecord(value) {
53
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
54
- }
55
- function requiredString(record, key, context) {
56
- const value = record[key];
57
- if (typeof value !== "string" || !value.trim()) {
58
- throw new Error(`${context}.${key} must be a non-empty string.`);
59
- }
60
- return value.trim();
61
- }
62
- function normalizedSourceIdentity(value) {
63
- if (!isRecord(value)) return {};
64
- return {
65
- git_revision: typeof value.git_revision === "string" && value.git_revision.trim() ? value.git_revision.trim() : void 0,
66
- repository: typeof value.repository === "string" && value.repository.trim() ? value.repository.trim() : void 0,
67
- dirty: typeof value.dirty === "boolean" ? value.dirty : void 0,
68
- label: typeof value.label === "string" && value.label.trim() ? value.label.trim() : void 0
69
- };
70
- }
71
- function parseRiddlePreviewReceipt(value) {
72
- if (!isRecord(value)) throw new Error("Preview receipt must be an object.");
73
- if (value.version !== RIDDLE_PREVIEW_RECEIPT_VERSION) {
74
- throw new Error(`Unsupported Preview receipt version ${String(value.version || "missing")}.`);
75
- }
76
- if (!isRecord(value.source)) throw new Error("Preview receipt source must be an object.");
77
- const expiresAt = requiredString(value, "expires_at", "preview receipt");
78
- const publishedAt = requiredString(value, "published_at", "preview receipt");
79
- const contentDigest = requiredString(value, "content_digest", "preview receipt");
80
- if (!contentDigest.startsWith("sha256:") || contentDigest.length <= "sha256:".length) {
81
- throw new Error("preview receipt.content_digest must be a sha256 digest.");
82
- }
83
- if (!Number.isFinite(Date.parse(expiresAt)) || !Number.isFinite(Date.parse(publishedAt))) {
84
- throw new Error("Preview receipt timestamps must be valid ISO date strings.");
85
- }
86
- return {
87
- version: RIDDLE_PREVIEW_RECEIPT_VERSION,
88
- preview_id: requiredString(value, "preview_id", "preview receipt"),
89
- url: requiredString(value, "url", "preview receipt"),
90
- expires_at: expiresAt,
91
- content_digest: contentDigest,
92
- source: normalizedSourceIdentity(value.source),
93
- published_at: publishedAt
94
- };
95
- }
96
- function comparableArtifactName(value) {
97
- return (value || "").split(/[/?#]/).pop()?.toLowerCase().replace(/\.(png|jpe?g|gif|webp|avif|svg)$/u, "").replace(/[^a-z0-9_-]+/gu, "-").replace(/^-+|-+$/g, "") || "";
98
- }
99
- function artifactMatchesLabel(artifact, label) {
100
- const expected = comparableArtifactName(label);
101
- if (!expected) return false;
102
- return [artifact.name, artifact.url, artifact.path].map(comparableArtifactName).some((name) => name === expected || name.endsWith(`-${expected}`));
103
- }
104
- function artifactLooksLikeScreenshot(ref) {
105
- const text = [ref.name, ref.url, ref.path, ref.kind, ref.content_type].filter(Boolean).join(" ").toLowerCase();
106
- return /screenshot|\bimage\b/.test(text) || /\.(png|jpe?g|gif|webp|avif|svg)(\?|#|$)/.test(text);
107
- }
108
- function finalScreenshotLabels(result) {
109
- const explicit = result.artifacts.canonical_screenshots || [];
110
- if (explicit.length) return explicit;
111
- const fromEvidence = (result.evidence?.viewports || []).map((viewport) => viewport.screenshot_label).filter((label) => typeof label === "string" && Boolean(label.trim()));
112
- if (fromEvidence.length) return fromEvidence;
113
- return (result.artifacts.screenshots || []).slice(0, 1);
114
- }
115
- function setupScreenshotLabels(result) {
116
- const explicit = result.artifacts.setup_screenshots || [];
117
- if (explicit.length) return explicit;
118
- return (result.evidence?.viewports || []).flatMap(
119
- (viewport) => (viewport.setup_action_results || []).filter((action) => action.action === "screenshot" && action.ok !== false && typeof action.screenshot_label === "string").map((action) => String(action.screenshot_label))
120
- );
121
- }
122
- function observationArtifactFromRef(ref, canonicalLabels, setupLabels) {
123
- const base = {
124
- name: ref.name,
125
- role: ref.role || "artifact",
126
- url: ref.url,
127
- path: ref.path,
128
- kind: ref.kind,
129
- content_type: ref.content_type,
130
- source: ref.source
131
- };
132
- if (!artifactLooksLikeScreenshot(ref)) return base;
133
- if (canonicalLabels.some((label) => artifactMatchesLabel(base, label))) {
134
- return { ...base, role: "canonical_screenshot" };
135
- }
136
- if (setupLabels.some((label) => artifactMatchesLabel(base, label))) {
137
- return { ...base, role: "setup_screenshot" };
138
- }
139
- return { ...base, role: "diagnostic" };
140
- }
141
- function profileObservationArtifacts(result) {
142
- const canonicalLabels = finalScreenshotLabels(result);
143
- const setupLabels = setupScreenshotLabels(result);
144
- const artifacts = [];
145
- const seen = /* @__PURE__ */ new Set();
146
- const add = (artifact) => {
147
- const key = artifact.url || artifact.path || `${artifact.role}:${artifact.name}`;
148
- if (!artifact.name || seen.has(key)) return;
149
- seen.add(key);
150
- artifacts.push(artifact);
151
- };
152
- for (const ref of result.artifacts.riddle_artifacts || []) {
153
- add(observationArtifactFromRef(ref, canonicalLabels, setupLabels));
154
- }
155
- for (const label of canonicalLabels) {
156
- if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
157
- add({ name: label, path: label, role: "canonical_screenshot", kind: "image" });
158
- }
159
- }
160
- for (const label of setupLabels) {
161
- if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
162
- add({ name: label, path: label, role: "setup_screenshot", kind: "image" });
163
- }
164
- }
165
- for (const label of result.artifacts.screenshots || []) {
166
- if (!artifacts.some((artifact) => artifactMatchesLabel(artifact, label))) {
167
- add({ name: label, path: label, role: "diagnostic", kind: "image" });
168
- }
169
- }
170
- return artifacts;
171
- }
172
- function mergeObservationArtifacts(profileArtifacts, suppliedArtifacts) {
173
- const artifacts = [...profileArtifacts];
174
- for (const supplied of suppliedArtifacts) {
175
- const suppliedNames = [supplied.name, supplied.url, supplied.path].map(comparableArtifactName).filter(Boolean);
176
- const existingIndex = artifacts.findIndex((artifact) => {
177
- if (supplied.url && artifact.url === supplied.url) return true;
178
- if (supplied.path && artifact.path === supplied.path) return true;
179
- return [artifact.name, artifact.url, artifact.path].map(comparableArtifactName).some((name) => name && suppliedNames.includes(name));
180
- });
181
- if (existingIndex < 0) {
182
- artifacts.push(supplied);
183
- continue;
184
- }
185
- const existing = artifacts[existingIndex];
186
- const role = supplied.role === "canonical_screenshot" || supplied.role === "setup_screenshot" ? supplied.role : existing.role === "canonical_screenshot" || existing.role === "setup_screenshot" ? existing.role : supplied.role === "artifact" ? existing.role : supplied.role;
187
- artifacts[existingIndex] = {
188
- ...existing,
189
- ...supplied,
190
- role
191
- };
192
- }
193
- return artifacts;
194
- }
195
- function defaultObservationId(role, capturedAt) {
196
- return `obs_${role}_${capturedAt.replace(/[^0-9]/g, "").slice(0, 17) || "unknown"}`;
197
- }
198
- function profileCheckCounts(result) {
199
- const counts = { total: result.checks.length, passed: 0, failed: 0, skipped: 0, needs_human_review: 0 };
200
- for (const check of result.checks) {
201
- if (check.status === "passed") counts.passed += 1;
202
- if (check.status === "failed") counts.failed += 1;
203
- if (check.status === "skipped") counts.skipped += 1;
204
- if (check.status === "needs_human_review") counts.needs_human_review += 1;
205
- }
206
- return counts;
207
- }
208
- function createRiddleProofObservationReceipt(input) {
209
- const capturedAt = input.captured_at || input.profile_result?.captured_at || (/* @__PURE__ */ new Date()).toISOString();
210
- const profileArtifacts = input.profile_result ? profileObservationArtifacts(input.profile_result) : [];
211
- const requestedCanonical = input.canonical_screenshot ? { ...input.canonical_screenshot, role: "canonical_screenshot" } : void 0;
212
- const artifacts = mergeObservationArtifacts(
213
- profileArtifacts,
214
- [...input.artifacts || [], ...requestedCanonical ? [requestedCanonical] : []]
215
- );
216
- const canonicalScreenshot = requestedCanonical ? artifacts.find((artifact) => artifact.role === "canonical_screenshot" && artifactMatchesLabel(artifact, requestedCanonical.name)) || requestedCanonical : artifacts.find((artifact) => artifact.role === "canonical_screenshot");
217
- const target = input.target.kind === "preview" && input.target.preview ? { ...input.target, preview: parseRiddlePreviewReceipt(input.target.preview) } : input.target;
218
- return {
219
- version: RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
220
- observation_id: input.observation_id || defaultObservationId(input.comparison_role, capturedAt),
221
- comparison_role: input.comparison_role,
222
- executor: input.executor,
223
- target,
224
- source: normalizedSourceIdentity(input.source || input.target.preview?.source),
225
- captured_at: capturedAt,
226
- artifacts,
227
- canonical_screenshot: canonicalScreenshot,
228
- profile_summary: input.profile_result ? {
229
- profile_name: input.profile_result.profile_name,
230
- status: input.profile_result.status,
231
- summary: input.profile_result.summary,
232
- route: input.profile_result.route,
233
- checks: profileCheckCounts(input.profile_result)
234
- } : void 0,
235
- proof: input.profile_result ? {
236
- profile_name: input.profile_result.profile_name,
237
- result: input.profile_result
238
- } : void 0,
239
- publication: input.publication,
240
- execution: input.execution,
241
- metadata: input.metadata
242
- };
243
- }
244
- function parseRiddleProofObservationReceipt(value) {
245
- if (!isRecord(value)) throw new Error("Observation receipt must be an object.");
246
- if (value.version !== RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION) {
247
- throw new Error(`Unsupported Observation receipt version ${String(value.version || "missing")}.`);
248
- }
249
- if (!isRecord(value.executor)) throw new Error("Observation receipt executor must be an object.");
250
- if (!isRecord(value.target)) throw new Error("Observation receipt target must be an object.");
251
- if (!isRecord(value.source)) throw new Error("Observation receipt source must be an object.");
252
- requiredString(value, "observation_id", "observation receipt");
253
- requiredString(value, "captured_at", "observation receipt");
254
- const executorKind = requiredString(value.executor, "kind", "observation receipt executor");
255
- if (!"local_playwright,riddle_hosted,browser_api,other".split(",").includes(executorKind)) {
256
- throw new Error(`Unsupported observation executor kind ${executorKind}.`);
257
- }
258
- if (value.executor.runner !== void 0) {
259
- requiredString(value.executor, "runner", "observation receipt executor");
260
- }
261
- const role = requiredString(value, "comparison_role", "observation receipt");
262
- if (!["before", "after", "standalone"].includes(role)) {
263
- throw new Error(`Unsupported observation comparison role ${role}.`);
264
- }
265
- const targetKind = requiredString(value.target, "kind", "observation receipt target");
266
- if (targetKind !== "url" && targetKind !== "preview") {
267
- throw new Error(`Unsupported observation target kind ${targetKind}.`);
268
- }
269
- requiredString(value.target, "url", "observation receipt target");
270
- if (targetKind === "preview") {
271
- if (value.target.preview === void 0) {
272
- throw new Error("Preview Observation target must include its Preview receipt.");
273
- }
274
- parseRiddlePreviewReceipt(value.target.preview);
275
- }
276
- if (!Array.isArray(value.artifacts)) throw new Error("Observation receipt artifacts must be an array.");
277
- const artifactRoles = /* @__PURE__ */ new Set(["canonical_screenshot", "setup_screenshot", "data", "diagnostic", "artifact"]);
278
- const artifacts = value.artifacts.map((artifact, index) => {
279
- if (!isRecord(artifact)) throw new Error(`Observation receipt artifact ${index} must be an object.`);
280
- requiredString(artifact, "name", `observation receipt artifact ${index}`);
281
- const artifactRole = requiredString(artifact, "role", `observation receipt artifact ${index}`);
282
- if (!artifactRoles.has(artifactRole)) {
283
- throw new Error(`Unsupported observation artifact role ${artifactRole}.`);
284
- }
285
- return artifact;
286
- });
287
- if (value.canonical_screenshot !== void 0) {
288
- if (!isRecord(value.canonical_screenshot) || value.canonical_screenshot.role !== "canonical_screenshot") {
289
- throw new Error("Observation canonical_screenshot must have the canonical_screenshot role.");
290
- }
291
- const canonical = value.canonical_screenshot;
292
- const included = artifacts.some((artifact) => artifact.role === "canonical_screenshot" && artifact.name === canonical.name && artifact.url === canonical.url && artifact.path === canonical.path);
293
- if (!included) {
294
- throw new Error("Observation canonical_screenshot must reference an artifact in the receipt.");
295
- }
296
- }
297
- return value;
298
- }
51
+ var receipts_exports = {};
52
+ __export(receipts_exports, {
53
+ RIDDLE_PREVIEW_RECEIPT_VERSION: () => import_receipts.RIDDLE_PREVIEW_RECEIPT_VERSION,
54
+ RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION: () => import_receipts.RIDDLE_PROOF_OBSERVATION_RECEIPT_VERSION,
55
+ createRiddleProofObservationReceipt: () => import_receipts.createRiddleProofObservationReceipt,
56
+ parseRiddlePreviewReceipt: () => import_receipts.parseRiddlePreviewReceipt,
57
+ parseRiddleProofObservationReceipt: () => import_receipts.parseRiddleProofObservationReceipt
58
+ });
59
+ __reExport(receipts_exports, require("@riddledc/riddle-proof-core/receipts"));
60
+ var import_receipts = require("@riddledc/riddle-proof-core/receipts");
299
61
 
300
62
  // src/change-proof.ts
301
63
  var RIDDLE_PROOF_CHANGE_CONTRACT_VERSION = "riddle-proof.change-contract.v1";
@@ -639,7 +401,7 @@ function changeReceiptVerdict(status) {
639
401
  if (status === "proof_insufficient") return "proof_insufficient";
640
402
  return "not_mergeable";
641
403
  }
642
- function profileCheckCounts2(result) {
404
+ function profileCheckCounts(result) {
643
405
  const counts = {
644
406
  total: result.checks.length,
645
407
  passed: 0,
@@ -712,7 +474,7 @@ function observationExecutor(result) {
712
474
  function observationForReceiptSide(side, result, source, sourceIdentity) {
713
475
  if (!result) throw new Error(`${side}_result or ${side}_observation is required.`);
714
476
  if (!source) throw new Error(`${side}_source or ${side}_observation is required.`);
715
- return createRiddleProofObservationReceipt({
477
+ return (0, import_receipts.createRiddleProofObservationReceipt)({
716
478
  comparison_role: side,
717
479
  executor: observationExecutor(result),
718
480
  target: { kind: "url", url: source },
@@ -723,8 +485,8 @@ function observationForReceiptSide(side, result, source, sourceIdentity) {
723
485
  });
724
486
  }
725
487
  function createRiddleProofChangeReceipt(input) {
726
- const before = input.before_observation ? parseRiddleProofObservationReceipt(input.before_observation) : observationForReceiptSide("before", input.before_result, input.before_source, input.before_source_identity);
727
- const after = input.after_observation ? parseRiddleProofObservationReceipt(input.after_observation) : observationForReceiptSide("after", input.after_result, input.after_source, input.after_source_identity);
488
+ const before = input.before_observation ? (0, import_receipts.parseRiddleProofObservationReceipt)(input.before_observation) : observationForReceiptSide("before", input.before_result, input.before_source, input.before_source_identity);
489
+ const after = input.after_observation ? (0, import_receipts.parseRiddleProofObservationReceipt)(input.after_observation) : observationForReceiptSide("after", input.after_result, input.after_source, input.after_source_identity);
728
490
  const verdict = changeReceiptVerdict(input.result.status);
729
491
  const shippingAuthorization = input.shipping_authorization || noShippingAuthorization();
730
492
  assertShippingAuthorizationConsistent(shippingAuthorization, "Change receipt");
@@ -754,7 +516,7 @@ function createRiddleProofChangeReceipt(input) {
754
516
  metadata: input.result.metadata
755
517
  };
756
518
  }
757
- function isRecord2(value) {
519
+ function isRecord(value) {
758
520
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
759
521
  }
760
522
  function migratedObservationFromLegacySide(side, legacy) {
@@ -831,7 +593,7 @@ function migrateRiddleProofChangeReceipt(legacy) {
831
593
  };
832
594
  }
833
595
  function parseRiddleProofChangeReceipt(value) {
834
- if (!isRecord2(value)) throw new Error("Change receipt must be an object.");
596
+ if (!isRecord(value)) throw new Error("Change receipt must be an object.");
835
597
  if (value.version === RIDDLE_PROOF_CHANGE_RECEIPT_V1_VERSION) {
836
598
  return migrateRiddleProofChangeReceipt(value);
837
599
  }
@@ -842,8 +604,8 @@ function parseRiddleProofChangeReceipt(value) {
842
604
  if (!RIDDLE_PROOF_PROFILE_STATUSES.includes(receipt.status)) {
843
605
  throw new Error(`Unsupported Change receipt status ${String(receipt.status || "missing")}.`);
844
606
  }
845
- parseRiddleProofObservationReceipt(receipt.before);
846
- parseRiddleProofObservationReceipt(receipt.after);
607
+ (0, import_receipts.parseRiddleProofObservationReceipt)(receipt.before);
608
+ (0, import_receipts.parseRiddleProofObservationReceipt)(receipt.after);
847
609
  if (receipt.before.comparison_role !== "before" || receipt.after.comparison_role !== "after") {
848
610
  throw new Error("Change receipt observations must preserve their before and after comparison roles.");
849
611
  }
@@ -875,8 +637,8 @@ function createRiddleProofHandoffReceipt(changeReceipt, options = {}) {
875
637
  };
876
638
  }
877
639
  function parseRiddleProofHandoffReceipt(value) {
878
- if (!isRecord2(value) || value.version !== RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION) {
879
- throw new Error(`Unsupported Handoff receipt version ${String(isRecord2(value) ? value.version || "missing" : "missing")}.`);
640
+ if (!isRecord(value) || value.version !== RIDDLE_PROOF_HANDOFF_RECEIPT_VERSION) {
641
+ throw new Error(`Unsupported Handoff receipt version ${String(isRecord(value) ? value.version || "missing" : "missing")}.`);
880
642
  }
881
643
  const receipt = value;
882
644
  if (!Number.isFinite(Date.parse(receipt.created_at))) {
@@ -931,7 +693,7 @@ function receiptSideView(side, observation) {
931
693
  summary: summary?.summary || observation.proof?.result.summary || "No profile summary recorded.",
932
694
  route: summary?.route,
933
695
  captured_at: observation.captured_at,
934
- checks: summary?.checks || (observation.proof ? profileCheckCounts2(observation.proof.result) : {
696
+ checks: summary?.checks || (observation.proof ? profileCheckCounts(observation.proof.result) : {
935
697
  total: 0,
936
698
  passed: 0,
937
699
  failed: 0,
@@ -1,5 +1,5 @@
1
1
  import { RiddleProofProfileResult, RiddleProofProfileStatus, RiddleProofProfileCheckResult } from './profile.cjs';
2
- import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from './receipts.cjs';
2
+ import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from '@riddledc/riddle-proof-core/receipts';
3
3
  import { JsonValue } from './types.cjs';
4
4
  import './public-state.cjs';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { RiddleProofProfileResult, RiddleProofProfileStatus, RiddleProofProfileCheckResult } from './profile.js';
2
- import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from './receipts.js';
2
+ import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from '@riddledc/riddle-proof-core/receipts';
3
3
  import { JsonValue } from './types.js';
4
4
  import './public-state.js';
5
5
 
@@ -12,8 +12,8 @@ import {
12
12
  parseRiddleProofHandoffReceipt,
13
13
  riddleProofChangeReceiptHtml,
14
14
  riddleProofChangeReceiptMarkdown
15
- } from "./chunk-LR4UYJDY.js";
16
- import "./chunk-MEVVL4TI.js";
15
+ } from "./chunk-O2AO726C.js";
16
+ import "./chunk-OHDNCXRM.js";
17
17
  import "./chunk-2K3DIK7A.js";
18
18
  import "./chunk-MLKGABMK.js";
19
19
  export {