@riddledc/riddle-proof 0.8.78 → 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/cli/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import "../chunk-HSGZV2NK.js";
1
+ import "../chunk-N7EETHYG.js";
2
2
  import "../chunk-5IFZSUPF.js";
3
3
  import "../chunk-JFQXAJH2.js";
4
- import "../chunk-7N6X54WG.js";
5
- import "../chunk-RQPCKRKT.js";
6
- import "../chunk-6VFS2JFR.js";
4
+ import "../chunk-6T6ZAK77.js";
5
+ import "../chunk-A4EF4M3B.js";
6
+ import "../chunk-IL7MLYB5.js";
7
7
  import "../chunk-MEVVL4TI.js";
8
- import "../chunk-FCSJZBC5.js";
8
+ import "../chunk-ZNVYJFR7.js";
9
9
  import "../chunk-KXLEN4SA.js";
10
10
  import "../chunk-WLUMLHII.js";
11
11
  import "../chunk-CGJX7LJO.js";
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,
@@ -10525,6 +10722,51 @@ function dialogCountFieldForCheckType(type) {
10525
10722
  if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
10526
10723
  return "dialog_count";
10527
10724
  }
10725
+ function normalizeOrderedTraceEvents(value, label) {
10726
+ if (value === void 0) return void 0;
10727
+ if (!Array.isArray(value) || !value.length) throw new Error(`${label} must be a non-empty array.`);
10728
+ const seenLabels = /* @__PURE__ */ new Set();
10729
+ return value.map((item, eventIndex) => {
10730
+ const eventLabel = `${label}[${eventIndex}]`;
10731
+ if (!isRecord2(item)) throw new Error(`${eventLabel} must be an object.`);
10732
+ const name = stringFromOwn(item, "label", "name", "event");
10733
+ if (!name) throw new Error(`${eventLabel}.label is required.`);
10734
+ if (seenLabels.has(name)) throw new Error(`${eventLabel}.label must be unique.`);
10735
+ seenLabels.add(name);
10736
+ const predicatesInput = item.predicates ?? item.all ?? item.where;
10737
+ if (!Array.isArray(predicatesInput) || !predicatesInput.length) {
10738
+ throw new Error(`${eventLabel}.predicates must be a non-empty array.`);
10739
+ }
10740
+ const predicates = predicatesInput.map((predicateInput, predicateIndex) => {
10741
+ const predicateLabel = `${eventLabel}.predicates[${predicateIndex}]`;
10742
+ if (!isRecord2(predicateInput)) throw new Error(`${predicateLabel} must be an object.`);
10743
+ const path7 = stringFromOwn(predicateInput, "path", "field", "key");
10744
+ if (!path7) throw new Error(`${predicateLabel}.path is required.`);
10745
+ const op = stringFromOwn(predicateInput, "op", "operator");
10746
+ if (!op || !RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.includes(op)) {
10747
+ throw new Error(`${predicateLabel}.op must be one of ${RIDDLE_PROOF_ORDERED_TRACE_OPERATORS.join(", ")}.`);
10748
+ }
10749
+ const requiresValue = !["exists", "truthy", "falsy"].includes(op);
10750
+ const hasValue = hasOwn(predicateInput, "value") || hasOwn(predicateInput, "expected");
10751
+ if (requiresValue && !hasValue) throw new Error(`${predicateLabel}.value is required for ${op}.`);
10752
+ const value2 = hasOwn(predicateInput, "value") ? predicateInput.value : predicateInput.expected;
10753
+ if (["gt", "gte", "lt", "lte", "abs_gt", "abs_gte", "abs_lt", "abs_lte"].includes(op)) {
10754
+ if (typeof value2 !== "number" || !Number.isFinite(value2)) {
10755
+ throw new Error(`${predicateLabel}.value must be a finite number for ${op}.`);
10756
+ }
10757
+ if (op.startsWith("abs_") && value2 < 0) {
10758
+ throw new Error(`${predicateLabel}.value must be non-negative for ${op}.`);
10759
+ }
10760
+ }
10761
+ return {
10762
+ path: path7,
10763
+ op,
10764
+ value: requiresValue ? toJsonValue(value2) : void 0
10765
+ };
10766
+ });
10767
+ return { label: name, predicates };
10768
+ });
10769
+ }
10528
10770
  function normalizeCheck(input, index) {
10529
10771
  if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
10530
10772
  const type = stringValue3(input.type);
@@ -10575,6 +10817,17 @@ function normalizeCheck(input, index) {
10575
10817
  if (!stringValue3(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
10576
10818
  if (!expectedTexts?.length) throw new Error(`checks[${index}] selector_text_order requires expected_texts.`);
10577
10819
  }
10820
+ const setupActionLabel = stringFromOwn(input, "setup_action_label", "setupActionLabel", "source_action_label", "sourceActionLabel");
10821
+ const tracePath = stringFromOwn(input, "trace_path", "tracePath", "path");
10822
+ const orderedTraceEvents = normalizeOrderedTraceEvents(
10823
+ input.events ?? input.sequence ?? input.ordered_events ?? input.orderedEvents,
10824
+ `checks[${index}].events`
10825
+ );
10826
+ if (type === "ordered_trace") {
10827
+ if (!setupActionLabel) throw new Error(`checks[${index}] ordered_trace requires setup_action_label.`);
10828
+ if (!tracePath) throw new Error(`checks[${index}] ordered_trace requires trace_path.`);
10829
+ if (!orderedTraceEvents?.length) throw new Error(`checks[${index}] ordered_trace requires events.`);
10830
+ }
10578
10831
  const expectedRoutes = normalizeRouteInventoryRoutes(input.expected_routes ?? input.expectedRoutes, index);
10579
10832
  if (type === "route_inventory" && !expectedRoutes?.length) {
10580
10833
  throw new Error(`checks[${index}] route_inventory requires expected_routes.`);
@@ -10647,6 +10900,9 @@ function normalizeCheck(input, index) {
10647
10900
  body_not_patterns: bodyNotPatterns,
10648
10901
  body_json_assertions: bodyJsonAssertions,
10649
10902
  expected_texts: expectedTexts,
10903
+ setup_action_label: type === "ordered_trace" ? setupActionLabel : void 0,
10904
+ trace_path: type === "ordered_trace" ? tracePath : void 0,
10905
+ events: type === "ordered_trace" ? orderedTraceEvents : void 0,
10650
10906
  link_selector: stringValue3(input.link_selector) || stringValue3(input.linkSelector),
10651
10907
  source_selector: stringValue3(input.source_selector) || stringValue3(input.sourceSelector),
10652
10908
  route_path_prefix: stringValue3(input.route_path_prefix) || stringValue3(input.routePathPrefix),
@@ -10713,6 +10969,20 @@ function normalizeRiddleProofProfile(input, options = {}) {
10713
10969
  const targetUrl = stringValue3(options.url) || stringValue3(targetInput.url);
10714
10970
  const route = stringValue3(options.route) || stringValue3(targetInput.route);
10715
10971
  if (!targetUrl && !route) throw new Error("profile.target requires url or route, or pass --url.");
10972
+ const setupActions = normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions);
10973
+ for (const [index, check] of checks.entries()) {
10974
+ if (check.type !== "ordered_trace") continue;
10975
+ const matches = (setupActions || []).filter((action) => action.label === check.setup_action_label);
10976
+ if (matches.length !== 1) {
10977
+ throw new Error(`checks[${index}] ordered_trace setup_action_label must match exactly one target.setup_actions label.`);
10978
+ }
10979
+ if (!["window_eval", "window_call", "window_call_until"].includes(matches[0].type)) {
10980
+ throw new Error(`checks[${index}] ordered_trace source action must capture a window_eval, window_call, or window_call_until return.`);
10981
+ }
10982
+ if (matches[0].capture_return === false) {
10983
+ throw new Error(`checks[${index}] ordered_trace source action must not set capture_return to false.`);
10984
+ }
10985
+ }
10716
10986
  return {
10717
10987
  version: RIDDLE_PROOF_PROFILE_VERSION,
10718
10988
  name: normalizeName(input.name, "riddle-proof-profile"),
@@ -10725,7 +10995,7 @@ function normalizeRiddleProofProfile(input, options = {}) {
10725
10995
  wait_for_selector: stringValue3(targetInput.wait_for_selector) || stringValue3(targetInput.waitForSelector),
10726
10996
  wait_ms: numberValue2(targetInput.wait_ms) ?? numberValue2(targetInput.waitMs),
10727
10997
  screenshot_full_page: normalizeTargetScreenshotFullPage(targetInput),
10728
- setup_actions: normalizeSetupActions(targetInput.setup_actions ?? targetInput.setupActions),
10998
+ setup_actions: setupActions,
10729
10999
  network_mocks: normalizeNetworkMocks(targetInput.network_mocks ?? targetInput.networkMocks)
10730
11000
  },
10731
11001
  checks,
@@ -11738,6 +12008,32 @@ function assessCheckFromEvidence(check, evidence) {
11738
12008
  message: failed ? `Selector ${key} text order failed in ${failed} viewport(s).` : void 0
11739
12009
  };
11740
12010
  }
12011
+ if (check.type === "ordered_trace") {
12012
+ const assessments = viewports.map((viewport) => ({
12013
+ viewport: viewport.name,
12014
+ assessment: assessRiddleProofOrderedTraceSetupResults(
12015
+ viewport.setup_action_results,
12016
+ check.setup_action_label || "",
12017
+ check.trace_path || "",
12018
+ check.events || []
12019
+ )
12020
+ }));
12021
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
12022
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
12023
+ const status = insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed";
12024
+ return {
12025
+ type: check.type,
12026
+ label: checkLabel(check),
12027
+ status,
12028
+ evidence: {
12029
+ setup_action_label: check.setup_action_label || "",
12030
+ trace_path: check.trace_path || "",
12031
+ events: toJsonValue((check.events || []).map((event) => event.label)),
12032
+ viewports: toJsonValue(assessments)
12033
+ },
12034
+ 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
12035
+ };
12036
+ }
11741
12037
  if (check.type === "observe_within") {
11742
12038
  const key = observeWithinKey(check);
11743
12039
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -12237,6 +12533,7 @@ function profileStatusFromEvidence(profile, evidence, checks) {
12237
12533
  if (!viewports.length || !checks.length) return "proof_insufficient";
12238
12534
  if (viewports.some((viewport) => viewport.navigation_error)) return "environment_blocked";
12239
12535
  if (expectedViewportCount && viewports.length < expectedViewportCount) return "proof_insufficient";
12536
+ if (checks.some((check) => check.status === "proof_insufficient")) return "proof_insufficient";
12240
12537
  if (checks.some((check) => check.status === "needs_human_review")) return "needs_human_review";
12241
12538
  if (checks.some((check) => check.status === "failed")) return "product_regression";
12242
12539
  return "passed";
@@ -12566,8 +12863,12 @@ function createRiddleProofProfileInsufficientResult(input) {
12566
12863
  error: message
12567
12864
  };
12568
12865
  }
12569
- function runtimeScriptAssessmentSource() {
12866
+ function runtimeScriptAssessmentSource(includeOrderedTrace = false) {
12867
+ const orderedTraceSource = includeOrderedTrace ? String.raw`
12868
+ const assessRiddleProofOrderedTrace = ${assessRiddleProofOrderedTrace.toString()};
12869
+ const assessRiddleProofOrderedTraceSetupResults = ${assessRiddleProofOrderedTraceSetupResults.toString()};` : "";
12570
12870
  return String.raw`
12871
+ ${orderedTraceSource}
12571
12872
  function normalizeRoutePath(path) {
12572
12873
  const value = path || "/";
12573
12874
  if (value === "/") return "/";
@@ -13397,6 +13698,7 @@ function profileSetupWindowCallReceipts(results) {
13397
13698
  .map((result) => {
13398
13699
  const receipt = {
13399
13700
  ordinal: result.ordinal ?? null,
13701
+ label: result.label ?? null,
13400
13702
  ok: result.ok !== false,
13401
13703
  path: result.path ?? null,
13402
13704
  return_captured: result.return_captured ?? null,
@@ -13417,6 +13719,7 @@ function profileSetupWindowEvalReceipts(results) {
13417
13719
  .map((result) => {
13418
13720
  const receipt = {
13419
13721
  ordinal: result.ordinal ?? null,
13722
+ label: result.label ?? null,
13420
13723
  ok: result.ok !== false,
13421
13724
  script_length: result.script_length ?? null,
13422
13725
  return_captured: result.return_captured ?? null,
@@ -14232,6 +14535,36 @@ function assessProfile(profile, evidence) {
14232
14535
  });
14233
14536
  continue;
14234
14537
  }
14538
+ if (check.type === "ordered_trace") {
14539
+ const assessments = checkViewports.map((viewport) => ({
14540
+ viewport: viewport.name,
14541
+ assessment: assessRiddleProofOrderedTraceSetupResults(
14542
+ viewport.setup_action_results,
14543
+ check.setup_action_label || "",
14544
+ check.trace_path || "",
14545
+ check.events || [],
14546
+ ),
14547
+ }));
14548
+ const insufficient = assessments.filter((item) => item.assessment.status === "proof_insufficient");
14549
+ const failed = assessments.filter((item) => item.assessment.status === "failed");
14550
+ checks.push({
14551
+ type: check.type,
14552
+ label: check.label || check.type,
14553
+ status: insufficient.length ? "proof_insufficient" : failed.length ? "failed" : "passed",
14554
+ evidence: {
14555
+ setup_action_label: check.setup_action_label || "",
14556
+ trace_path: check.trace_path || "",
14557
+ events: (check.events || []).map((event) => event.label),
14558
+ viewports: assessments,
14559
+ },
14560
+ message: insufficient.length
14561
+ ? "Ordered trace evidence was insufficient in " + insufficient.length + " viewport(s)."
14562
+ : failed.length
14563
+ ? "Ordered trace did not contain the required event sequence in " + failed.length + " viewport(s)."
14564
+ : undefined,
14565
+ });
14566
+ continue;
14567
+ }
14235
14568
  if (check.type === "observe_within") {
14236
14569
  const key = observeWithinKey(check);
14237
14570
  const timeoutMs = observeWithinTimeoutMs(check);
@@ -14588,6 +14921,7 @@ function assessProfile(profile, evidence) {
14588
14921
  if (!viewports.length || !checks.length) status = "proof_insufficient";
14589
14922
  else if (viewports.some((viewport) => viewport.navigation_error)) status = "environment_blocked";
14590
14923
  else if (expectedViewportCount && viewports.length < expectedViewportCount) status = "proof_insufficient";
14924
+ else if (checks.some((check) => check.status === "proof_insufficient")) status = "proof_insufficient";
14591
14925
  else if (checks.some((check) => check.status === "needs_human_review")) status = "needs_human_review";
14592
14926
  else if (checks.some((check) => check.status === "failed")) status = "product_regression";
14593
14927
  const screenshotLabels = profileScreenshotLabels(viewports);
@@ -15519,7 +15853,7 @@ let activeViewportName = null;
15519
15853
  async function executeSetupAction(action, ordinal, viewport) {
15520
15854
  const type = setupActionType(action);
15521
15855
  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 };
15856
+ 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
15857
  const timeout = setupNumber(action.timeout_ms, 5000);
15524
15858
  try {
15525
15859
  if (type === "wait") {
@@ -18171,7 +18505,7 @@ async function captureViewport(viewport) {
18171
18505
  wait_error: waitError,
18172
18506
  };
18173
18507
  }
18174
- ${runtimeScriptAssessmentSource()}
18508
+ ${runtimeScriptAssessmentSource(profile.checks.some((check) => check.type === "ordered_trace"))}
18175
18509
  const viewports = [];
18176
18510
  function buildProfileEvidence(currentViewports) {
18177
18511
  const expectedViewportCount = (profile.target.viewports || []).length;
@@ -23812,7 +24146,22 @@ function profileHttpStatusSummaryMarkdown(result) {
23812
24146
  }
23813
24147
  function profileResultTargetUrl(result) {
23814
24148
  const legacyRoute = result.route;
23815
- return result.route.observed || result.route.requested || legacyRoute.url || result.evidence?.target_url || "unknown";
24149
+ const observed = result.route.observed;
24150
+ const requested = result.route.requested || legacyRoute.url || result.evidence?.target_url;
24151
+ if (observed) {
24152
+ try {
24153
+ return new URL(observed, requested).href;
24154
+ } catch {
24155
+ }
24156
+ }
24157
+ if (requested) {
24158
+ try {
24159
+ return new URL(requested).href;
24160
+ } catch {
24161
+ return requested;
24162
+ }
24163
+ }
24164
+ return observed || "unknown";
23816
24165
  }
23817
24166
  function profileObservationForOutput(result, outputDir, options) {
23818
24167
  if (options.observation) return options.observation;
package/dist/cli.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-HSGZV2NK.js";
2
+ import "./chunk-N7EETHYG.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-6T6ZAK77.js";
6
+ import "./chunk-A4EF4M3B.js";
7
+ import "./chunk-IL7MLYB5.js";
8
8
  import "./chunk-MEVVL4TI.js";
9
- import "./chunk-FCSJZBC5.js";
9
+ import "./chunk-ZNVYJFR7.js";
10
10
  import "./chunk-KXLEN4SA.js";
11
11
  import "./chunk-WLUMLHII.js";
12
12
  import "./chunk-CGJX7LJO.js";