@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.
- package/README.md +193 -0
- package/capabilities.json +17 -0
- package/dist/advanced/engine-harness.js +2 -2
- package/dist/advanced/index.js +4 -4
- package/dist/advanced/runner.js +2 -2
- package/dist/change-proof.cjs +22 -260
- package/dist/change-proof.d.cts +1 -1
- package/dist/change-proof.d.ts +1 -1
- package/dist/change-proof.js +2 -2
- package/dist/checked-meaning.cjs +67 -0
- package/dist/checked-meaning.d.cts +2 -0
- package/dist/checked-meaning.d.ts +2 -0
- package/dist/checked-meaning.js +41 -0
- package/dist/{chunk-QYZ3GKCP.js → chunk-AFARUBE4.js} +12 -11
- package/dist/chunk-J2SIQGQI.js +71 -0
- package/dist/{chunk-7OAETQU3.js → chunk-JZKLCY5G.js} +1 -1
- package/dist/chunk-KB7FYRBG.js +46 -0
- package/dist/chunk-NWLKJ2WI.js +31 -0
- package/dist/{chunk-LR4UYJDY.js → chunk-O2AO726C.js} +1 -1
- package/dist/chunk-ODLGSEP2.js +43 -0
- package/dist/chunk-OHDNCXRM.js +17 -0
- package/dist/cli/index.js +7 -7
- package/dist/cli.cjs +265 -1122
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +7 -7
- package/dist/engine-harness.js +2 -2
- package/dist/grounded-evidence.cjs +95 -0
- package/dist/grounded-evidence.d.cts +2 -0
- package/dist/grounded-evidence.d.ts +2 -0
- package/dist/grounded-evidence.js +69 -0
- package/dist/index.cjs +314 -2042
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +126 -18
- package/dist/pr-comment.cjs +17 -107
- package/dist/pr-comment.d.cts +1 -1
- package/dist/pr-comment.d.ts +1 -1
- package/dist/pr-comment.js +3 -3
- package/dist/receipts.cjs +10 -255
- package/dist/receipts.d.cts +7 -115
- package/dist/receipts.d.ts +7 -115
- package/dist/receipts.js +1 -1
- package/dist/riddle-client.cjs +23 -695
- package/dist/riddle-client.d.cts +1 -188
- package/dist/riddle-client.d.ts +1 -188
- package/dist/riddle-client.js +5 -2
- package/dist/runner.js +2 -2
- package/dist/runtime/index.cjs +23 -695
- package/dist/runtime/index.d.cts +1 -5
- package/dist/runtime/index.d.ts +1 -5
- package/dist/runtime/index.js +5 -2
- package/dist/runtime/riddle-client.cjs +23 -695
- package/dist/runtime/riddle-client.d.cts +1 -5
- package/dist/runtime/riddle-client.d.ts +1 -5
- package/dist/runtime/riddle-client.js +5 -2
- package/dist/semantic-certificate.cjs +17 -1083
- package/dist/semantic-certificate.d.cts +2 -310
- package/dist/semantic-certificate.d.ts +2 -310
- package/dist/semantic-certificate.js +1 -1
- package/package.json +28 -5
- package/runtime/lib/riddle_core_call.mjs +3 -806
- package/dist/chunk-5IFZSUPF.js +0 -644
- package/dist/chunk-AQTCU6W5.js +0 -1086
- package/dist/chunk-MEVVL4TI.js +0 -258
- package/dist/{chunk-WLUMLHII.js → chunk-BID7CKMM.js} +9 -9
- 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-
|
|
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";
|
package/dist/advanced/index.js
CHANGED
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
} from "../chunk-VYJD6XYF.js";
|
|
4
4
|
import {
|
|
5
5
|
runner_exports
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-IVSP24XI.js";
|
|
7
7
|
import {
|
|
8
8
|
engine_harness_exports
|
|
9
|
-
} from "../chunk-
|
|
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";
|
package/dist/advanced/runner.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runRiddleProof
|
|
3
|
-
} from "../chunk-
|
|
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";
|
package/dist/change-proof.cjs
CHANGED
|
@@ -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
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
879
|
-
throw new Error(`Unsupported Handoff receipt version ${String(
|
|
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 ?
|
|
696
|
+
checks: summary?.checks || (observation.proof ? profileCheckCounts(observation.proof.result) : {
|
|
935
697
|
total: 0,
|
|
936
698
|
passed: 0,
|
|
937
699
|
failed: 0,
|
package/dist/change-proof.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RiddleProofProfileResult, RiddleProofProfileStatus, RiddleProofProfileCheckResult } from './profile.cjs';
|
|
2
|
-
import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from '
|
|
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
|
|
package/dist/change-proof.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RiddleProofProfileResult, RiddleProofProfileStatus, RiddleProofProfileCheckResult } from './profile.js';
|
|
2
|
-
import { RiddleProofObservationReceipt, RiddleProofSourceIdentity, RiddleProofObservationArtifact } from '
|
|
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
|
|
package/dist/change-proof.js
CHANGED
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
parseRiddleProofHandoffReceipt,
|
|
13
13
|
riddleProofChangeReceiptHtml,
|
|
14
14
|
riddleProofChangeReceiptMarkdown
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
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 {
|