@riddledc/riddle-proof 0.5.32 → 0.5.34
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/dist/{chunk-R4BPJNAM.js → chunk-4YCWZVBN.js} +101 -8
- package/dist/{chunk-LIDYNU7Q.js → chunk-7R6ZQE3X.js} +39 -2
- package/dist/{chunk-TMMKRKY5.js → chunk-J2MERROF.js} +1 -0
- package/dist/{chunk-F6VFKS7K.js → chunk-MQ2BHHLX.js} +2 -2
- package/dist/{chunk-7ZJAUEUN.js → chunk-OASB3CYU.js} +6 -1
- package/dist/chunk-ODORKNSO.js +121 -0
- package/dist/engine-harness.cjs +143 -9
- package/dist/engine-harness.js +4 -3
- package/dist/index.cjs +271 -11
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +24 -7
- package/dist/openclaw.cjs +5 -0
- package/dist/openclaw.js +2 -2
- package/dist/proof-run-core.cjs +104 -8
- package/dist/proof-run-core.d.cts +24 -1
- package/dist/proof-run-core.d.ts +24 -1
- package/dist/proof-run-core.js +7 -1
- package/dist/proof-run-engine.cjs +101 -8
- package/dist/proof-run-engine.d.cts +24 -0
- package/dist/proof-run-engine.d.ts +24 -0
- package/dist/proof-run-engine.js +4 -1
- package/dist/proof-session.cjs +151 -0
- package/dist/proof-session.d.cts +37 -0
- package/dist/proof-session.d.ts +37 -0
- package/dist/proof-session.js +18 -0
- package/dist/result.cjs +1 -0
- package/dist/result.js +1 -1
- package/dist/runner.cjs +6 -0
- package/dist/runner.js +3 -3
- package/dist/state.cjs +5 -0
- package/dist/state.js +2 -2
- package/dist/types.d.cts +67 -1
- package/dist/types.d.ts +67 -1
- package/package.json +7 -2
- package/runtime/lib/preflight.py +42 -2
- package/runtime/lib/ship.py +55 -1
- package/runtime/lib/util.py +237 -0
- package/runtime/lib/verify.py +93 -6
- package/runtime/tests/recon_verify_smoke.py +181 -3
|
@@ -63,6 +63,11 @@ function ensureAction(action) {
|
|
|
63
63
|
function workflowFile(riddleProofDir, action) {
|
|
64
64
|
return path.join(riddleProofDir, "pipelines", `riddle-proof-${action}.lobster`);
|
|
65
65
|
}
|
|
66
|
+
function asJsonString(value) {
|
|
67
|
+
if (value === void 0 || value === null || value === "") return "";
|
|
68
|
+
if (typeof value === "string") return value;
|
|
69
|
+
return JSON.stringify(value);
|
|
70
|
+
}
|
|
66
71
|
function buildSetupArgs(params, config) {
|
|
67
72
|
if (!params.repo) throw new Error("repo is required for setup/run");
|
|
68
73
|
if (!params.change_request) throw new Error("change_request is required for setup/run");
|
|
@@ -78,8 +83,13 @@ function buildSetupArgs(params, config) {
|
|
|
78
83
|
prod_url: params.prod_url || "",
|
|
79
84
|
capture_script: captureScript,
|
|
80
85
|
success_criteria: params.success_criteria || "",
|
|
81
|
-
assertions_json: params.assertions_json ||
|
|
86
|
+
assertions_json: params.assertions_json || asJsonString(params.assertions),
|
|
82
87
|
verification_mode: params.verification_mode || "proof",
|
|
88
|
+
resume_session: params.resume_session || "",
|
|
89
|
+
target_image_url: params.target_image_url || "",
|
|
90
|
+
target_image_hash: params.target_image_hash || "",
|
|
91
|
+
viewport_matrix_json: params.viewport_matrix_json || asJsonString(params.viewport_matrix),
|
|
92
|
+
deterministic_setup_json: params.deterministic_setup_json || asJsonString(params.deterministic_setup),
|
|
83
93
|
reference: requestedReference,
|
|
84
94
|
base_branch: params.base_branch || "main",
|
|
85
95
|
before_ref: params.before_ref || "",
|
|
@@ -322,6 +332,54 @@ function normalizedProofAssessment(state = {}) {
|
|
|
322
332
|
source: source || null
|
|
323
333
|
};
|
|
324
334
|
}
|
|
335
|
+
var VISUAL_FIRST_MODES = /* @__PURE__ */ new Set([
|
|
336
|
+
"visual",
|
|
337
|
+
"render",
|
|
338
|
+
"interaction",
|
|
339
|
+
"ui",
|
|
340
|
+
"layout",
|
|
341
|
+
"screenshot",
|
|
342
|
+
"canvas",
|
|
343
|
+
"animation"
|
|
344
|
+
]);
|
|
345
|
+
function objectValue(value) {
|
|
346
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
347
|
+
}
|
|
348
|
+
function normalizedVerificationMode(state = {}) {
|
|
349
|
+
const bundle = objectValue(state?.evidence_bundle);
|
|
350
|
+
const bundleMode = String(bundle.verification_mode || "").trim().toLowerCase();
|
|
351
|
+
if (bundleMode) return bundleMode;
|
|
352
|
+
return String(state?.verification_mode || "proof").trim().toLowerCase() || "proof";
|
|
353
|
+
}
|
|
354
|
+
function visualDeltaRequiredForState(state = {}) {
|
|
355
|
+
const bundle = objectValue(state?.evidence_bundle);
|
|
356
|
+
const contract = objectValue(bundle.artifact_contract);
|
|
357
|
+
const required = objectValue(contract.required);
|
|
358
|
+
return required.visual_delta === true || VISUAL_FIRST_MODES.has(normalizedVerificationMode(state));
|
|
359
|
+
}
|
|
360
|
+
function visualDeltaForState(state = {}) {
|
|
361
|
+
const bundle = objectValue(state?.evidence_bundle);
|
|
362
|
+
const after = objectValue(bundle.after);
|
|
363
|
+
const afterDelta = objectValue(after.visual_delta);
|
|
364
|
+
if (Object.keys(afterDelta).length) return afterDelta;
|
|
365
|
+
const request = objectValue(state?.proof_assessment_request);
|
|
366
|
+
return objectValue(request.visual_delta);
|
|
367
|
+
}
|
|
368
|
+
function visualDeltaShipGateReason(state = {}) {
|
|
369
|
+
if (!visualDeltaRequiredForState(state)) return null;
|
|
370
|
+
const visualDelta = visualDeltaForState(state);
|
|
371
|
+
if (visualDelta.status === "measured" && visualDelta.passed === true) return null;
|
|
372
|
+
const status = String(visualDelta.status || "missing");
|
|
373
|
+
if (status === "unmeasured") {
|
|
374
|
+
return "visual_delta.status=unmeasured blocks ready_to_ship for visual/UI proof";
|
|
375
|
+
}
|
|
376
|
+
if (status === "measured" && visualDelta.passed === false) {
|
|
377
|
+
return "visual_delta.status=measured but visual_delta.passed=false blocks ready_to_ship for visual/UI proof";
|
|
378
|
+
}
|
|
379
|
+
const reason = String(visualDelta.reason || "").trim();
|
|
380
|
+
if (reason) return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof: ${reason}`;
|
|
381
|
+
return `visual_delta.status=${status} blocks ready_to_ship for visual/UI proof`;
|
|
382
|
+
}
|
|
325
383
|
function requiredBaselineLabelsForState(state = {}) {
|
|
326
384
|
const reference = normalizedReference(state);
|
|
327
385
|
const labels = [];
|
|
@@ -337,6 +395,10 @@ function validateShipGate(state = {}) {
|
|
|
337
395
|
const afterCdn = String(state?.after_cdn || "").trim();
|
|
338
396
|
const verifyStatus = String(state?.verify_status || "").trim();
|
|
339
397
|
const proofAssessment = normalizedProofAssessment(state);
|
|
398
|
+
const verificationMode = normalizedVerificationMode(state);
|
|
399
|
+
const visualDelta = visualDeltaForState(state);
|
|
400
|
+
const visualDeltaRequired = visualDeltaRequiredForState(state);
|
|
401
|
+
const visualDeltaBlocker = visualDeltaShipGateReason(state);
|
|
340
402
|
const reasons = [];
|
|
341
403
|
if (!["before", "prod", "both"].includes(reference)) {
|
|
342
404
|
reasons.push(`reference must be before, prod, or both; got ${reference}`);
|
|
@@ -365,19 +427,26 @@ function validateShipGate(state = {}) {
|
|
|
365
427
|
if (proofAssessment.decision !== "ready_to_ship") {
|
|
366
428
|
reasons.push("proof_assessment.decision must be ready_to_ship before ship");
|
|
367
429
|
}
|
|
430
|
+
if (visualDeltaBlocker) {
|
|
431
|
+
reasons.push(visualDeltaBlocker);
|
|
432
|
+
}
|
|
368
433
|
return {
|
|
369
434
|
ok: reasons.length === 0,
|
|
370
435
|
reasons,
|
|
371
436
|
required_baselines: requiredBaselines,
|
|
372
437
|
evidence: {
|
|
373
438
|
reference,
|
|
439
|
+
verification_mode: verificationMode || null,
|
|
374
440
|
prod_url: prodUrl || null,
|
|
375
441
|
before_cdn: beforeCdn || null,
|
|
376
442
|
prod_cdn: prodCdn || null,
|
|
377
443
|
after_cdn: afterCdn || null,
|
|
378
444
|
verify_status: verifyStatus || null,
|
|
379
445
|
proof_assessment_decision: proofAssessment.decision,
|
|
380
|
-
proof_assessment_source: proofAssessment.source
|
|
446
|
+
proof_assessment_source: proofAssessment.source,
|
|
447
|
+
visual_delta_required: visualDeltaRequired,
|
|
448
|
+
visual_delta_status: typeof visualDelta.status === "string" ? visualDelta.status : null,
|
|
449
|
+
visual_delta_passed: typeof visualDelta.passed === "boolean" ? visualDelta.passed : null
|
|
381
450
|
}
|
|
382
451
|
};
|
|
383
452
|
}
|
|
@@ -590,6 +659,11 @@ function mergeStateFromParams(statePath, params) {
|
|
|
590
659
|
"success_criteria",
|
|
591
660
|
"assertions_json",
|
|
592
661
|
"verification_mode",
|
|
662
|
+
"resume_session",
|
|
663
|
+
"target_image_url",
|
|
664
|
+
"target_image_hash",
|
|
665
|
+
"viewport_matrix_json",
|
|
666
|
+
"deterministic_setup_json",
|
|
593
667
|
"base_branch",
|
|
594
668
|
"before_ref",
|
|
595
669
|
"context",
|
|
@@ -691,23 +765,36 @@ function mergeStateFromParams(statePath, params) {
|
|
|
691
765
|
state.proof_assessment_source = null;
|
|
692
766
|
} else {
|
|
693
767
|
const parsed = JSON.parse(raw);
|
|
694
|
-
|
|
768
|
+
const assessment = {
|
|
695
769
|
...parsed,
|
|
696
770
|
source: (parsed?.source || "supervising_agent").toString()
|
|
697
771
|
};
|
|
772
|
+
const readyBlocker = assessment?.decision === "ready_to_ship" ? visualDeltaShipGateReason({ ...state, proof_assessment: assessment, proof_assessment_source: assessment.source }) : null;
|
|
773
|
+
if (readyBlocker) {
|
|
774
|
+
assessment.blocked_decision = assessment.decision;
|
|
775
|
+
assessment.decision = "needs_richer_proof";
|
|
776
|
+
if (assessment.recommended_stage === "ship") assessment.recommended_stage = "verify";
|
|
777
|
+
if (assessment.continue_with_stage === "ship") assessment.continue_with_stage = "verify";
|
|
778
|
+
const blockers = Array.isArray(assessment.blockers) ? assessment.blockers : [];
|
|
779
|
+
assessment.blockers = [...blockers, readyBlocker];
|
|
780
|
+
}
|
|
781
|
+
state.proof_assessment = assessment;
|
|
698
782
|
state.proof_assessment_source = state.proof_assessment.source;
|
|
699
|
-
if (typeof
|
|
700
|
-
state.proof_decision =
|
|
783
|
+
if (typeof state.proof_assessment?.decision === "string") {
|
|
784
|
+
state.proof_decision = state.proof_assessment.decision;
|
|
701
785
|
}
|
|
702
786
|
if (typeof parsed?.summary === "string") {
|
|
703
787
|
state.proof_assessment_summary = normalizeOptionalString(parsed.summary) || null;
|
|
704
788
|
}
|
|
705
|
-
if (
|
|
789
|
+
if (state.proof_assessment?.decision === "ready_to_ship") {
|
|
706
790
|
state.merge_recommendation = "ready-to-ship";
|
|
707
|
-
} else if (typeof
|
|
791
|
+
} else if (typeof state.proof_assessment?.decision === "string" && state.proof_assessment.decision.trim()) {
|
|
708
792
|
state.merge_recommendation = "do-not-merge";
|
|
709
793
|
}
|
|
710
794
|
appendProofSummaryLine(state, `Supervising proof assessment: ${state.proof_assessment.decision || "unknown"}`);
|
|
795
|
+
if (readyBlocker) {
|
|
796
|
+
appendProofSummaryLine(state, `Ready-to-ship assessment blocked: ${readyBlocker}`);
|
|
797
|
+
}
|
|
711
798
|
if (state.proof_assessment_summary) {
|
|
712
799
|
appendProofSummaryLine(state, `Assessment summary: ${state.proof_assessment_summary}`);
|
|
713
800
|
}
|
|
@@ -808,7 +895,10 @@ function summarizeState(state) {
|
|
|
808
895
|
explicit_stage_gate: Boolean(state.explicit_stage_gate),
|
|
809
896
|
last_requested_advance_stage: state.last_requested_advance_stage || null,
|
|
810
897
|
recon_results: state.recon_results || null,
|
|
811
|
-
verify_results: state.verify_results || null
|
|
898
|
+
verify_results: state.verify_results || null,
|
|
899
|
+
proof_session: state.proof_session || null,
|
|
900
|
+
parent_proof_session: state.parent_proof_session || null,
|
|
901
|
+
proof_session_artifact_url: state.proof_session_artifact_url || null
|
|
812
902
|
};
|
|
813
903
|
const parts = [
|
|
814
904
|
state.workspace_ready ? "workspace ready" : "workspace not ready",
|
|
@@ -848,6 +938,9 @@ export {
|
|
|
848
938
|
setStageDecisionRequest,
|
|
849
939
|
checkpointContinueStage,
|
|
850
940
|
invalidateVerifyEvidence,
|
|
941
|
+
visualDeltaRequiredForState,
|
|
942
|
+
visualDeltaForState,
|
|
943
|
+
visualDeltaShipGateReason,
|
|
851
944
|
requiredBaselineLabelsForState,
|
|
852
945
|
validateShipGate,
|
|
853
946
|
buildCheckpointContract,
|
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
createRunStatusSnapshot,
|
|
6
6
|
normalizeRunParams,
|
|
7
7
|
setRunStatus
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OASB3CYU.js";
|
|
9
|
+
import {
|
|
10
|
+
visualDeltaShipGateReason
|
|
11
|
+
} from "./chunk-4YCWZVBN.js";
|
|
9
12
|
import {
|
|
10
13
|
applyTerminalMetadata,
|
|
11
14
|
compactRecord,
|
|
@@ -13,7 +16,7 @@ import {
|
|
|
13
16
|
nonEmptyString,
|
|
14
17
|
normalizeTerminalMetadata,
|
|
15
18
|
recordValue
|
|
16
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-J2MERROF.js";
|
|
17
20
|
|
|
18
21
|
// src/engine-harness.ts
|
|
19
22
|
import { execFileSync } from "child_process";
|
|
@@ -291,6 +294,26 @@ function proofAssessmentContinuation(result, payload) {
|
|
|
291
294
|
const proof_assessment_json = jsonParam(payload);
|
|
292
295
|
return { ...baseContinuation(result), proof_assessment_json };
|
|
293
296
|
}
|
|
297
|
+
function proofAssessmentVisualBlocker(state, payload) {
|
|
298
|
+
if (!proofAssessmentRequestsShip(payload)) return null;
|
|
299
|
+
const source = nonEmptyString(payload.source) || "supervising_agent";
|
|
300
|
+
return visualDeltaShipGateReason({
|
|
301
|
+
...state || {},
|
|
302
|
+
proof_assessment: { ...payload, source },
|
|
303
|
+
proof_assessment_source: source
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function blockedProofAssessmentPayload(payload, blocker) {
|
|
307
|
+
const blockers = Array.isArray(payload.blockers) ? payload.blockers.filter((item) => typeof item === "string") : [];
|
|
308
|
+
return {
|
|
309
|
+
...payload,
|
|
310
|
+
blocked_decision: payload.decision || "ready_to_ship",
|
|
311
|
+
decision: "needs_richer_proof",
|
|
312
|
+
recommended_stage: payload.recommended_stage === "ship" ? "verify" : payload.recommended_stage || "verify",
|
|
313
|
+
continue_with_stage: payload.continue_with_stage === "ship" ? "verify" : payload.continue_with_stage || "verify",
|
|
314
|
+
blockers: [...blockers, blocker]
|
|
315
|
+
};
|
|
316
|
+
}
|
|
294
317
|
function contextFor(request, state, result) {
|
|
295
318
|
return {
|
|
296
319
|
request,
|
|
@@ -660,6 +683,20 @@ async function routeCheckpoint(request, state, result, agent, input) {
|
|
|
660
683
|
summary: assessment.summary,
|
|
661
684
|
details: { payload }
|
|
662
685
|
});
|
|
686
|
+
const visualBlocker = proofAssessmentVisualBlocker({
|
|
687
|
+
...context.fullRiddleState || {},
|
|
688
|
+
verification_mode: context.fullRiddleState?.verification_mode || request.verification_mode
|
|
689
|
+
}, payload);
|
|
690
|
+
if (visualBlocker) {
|
|
691
|
+
recordEvent(state, {
|
|
692
|
+
kind: "agent.proof_assessment.blocked",
|
|
693
|
+
checkpoint,
|
|
694
|
+
stage: "verify",
|
|
695
|
+
summary: visualBlocker,
|
|
696
|
+
details: { payload }
|
|
697
|
+
});
|
|
698
|
+
return { next: proofAssessmentContinuation(result, blockedProofAssessmentPayload(payload, visualBlocker)) };
|
|
699
|
+
}
|
|
663
700
|
if (effectiveShipMode(request, input.config) !== "ship" && proofAssessmentRequestsShip(payload)) {
|
|
664
701
|
return {
|
|
665
702
|
terminal: terminalResult(
|
|
@@ -202,6 +202,7 @@ function createRunResult(input) {
|
|
|
202
202
|
merge_recommendation: state.merge_recommendation,
|
|
203
203
|
finalized: state.finalized,
|
|
204
204
|
blocker: state.blocker,
|
|
205
|
+
proof_session: state.proof_session,
|
|
205
206
|
evidence_bundle: input.evidence_bundle,
|
|
206
207
|
raw: input.raw
|
|
207
208
|
});
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
appendStageHeartbeat,
|
|
4
4
|
createRunState,
|
|
5
5
|
setRunStatus
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OASB3CYU.js";
|
|
7
7
|
import {
|
|
8
8
|
createRunResult
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-J2MERROF.js";
|
|
10
10
|
|
|
11
11
|
// src/runner.ts
|
|
12
12
|
function errorDetails(error) {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isTerminalStatus,
|
|
4
4
|
nonEmptyString,
|
|
5
5
|
recordValue
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-J2MERROF.js";
|
|
7
7
|
|
|
8
8
|
// src/state.ts
|
|
9
9
|
var RIDDLE_PROOF_RUN_STATE_VERSION = "riddle-proof.run-state.v1";
|
|
@@ -77,6 +77,11 @@ function normalizeRunParams(input) {
|
|
|
77
77
|
success_criteria: input.success_criteria,
|
|
78
78
|
assertions: input.assertions,
|
|
79
79
|
verification_mode: input.verification_mode,
|
|
80
|
+
resume_session: input.resume_session,
|
|
81
|
+
target_image_url: input.target_image_url,
|
|
82
|
+
target_image_hash: input.target_image_hash,
|
|
83
|
+
viewport_matrix: input.viewport_matrix,
|
|
84
|
+
deterministic_setup: input.deterministic_setup,
|
|
80
85
|
reference: input.reference,
|
|
81
86
|
base_branch: input.base_branch,
|
|
82
87
|
before_ref: input.before_ref,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/proof-session.ts
|
|
2
|
+
import { createHash, randomUUID } from "crypto";
|
|
3
|
+
var RIDDLE_PROOF_VISUAL_SESSION_VERSION = "riddle-proof.visual-session.v1";
|
|
4
|
+
var RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION = "riddle-proof.visual-session.fingerprint.v1";
|
|
5
|
+
function trim(value) {
|
|
6
|
+
const text = String(value ?? "").trim();
|
|
7
|
+
return text || void 0;
|
|
8
|
+
}
|
|
9
|
+
function hashString(value) {
|
|
10
|
+
const text = trim(value);
|
|
11
|
+
if (!text) return void 0;
|
|
12
|
+
return createHash("sha256").update(text).digest("hex");
|
|
13
|
+
}
|
|
14
|
+
function stableJson(value) {
|
|
15
|
+
if (value === void 0) return "null";
|
|
16
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
17
|
+
if (Array.isArray(value)) return `[${value.map((item) => stableJson(item)).join(",")}]`;
|
|
18
|
+
const record = value;
|
|
19
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
|
|
20
|
+
}
|
|
21
|
+
function withoutUndefined(record) {
|
|
22
|
+
for (const key of Object.keys(record)) {
|
|
23
|
+
if (record[key] === void 0) delete record[key];
|
|
24
|
+
}
|
|
25
|
+
return record;
|
|
26
|
+
}
|
|
27
|
+
function visualSessionFingerprintBasis(input) {
|
|
28
|
+
return withoutUndefined({
|
|
29
|
+
version: RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
|
|
30
|
+
repo: trim(input.repo),
|
|
31
|
+
route: trim(input.route),
|
|
32
|
+
wait_for_selector: trim(input.wait_for_selector),
|
|
33
|
+
reference: trim(input.reference),
|
|
34
|
+
verification_mode: trim(input.verification_mode)?.toLowerCase(),
|
|
35
|
+
target_image_url: trim(input.target_image_url),
|
|
36
|
+
target_image_hash: trim(input.target_image_hash),
|
|
37
|
+
viewport_matrix: input.viewport_matrix,
|
|
38
|
+
deterministic_setup: input.deterministic_setup,
|
|
39
|
+
assertions: input.assertions,
|
|
40
|
+
capture_script_hash: hashString(input.capture_script)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function visualSessionFingerprint(input) {
|
|
44
|
+
const basis = input.version === RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION ? input : visualSessionFingerprintBasis(input);
|
|
45
|
+
return createHash("sha256").update(stableJson(basis)).digest("hex");
|
|
46
|
+
}
|
|
47
|
+
function buildVisualProofSession(input) {
|
|
48
|
+
const basis = visualSessionFingerprintBasis(input);
|
|
49
|
+
const fingerprint = visualSessionFingerprint(basis);
|
|
50
|
+
const session = {
|
|
51
|
+
version: RIDDLE_PROOF_VISUAL_SESSION_VERSION,
|
|
52
|
+
session_id: `rps_${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}_${randomUUID().slice(0, 8)}`,
|
|
53
|
+
run_id: trim(input.run_id),
|
|
54
|
+
parent_session_id: input.parent?.session_id || null,
|
|
55
|
+
parent_fingerprint: input.parent?.fingerprint || null,
|
|
56
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
57
|
+
fingerprint,
|
|
58
|
+
fingerprint_basis: basis,
|
|
59
|
+
repo: trim(input.repo),
|
|
60
|
+
branch: trim(input.branch),
|
|
61
|
+
route: withoutUndefined({
|
|
62
|
+
path: trim(input.route),
|
|
63
|
+
observed_after_path: trim(input.observed_after_path)
|
|
64
|
+
}),
|
|
65
|
+
reference: trim(input.reference),
|
|
66
|
+
verification_mode: trim(input.verification_mode),
|
|
67
|
+
target_image: withoutUndefined({
|
|
68
|
+
url: trim(input.target_image_url),
|
|
69
|
+
hash: trim(input.target_image_hash)
|
|
70
|
+
}),
|
|
71
|
+
viewport_matrix: input.viewport_matrix,
|
|
72
|
+
deterministic_setup: input.deterministic_setup,
|
|
73
|
+
capture: withoutUndefined({
|
|
74
|
+
proof_plan: trim(input.proof_plan),
|
|
75
|
+
capture_script: trim(input.capture_script),
|
|
76
|
+
wait_for_selector: trim(input.wait_for_selector)
|
|
77
|
+
}),
|
|
78
|
+
assertions: input.assertions,
|
|
79
|
+
artifacts: input.artifacts,
|
|
80
|
+
evidence: input.evidence,
|
|
81
|
+
status: trim(input.status)
|
|
82
|
+
};
|
|
83
|
+
return JSON.parse(JSON.stringify(session));
|
|
84
|
+
}
|
|
85
|
+
function parseVisualProofSession(value) {
|
|
86
|
+
const parsed = typeof value === "string" ? JSON.parse(value) : value;
|
|
87
|
+
if (!parsed || typeof parsed !== "object") throw new Error("proof session must be a JSON object");
|
|
88
|
+
const session = parsed;
|
|
89
|
+
if (session.version !== RIDDLE_PROOF_VISUAL_SESSION_VERSION) {
|
|
90
|
+
throw new Error(`unsupported proof session version: ${String(session.version || "")}`);
|
|
91
|
+
}
|
|
92
|
+
if (!session.session_id) throw new Error("proof session missing session_id");
|
|
93
|
+
if (!session.fingerprint) throw new Error("proof session missing fingerprint");
|
|
94
|
+
return session;
|
|
95
|
+
}
|
|
96
|
+
function compareVisualProofSessionFingerprint(parent, input) {
|
|
97
|
+
const actual = visualSessionFingerprintBasis(input);
|
|
98
|
+
const expected = parent.fingerprint_basis || {};
|
|
99
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(expected), ...Object.keys(actual)]);
|
|
100
|
+
const expectedRecord = expected;
|
|
101
|
+
const actualRecord = actual;
|
|
102
|
+
const mismatches = [];
|
|
103
|
+
for (const key of keys) {
|
|
104
|
+
const expectedValue = expectedRecord[key];
|
|
105
|
+
const actualValue = actualRecord[key];
|
|
106
|
+
if (stableJson(expectedValue) !== stableJson(actualValue)) {
|
|
107
|
+
mismatches.push({ key, expected: expectedValue, actual: actualValue });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return mismatches;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
RIDDLE_PROOF_VISUAL_SESSION_VERSION,
|
|
115
|
+
RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
|
|
116
|
+
visualSessionFingerprintBasis,
|
|
117
|
+
visualSessionFingerprint,
|
|
118
|
+
buildVisualProofSession,
|
|
119
|
+
parseVisualProofSession,
|
|
120
|
+
compareVisualProofSessionFingerprint
|
|
121
|
+
};
|