@riddledc/riddle-proof 0.7.139 → 0.7.141

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/README.md CHANGED
@@ -401,7 +401,7 @@ transport control, or other bounded interaction. Supported setup actions are
401
401
  `assert_text_absent`, `assert_selector_count`, `assert_window_value`,
402
402
  `assert_window_number`, `local_storage`, `session_storage`, `clear_storage`,
403
403
  `clear_console`, `screenshot`, `wait`, `wait_for_selector`, `wait_for_text`,
404
- `window_call`, and `window_call_until`;
404
+ `window_eval`, `window_call`, and `window_call_until`;
405
405
  a failed setup action is recorded as a failed `setup_actions_succeeded` check so
406
406
  the profile cannot pass without reaching the intended state. Text-matched `click` actions prefer
407
407
  visible matching elements, which keeps responsive layouts from selecting hidden
@@ -447,6 +447,12 @@ errors, but keeps network mock hit evidence intact. Any setup action can include
447
447
  with `repeat_index` and `repeat_count`, and `after_ms` runs after each
448
448
  repetition. Use it for bounded game proof helpers, retry controls, or other
449
449
  workflows where one declarative action needs to advance the app several times.
450
+ Use `window_eval` for async browser-side helper code that is easier to express
451
+ as a short script body than as a preexisting `window` function. It accepts
452
+ `script` plus optional JSON `args`, can compare `expect_return`, can store the
453
+ JSON-safe return value with `store_return_to`, and honors `capture_return:
454
+ false` for compact receipts. The script runs as an async function body with
455
+ `args` available in scope, so `return { ok: true }` records a structured return.
450
456
  Use `window_call_until` when a proof helper needs to advance randomized or
451
457
  progressive state until a window-state receipt is true. It accepts `path` plus
452
458
  optional `args`, `until_path`, `until_expected_value`, `max_calls` from 1 to
@@ -486,7 +492,9 @@ Profile final viewport screenshots are full-page by default. Set
486
492
  `target.screenshot_full_page: false`, `target.screenshotFullPage: false`, or
487
493
  `target.screenshot_mode: "viewport"` when the automatic final screenshots
488
494
  should capture only the current viewport, for example when fixed or sticky
489
- headers make full-page captures misleading.
495
+ headers make full-page captures misleading. Compact profile summaries include
496
+ the final screenshot count and mode when a profile sets an explicit target
497
+ screenshot mode.
490
498
 
491
499
  Use `allowed_console_patterns` / `allowed_console_texts` on
492
500
  `no_fatal_console_errors` when a negative-path profile intentionally triggers a
@@ -61,6 +61,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
61
61
  "wait",
62
62
  "wait_for_selector",
63
63
  "wait_for_text",
64
+ "window_eval",
64
65
  "window_call",
65
66
  "window_call_until"
66
67
  ];
@@ -480,6 +481,21 @@ function profileSetupWindowCallReceipts(results) {
480
481
  return receipt;
481
482
  });
482
483
  }
484
+ function profileSetupWindowEvalReceipts(results) {
485
+ return results.filter((result) => profileSetupResultAction(result) === "window_eval").map((result) => {
486
+ const receipt = {
487
+ ordinal: result.ordinal ?? null,
488
+ ok: result.ok !== false,
489
+ script_length: result.script_length ?? null,
490
+ return_captured: result.return_captured ?? null,
491
+ return_stored_to: result.return_stored_to ?? null,
492
+ reason: result.reason ?? result.error ?? result.store_reason ?? null
493
+ };
494
+ if (result.returned !== void 0) receipt.returned = result.returned;
495
+ if (result.expected_return !== void 0) receipt.expected_return = result.expected_return;
496
+ return receipt;
497
+ });
498
+ }
483
499
  function sampleProfileSetupSummaryItems(items, limit) {
484
500
  if (items.length <= limit) return items;
485
501
  const firstCount = Math.floor(limit / 2);
@@ -494,12 +510,18 @@ function profileScreenshotLabels(viewports) {
494
510
  }
495
511
  return labels;
496
512
  }
