@riddledc/riddle-proof 0.8.79 → 0.8.80

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/profile.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var profile_exports = {};
22
22
  __export(profile_exports, {
23
23
  RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS: () => RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
24
+ RIDDLE_PROOF_ORDERED_TRACE_OPERATORS: () => RIDDLE_PROOF_ORDERED_TRACE_OPERATORS,
24
25
  RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
26
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
26
27
  RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES: () => RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
@@ -29,6 +30,8 @@ __export(profile_exports, {
29
30
  RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
30
31
  RIDDLE_PROOF_PROFILE_VERSION: () => RIDDLE_PROOF_PROFILE_VERSION,
31
32
  applyRiddleProofProfileArtifactCompleteness: () => applyRiddleProofProfileArtifactCompleteness,
33
+ assessRiddleProofOrderedTrace: () => assessRiddleProofOrderedTrace,
34
+ assessRiddleProofOrderedTraceSetupResults: () => assessRiddleProofOrderedTraceSetupResults,
32
35
  assessRiddleProofProfileArtifactCompleteness: () => assessRiddleProofProfileArtifactCompleteness,
33
36
  assessRiddleProofProfileEvidence: () => assessRiddleProofProfileEvidence,
34
37
  buildRiddleProofProfileScript: () => buildRiddleProofProfileScript,
@@ -77,6 +80,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
77
80
  "selector_text_visible",
78
81
  "selector_text_absent",
79
82
  "selector_text_order",
83
+ "ordered_trace",
80
84
  "observe_within",
81
85
  "frame_text_visible",
82
86
  "frame_url_equals",
@@ -140,6 +144,21 @@ var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
140
144
  "timedout",
141
145
  "failed"
142
146
  ];
147
+ var RIDDLE_PROOF_ORDERED_TRACE_OPERATORS = [
148
+ "exists",
149
+ "equals",
150
+ "not_equals",
151
+ "truthy",
152
+ "falsy",
153
+ "gt",
154
+ "gte",
155
+ "lt",
156
+ "lte",
157
+ "abs_gt",
158
+ "abs_gte",
159
+ "abs_lt",
160
+ "abs_lte"
161
+ ];
143
162
  function uniqueNonEmptyStrings(values) {
144
163
  const seen = /* @__PURE__ */ new Set();
145
164
  const result = [];
@@ -431,6 +450,185 @@ function resolveJsonPath(root, path) {
431
450
  }
432
451
  return { exists: true, value: current };
433
452
  }
453
+ function assessRiddleProofOrderedTrace(trace, events) {
454
+ const insufficient = (reason, traceLength = Array.isArray(trace) ? trace.length : 0, witnesses2 = [], missingEvent, missingPaths) => ({
455
+ version: "riddle-proof.ordered-trace-assessment.v1",
456
+ status: "proof_insufficient",
457
+ trace_length: traceLength,
458
+ witnesses: witnesses2,
459
+ missing_event: missingEvent,
460
+ missing_paths: missingPaths,
461
+ reason
462
+ });
463
+ const parsePath = (path) => {
464
+ const segments = [];
465
+ let token = "";
466
+ const pushToken = () => {
467
+ const value = token.trim();
468
+ if (value) segments.push(value);
469
+ token = "";
470
+ };
471
+ for (let index = 0; index < path.length; index += 1) {
472
+ const char = path[index];
473
+ if (char === ".") {
474
+ pushToken();
475
+ continue;
476
+ }
477
+ if (char !== "[") {
478
+ token += char;
479
+ continue;
480
+ }
481
+ pushToken();
482
+ const closeIndex = path.indexOf("]", index + 1);
483
+ if (closeIndex === -1) throw new Error(`unterminated bracket at ${index}`);
484
+ const bracket = path.slice(index + 1, closeIndex).trim();
485
+ if (!bracket) throw new Error(`empty bracket at ${index}`);
486
+ if (/^\d+$/.test(bracket)) {
487
+ segments.push(Number(bracket));
488
+ } else {
489
+ segments.push(bracket.replace(/^['"]|['"]$/g, ""));
490
+ }
491
+ index = closeIndex;
492
+ }
493
+ pushToken();
494
+ return segments;
495
+ };
496
+ const resolve = (root, path) => {
497
+ let segments;
498
+ try {
499
+ segments = parsePath(path);
500
+ } catch {
501
+ return { exists: false };
502
+ }
503
+ let current = root;
504
+ for (const segment of segments) {
505
+ if (Array.isArray(current)) {
506
+ const index = typeof segment === "number" ? segment : /^\d+$/.test(segment) ? Number(segment) : -1;
507
+ if (index < 0 || index >= current.length) return { exists: false };
508
+ current = current[index];
509
+ continue;
510
+ }
511
+ if (typeof segment !== "string" || current === null || typeof current !== "object") return { exists: false };
512
+ if (!Object.hasOwn(current, segment)) return { exists: false };
513
+ current = current[segment];
514
+ }
515
+ return { exists: true, value: current };
516
+ };
517
+ const valuesEqual = (left, right) => {
518
+ if (Object.is(left, right)) return true;
519
+ if (Array.isArray(left) || Array.isArray(right)) {
520
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => valuesEqual(value, right[index]));
521
+ }
522
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object") return false;
523
+ const leftRecord = left;
524
+ const rightRecord = right;
525
+ const leftKeys = Object.keys(leftRecord).sort();
526
+ const rightKeys = Object.keys(rightRecord).sort();
527
+ return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && valuesEqual(leftRecord[key], rightRecord[key]));
528
+ };
529
+ const numericOperator = (op) => [
530
+ "gt",
531
+ "gte",
532
+ "lt",
533
+ "lte",
534
+ "abs_gt",
535
+ "abs_gte",
536
+ "abs_lt",
537
+ "abs_lte"
538
+ ].includes(op);
539
+ const matches = (value, predicate) => {
540
+ if (predicate.op === "exists") return true;
541
+ if (predicate.op === "equals") return valuesEqual(value, predicate.value);
542
+ if (predicate.op === "not_equals") return !valuesEqual(value, predicate.value);
543
+ if (predicate.op === "truthy") return Boolean(value);
544
+ if (predicate.op === "falsy") return !value;
545
+ const observed = typeof value === "number" ? value : Number.NaN;
546
+ const expected = typeof predicate.value === "number" ? predicate.value : Number.NaN;
547
+ if (!Number.isFinite(observed) || !Number.isFinite(expected)) return false;
548
+ const candidate = predicate.op.startsWith("abs_") ? Math.abs(observed) : observed;
549
+ if (predicate.op === "gt" || predicate.op === "abs_gt") return candidate > expected;
550
+ if (predicate.op === "gte" || predicate.op === "abs_gte") return candidate >= expected;
551
+ if (predicate.op === "lt" || predicate.op === "abs_lt") return candidate < expected;
552
+ return candidate <= expected;
553
+ };
554
+ if (!Array.isArray(trace) || trace.length === 0) return insufficient("trace_missing_or_empty");
555
+ if (!Array.isArray(events) || events.length === 0) return insufficient("events_missing", trace.length);
556
+ for (const event of events) {
557
+ const missingPaths = event.predicates.filter((predicate) => !trace.some((sample) => {
558
+ const resolved = resolve(sample, predicate.path);
559
+ return resolved.exists && (!numericOperator(predicate.op) || typeof resolved.value === "number" && Number.isFinite(resolved.value));
560
+ })).map((predicate) => predicate.path);
561
+ if (missingPaths.length) {
562
+ return insufficient("required_trace_field_missing", trace.length, [], event.label, Array.from(new Set(missingPaths)));
563
+ }
564
+ }
565
+ const witnesses = [];
566
+ let cursor = 0;
567
+ for (const event of events) {
568
+ let witnessIndex = -1;
569
+ for (let index = cursor; index < trace.length; index += 1) {
570
+ if (event.predicates.every((predicate) => {
571
+ const resolved = resolve(trace[index], predicate.path);
572
+ return resolved.exists && matches(resolved.value, predicate);
573
+ })) {
574
+ witnessIndex = index;
575
+ break;
576
+ }
577
+ }
578
+ if (witnessIndex < 0) {
579
+ return {
580
+ version: "riddle-proof.ordered-trace-assessment.v1",
581
+ status: "failed",
582
+ trace_length: trace.length,
583
+ witnesses,
584
+ missing_event: event.label,
585
+ reason: "ordered_event_not_observed"
586
+ };
587
+ }
588
+ witnesses.push({
589
+ label: event.label,
590
+ index: witnessIndex,
591
+ observations: event.predicates.map((predicate) => {
592
+ const observed = resolve(trace[witnessIndex], predicate.path).value;
593
+ return {
594
+ path: predicate.path,
595
+ op: predicate.op,
596
+ expected: predicate.value,
597
+ observed
598
+ };
599
+ })
600
+ });
601
+ cursor = witnessIndex + 1;
602
+ }
603
+ return {
604
+ version: "riddle-proof.ordered-trace-assessment.v1",
605
+ status: "passed",
606
+ trace_length: trace.length,
607
+ witnesses
608
+ };
609
+ }
610
+ function assessRiddleProofOrderedTraceSetupResults(results, setupActionLabel, tracePath, events) {
611
+ const insufficient = (reason) => ({
612
+ version: "riddle-proof.ordered-trace-assessment.v1",
613
+ status: "proof_insufficient",
614
+ trace_length: 0,
615
+ witnesses: [],
616
+ reason
617
+ });
618
+ if (!Array.isArray(results)) return insufficient("setup_results_missing");
619
+ const source = results.find((item) => item && typeof item === "object" && !Array.isArray(item) && item.label === setupActionLabel);
620
+ if (!source) return insufficient("setup_action_result_missing");
621
+ if (!Object.hasOwn(source, "returned")) return insufficient("setup_action_return_missing");
622
+ const segments = tracePath.split(".").map((segment) => segment.trim()).filter(Boolean);
623
+ let trace = source.returned;
624
+ for (const segment of segments) {
625
+ if (trace === null || typeof trace !== "object" || Array.isArray(trace) || !Object.hasOwn(trace, segment)) {
626
+ return insufficient("trace_path_missing");
627
+ }
628
+ trace = trace[segment];
629
+ }
630
+ return assessRiddleProofOrderedTrace(trace, events);
631
+ }
434
632
  function evaluateHttpStatusBodyJsonAssertion(root, assertion) {
435
633
  const resolved = resolveJsonPath(root, assertion.path);
436
634
  const errors = [];
@@ -537,6 +735,7 @@ function profileSetupWindowCallReceipts(results) {
537
735
  return results.filter((result) => profileSetupResultAction(result) === "window_call").map((result) => {
538
736
  const receipt = {
539
737
  ordinal: result.ordinal ?? null,
738
+ label: result.label ?? null,
540
739
  ok: result.ok !== false,
541
740
  path: result.path ?? null,
542
741
  return_captured: result.return_captured ?? null,
@@ -555,6 +754,7 @@ function profileSetupWindowEvalReceipts(results) {
555
754
  return results.filter((result) => profileSetupResultAction(result) === "window_eval").map((result) => {
556
755
  const receipt = {
557
756
  ordinal: result.ordinal ?? null,
757
+ label: result.label ?? null,
558
758
  ok: result.ok !== false,
559
759
  script_length: result.script_length ?? null,
560
760
  return_captured: result.return_captured ?? null,
@@ -1827,6 +2027,51 @@ function dialogCountFieldForCheckType(type) {
1827
2027
  if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
1828
2028
  return "dialog_count";
1829
2029
  }
2030
+ function normalizeOrderedTraceEvents(value, label) {
2031
+ if (value === void 0) return void 0;
2032
+ if (!Array.isArray(value) || !value.length) throw new Error(`${label} must be a non-empty array.`);
2033
+ const seenLabels = /* @__PURE__ */ new Set();
2034
+ return value.map((item, eventIndex) => {
2035
+ const eventLabel = `${label}[${eventIndex}]`;
2036
+ if (!isRecord(item)) throw new Error(`${eventLabel} must be an object.`);
2037
+ const name = stringFromOwn(item, "label", "name", "event");
2038
+ if (!name) throw new Error(`${eventLabel}.label is required.`);
2039
+ if (seenLabels.has(name)) throw new Error(`${eventLabel}.label must be unique.`);
2040
+ seenLabels.add(name);
2041
+ const predicatesInput = item.predicates ?? item.all ?? item.where;
2042
+ if (!Array.isArray(predicatesInput) || !predicatesInput.length) {
2043
+ throw new Error(`${eventLabel}.predicates must be a non-empty array.`);
2044
+ }
2045
+ const predicates = predicatesInput.map((predicateInput, predicateIndex) => {
2046
+ const predicateLabel = `${eventLabel}.predicates[${predicateIndex}]`;
2047
+ if (!isRecord(predicateInput)) throw new Error(`${predicateLabel} must be an object.`);
2048
+ const path = stringFromOwn(predicateInput, "path", "field", "key");
2049
+ if (!path) throw new Error(`${predicateLabel}.path is required.`);
2050
+ const op = stringFromOwn(predicateInput, "op", "operator");
2051
+ if (!op || !RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.includes(op)) {
2052
+ throw new Error(`${predicateLabel}.op must be one of ${RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.join(", ")}.`);
2053
+ }
2054
+ const requiresValue = !["exists", "truthy", "falsy"].includes(op);
2055
+ const hasValue = hasOwn(predicateInput, "value") || hasOwn(predicateInput, "expected");
2056
+ if (requiresValue && !hasValue) throw new Error(`${predicateLabel}.value is required for ${op}.`);
2057
+ const value2 = hasOwn(predicateInput, "value") ? predicateInput.value : predicateInput.expected;
2058
+ if (["gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"].includes(op)) {
2059
+ if (typeof value2 !== "number" || !Number.isFinite(value2)) {
2060
+ throw new Error(`${predicateLabel}.value must be a finite number for ${op}.`);
2061
+ }
2062
+ if (op.startsWith("abs_") && value2 < 0) {
2063
+ throw new Error(`${predicateLabel}.value must be non-negative for ${op}.`);
2064
+ }
2065
+ }
2066
+ return {
2067
+ path,
2068
+ op,
2069
+ value: requiresValue ? toJsonValue(value2) : void 0
2070
+ };
2071
+ });
2072
+ return { label: name, predicates };
2073
+ });
2074
+ }
1830
2075
  function normalizeCheck(input, index) {
1831
2076
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
1832
2077
  const type = stringValue(input.type);
@@ -1877,6 +2122,17 @@ function normalizeCheck(input, index) {
1877
2122
  if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
1878
2123
  if (!expectedTexts?.length) throw new Error(`checks[${index}] selector_text_order requires expected_texts.`);
1879
2124
  }
2125
+ const setupActionLabel = stringFromOwn(input, "setup_action_label", "setupActionLabel", "source_action_label", "sourceActionLabel");
2126
+ const tracePath = stringFromOwn(input, "trace_path", "tracePath", "path");
2127
+ const orderedTraceEvents = normalizeOrderedTraceEvents(
2128
+ input.events ?? input.sequence ?? input.ordered_events ?? input.orderedEvents,
2129
+ `checks[${index}].events`
2130
+ );
2131
+ if (type === "ordered_trace") {
2132
+ if (!setupActionLabel) throw new Error(`checks[${index}] ordered_trace requires setup_action_label.`);
2133
+ if (!tracePath) throw new Error(`checks[${index}] ordered_trace requires trace_path.`);
2134
+ if (!orderedTraceEvents?.length) throw new Error(`checks[${index}] ordered_trace requires events.`);
2135
+ }
1880
2136
  const expectedRoutes = normalizeRouteInventoryRoutes(input.expected_routes ?? input.expectedRoutes, index);
1881
2137
  if (type === "route_inventory" && !expectedRoutes?.length) {
1882
2138
  throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
@@ -1949,6 +2205,9 @@ function normalizeCheck(input, index) {
1949
2205
  body_not_patterns: bodyNotPatterns,
1950
2206
  body_json_assertions: bodyJsonAssertions,
1951
2207
  expected_texts: expectedTexts,
2208
+ setup_action_label: type === "ordered_trace" ? setupActionLabel : void 0,
2209
+ trace_path: type === "ordered_trace" ? tracePath : void 0,
2210
+ events: type === "ordered_trace" ? orderedTraceEvents : void 0,
1952
2211
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
1953
2212
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
1954
2213
  route_path_prefix: stringValue(input.route_path_prefix) || stringValue(input.routePathPrefix),
@@ -2015,6 +2274,20 @@ function normalizeRiddleProofProfile(input, options = {}) {
2015
2274
  const targetUrl = stringValue(options.url) || stringValue(targetInput.url);
2016
2275
  const route = stringValue(options.route) || stringValue(targetInput.route);
2017
2276
  if (!targetUrl && !route) throw new Error("profile.target requires url or route, or pass --url.");
2277
+ const setupActions = normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions);
2278
+ for (const [index, check] of checks.entries()) {
2279
+ if (check.type !== "ordered_trace") continue;
2280
+ const matches = (setupActions || []).filter((action) => action.label === check.setup_action_label);
2281
+ if (matches.length !== 1) {
2282
+ throw new Error(`checks[${index}] ordered_trace setup_action_label must match exactly one target.setup_actions label.`);
2283
+ }
2284
+ if (!["window_eval", "window_call", "window_call_until"].includes(matches[0].type)) {
2285
+ throw new Error(`checks[${index}] ordered_trace source action must capture a window_eval, window_call, or window_call_until return.`);
2286
+ }
2287
+ if (matches[0].capture_return === false) {
2288
+ throw new Error(`checks[${index}] ordered_trace source action must not set capture_return to false.`);
2289
+ }
2290
+ }
2018
2291
  return {
2019
2292
  version: RIDDLE_PROOF_PROFILE_VERSION,
2020
2293
  name: normalizeName(input.name, "riddle-proof-profile"),
@@ -2027,7 +2300,7 @@ function normalizeRiddleProofProfile(input, options = {}) {
2027
2300
  wait_for_selector: stringValue(targetInput.wait_for_selector) || stringValue(targetInput.waitForSelector),
2028
2301
  wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs),
2029
2302
  screenshot_full_page: normalizeTargetScreenshotFullPage(targetInput),
2030
- setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions),
2303
+ setup_actions: setupActions,
2031
2304
  network_mocks: normalizeNetworkMocks(targetInput.network_mocks ?? targetInput.networkMocks)
2032
2305
  },
2033
2306
  checks,
@@ -3040,6 +3313,32 @@ function assessCheckFromEvidence(check, evidence) {
3040
3313
  message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
3041
3314
  };
3042
3315
  }
3316
+ if (check.type === "ordered_trace") {
3317
+ const assessments = viewports.map((viewport) => ({
3318
+ viewport: viewport.name,
3319
+ assessment: assessRiddleProofOrderedTraceSetupResults(
3320
+ viewport.setup_action_results,
3321
+ check.setup_action_label || "",
3322
+ check.trace_path || "",
3323
+ check.events || []
3324
+ )
3325
+ }));
3326
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
3327
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
3328
+ const status = insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed";
3329
+ return {
3330
+ type: check.type,
3331
+ label: checkLabel(check),
3332
+ status,
3333
+ evidence: {
3334
+ setup_action_label: check.setup_action_label || "",
3335
+ trace_path: check.trace_path || "",
3336
+ events: toJsonValue((check.events || []).map((event) => event.label)),
3337
+ viewports: toJsonValue(assessments)
3338
+ },
3339
+ message: insufficient.length ? `Ordered trace evidence was insufficient in ${insufficient.length} viewport(s).` : failed.length ? `Ordered trace did not contain the required event sequence in ${failed.length} viewport(s).` : void 0
3340
+ };
3341
+ }
3043
3342
  if (check.type === "observe_within") {
3044
3343
  const key = observeWithinKey(check);
3045
3344
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -3539,6 +3838,7 @@ function profileStatusFromEvidence(profile, evidence, checks) {
3539
3838
  if (!viewports.length || !checks.length) return "proof_insufficient";
3540
3839
  if (viewports.some((viewport) => viewport.navigation_error)) return "environment_blocked";
3541
3840
  if (expectedViewportCount && viewports.length < expectedViewportCount) return "proof_insufficient";
3841
+ if (checks.some((check) => check.status === "proof_insufficient")) return "proof_insufficient";
3542
3842
  if (checks.some((check) => check.status === "needs_human_review")) return "needs_human_review";
3543
3843
  if (checks.some((check) => check.status === "failed")) return "product_regression";
3544
3844
  return "passed";
@@ -3868,8 +4168,12 @@ function createRiddleProofProfileInsufficientResult(input) {
3868
4168
  error: message
3869
4169
  };
3870
4170
  }
3871
- function runtimeScriptAssessmentSource() {
4171
+ function runtimeScriptAssessmentSource(includeOrderedTrace = false) {
4172
+ const orderedTraceSource = includeOrderedTrace ? String.raw`
4173
+ const assessRiddleProofOrderedTrace = ${assessRiddleProofOrderedTrace.toString()};
4174
+ const assessRiddleProofOrderedTraceSetupResults = ${assessRiddleProofOrderedTraceSetupResults.toString()};` : "";
3872
4175
  return String.raw`
4176
+ ${orderedTraceSource}
3873
4177
  function normalizeRoutePath(path) {
3874
4178
  const value = path || "/";
3875
4179
  if (value === "/") return "/";
@@ -4699,6 +5003,7 @@ function profileSetupWindowCallReceipts(results) {
4699
5003
  .map((result) => {
4700
5004
  const receipt = {
4701
5005
  ordinal: result.ordinal ?? null,
5006
+ label: result.label ?? null,
4702
5007
  ok: result.ok !== false,
4703
5008
  path: result.path ?? null,
4704
5009
  return_captured: result.return_captured ?? null,
@@ -4719,6 +5024,7 @@ function profileSetupWindowEvalReceipts(results) {
4719
5024
  .map((result) => {
4720
5025
  const receipt = {
4721
5026
  ordinal: result.ordinal ?? null,
5027
+ label: result.label ?? null,
4722
5028
  ok: result.ok !== false,
4723
5029
  script_length: result.script_length ?? null,
4724
5030
  return_captured: result.return_captured ?? null,
@@ -5534,6 +5840,36 @@ function assessProfile(profile, evidence) {
5534
5840
  });
5535
5841
  continue;
5536
5842
  }
5843
+ if (check.type === "ordered_trace") {
5844
+ const assessments = checkViewports.map((viewport) => ({
5845
+ viewport: viewport.name,
5846
+ assessment: assessRiddleProofOrderedTraceSetupResults(
5847
+ viewport.setup_action_results,
5848
+ check.setup_action_label || "",
5849
+ check.trace_path || "",
5850
+ check.events || [],
5851
+ ),
5852
+ }));
5853
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
5854
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
5855
+ checks.push({
5856
+ type: check.type,
5857
+ label: check.label || check.type,
5858
+ status: insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed",
5859
+ evidence: {
5860
+ setup_action_label: check.setup_action_label || "",
5861
+ trace_path: check.trace_path || "",
5862
+ events: (check.events || []).map((event) => event.label),
5863
+ viewports: assessments,
5864
+ },
5865
+ message: insufficient.length
5866
+ ? "Ordered trace evidence was insufficient in " + insufficient.length + " viewport(s)."
5867
+ : failed.length
5868
+ ? "Ordered trace did not contain the required event sequence in " + failed.length + " viewport(s)."
5869
+ : undefined,
5870
+ });
5871
+ continue;
5872
+ }
5537
5873
  if (check.type === "observe_within") {
5538
5874
  const key = observeWithinKey(check);
5539
5875
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -5890,6 +6226,7 @@ function assessProfile(profile, evidence) {
5890
6226
  if (!viewports.length || !checks.length) status = "proof_insufficient";
5891
6227
  else if (viewports.some((viewport) => viewport.navigation_error)) status = "environment_blocked";
5892
6228
  else if (expectedViewportCount && viewports.length < expectedViewportCount) status = "proof_insufficient";
6229
+ else if (checks.some((check) => check.status === "proof_insufficient")) status = "proof_insufficient";
5893
6230
  else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
5894
6231
  else if (checks.some((check) => check.status === "failed")) status = "product_regression";
5895
6232
  const screenshotLabels = profileScreenshotLabels(viewports);
@@ -6821,7 +7158,7 @@ let activeViewportName = null;
6821
7158
  async function executeSetupAction(action, ordinal, viewport) {
6822
7159
  const type = setupActionType(action);
6823
7160
  const frameSelector = setupFrameSelector(action);
6824
- const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
7161
+ const base = { ok: false, action: type || "unknown", ordinal, label: action.label || null, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
6825
7162
  const timeout = setupNumber(action.timeout_ms, 5000);
6826
7163
  try {
6827
7164
  if (type === "wait") {
@@ -9473,7 +9810,7 @@ async function captureViewport(viewport) {
9473
9810
  wait_error: waitError,
9474
9811
  };
9475
9812
  }
9476
- ${runtimeScriptAssessmentSource()}
9813
+ ${runtimeScriptAssessmentSource(profile.checks.some((check) => check.type === "ordered_trace"))}
9477
9814
  const viewports = [];
9478
9815
  function buildProfileEvidence(currentViewports) {
9479
9816
  const expectedViewportCount = (profile.target.viewports || []).length;
@@ -9678,6 +10015,7 @@ function extractRiddleProofProfileResult(input) {
9678
10015
  // Annotate the CommonJS export names for ESM import in node:
9679
10016
  0 && (module.exports = {
9680
10017
  RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
10018
+ RIDDLE_PROOF_ORDERED_TRACE_OPERATORS,
9681
10019
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
9682
10020
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
9683
10021
  RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
@@ -9686,6 +10024,8 @@ function extractRiddleProofProfileResult(input) {
9686
10024
  RIDDLE_PROOF_PROFILE_STATUSES,
9687
10025
  RIDDLE_PROOF_PROFILE_VERSION,
9688
10026
  applyRiddleProofProfileArtifactCompleteness,
10027
+ assessRiddleProofOrderedTrace,
10028
+ assessRiddleProofOrderedTraceSetupResults,
9689
10029
  assessRiddleProofProfileArtifactCompleteness,
9690
10030
  assessRiddleProofProfileEvidence,
9691
10031
  buildRiddleProofProfileScript,
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
5
5
  declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
7
7
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
8
- declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
+ declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "ordered_trace", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
9
9
  declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "tap_until", "drag", "press", "key_down", "key_up", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
10
10
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
11
11
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
@@ -40,6 +40,36 @@ interface RiddleProofProfileHttpStatusPreflightFetchResponse {
40
40
  }
41
41
  type RiddleProofProfileHttpStatusPreflightFetch = (url: string, init?: Record<string, unknown>) => Promise<RiddleProofProfileHttpStatusPreflightFetchResponse>;
42
42
  type RiddleProofProfileJsonValueType = "array" | "boolean" | "null" | "number" | "object" | "string";
43
+ declare const RIDDLE_PROOF_ORDERED_TRACE_OPERATORS: readonly ["exists", "equals", "not_equals", "truthy", "falsy", "gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"];
44
+ type RiddleProofOrderedTraceOperator = typeof RIDDLE_PROOF_ORDERED_TRACE_OPERATORS[number];
45
+ interface RiddleProofOrderedTracePredicate {
46
+ path: string;
47
+ op: RiddleProofOrderedTraceOperator;
48
+ value?: JsonValue;
49
+ }
50
+ interface RiddleProofOrderedTraceEvent {
51
+ label: string;
52
+ predicates: RiddleProofOrderedTracePredicate[];
53
+ }
54
+ interface RiddleProofOrderedTraceWitness {
55
+ label: string;
56
+ index: number;
57
+ observations: Array<{
58
+ path: string;
59
+ op: RiddleProofOrderedTraceOperator;
60
+ expected?: JsonValue;
61
+ observed: JsonValue;
62
+ }>;
63
+ }
64
+ interface RiddleProofOrderedTraceAssessment {
65
+ version: "riddle-proof.ordered-trace-assessment.v1";
66
+ status: "passed" | "failed" | "proof_insufficient";
67
+ trace_length: number;
68
+ witnesses: RiddleProofOrderedTraceWitness[];
69
+ missing_event?: string;
70
+ missing_paths?: string[];
71
+ reason?: string;
72
+ }
43
73
  interface RiddleProofProfileHttpStatusBodyJsonAssertion {
44
74
  label?: string;
45
75
  path: string;
@@ -246,6 +276,9 @@ interface RiddleProofProfileCheck {
246
276
  body_not_patterns?: string[];
247
277
  body_json_assertions?: RiddleProofProfileHttpStatusBodyJsonAssertion[];
248
278
  expected_texts?: string[];
279
+ setup_action_label?: string;
280
+ trace_path?: string;
281
+ events?: RiddleProofOrderedTraceEvent[];
249
282
  link_selector?: string;
250
283
  source_selector?: string;
251
284
  route_path_prefix?: string;
@@ -372,7 +405,7 @@ interface RiddleProofProfileEvidence {
372
405
  interface RiddleProofProfileCheckResult {
373
406
  type: RiddleProofProfileCheckType | (string & {});
374
407
  label?: string;
375
- status: "passed" | "failed" | "skipped" | "needs_human_review";
408
+ status: "passed" | "failed" | "skipped" | "proof_insufficient" | "needs_human_review";
376
409
  evidence: Record<string, JsonValue>;
377
410
  message?: string;
378
411
  }
@@ -454,6 +487,8 @@ interface NormalizeRiddleProofProfileOptions {
454
487
  route?: string;
455
488
  viewports?: RiddleProofProfileViewport[];
456
489
  }
490
+ declare function assessRiddleProofOrderedTrace(trace: unknown, events: RiddleProofOrderedTraceEvent[]): RiddleProofOrderedTraceAssessment;
491
+ declare function assessRiddleProofOrderedTraceSetupResults(results: unknown, setupActionLabel: string, tracePath: string, events: RiddleProofOrderedTraceEvent[]): RiddleProofOrderedTraceAssessment;
457
492
  declare function slugifyRiddleProofProfileName(value: string): string;
458
493
  declare function collectRiddleProofProfileWarnings(profile: RiddleProofProfile): string[];
459
494
  declare function normalizeRiddleProofProfile(input: unknown, options?: NormalizeRiddleProofProfileOptions): RiddleProofProfile;
@@ -514,4 +549,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
514
549
  declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
515
550
  declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
516
551
 
517
- export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofProfile, type RiddleProofProfileArtifactCompleteness, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileHttpStatusBodyJsonAssertion, type RiddleProofProfileHttpStatusBodyJsonAssertionResult, type RiddleProofProfileHttpStatusPreflightCheckResult, type RiddleProofProfileHttpStatusPreflightFetch, type RiddleProofProfileHttpStatusPreflightFetchResponse, type RiddleProofProfileHttpStatusPreflightOptions, type RiddleProofProfileHttpStatusPreflightResult, type RiddleProofProfileJsonValueType, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileReturnSummaryField, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileRunnerArtifactPreflight, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, applyRiddleProofProfileArtifactCompleteness, assessRiddleProofProfileArtifactCompleteness, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, preflightRiddleProofProfileRunnerArtifacts, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
552
+ export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS, RIDDLE_PROOF_ORDERED_TRACE_OPERATORS, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofArtifactBodyAssertionInput, type RiddleProofArtifactBodyAssertionResult, type RiddleProofOrderedTraceAssessment, type RiddleProofOrderedTraceEvent, type RiddleProofOrderedTraceOperator, type RiddleProofOrderedTracePredicate, type RiddleProofOrderedTraceWitness, type RiddleProofProfile, type RiddleProofProfileArtifactCompleteness, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileHttpStatusBodyJsonAssertion, type RiddleProofProfileHttpStatusBodyJsonAssertionResult, type RiddleProofProfileHttpStatusPreflightCheckResult, type RiddleProofProfileHttpStatusPreflightFetch, type RiddleProofProfileHttpStatusPreflightFetchResponse, type RiddleProofProfileHttpStatusPreflightOptions, type RiddleProofProfileHttpStatusPreflightResult, type RiddleProofProfileJsonValueType, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileReturnSummaryField, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileRunnerArtifactPreflight, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, applyRiddleProofProfileArtifactCompleteness, assessRiddleProofOrderedTrace, assessRiddleProofOrderedTraceSetupResults, assessRiddleProofProfileArtifactCompleteness, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, preflightRiddleProofProfileRunnerArtifacts, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };