@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/cli.cjs CHANGED
@@ -8775,6 +8775,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8775
8775
  "selector_text_visible",
8776
8776
  "selector_text_absent",
8777
8777
  "selector_text_order",
8778
+ "ordered_trace",
8778
8779
  "observe_within",
8779
8780
  "frame_text_visible",
8780
8781
  "frame_url_equals",
@@ -8838,6 +8839,21 @@ var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
8838
8839
  "timedout",
8839
8840
  "failed"
8840
8841
  ];
8842
+ var RIDDLE_PROOF_ORDERED_TRACE_OPERATORS = [
8843
+ "exists",
8844
+ "equals",
8845
+ "not_equals",
8846
+ "truthy",
8847
+ "falsy",
8848
+ "gt",
8849
+ "gte",
8850
+ "lt",
8851
+ "lte",
8852
+ "abs_gt",
8853
+ "abs_gte",
8854
+ "abs_lt",
8855
+ "abs_lte"
8856
+ ];
8841
8857
  function uniqueNonEmptyStrings(values) {
8842
8858
  const seen = /* @__PURE__ */ new Set();
8843
8859
  const result = [];
@@ -9129,6 +9145,185 @@ function resolveJsonPath(root, path7) {
9129
9145
  }
9130
9146
  return { exists: true, value: current };
9131
9147
  }
9148
+ function assessRiddleProofOrderedTrace(trace, events) {
9149
+ const insufficient = (reason, traceLength = Array.isArray(trace) ? trace.length : 0, witnesses2 = [], missingEvent, missingPaths) => ({
9150
+ version: "riddle-proof.ordered-trace-assessment.v1",
9151
+ status: "proof_insufficient",
9152
+ trace_length: traceLength,
9153
+ witnesses: witnesses2,
9154
+ missing_event: missingEvent,
9155
+ missing_paths: missingPaths,
9156
+ reason
9157
+ });
9158
+ const parsePath = (path7) => {
9159
+ const segments = [];
9160
+ let token = "";
9161
+ const pushToken = () => {
9162
+ const value = token.trim();
9163
+ if (value) segments.push(value);
9164
+ token = "";
9165
+ };
9166
+ for (let index = 0; index < path7.length; index += 1) {
9167
+ const char = path7[index];
9168
+ if (char === ".") {
9169
+ pushToken();
9170
+ continue;
9171
+ }
9172
+ if (char !== "[") {
9173
+ token += char;
9174
+ continue;
9175
+ }
9176
+ pushToken();
9177
+ const closeIndex = path7.indexOf("]", index + 1);
9178
+ if (closeIndex === -1) throw new Error(`unterminated bracket at ${index}`);
9179
+ const bracket = path7.slice(index + 1, closeIndex).trim();
9180
+ if (!bracket) throw new Error(`empty bracket at ${index}`);
9181
+ if (/^\d+$/.test(bracket)) {
9182
+ segments.push(Number(bracket));
9183
+ } else {
9184
+ segments.push(bracket.replace(/^['"]|['"]$/g, ""));
9185
+ }
9186
+ index = closeIndex;
9187
+ }
9188
+ pushToken();
9189
+ return segments;
9190
+ };
9191
+ const resolve = (root, path7) => {
9192
+ let segments;
9193
+ try {
9194
+ segments = parsePath(path7);
9195
+ } catch {
9196
+ return { exists: false };
9197
+ }
9198
+ let current = root;
9199
+ for (const segment of segments) {
9200
+ if (Array.isArray(current)) {
9201
+ const index = typeof segment === "number" ? segment : /^\d+$/.test(segment) ? Number(segment) : -1;
9202
+ if (index < 0 || index >= current.length) return { exists: false };
9203
+ current = current[index];
9204
+ continue;
9205
+ }
9206
+ if (typeof segment !== "string" || current === null || typeof current !== "object") return { exists: false };
9207
+ if (!Object.hasOwn(current, segment)) return { exists: false };
9208
+ current = current[segment];
9209
+ }
9210
+ return { exists: true, value: current };
9211
+ };
9212
+ const valuesEqual = (left, right) => {
9213
+ if (Object.is(left, right)) return true;
9214
+ if (Array.isArray(left) || Array.isArray(right)) {
9215
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => valuesEqual(value, right[index]));
9216
+ }
9217
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object") return false;
9218
+ const leftRecord = left;
9219
+ const rightRecord = right;
9220
+ const leftKeys = Object.keys(leftRecord).sort();
9221
+ const rightKeys = Object.keys(rightRecord).sort();
9222
+ return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && valuesEqual(leftRecord[key], rightRecord[key]));
9223
+ };
9224
+ const numericOperator = (op) => [
9225
+ "gt",
9226
+ "gte",
9227
+ "lt",
9228
+ "lte",
9229
+ "abs_gt",
9230
+ "abs_gte",
9231
+ "abs_lt",
9232
+ "abs_lte"
9233
+ ].includes(op);
9234
+ const matches = (value, predicate) => {
9235
+ if (predicate.op === "exists") return true;
9236
+ if (predicate.op === "equals") return valuesEqual(value, predicate.value);
9237
+ if (predicate.op === "not_equals") return !valuesEqual(value, predicate.value);
9238
+ if (predicate.op === "truthy") return Boolean(value);
9239
+ if (predicate.op === "falsy") return !value;
9240
+ const observed = typeof value === "number" ? value : Number.NaN;
9241
+ const expected = typeof predicate.value === "number" ? predicate.value : Number.NaN;
9242
+ if (!Number.isFinite(observed) || !Number.isFinite(expected)) return false;
9243
+ const candidate = predicate.op.startsWith("abs_") ? Math.abs(observed) : observed;
9244
+ if (predicate.op === "gt" || predicate.op === "abs_gt") return candidate > expected;
9245
+ if (predicate.op === "gte" || predicate.op === "abs_gte") return candidate >= expected;
9246
+ if (predicate.op === "lt" || predicate.op === "abs_lt") return candidate < expected;
9247
+ return candidate <= expected;
9248
+ };
9249
+ if (!Array.isArray(trace) || trace.length === 0) return insufficient("trace_missing_or_empty");
9250
+ if (!Array.isArray(events) || events.length === 0) return insufficient("events_missing", trace.length);
9251
+ for (const event of events) {
9252
+ const missingPaths = event.predicates.filter((predicate) => !trace.some((sample) => {
9253
+ const resolved = resolve(sample, predicate.path);
9254
+ return resolved.exists && (!numericOperator(predicate.op) || typeof resolved.value === "number" && Number.isFinite(resolved.value));
9255
+ })).map((predicate) => predicate.path);
9256
+ if (missingPaths.length) {
9257
+ return insufficient("required_trace_field_missing", trace.length, [], event.label, Array.from(new Set(missingPaths)));
9258
+ }
9259
+ }
9260
+ const witnesses = [];
9261
+ let cursor = 0;
9262
+ for (const event of events) {
9263
+ let witnessIndex = -1;
9264
+ for (let index = cursor; index < trace.length; index += 1) {
9265
+ if (event.predicates.every((predicate) => {
9266
+ const resolved = resolve(trace[index], predicate.path);
9267
+ return resolved.exists && matches(resolved.value, predicate);
9268
+ })) {
9269
+ witnessIndex = index;
9270
+ break;
9271
+ }
9272
+ }
9273
+ if (witnessIndex < 0) {
9274
+ return {
9275
+ version: "riddle-proof.ordered-trace-assessment.v1",
9276
+ status: "failed",
9277
+ trace_length: trace.length,
9278
+ witnesses,
9279
+ missing_event: event.label,
9280
+ reason: "ordered_event_not_observed"
9281
+ };
9282
+ }
9283
+ witnesses.push({
9284
+ label: event.label,
9285
+ index: witnessIndex,
9286
+ observations: event.predicates.map((predicate) => {
9287
+ const observed = resolve(trace[witnessIndex], predicate.path).value;
9288
+ return {
9289
+ path: predicate.path,
9290
+ op: predicate.op,
9291
+ expected: predicate.value,
9292
+ observed
9293
+ };
9294
+ })
9295
+ });
9296
+ cursor = witnessIndex + 1;
9297
+ }
9298
+ return {
9299
+ version: "riddle-proof.ordered-trace-assessment.v1",
9300
+ status: "passed",
9301
+ trace_length: trace.length,
9302
+ witnesses
9303
+ };
9304
+ }
9305
+ function assessRiddleProofOrderedTraceSetupResults(results, setupActionLabel, tracePath, events) {
9306
+ const insufficient = (reason) => ({
9307
+ version: "riddle-proof.ordered-trace-assessment.v1",
9308
+ status: "proof_insufficient",
9309
+ trace_length: 0,
9310
+ witnesses: [],
9311
+ reason
9312
+ });
9313
+ if (!Array.isArray(results)) return insufficient("setup_results_missing");
9314
+ const source = results.find((item) => item && typeof item === "object" && !Array.isArray(item) && item.label === setupActionLabel);
9315
+ if (!source) return insufficient("setup_action_result_missing");
9316
+ if (!Object.hasOwn(source, "returned")) return insufficient("setup_action_return_missing");
9317
+ const segments = tracePath.split(".").map((segment) => segment.trim()).filter(Boolean);
9318
+ let trace = source.returned;
9319
+ for (const segment of segments) {
9320
+ if (trace === null || typeof trace !== "object" || Array.isArray(trace) || !Object.hasOwn(trace, segment)) {
9321
+ return insufficient("trace_path_missing");
9322
+ }
9323
+ trace = trace[segment];
9324
+ }
9325
+ return assessRiddleProofOrderedTrace(trace, events);
9326
+ }
9132
9327
  function evaluateHttpStatusBodyJsonAssertion(root, assertion) {
9133
9328
  const resolved = resolveJsonPath(root, assertion.path);
9134
9329
  const errors = [];
@@ -9235,6 +9430,7 @@ function profileSetupWindowCallReceipts(results) {
9235
9430
  return results.filter((result) => profileSetupResultAction(result) === "window_call").map((result) => {
9236
9431
  const receipt = {
9237
9432
  ordinal: result.ordinal ?? null,
9433
+ label: result.label ?? null,
9238
9434
  ok: result.ok !== false,
9239
9435
  path: result.path ?? null,
9240
9436
  return_captured: result.return_captured ?? null,
@@ -9253,6 +9449,7 @@ function profileSetupWindowEvalReceipts(results) {
9253
9449
  return results.filter((result) => profileSetupResultAction(result) === "window_eval").map((result) => {
9254
9450
  const receipt = {
9255
9451
  ordinal: result.ordinal ?? null,
9452
+ label: result.label ?? null,
9256
9453
  ok: result.ok !== false,
9257
9454
  script_length: result.script_length ?? null,
9258
9455
  return_captured: result.return_captured ?? null,
@@ -9696,10 +9893,14 @@ function normalizeViewport(input, index) {
9696
9893
  if (!width || !height || width < 100 || height < 100) {
9697
9894
  throw new Error(`target.viewports[${index}] requires numeric width and height >= 100.`);
9698
9895
  }
9896
+ const hasTouch = booleanValue2(valueFromOwn(input, "hasTouch", "has_touch"));
9897
+ const isMobile = booleanValue2(valueFromOwn(input, "isMobile", "is_mobile"));
9699
9898
  return {
9700
9899
  name: normalizeName(input.name || input.label, `viewport-${index + 1}`),
9701
9900
  width: Math.round(width),
9702
- height: Math.round(height)
9901
+ height: Math.round(height),
9902
+ ...hasTouch === void 0 ? {} : { hasTouch },
9903
+ ...isMobile === void 0 ? {} : { isMobile }
9703
9904
  };
9704
9905
  }
9705
9906
  function normalizeViewports(value) {
@@ -10525,6 +10726,51 @@ function dialogCountFieldForCheckType(type) {
10525
10726
  if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
10526
10727
  return "dialog_count";
10527
10728
  }
10729
+ function normalizeOrderedTraceEvents(value, label) {
10730
+ if (value === void 0) return void 0;
10731
+ if (!Array.isArray(value) || !value.length) throw new Error(`${label} must be a non-empty array.`);
10732
+ const seenLabels = /* @__PURE__ */ new Set();
10733
+ return value.map((item, eventIndex) => {
10734
+ const eventLabel = `${label}[${eventIndex}]`;
10735
+ if (!isRecord2(item)) throw new Error(`${eventLabel} must be an object.`);
10736
+ const name = stringFromOwn(item, "label", "name", "event");
10737
+ if (!name) throw new Error(`${eventLabel}.label is required.`);
10738
+ if (seenLabels.has(name)) throw new Error(`${eventLabel}.label must be unique.`);
10739
+ seenLabels.add(name);
10740
+ const predicatesInput = item.predicates ?? item.all ?? item.where;
10741
+ if (!Array.isArray(predicatesInput) || !predicatesInput.length) {
10742
+ throw new Error(`${eventLabel}.predicates must be a non-empty array.`);
10743
+ }
10744
+ const predicates = predicatesInput.map((predicateInput, predicateIndex) => {
10745
+ const predicateLabel = `${eventLabel}.predicates[${predicateIndex}]`;
10746
+ if (!isRecord2(predicateInput)) throw new Error(`${predicateLabel} must be an object.`);
10747
+ const path7 = stringFromOwn(predicateInput, "path", "field", "key");
10748
+ if (!path7) throw new Error(`${predicateLabel}.path is required.`);
10749
+ const op = stringFromOwn(predicateInput, "op", "operator");
10750
+ if (!op || !RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.includes(op)) {
10751
+ throw new Error(`${predicateLabel}.op must be one of ${RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.join(", ")}.`);
10752
+ }
10753
+ const requiresValue = !["exists", "truthy", "falsy"].includes(op);
10754
+ const hasValue = hasOwn(predicateInput, "value") || hasOwn(predicateInput, "expected");
10755
+ if (requiresValue && !hasValue) throw new Error(`${predicateLabel}.value is required for ${op}.`);
10756
+ const value2 = hasOwn(predicateInput, "value") ? predicateInput.value : predicateInput.expected;
10757
+ if (["gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"].includes(op)) {
10758
+ if (typeof value2 !== "number" || !Number.isFinite(value2)) {
10759
+ throw new Error(`${predicateLabel}.value must be a finite number for ${op}.`);
10760
+ }
10761
+ if (op.startsWith("abs_") && value2 < 0) {
10762
+ throw new Error(`${predicateLabel}.value must be non-negative for ${op}.`);
10763
+ }
10764
+ }
10765
+ return {
10766
+ path: path7,
10767
+ op,
10768
+ value: requiresValue ? toJsonValue(value2) : void 0
10769
+ };
10770
+ });
10771
+ return { label: name, predicates };
10772
+ });
10773
+ }
10528
10774
  function normalizeCheck(input, index) {
10529
10775
  if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
10530
10776
  const type = stringValue3(input.type);
@@ -10575,6 +10821,17 @@ function normalizeCheck(input, index) {
10575
10821
  if (!stringValue3(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
10576
10822
  if (!expectedTexts?.length) throw new Error(`checks[${index}] selector_text_order requires expected_texts.`);
10577
10823
  }
10824
+ const setupActionLabel = stringFromOwn(input, "setup_action_label", "setupActionLabel", "source_action_label", "sourceActionLabel");
10825
+ const tracePath = stringFromOwn(input, "trace_path", "tracePath", "path");
10826
+ const orderedTraceEvents = normalizeOrderedTraceEvents(
10827
+ input.events ?? input.sequence ?? input.ordered_events ?? input.orderedEvents,
10828
+ `checks[${index}].events`
10829
+ );
10830
+ if (type === "ordered_trace") {
10831
+ if (!setupActionLabel) throw new Error(`checks[${index}] ordered_trace requires setup_action_label.`);
10832
+ if (!tracePath) throw new Error(`checks[${index}] ordered_trace requires trace_path.`);
10833
+ if (!orderedTraceEvents?.length) throw new Error(`checks[${index}] ordered_trace requires events.`);
10834
+ }
10578
10835
  const expectedRoutes = normalizeRouteInventoryRoutes(input.expected_routes ?? input.expectedRoutes, index);
10579
10836
  if (type === "route_inventory" && !expectedRoutes?.length) {
10580
10837
  throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
@@ -10647,6 +10904,9 @@ function normalizeCheck(input, index) {
10647
10904
  body_not_patterns: bodyNotPatterns,
10648
10905
  body_json_assertions: bodyJsonAssertions,
10649
10906
  expected_texts: expectedTexts,
10907
+ setup_action_label: type === "ordered_trace" ? setupActionLabel : void 0,
10908
+ trace_path: type === "ordered_trace" ? tracePath : void 0,
10909
+ events: type === "ordered_trace" ? orderedTraceEvents : void 0,
10650
10910
  link_selector: stringValue3(input.link_selector) || stringValue3(input.linkSelector),
10651
10911
  source_selector: stringValue3(input.source_selector) || stringValue3(input.sourceSelector),
10652
10912
  route_path_prefix: stringValue3(input.route_path_prefix) || stringValue3(input.routePathPrefix),
@@ -10713,6 +10973,20 @@ function normalizeRiddleProofProfile(input, options = {}) {
10713
10973
  const targetUrl = stringValue3(options.url) || stringValue3(targetInput.url);
10714
10974
  const route = stringValue3(options.route) || stringValue3(targetInput.route);
10715
10975
  if (!targetUrl && !route) throw new Error("profile.target requires url or route, or pass --url.");
10976
+ const setupActions = normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions);
10977
+ for (const [index, check] of checks.entries()) {
10978
+ if (check.type !== "ordered_trace") continue;
10979
+ const matches = (setupActions || []).filter((action) => action.label === check.setup_action_label);
10980
+ if (matches.length !== 1) {
10981
+ throw new Error(`checks[${index}] ordered_trace setup_action_label must match exactly one target.setup_actions label.`);
10982
+ }
10983
+ if (!["window_eval", "window_call", "window_call_until"].includes(matches[0].type)) {
10984
+ throw new Error(`checks[${index}] ordered_trace source action must capture a window_eval, window_call, or window_call_until return.`);
10985
+ }
10986
+ if (matches[0].capture_return === false) {
10987
+ throw new Error(`checks[${index}] ordered_trace source action must not set capture_return to false.`);
10988
+ }
10989
+ }
10716
10990
  return {
10717
10991
  version: RIDDLE_PROOF_PROFILE_VERSION,
10718
10992
  name: normalizeName(input.name, "riddle-proof-profile"),
@@ -10725,7 +10999,7 @@ function normalizeRiddleProofProfile(input, options = {}) {
10725
10999
  wait_for_selector: stringValue3(targetInput.wait_for_selector) || stringValue3(targetInput.waitForSelector),
10726
11000
  wait_ms: numberValue2(targetInput.wait_ms) ?? numberValue2(targetInput.waitMs),
10727
11001
  screenshot_full_page: normalizeTargetScreenshotFullPage(targetInput),
10728
- setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions),
11002
+ setup_actions: setupActions,
10729
11003
  network_mocks: normalizeNetworkMocks(targetInput.network_mocks ?? targetInput.networkMocks)
10730
11004
  },
10731
11005
  checks,
@@ -11738,6 +12012,32 @@ function assessCheckFromEvidence(check, evidence) {
11738
12012
  message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
11739
12013
  };
11740
12014
  }
12015
+ if (check.type === "ordered_trace") {
12016
+ const assessments = viewports.map((viewport) => ({
12017
+ viewport: viewport.name,
12018
+ assessment: assessRiddleProofOrderedTraceSetupResults(
12019
+ viewport.setup_action_results,
12020
+ check.setup_action_label || "",
12021
+ check.trace_path || "",
12022
+ check.events || []
12023
+ )
12024
+ }));
12025
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
12026
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
12027
+ const status = insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed";
12028
+ return {
12029
+ type: check.type,
12030
+ label: checkLabel(check),
12031
+ status,
12032
+ evidence: {
12033
+ setup_action_label: check.setup_action_label || "",
12034
+ trace_path: check.trace_path || "",
12035
+ events: toJsonValue((check.events || []).map((event) => event.label)),
12036
+ viewports: toJsonValue(assessments)
12037
+ },
12038
+ 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
12039
+ };
12040
+ }
11741
12041
  if (check.type === "observe_within") {
11742
12042
  const key = observeWithinKey(check);
11743
12043
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -12237,6 +12537,7 @@ function profileStatusFromEvidence(profile, evidence, checks) {
12237
12537
  if (!viewports.length || !checks.length) return "proof_insufficient";
12238
12538
  if (viewports.some((viewport) => viewport.navigation_error)) return "environment_blocked";
12239
12539
  if (expectedViewportCount && viewports.length < expectedViewportCount) return "proof_insufficient";
12540
+ if (checks.some((check) => check.status === "proof_insufficient")) return "proof_insufficient";
12240
12541
  if (checks.some((check) => check.status === "needs_human_review")) return "needs_human_review";
12241
12542
  if (checks.some((check) => check.status === "failed")) return "product_regression";
12242
12543
  return "passed";
@@ -12566,8 +12867,12 @@ function createRiddleProofProfileInsufficientResult(input) {
12566
12867
  error: message
12567
12868
  };
12568
12869
  }
12569
- function runtimeScriptAssessmentSource() {
12870
+ function runtimeScriptAssessmentSource(includeOrderedTrace = false) {
12871
+ const orderedTraceSource = includeOrderedTrace ? String.raw`
12872
+ const assessRiddleProofOrderedTrace = ${assessRiddleProofOrderedTrace.toString()};
12873
+ const assessRiddleProofOrderedTraceSetupResults = ${assessRiddleProofOrderedTraceSetupResults.toString()};` : "";
12570
12874
  return String.raw`
12875
+ ${orderedTraceSource}
12571
12876
  function normalizeRoutePath(path) {
12572
12877
  const value = path || "/";
12573
12878
  if (value === "/") return "/";
@@ -13397,6 +13702,7 @@ function profileSetupWindowCallReceipts(results) {
13397
13702
  .map((result) => {
13398
13703
  const receipt = {
13399
13704
  ordinal: result.ordinal ?? null,
13705
+ label: result.label ?? null,
13400
13706
  ok: result.ok !== false,
13401
13707
  path: result.path ?? null,
13402
13708
  return_captured: result.return_captured ?? null,
@@ -13417,6 +13723,7 @@ function profileSetupWindowEvalReceipts(results) {
13417
13723
  .map((result) => {
13418
13724
  const receipt = {
13419
13725
  ordinal: result.ordinal ?? null,
13726
+ label: result.label ?? null,
13420
13727
  ok: result.ok !== false,
13421
13728
  script_length: result.script_length ?? null,
13422
13729
  return_captured: result.return_captured ?? null,
@@ -14232,6 +14539,36 @@ function assessProfile(profile, evidence) {
14232
14539
  });
14233
14540
  continue;
14234
14541
  }
14542
+ if (check.type === "ordered_trace") {
14543
+ const assessments = checkViewports.map((viewport) => ({
14544
+ viewport: viewport.name,
14545
+ assessment: assessRiddleProofOrderedTraceSetupResults(
14546
+ viewport.setup_action_results,
14547
+ check.setup_action_label || "",
14548
+ check.trace_path || "",
14549
+ check.events || [],
14550
+ ),
14551
+ }));
14552
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
14553
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
14554
+ checks.push({
14555
+ type: check.type,
14556
+ label: check.label || check.type,
14557
+ status: insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed",
14558
+ evidence: {
14559
+ setup_action_label: check.setup_action_label || "",
14560
+ trace_path: check.trace_path || "",
14561
+ events: (check.events || []).map((event) => event.label),
14562
+ viewports: assessments,
14563
+ },
14564
+ message: insufficient.length
14565
+ ? "Ordered trace evidence was insufficient in " + insufficient.length + " viewport(s)."
14566
+ : failed.length
14567
+ ? "Ordered trace did not contain the required event sequence in " + failed.length + " viewport(s)."
14568
+ : undefined,
14569
+ });
14570
+ continue;
14571
+ }
14235
14572
  if (check.type === "observe_within") {
14236
14573
  const key = observeWithinKey(check);
14237
14574
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -14588,6 +14925,7 @@ function assessProfile(profile, evidence) {
14588
14925
  if (!viewports.length || !checks.length) status = "proof_insufficient";
14589
14926
  else if (viewports.some((viewport) => viewport.navigation_error)) status = "environment_blocked";
14590
14927
  else if (expectedViewportCount && viewports.length < expectedViewportCount) status = "proof_insufficient";
14928
+ else if (checks.some((check) => check.status === "proof_insufficient")) status = "proof_insufficient";
14591
14929
  else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
14592
14930
  else if (checks.some((check) => check.status === "failed")) status = "product_regression";
14593
14931
  const screenshotLabels = profileScreenshotLabels(viewports);
@@ -15519,7 +15857,7 @@ let activeViewportName = null;
15519
15857
  async function executeSetupAction(action, ordinal, viewport) {
15520
15858
  const type = setupActionType(action);
15521
15859
  const frameSelector = setupFrameSelector(action);
15522
- const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
15860
+ const base = { ok: false, action: type || "unknown", ordinal, label: action.label || null, selector: action.selector || null, frame_selector: frameSelector || null, optional: action.optional === true };
15523
15861
  const timeout = setupNumber(action.timeout_ms, 5000);
15524
15862
  try {
15525
15863
  if (type === "wait") {
@@ -18171,7 +18509,7 @@ async function captureViewport(viewport) {
18171
18509
  wait_error: waitError,
18172
18510
  };
18173
18511
  }
18174
- ${runtimeScriptAssessmentSource()}
18512
+ ${runtimeScriptAssessmentSource(profile.checks.some((check) => check.type === "ordered_trace"))}
18175
18513
  const viewports = [];
18176
18514
  function buildProfileEvidence(currentViewports) {
18177
18515
  const expectedViewportCount = (profile.target.viewports || []).length;
package/dist/cli.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-NEXWITV4.js";
2
+ import "./chunk-QYZ3GKCP.js";
3
3
  import "./chunk-5IFZSUPF.js";
4
4
  import "./chunk-JFQXAJH2.js";
5
- import "./chunk-7N6X54WG.js";
6
- import "./chunk-RQPCKRKT.js";
7
- import "./chunk-6VFS2JFR.js";
5
+ import "./chunk-7OAETQU3.js";
6
+ import "./chunk-FW7CKARF.js";
7
+ import "./chunk-LR4UYJDY.js";
8
8
  import "./chunk-MEVVL4TI.js";
9
- import "./chunk-FCSJZBC5.js";
9
+ import "./chunk-2K3DIK7A.js";
10
10
  import "./chunk-KXLEN4SA.js";
11
11
  import "./chunk-WLUMLHII.js";
12
12
  import "./chunk-CGJX7LJO.js";