497
- function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport) {
513
+ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport, finalScreenshotFullPage) {
514
+ const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === void 0 ? void 0 : finalScreenshotFullPage !== false;
515
+ const finalScreenshotCount = viewports.filter((viewport) => typeof viewport.screenshot_label === "string" && viewport.screenshot_label.trim()).length;
498
516
  return toJsonValue({
499
517
  viewport_count: viewports.length,
500
518
  action_count: actionCount ?? null,
519
+ final_screenshot_count: finalScreenshotCount,
520
+ final_screenshot_full_page: normalizedFinalScreenshotFullPage ?? null,
521
+ final_screenshot_mode: normalizedFinalScreenshotFullPage === void 0 ? null : normalizedFinalScreenshotFullPage ? "full_page" : "viewport",
501
522
  viewports: viewports.map((viewport) => {
502
523
  const expectedActionCount = expectedActionCountByViewport?.get(viewport.name) ?? actionCount;
524
+ const viewportFinalScreenshotFullPage = typeof viewport.screenshot_full_page === "boolean" ? viewport.screenshot_full_page : normalizedFinalScreenshotFullPage;
503
525
  const results = viewport.setup_action_results || [];
504
526
  const failed = results.filter((result) => result.ok === false && result.optional !== true);
505
527
  const optionalFailed = results.filter((result) => result.ok === false && result.optional === true);
@@ -512,6 +534,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
512
534
  const windowCallStoredTotal = windowCallReceipts.filter((result) => typeof result.return_stored_to === "string" && result.return_stored_to.trim()).length;
513
535
  const windowCallCapturedTotal = windowCallReceipts.filter((result) => result.return_captured === true).length;
514
536
  const sampledWindowCallReceipts = sampleProfileSetupSummaryItems(windowCallReceipts, 8);
537
+ const windowEvalReceipts = profileSetupWindowEvalReceipts(results);
538
+ const windowEvalStoredTotal = windowEvalReceipts.filter((result) => typeof result.return_stored_to === "string" && result.return_stored_to.trim()).length;
539
+ const windowEvalCapturedTotal = windowEvalReceipts.filter((result) => result.return_captured === true).length;
540
+ const sampledWindowEvalReceipts = sampleProfileSetupSummaryItems(windowEvalReceipts, 8);
515
541
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
516
542
  const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
517
543
  return {
@@ -539,6 +565,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
539
565
  action_counts: profileSetupActionCounts(results),
540
566
  frame_action_count: results.filter((result) => result.frame_selector).length,
541
567
  frame_urls: profileSetupFrameUrls(viewport),
568
+ final_screenshot: viewport.screenshot_label ?? null,
569
+ final_screenshot_full_page: viewportFinalScreenshotFullPage ?? null,
542
570
  setup_screenshots: profileSetupScreenshotLabels(results),
543
571
  clicked_total: clickedItems.length,
544
572
  clicked_truncated: clickedItems.length > clicked.length,
@@ -553,6 +581,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
553
581
  window_call_captured_total: windowCallCapturedTotal,
554
582
  window_call_truncated: windowCallReceipts.length > sampledWindowCallReceipts.length,
555
583
  window_call: sampledWindowCallReceipts,
584
+ window_eval_total: windowEvalReceipts.length,
585
+ window_eval_stored_total: windowEvalStoredTotal,
586
+ window_eval_captured_total: windowEvalCapturedTotal,
587
+ window_eval_truncated: windowEvalReceipts.length > sampledWindowEvalReceipts.length,
588
+ window_eval: sampledWindowEvalReceipts,
556
589
  clicked,
557
590
  text_samples,
558
591
  failed: failed.map((result) => ({
@@ -605,7 +638,7 @@ function isSupportedCheckType(value) {
605
638
  }
606
639
  function normalizeSetupActionType(value, index) {
607
640
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
608
- const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput;
641
+ const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
609
642
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
610
643
  return normalized;
611
644
  }
@@ -623,7 +656,7 @@ function normalizeSetupActionArgs(input, index) {
623
656
  const argsInput = valueFromOwn(input, "args", "arguments", "args_json", "argsJson");
624
657
  if (argsInput === void 0) return void 0;
625
658
  if (!Array.isArray(argsInput)) {
626
- throw new Error(`target.setup_actions[${index}] window_call args must be an array.`);
659
+ throw new Error(`target.setup_actions[${index}] window_call/window_eval args must be an array.`);
627
660
  }
628
661
  return argsInput.map(toJsonValue);
629
662
  }
@@ -767,7 +800,11 @@ function normalizeSetupAction(input, index) {
767
800
  if ((type === "window_call" || type === "window_call_until" || type === "assert_window_value" || type === "assert_window_number") && !path) {
768
801
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
769
802
  }
770
- const args = type === "window_call" || type === "window_call_until" ? normalizeSetupActionArgs(input, index) : void 0;
803
+ const script = stringFromOwn(input, "script", "code", "source", "body");
804
+ if (type === "window_eval" && !script) {
805
+ throw new Error(`target.setup_actions[${index}] window_eval requires script.`);
806
+ }
807
+ const args = type === "window_call" || type === "window_call_until" || type === "window_eval" ? normalizeSetupActionArgs(input, index) : void 0;
771
808
  const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
772
809
  if (type === "assert_window_value" && !hasExpectedValue) {
773
810
  throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
@@ -838,6 +875,7 @@ function normalizeSetupAction(input, index) {
838
875
  value,
839
876
  value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
840
877
  label: stringFromOwn(input, "label", "name", "screenshot_label", "screenshotLabel"),
878
+ script,
841
879
  path,
842
880
  args,
843
881
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
@@ -2783,7 +2821,7 @@ function assessSetupActionsFromEvidence(profile, evidence) {
2783
2821
  ok: (viewport.setup_action_results || []).length >= (expectedActionCountByViewport.get(viewport.name) ?? actionCount) && (viewport.setup_action_results || []).every((result) => result.ok !== false || result.optional === true),
2784
2822
  result_count: (viewport.setup_action_results || []).length
2785
2823
  })),
2786
- setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport),
2824
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport, profile.target.screenshot_full_page),
2787
2825
  failed
2788
2826
  },
2789
2827
  message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
@@ -3789,6 +3827,23 @@ function profileSetupWindowCallReceipts(results) {
3789
3827
  return receipt;
3790
3828
  });
3791
3829
  }
3830
+ function profileSetupWindowEvalReceipts(results) {
3831
+ return (results || [])
3832
+ .filter((result) => result && profileSetupResultAction(result) === "window_eval")
3833
+ .map((result) => {
3834
+ const receipt = {
3835
+ ordinal: result.ordinal ?? null,
3836
+ ok: result.ok !== false,
3837
+ script_length: result.script_length ?? null,
3838
+ return_captured: result.return_captured ?? null,
3839
+ return_stored_to: result.return_stored_to ?? null,
3840
+ reason: result.reason || result.error || result.store_reason || null,
3841
+ };
3842
+ if (result.returned !== undefined) receipt.returned = result.returned;
3843
+ if (result.expected_return !== undefined) receipt.expected_return = result.expected_return;
3844
+ return receipt;
3845
+ });
3846
+ }
3792
3847
  function sampleProfileSetupSummaryItems(items, limit) {
3793
3848
  if ((items || []).length <= limit) return items || [];
3794
3849
  const firstCount = Math.floor(limit / 2);
@@ -3803,14 +3858,28 @@ function profileScreenshotLabels(viewports) {
3803
3858
  }
3804
3859
  return labels;
3805
3860
  }
3806
- function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport) {
3861
+ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport, finalScreenshotFullPage) {
3862
+ const normalizedFinalScreenshotFullPage = finalScreenshotFullPage === undefined
3863
+ ? undefined
3864
+ : finalScreenshotFullPage !== false;
3865
+ const finalScreenshotCount = (viewports || []).filter((viewport) => viewport && typeof viewport.screenshot_label === "string" && viewport.screenshot_label.trim()).length;
3807
3866
  return {
3808
3867
  viewport_count: (viewports || []).length,
3809
3868
  action_count: actionCount ?? null,
3869
+ final_screenshot_count: finalScreenshotCount,
3870
+ final_screenshot_full_page: normalizedFinalScreenshotFullPage ?? null,
3871
+ final_screenshot_mode: normalizedFinalScreenshotFullPage === undefined
3872
+ ? null
3873
+ : normalizedFinalScreenshotFullPage
3874
+ ? "full_page"
3875
+ : "viewport",
3810
3876
  viewports: (viewports || []).map((viewport) => {
3811
3877
  const expectedActionCount = expectedActionCountsByViewport && expectedActionCountsByViewport[viewport.name] !== undefined
3812
3878
  ? expectedActionCountsByViewport[viewport.name]
3813
3879
  : actionCount;
3880
+ const viewportFinalScreenshotFullPage = typeof viewport.screenshot_full_page === "boolean"
3881
+ ? viewport.screenshot_full_page
3882
+ : normalizedFinalScreenshotFullPage;
3814
3883
  const results = viewport.setup_action_results || [];
3815
3884
  const failed = results.filter((result) => result && result.ok === false && result.optional !== true);
3816
3885
  const optionalFailed = results.filter((result) => result && result.ok === false && result.optional === true);
@@ -3827,6 +3896,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
3827
3896
  const windowCallStoredTotal = windowCallReceipts.filter((result) => typeof result.return_stored_to === "string" && result.return_stored_to.trim()).length;
3828
3897
  const windowCallCapturedTotal = windowCallReceipts.filter((result) => result.return_captured === true).length;
3829
3898
  const sampledWindowCallReceipts = sampleProfileSetupSummaryItems(windowCallReceipts, 8);
3899
+ const windowEvalReceipts = profileSetupWindowEvalReceipts(results);
3900
+ const windowEvalStoredTotal = windowEvalReceipts.filter((result) => typeof result.return_stored_to === "string" && result.return_stored_to.trim()).length;
3901
+ const windowEvalCapturedTotal = windowEvalReceipts.filter((result) => result.return_captured === true).length;
3902
+ const sampledWindowEvalReceipts = sampleProfileSetupSummaryItems(windowEvalReceipts, 8);
3830
3903
  const clickedItems = results
3831
3904
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
3832
3905
  .map((result) => {
@@ -3864,6 +3937,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
3864
3937
  action_counts: profileSetupActionCounts(results),
3865
3938
  frame_action_count: results.filter((result) => result && result.frame_selector).length,
3866
3939
  frame_urls: profileSetupFrameUrls(viewport),
3940
+ final_screenshot: viewport.screenshot_label || null,
3941
+ final_screenshot_full_page: viewportFinalScreenshotFullPage ?? null,
3867
3942
  setup_screenshots: profileSetupScreenshotLabels(results),
3868
3943
  clicked_total: clickedItems.length,
3869
3944
  clicked_truncated: clickedItems.length > clicked.length,
@@ -3878,6 +3953,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
3878
3953
  window_call_captured_total: windowCallCapturedTotal,
3879
3954
  window_call_truncated: windowCallReceipts.length > sampledWindowCallReceipts.length,
3880
3955
  window_call: sampledWindowCallReceipts,
3956
+ window_eval_total: windowEvalReceipts.length,
3957
+ window_eval_stored_total: windowEvalStoredTotal,
3958
+ window_eval_captured_total: windowEvalCapturedTotal,
3959
+ window_eval_truncated: windowEvalReceipts.length > sampledWindowEvalReceipts.length,
3960
+ window_eval: sampledWindowEvalReceipts,
3881
3961
  clicked,
3882
3962
  text_samples: textSamples,
3883
3963
  failed: failed.map((result) => ({
@@ -4048,7 +4128,7 @@ function assessProfile(profile, evidence) {
4048
4128
  && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false || result.optional === true),
4049
4129
  result_count: (viewport.setup_action_results || []).length,
4050
4130
  })),
4051
- setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport),
4131
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport, profile.target && profile.target.screenshot_full_page),
4052
4132
  failed,
4053
4133
  },
4054
4134
  message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
@@ -4858,6 +4938,49 @@ async function setupCallWindowFunction(context, path, args, storeReturnTo, captu
4858
4938
  }
4859
4939
  }, { path, args, storeReturnTo, captureReturn });
4860
4940
  }
4941
+ async function setupEvaluateWindowScript(context, script, args, storeReturnTo, captureReturn) {
4942
+ return await context.evaluate(async ({ script, args, storeReturnTo, captureReturn }) => {
4943
+ const toJsonValue = (value) => {
4944
+ if (value === null || value === undefined) return null;
4945
+ if (typeof value === "string" || typeof value === "boolean") return value;
4946
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
4947
+ if (Array.isArray(value)) return value.map(toJsonValue);
4948
+ if (typeof value === "object") {
4949
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
4950
+ }
4951
+ return String(value);
4952
+ };
4953
+ const storeWindowReturn = (storePath, value) => {
4954
+ const pathParts = String(storePath || "").split(".").map((part) => part.trim()).filter(Boolean);
4955
+ if (pathParts[0] === "window") pathParts.shift();
4956
+ if (!pathParts.length) return { ok: false, reason: "missing_store_path" };
4957
+ let target = window;
4958
+ for (let index = 0; index < pathParts.length - 1; index += 1) {
4959
+ const part = pathParts[index];
4960
+ if (target[part] === null || typeof target[part] !== "object") target[part] = {};
4961
+ target = target[part];
4962
+ }
4963
+ target[pathParts[pathParts.length - 1]] = value;
4964
+ return { ok: true, path: pathParts.join(".") };
4965
+ };
4966
+ const body = String(script || "");
4967
+ if (!body.trim()) return { ok: false, reason: "missing_script" };
4968
+ try {
4969
+ const run = new Function("args", "\"use strict\"; return (async () => {\\n" + body + "\\n})();");
4970
+ const returned = await run(Array.isArray(args) ? args : []);
4971
+ const jsonReturned = toJsonValue(returned);
4972
+ const returnedForResult = captureReturn === false ? undefined : jsonReturned;
4973
+ if (storeReturnTo) {
4974
+ const stored = storeWindowReturn(storeReturnTo, jsonReturned);
4975
+ if (!stored.ok) return { ok: false, reason: "return_store_failed", store_reason: stored.reason, returned: returnedForResult };
4976
+ return { ok: true, returned: returnedForResult, return_stored_to: stored.path };
4977
+ }
4978
+ return { ok: true, returned: returnedForResult };
4979
+ } catch (error) {
4980
+ return { ok: false, reason: "script_threw", error: String(error && error.message ? error.message : error).slice(0, 1000) };
4981
+ }
4982
+ }, { script, args, storeReturnTo, captureReturn });
4983
+ }
4861
4984
  function setupFrameSelector(action) {
4862
4985
  return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
4863
4986
  }
@@ -5371,6 +5494,44 @@ async function executeSetupAction(action, ordinal, viewport) {
5371
5494
  }
5372
5495
  return { ...base, ...setupScopeEvidence(scope), ok: true, storage, reload: action.reload === true };
5373
5496
  }
5497
+ if (type === "window_eval") {
5498
+ const script = String(action.script || action.code || action.source || action.body || "");
5499
+ const args = Array.isArray(action.args) ? action.args : [];
5500
+ const storeReturnTo = String(action.store_return_to || action.storeReturnTo || action.save_return_to || action.saveReturnTo || action.assign_return_to || action.assignReturnTo || action.return_state_path || action.returnStatePath || "").trim();
5501
+ if (!script.trim()) return { ...base, reason: "missing_script" };
5502
+ const scope = await setupActionScope(action, timeout);
5503
+ if (!scope.ok) return setupScopeFailure(base, scope);
5504
+ const hasExpectation = setupHasOwn(action, "expect_return")
5505
+ || setupHasOwn(action, "expectReturn")
5506
+ || setupHasOwn(action, "expected_return")
5507
+ || setupHasOwn(action, "expectedReturn");
5508
+ const expected = setupHasOwn(action, "expect_return")
5509
+ ? action.expect_return
5510
+ : setupHasOwn(action, "expectReturn")
5511
+ ? action.expectReturn
5512
+ : setupHasOwn(action, "expected_return")
5513
+ ? action.expected_return
5514
+ : action.expectedReturn;
5515
+ const captureReturn = action.capture_return === false || action.captureReturn === false || action.include_return === false || action.includeReturn === false || action.omit_return === true || action.omitReturn === true
5516
+ ? hasExpectation
5517
+ : true;
5518
+ const result = await setupEvaluateWindowScript(scope.context, script, args, storeReturnTo, captureReturn);
5519
+ const expectationMet = !hasExpectation || setupValuesEqual(result.returned, expected);
5520
+ return {
5521
+ ...base,
5522
+ ...setupScopeEvidence(scope),
5523
+ ok: Boolean(result.ok && expectationMet),
5524
+ script_length: script.length,
5525
+ arg_count: args.length,
5526
+ returned: captureReturn ? setupJsonValue(result.returned) : undefined,
5527
+ return_captured: captureReturn,
5528
+ expected_return: hasExpectation ? setupJsonValue(expected) : undefined,
5529
+ return_stored_to: result.return_stored_to || storeReturnTo || undefined,
5530
+ reason: result.ok ? (expectationMet ? undefined : "unexpected_return_value") : result.reason,
5531
+ store_reason: result.store_reason || undefined,
5532
+ error: result.error || undefined,
5533
+ };
5534
+ }
5374
5535
  if (type === "window_call") {
5375
5536
  const path = String(action.path || action.function_path || action.functionPath || "");
5376
5537
  const args = Array.isArray(action.args) ? action.args : [];
@@ -6926,9 +7087,13 @@ async function captureViewport(viewport) {
6926
7087
  }
6927
7088
  }
6928
7089
  const screenshotLabel = profileSlug + "-" + viewport.name;
7090
+ let screenshotFullPage = null;
6929
7091
  try {
6930
7092
  const screenshotOptions = {};
6931
- if (profile.target && profile.target.screenshot_full_page !== undefined) screenshotOptions.fullPage = profile.target.screenshot_full_page !== false;
7093
+ if (profile.target && profile.target.screenshot_full_page !== undefined) {
7094
+ screenshotFullPage = profile.target.screenshot_full_page !== false;
7095
+ screenshotOptions.fullPage = screenshotFullPage;
7096
+ }
6932
7097
  if (typeof saveScreenshot === "function") await saveScreenshot(screenshotLabel, screenshotOptions);
6933
7098
  } catch (error) {
6934
7099
  pageErrors.push({ message: "saveScreenshot failed: " + String(error && error.message ? error.message : error).slice(0, 500) });
@@ -6996,6 +7161,7 @@ async function captureViewport(viewport) {
6996
7161
  route_inventory: routeInventory,
6997
7162
  setup_action_results: setupActionResults,
6998
7163
  screenshot_label: screenshotLabel,
7164
+ screenshot_full_page: screenshotFullPage,
6999
7165
  navigation_error: navigationError,
7000
7166
  wait_error: waitError,
7001
7167
  };