@riddledc/riddle-proof 0.8.79 → 0.8.81

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,
@@ -998,10 +1198,14 @@ function normalizeViewport(input, index) {
998
1198
  if (!width || !height || width < 100 || height < 100) {
999
1199
  throw new Error(`target.viewports[${index}] requires numeric width and height >= 100.`);
1000
1200
  }
1201
+ const hasTouch = booleanValue(valueFromOwn(input, "hasTouch", "has_touch"));
1202
+ const isMobile = booleanValue(valueFromOwn(input, "isMobile", "is_mobile"));
1001
1203
  return {
1002
1204
  name: normalizeName(input.name || input.label, `viewport-${index + 1}`),
1003
1205
  width: Math.round(width),
1004
- height: Math.round(height)
1206
+ height: Math.round(height),
1207
+ ...hasTouch === void 0 ? {} : { hasTouch },
1208
+ ...isMobile === void 0 ? {} : { isMobile }
1005
1209
  };
1006
1210
  }
1007
1211
  function normalizeViewports(value) {
@@ -1827,6 +2031,51 @@ function dialogCountFieldForCheckType(type) {
1827
2031
  if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
1828
2032
  return "dialog_count";
1829
2033
  }
2034
+ function normalizeOrderedTraceEvents(value, label) {
2035
+ if (value === void 0) return void 0;
2036
+ if (!Array.isArray(value) || !value.length) throw new Error(`${label} must be a non-empty array.`);
2037
+ const seenLabels = /* @__PURE__ */ new Set();
2038
+ return value.map((item, eventIndex) => {
2039
+ const eventLabel = `${label}[${eventIndex}]`;
2040
+ if (!isRecord(item)) throw new Error(`${eventLabel} must be an object.`);
2041
+ const name = stringFromOwn(item, "label", "name", "event");
2042
+ if (!name) throw new Error(`${eventLabel}.label is required.`);
2043
+ if (seenLabels.has(name)) throw new Error(`${eventLabel}.label must be unique.`);
2044
+ seenLabels.add(name);
2045
+ const predicatesInput = item.predicates ?? item.all ?? item.where;
2046
+ if (!Array.isArray(predicatesInput) || !predicatesInput.length) {
2047
+ throw new Error(`${eventLabel}.predicates must be a non-empty array.`);
2048
+ }
2049
+ const predicates = predicatesInput.map((predicateInput, predicateIndex) => {
2050
+ const predicateLabel = `${eventLabel}.predicates[${predicateIndex}]`;
2051
+ if (!isRecord(predicateInput)) throw new Error(`${predicateLabel} must be an object.`);
2052
+ const path = stringFromOwn(predicateInput, "path", "field", "key");
2053
+ if (!path) throw new Error(`${predicateLabel}.path is required.`);
2054
+ const op = stringFromOwn(predicateInput, "op", "operator");
2055
+ if (!op || !RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.includes(op)) {
2056
+ throw new Error(`${predicateLabel}.op must be one of ${RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.join(", ")}.`);
2057
+ }
2058
+ const requiresValue = !["exists", "truthy", "falsy"].includes(op);
2059
+ const hasValue = hasOwn(predicateInput, "value") || hasOwn(predicateInput, "expected");
2060
+ if (requiresValue && !hasValue) throw new Error(`${predicateLabel}.value is required for ${op}.`);
2061
+ const value2 = hasOwn(predicateInput, "value") ? predicateInput.value : predicateInput.expected;
2062
+ if (["gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"].includes(op)) {
2063
+ if (typeof value2 !== "number" || !Number.isFinite(value2)) {
2064
+ throw new Error(`${predicateLabel}.value must be a finite number for ${op}.`);
2065
+ }
2066
+ if (op.startsWith("abs_") && value2 < 0) {
2067
+ throw new Error(`${predicateLabel}.value must be non-negative for ${op}.`);
2068
+ }
2069
+ }
2070
+ return {
2071
+ path,
2072
+ op,
2073
+ value: requiresValue ? toJsonValue(value2) : void 0
2074
+ };
2075
+ });
2076
+ return { label: name, predicates };
2077
+ });
2078
+ }
1830
2079
  function normalizeCheck(input, index) {
1831
2080
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
1832
2081
  const type = stringValue(input.type);
@@ -1877,6 +2126,17 @@ function normalizeCheck(input, index) {
1877
2126
  if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
1878
2127
  if (!expectedTexts?.length) throw new Error(`checks[${index}] selector_text_order requires expected_texts.`);
1879
2128
  }
2129
+ const setupActionLabel = stringFromOwn(input, "setup_action_label", "setupActionLabel", "source_action_label", "sourceActionLabel");
2130
+ const tracePath = stringFromOwn(input, "trace_path", "tracePath", "path");
2131
+ const orderedTraceEvents = normalizeOrderedTraceEvents(
2132
+ input.events ?? input.sequence ?? input.ordered_events ?? input.orderedEvents,
2133
+ `checks[${index}].events`
2134
+ );
2135
+ if (type === "ordered_trace") {
2136
+ if (!setupActionLabel) throw new Error(`checks[${index}] ordered_trace requires setup_action_label.`);
2137
+ if (!tracePath) throw new Error(`checks[${index}] ordered_trace requires trace_path.`);
2138
+ if (!orderedTraceEvents?.length) throw new Error(`checks[${index}] ordered_trace requires events.`);
2139
+ }
1880
2140
  const expectedRoutes = normalizeRouteInventoryRoutes(input.expected_routes ?? input.expectedRoutes, index);
1881
2141
  if (type === "route_inventory" && !expectedRoutes?.length) {
1882
2142
  throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
@@ -1949,6 +2209,9 @@ function normalizeCheck(input, index) {
1949
2209
  body_not_patterns: bodyNotPatterns,
1950
2210
  body_json_assertions: bodyJsonAssertions,
1951
2211
  expected_texts: expectedTexts,
2212
+ setup_action_label: type === "ordered_trace" ? setupActionLabel : void 0,
2213
+ trace_path: type === "ordered_trace" ? tracePath : void 0,
2214
+ events: type === "ordered_trace" ? orderedTraceEvents : void 0,
1952
2215
  link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
1953
2216
  source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
1954
2217
  route_path_prefix: stringValue(input.route_path_prefix) || stringValue(input.routePathPrefix),
@@ -2015,6 +2278,20 @@ function normalizeRiddleProofProfile(input, options = {}) {
2015
2278
  const targetUrl = stringValue(options.url) || stringValue(targetInput.url);
2016
2279
  const route = stringValue(options.route) || stringValue(targetInput.route);
2017
2280
  if (!targetUrl && !route) throw new Error("profile.target requires url or route, or pass --url.");
2281
+ const setupActions = normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions);
2282
+ for (const [index, check] of checks.entries()) {
2283
+ if (check.type !== "ordered_trace") continue;
2284
+ const matches = (setupActions || []).filter((action) => action.label === check.setup_action_label);
2285
+ if (matches.length !== 1) {
2286
+ throw new Error(`checks[${index}] ordered_trace setup_action_label must match exactly one target.setup_actions label.`);
2287
+ }
2288
+ if (!["window_eval", "window_call", "window_call_until"].includes(matches[0].type)) {
2289
+ throw new Error(`checks[${index}] ordered_trace source action must capture a window_eval, window_call, or window_call_until return.`);
2290
+ }
2291
+ if (matches[0].capture_return === false) {
2292
+ throw new Error(`checks[${index}] ordered_trace source action must not set capture_return to false.`);
2293
+ }
2294
+ }
2018
2295
  return {
2019
2296
  version: RIDDLE_PROOF_PROFILE_VERSION,
2020
2297
  name: normalizeName(input.name, "riddle-proof-profile"),
@@ -2027,7 +2304,7 @@ function normalizeRiddleProofProfile(input, options = {}) {
2027
2304
  wait_for_selector: stringValue(targetInput.wait_for_selector) || stringValue(targetInput.waitForSelector),
2028
2305
  wait_ms: numberValue(targetInput.wait_ms) ?? numberValue(targetInput.waitMs),
2029
2306
  screenshot_full_page: normalizeTargetScreenshotFullPage(targetInput),
2030
- setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions),
2307
+ setup_actions: setupActions,
2031
2308
  network_mocks: normalizeNetworkMocks(targetInput.network_mocks ?? targetInput.networkMocks)
2032
2309
  },
2033
2310
  checks,
@@ -3040,6 +3317,32 @@ function assessCheckFromEvidence(check, evidence) {
3040
3317
  message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
3041
3318
  };
3042
3319
  }
3320
+ if (check.type === "ordered_trace") {
3321
+ const assessments = viewports.map((viewport) => ({
3322
+ viewport: viewport.name,
3323
+ assessment: assessRiddleProofOrderedTraceSetupResults(
3324
+ viewport.setup_action_results,
3325
+ check.setup_action_label || "",
3326
+ check.trace_path || "",
3327
+ check.events || []
3328
+ )
3329
+ }));
3330
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
3331
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
3332
+ const status = insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed";
3333
+ return {
3334
+ type: check.type,
3335
+ label: checkLabel(check),
3336
+ status,
3337
+ evidence: {
3338
+ setup_action_label: check.setup_action_label || "",
3339
+ trace_path: check.trace_path || "",
3340
+ events: toJsonValue((check.events || []).map((event) => event.label)),
3341
+ viewports: toJsonValue(assessments)
3342
+ },
3343
+ 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
3344
+ };
3345
+ }
3043
3346
  if (check.type === "observe_within") {
3044
3347
  const key = observeWithinKey(check);
3045
3348
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -3539,6 +3842,7 @@ function profileStatusFromEvidence(profile, evidence, checks) {
3539
3842
  if (!viewports.length || !checks.length) return "proof_insufficient";
3540
3843
  if (viewports.some((viewport) => viewport.navigation_error)) return "environment_blocked";
3541
3844
  if (expectedViewportCount && viewports.length < expectedViewportCount) return "proof_insufficient";
3845
+ if (checks.some((check) => check.status === "proof_insufficient")) return "proof_insufficient";
3542
3846
  if (checks.some((check) => check.status === "needs_human_review")) return "needs_human_review";
3543
3847
  if (checks.some((check) => check.status === "failed")) return "product_regression";
3544
3848
  return "passed";
@@ -3868,8 +4172,12 @@ function createRiddleProofProfileInsufficientResult(input) {
3868
4172
  error: message
3869
4173
  };
3870
4174
  }
3871
- function runtimeScriptAssessmentSource() {
4175
+ function runtimeScriptAssessmentSource(includeOrderedTrace = false) {
4176
+ const orderedTraceSource = includeOrderedTrace ? String.raw`
4177
+ const assessRiddleProofOrderedTrace = ${assessRiddleProofOrderedTrace.toString()};
4178
+ const assessRiddleProofOrderedTraceSetupResults = ${assessRiddleProofOrderedTraceSetupResults.toString()};` : "";
3872
4179
  return String.raw`
4180
+ ${orderedTraceSource}
3873
4181
  function normalizeRoutePath(path) {
3874
4182
  const value = path || "/";
3875
4183
  if (value === "/") return "/";
@@ -4699,6 +5007,7 @@ function profileSetupWindowCallReceipts(results) {
4699
5007
  .map((result) => {
4700
5008
  const receipt = {
4701
5009
  ordinal: result.ordinal ?? null,
5010
+ label: result.label ?? null,
4702
5011
  ok: result.ok !== false,
4703
5012
  path: result.path ?? null,
4704
5013
  return_captured: result.return_captured ?? null,
@@ -4719,6 +5028,7 @@ function profileSetupWindowEvalReceipts(results) {
4719
5028
  .map((result) => {
4720
5029
  const receipt = {
4721
5030
  ordinal: result.ordinal ?? null,
5031
+ label: result.label ?? null,
4722
5032
  ok: result.ok !== false,
4723
5033
  script_length: result.script_length ?? null,
4724
5034
  return_captured: result.return_captured ?? null,
@@ -5534,6 +5844,36 @@ function assessProfile(profile, evidence) {
5534
5844
  });
5535
5845
  continue;
5536
5846
  }
5847
+ if (check.type === "ordered_trace") {
5848
+ const assessments = checkViewports.map((viewport) => ({
5849
+ viewport: viewport.name,
5850
+ assessment: assessRiddleProofOrderedTraceSetupResults(
5851
+ viewport.setup_action_results,
5852
+ check.setup_action_label || "",
5853
+ check.trace_path || "",
5854
+ check.events || [],
5855
+ ),
5856
+ }));
5857
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
5858
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
5859
+ checks.push({
5860
+ type: check.type,
5861
+ label: check.label || check.type,
5862
+ status: insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed",
5863
+ evidence: {
5864
+ setup_action_label: check.setup_action_label || "",
5865
+ trace_path: check.trace_path || "",
5866
+ events: (check.events || []).map((event) => event.label),
5867
+ viewports: assessments,
5868
+ },
5869
+ message: insufficient.length
5870
+ ? "Ordered trace evidence was insufficient in " + insufficient.length + " viewport(s)."
5871
+ : failed.length
5872
+ ? "Ordered trace did not contain the required event sequence in " + failed.length + " viewport(s)."
5873
+ : undefined,
5874
+ });
5875
+ continue;
5876
+ }
5537
5877
  if (check.type === "observe_within") {
5538
5878
  const key = observeWithinKey(check);
5539
5879
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -5890,6 +6230,7 @@ function assessProfile(profile, evidence) {
5890
6230
  if (!viewports.length || !checks.length) status = "proof_insufficient";
5891
6231
  else if (viewports.some((viewport) => viewport.navigation_error)) status = "environment_blocked";
5892
6232
  else if (expectedViewportCount && viewports.length < expectedViewportCount) status = "proof_insufficient";
6233
+ else if (checks.some((check) => check.status === "proof_insufficient")) status = "proof_insufficient";
5893
6234
  else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
5894
6235
  else if (checks.some((check) => check.status === "failed")) status = "product_regression";
5895
6236
  const screenshotLabels = profileScreenshotLabels(viewports);
@@ -6821,7 +7162,7 @@ let activeViewportName = null;
6821
7162
  async function executeSetupAction(action, ordinal, viewport) {
6822
7163
  const type = setupActionType(action);
6823
7164
  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 };
7165
+ 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
7166
  const timeout = setupNumber(action.timeout_ms, 5000);
6826
7167
  try {
6827
7168
  if (type === "wait") {
@@ -9473,7 +9814,7 @@ async function captureViewport(viewport) {
9473
9814
  wait_error: waitError,
9474
9815
  };
9475
9816
  }
9476
- ${runtimeScriptAssessmentSource()}
9817
+ ${runtimeScriptAssessmentSource(profile.checks.some((check) => check.type === "ordered_trace"))}
9477
9818
  const viewports = [];
9478
9819
  function buildProfileEvidence(currentViewports) {
9479
9820
  const expectedViewportCount = (profile.target.viewports || []).length;
@@ -9678,6 +10019,7 @@ function extractRiddleProofProfileResult(input) {
9678
10019
  // Annotate the CommonJS export names for ESM import in node:
9679
10020
  0 && (module.exports = {
9680
10021
  RIDDLE_PROOF_HOSTED_PROFILE_ARTIFACTS,
10022
+ RIDDLE_PROOF_ORDERED_TRACE_OPERATORS,
9681
10023
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
9682
10024
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
9683
10025
  RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
@@ -9686,6 +10028,8 @@ function extractRiddleProofProfileResult(input) {
9686
10028
  RIDDLE_PROOF_PROFILE_STATUSES,
9687
10029
  RIDDLE_PROOF_PROFILE_VERSION,
9688
10030
  applyRiddleProofProfileArtifactCompleteness,
10031
+ assessRiddleProofOrderedTrace,
10032
+ assessRiddleProofOrderedTraceSetupResults,
9689
10033
  assessRiddleProofProfileArtifactCompleteness,
9690
10034
  assessRiddleProofProfileEvidence,
9691
10035
  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;
@@ -107,6 +137,8 @@ interface RiddleProofProfileViewport {
107
137
  name: string;
108
138
  width: number;
109
139
  height: number;
140
+ hasTouch?: boolean;
141
+ isMobile?: boolean;
110
142
  }
111
143
  interface RiddleProofProfileSetupAction {
112
144
  type: RiddleProofProfileSetupActionType;
@@ -246,6 +278,9 @@ interface RiddleProofProfileCheck {
246
278
  body_not_patterns?: string[];
247
279
  body_json_assertions?: RiddleProofProfileHttpStatusBodyJsonAssertion[];
248
280
  expected_texts?: string[];
281
+ setup_action_label?: string;
282
+ trace_path?: string;
283
+ events?: RiddleProofOrderedTraceEvent[];
249
284
  link_selector?: string;
250
285
  source_selector?: string;
251
286
  route_path_prefix?: string;
@@ -372,7 +407,7 @@ interface RiddleProofProfileEvidence {
372
407
  interface RiddleProofProfileCheckResult {
373
408
  type: RiddleProofProfileCheckType | (string & {});
374
409
  label?: string;
375
- status: "passed" | "failed" | "skipped" | "needs_human_review";
410
+ status: "passed" | "failed" | "skipped" | "proof_insufficient" | "needs_human_review";
376
411
  evidence: Record<string, JsonValue>;
377
412
  message?: string;
378
413
  }
@@ -454,6 +489,8 @@ interface NormalizeRiddleProofProfileOptions {
454
489
  route?: string;
455
490
  viewports?: RiddleProofProfileViewport[];
456
491
  }
492
+ declare function assessRiddleProofOrderedTrace(trace: unknown, events: RiddleProofOrderedTraceEvent[]): RiddleProofOrderedTraceAssessment;
493
+ declare function assessRiddleProofOrderedTraceSetupResults(results: unknown, setupActionLabel: string, tracePath: string, events: RiddleProofOrderedTraceEvent[]): RiddleProofOrderedTraceAssessment;
457
494
  declare function slugifyRiddleProofProfileName(value: string): string;
458
495
  declare function collectRiddleProofProfileWarnings(profile: RiddleProofProfile): string[];
459
496
  declare function normalizeRiddleProofProfile(input: unknown, options?: NormalizeRiddleProofProfileOptions): RiddleProofProfile;
@@ -514,4 +551,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
514
551
  declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
515
552
  declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
516
553
 
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 };
554
+ 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 };