@riddledc/riddle-proof 0.7.52 → 0.7.54

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
@@ -256,7 +256,11 @@ proof state must expose a terminal flag. `assert_selector_count` accepts
256
256
  `local_storage` and `session_storage` accept a `key` plus string `value` or
257
257
  JSON `json` / `value_json`, and can reload the page with `reload: true`.
258
258
  `clear_storage` clears `local`, `session`, or `both` browser storage scopes,
259
- defaults to `both`, and can also reload with `reload: true`.
259
+ defaults to `both`, and can also reload with `reload: true`. Any setup action
260
+ can include `repeat` / `repeat_count` / `times` from 1 to 100; each repetition
261
+ is recorded with `repeat_index` and `repeat_count`, and `after_ms` runs after
262
+ each repetition. Use it for bounded game proof helpers, retry controls, or other
263
+ workflows where one declarative action needs to advance the app several times.
260
264
 
261
265
  `target.timeout_sec` is optional. Use it for known-heavy profile targets so the
262
266
  profile carries its own hosted Riddle worker budget; an explicit CLI `--timeout`
@@ -220,6 +220,14 @@ function normalizeSetupActionArgs(input, index) {
220
220
  }
221
221
  return argsInput.map(toJsonValue);
222
222
  }
223
+ function normalizeSetupActionRepeat(input, index) {
224
+ const repeat = numberValue(valueFromOwn(input, "repeat", "repeat_count", "repeatCount", "times"));
225
+ if (repeat === void 0) return void 0;
226
+ if (!Number.isInteger(repeat) || repeat < 1 || repeat > 100) {
227
+ throw new Error(`target.setup_actions[${index}].repeat must be an integer from 1 to 100.`);
228
+ }
229
+ return repeat;
230
+ }
223
231
  function normalizeSetupAction(input, index) {
224
232
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
225
233
  const type = normalizeSetupActionType(stringValue(input.type), index);
@@ -278,6 +286,7 @@ function normalizeSetupAction(input, index) {
278
286
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
279
287
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
280
288
  after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
289
+ repeat: normalizeSetupActionRepeat(input, index),
281
290
  reload: input.reload === true,
282
291
  storage: normalizeSetupActionStorage(input.storage, index),
283
292
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
@@ -2426,11 +2435,22 @@ async function executeSetupActions(actions) {
2426
2435
  const results = [];
2427
2436
  for (let index = 0; index < (actions || []).length; index += 1) {
2428
2437
  const action = actions[index] || {};
2429
- const result = await executeSetupAction(action, index);
2430
- results.push(result);
2431
- const afterMs = setupNumber(action.after_ms, 0);
2432
- if (afterMs) await page.waitForTimeout(afterMs);
2433
- if (result.ok === false && action.continue_on_failure !== true) break;
2438
+ const requestedRepeat = setupNumber(action.repeat, 1);
2439
+ const repeatCount = Math.min(100, Math.max(1, Math.floor(requestedRepeat || 1)));
2440
+ let shouldStop = false;
2441
+ for (let repeatIndex = 0; repeatIndex < repeatCount; repeatIndex += 1) {
2442
+ const result = await executeSetupAction(action, index);
2443
+ results.push(repeatCount > 1
2444
+ ? { ...result, repeat_index: repeatIndex, repeat_count: repeatCount }
2445
+ : result);
2446
+ const afterMs = setupNumber(action.after_ms, 0);
2447
+ if (afterMs) await page.waitForTimeout(afterMs);
2448
+ if (result.ok === false && action.continue_on_failure !== true) {
2449
+ shouldStop = true;
2450
+ break;
2451
+ }
2452
+ }
2453
+ if (shouldStop) break;
2434
2454
  }
2435
2455
  return results;
2436
2456
  }
@@ -2496,7 +2516,7 @@ async function frameEvidence(selector) {
2496
2516
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
2497
2517
  const viewportWidth = clientWidth || window.innerWidth;
2498
2518
  const overflowOffenders = [];
2499
- function isContainedByHorizontalScroller(element) {
2519
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
2500
2520
  let current = element.parentElement;
2501
2521
  while (current && current !== body && current !== documentElement) {
2502
2522
  const style = window.getComputedStyle(current);
@@ -2506,6 +2526,11 @@ async function frameEvidence(selector) {
2506
2526
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
2507
2527
  if (contained) return true;
2508
2528
  }
2529
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
2530
+ const currentRect = current.getBoundingClientRect();
2531
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
2532
+ if (clippedByAncestor) return true;
2533
+ }
2509
2534
  current = current.parentElement;
2510
2535
  }
2511
2536
  return false;
@@ -2519,7 +2544,7 @@ async function frameEvidence(selector) {
2519
2544
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
2520
2545
  const overflow = Math.max(leftOverflow, rightOverflow);
2521
2546
  if (overflow <= 0.5) continue;
2522
- if (isContainedByHorizontalScroller(element)) continue;
2547
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
2523
2548
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
2524
2549
  const id = element.id ? "#" + element.id : "";
2525
2550
  const className = typeof element.className === "string"
@@ -2899,7 +2924,7 @@ async function captureViewport(viewport) {
2899
2924
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
2900
2925
  const viewportWidth = clientWidth || window.innerWidth;
2901
2926
  const overflowOffenders = [];
2902
- function isContainedByHorizontalScroller(element) {
2927
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
2903
2928
  let current = element.parentElement;
2904
2929
  while (current && current !== body && current !== documentElement) {
2905
2930
  const style = window.getComputedStyle(current);
@@ -2909,6 +2934,11 @@ async function captureViewport(viewport) {
2909
2934
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
2910
2935
  if (contained) return true;
2911
2936
  }
2937
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
2938
+ const currentRect = current.getBoundingClientRect();
2939
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
2940
+ if (clippedByAncestor) return true;
2941
+ }
2912
2942
  current = current.parentElement;
2913
2943
  }
2914
2944
  return false;
@@ -2922,7 +2952,7 @@ async function captureViewport(viewport) {
2922
2952
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
2923
2953
  const overflow = Math.max(leftOverflow, rightOverflow);
2924
2954
  if (overflow <= 0.5) continue;
2925
- if (isContainedByHorizontalScroller(element)) continue;
2955
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
2926
2956
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
2927
2957
  const id = element.id ? "#" + element.id : "";
2928
2958
  const className = typeof element.className === "string"
package/dist/cli.cjs CHANGED
@@ -7093,6 +7093,14 @@ function normalizeSetupActionArgs(input, index) {
7093
7093
  }
7094
7094
  return argsInput.map(toJsonValue);
7095
7095
  }
7096
+ function normalizeSetupActionRepeat(input, index) {
7097
+ const repeat = numberValue(valueFromOwn(input, "repeat", "repeat_count", "repeatCount", "times"));
7098
+ if (repeat === void 0) return void 0;
7099
+ if (!Number.isInteger(repeat) || repeat < 1 || repeat > 100) {
7100
+ throw new Error(`target.setup_actions[${index}].repeat must be an integer from 1 to 100.`);
7101
+ }
7102
+ return repeat;
7103
+ }
7096
7104
  function normalizeSetupAction(input, index) {
7097
7105
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
7098
7106
  const type = normalizeSetupActionType(stringValue2(input.type), index);
@@ -7151,6 +7159,7 @@ function normalizeSetupAction(input, index) {
7151
7159
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
7152
7160
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
7153
7161
  after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
7162
+ repeat: normalizeSetupActionRepeat(input, index),
7154
7163
  reload: input.reload === true,
7155
7164
  storage: normalizeSetupActionStorage(input.storage, index),
7156
7165
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
@@ -9283,11 +9292,22 @@ async function executeSetupActions(actions) {
9283
9292
  const results = [];
9284
9293
  for (let index = 0; index < (actions || []).length; index += 1) {
9285
9294
  const action = actions[index] || {};
9286
- const result = await executeSetupAction(action, index);
9287
- results.push(result);
9288
- const afterMs = setupNumber(action.after_ms, 0);
9289
- if (afterMs) await page.waitForTimeout(afterMs);
9290
- if (result.ok === false && action.continue_on_failure !== true) break;
9295
+ const requestedRepeat = setupNumber(action.repeat, 1);
9296
+ const repeatCount = Math.min(100, Math.max(1, Math.floor(requestedRepeat || 1)));
9297
+ let shouldStop = false;
9298
+ for (let repeatIndex = 0; repeatIndex < repeatCount; repeatIndex += 1) {
9299
+ const result = await executeSetupAction(action, index);
9300
+ results.push(repeatCount > 1
9301
+ ? { ...result, repeat_index: repeatIndex, repeat_count: repeatCount }
9302
+ : result);
9303
+ const afterMs = setupNumber(action.after_ms, 0);
9304
+ if (afterMs) await page.waitForTimeout(afterMs);
9305
+ if (result.ok === false && action.continue_on_failure !== true) {
9306
+ shouldStop = true;
9307
+ break;
9308
+ }
9309
+ }
9310
+ if (shouldStop) break;
9291
9311
  }
9292
9312
  return results;
9293
9313
  }
@@ -9353,7 +9373,7 @@ async function frameEvidence(selector) {
9353
9373
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
9354
9374
  const viewportWidth = clientWidth || window.innerWidth;
9355
9375
  const overflowOffenders = [];
9356
- function isContainedByHorizontalScroller(element) {
9376
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
9357
9377
  let current = element.parentElement;
9358
9378
  while (current && current !== body && current !== documentElement) {
9359
9379
  const style = window.getComputedStyle(current);
@@ -9363,6 +9383,11 @@ async function frameEvidence(selector) {
9363
9383
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
9364
9384
  if (contained) return true;
9365
9385
  }
9386
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
9387
+ const currentRect = current.getBoundingClientRect();
9388
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
9389
+ if (clippedByAncestor) return true;
9390
+ }
9366
9391
  current = current.parentElement;
9367
9392
  }
9368
9393
  return false;
@@ -9376,7 +9401,7 @@ async function frameEvidence(selector) {
9376
9401
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
9377
9402
  const overflow = Math.max(leftOverflow, rightOverflow);
9378
9403
  if (overflow <= 0.5) continue;
9379
- if (isContainedByHorizontalScroller(element)) continue;
9404
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
9380
9405
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
9381
9406
  const id = element.id ? "#" + element.id : "";
9382
9407
  const className = typeof element.className === "string"
@@ -9756,7 +9781,7 @@ async function captureViewport(viewport) {
9756
9781
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
9757
9782
  const viewportWidth = clientWidth || window.innerWidth;
9758
9783
  const overflowOffenders = [];
9759
- function isContainedByHorizontalScroller(element) {
9784
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
9760
9785
  let current = element.parentElement;
9761
9786
  while (current && current !== body && current !== documentElement) {
9762
9787
  const style = window.getComputedStyle(current);
@@ -9766,6 +9791,11 @@ async function captureViewport(viewport) {
9766
9791
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
9767
9792
  if (contained) return true;
9768
9793
  }
9794
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
9795
+ const currentRect = current.getBoundingClientRect();
9796
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
9797
+ if (clippedByAncestor) return true;
9798
+ }
9769
9799
  current = current.parentElement;
9770
9800
  }
9771
9801
  return false;
@@ -9779,7 +9809,7 @@ async function captureViewport(viewport) {
9779
9809
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
9780
9810
  const overflow = Math.max(leftOverflow, rightOverflow);
9781
9811
  if (overflow <= 0.5) continue;
9782
- if (isContainedByHorizontalScroller(element)) continue;
9812
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
9783
9813
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
9784
9814
  const id = element.id ? "#" + element.id : "";
9785
9815
  const className = typeof element.className === "string"
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-4S6RC5IJ.js";
13
+ } from "./chunk-H3DOYKAQ.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8934,6 +8934,14 @@ function normalizeSetupActionArgs(input, index) {
8934
8934
  }
8935
8935
  return argsInput.map(toJsonValue);
8936
8936
  }
8937
+ function normalizeSetupActionRepeat(input, index) {
8938
+ const repeat = numberValue3(valueFromOwn(input, "repeat", "repeat_count", "repeatCount", "times"));
8939
+ if (repeat === void 0) return void 0;
8940
+ if (!Number.isInteger(repeat) || repeat < 1 || repeat > 100) {
8941
+ throw new Error(`target.setup_actions[${index}].repeat must be an integer from 1 to 100.`);
8942
+ }
8943
+ return repeat;
8944
+ }
8937
8945
  function normalizeSetupAction(input, index) {
8938
8946
  if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
8939
8947
  const type = normalizeSetupActionType(stringValue5(input.type), index);
@@ -8992,6 +9000,7 @@ function normalizeSetupAction(input, index) {
8992
9000
  ms: numberValue3(input.ms) ?? numberValue3(input.wait_ms) ?? numberValue3(input.waitMs),
8993
9001
  timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
8994
9002
  after_ms: numberValue3(input.after_ms) ?? numberValue3(input.afterMs),
9003
+ repeat: normalizeSetupActionRepeat(input, index),
8995
9004
  reload: input.reload === true,
8996
9005
  storage: normalizeSetupActionStorage(input.storage, index),
8997
9006
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
@@ -11140,11 +11149,22 @@ async function executeSetupActions(actions) {
11140
11149
  const results = [];
11141
11150
  for (let index = 0; index < (actions || []).length; index += 1) {
11142
11151
  const action = actions[index] || {};
11143
- const result = await executeSetupAction(action, index);
11144
- results.push(result);
11145
- const afterMs = setupNumber(action.after_ms, 0);
11146
- if (afterMs) await page.waitForTimeout(afterMs);
11147
- if (result.ok === false && action.continue_on_failure !== true) break;
11152
+ const requestedRepeat = setupNumber(action.repeat, 1);
11153
+ const repeatCount = Math.min(100, Math.max(1, Math.floor(requestedRepeat || 1)));
11154
+ let shouldStop = false;
11155
+ for (let repeatIndex = 0; repeatIndex < repeatCount; repeatIndex += 1) {
11156
+ const result = await executeSetupAction(action, index);
11157
+ results.push(repeatCount > 1
11158
+ ? { ...result, repeat_index: repeatIndex, repeat_count: repeatCount }
11159
+ : result);
11160
+ const afterMs = setupNumber(action.after_ms, 0);
11161
+ if (afterMs) await page.waitForTimeout(afterMs);
11162
+ if (result.ok === false && action.continue_on_failure !== true) {
11163
+ shouldStop = true;
11164
+ break;
11165
+ }
11166
+ }
11167
+ if (shouldStop) break;
11148
11168
  }
11149
11169
  return results;
11150
11170
  }
@@ -11210,7 +11230,7 @@ async function frameEvidence(selector) {
11210
11230
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
11211
11231
  const viewportWidth = clientWidth || window.innerWidth;
11212
11232
  const overflowOffenders = [];
11213
- function isContainedByHorizontalScroller(element) {
11233
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
11214
11234
  let current = element.parentElement;
11215
11235
  while (current && current !== body && current !== documentElement) {
11216
11236
  const style = window.getComputedStyle(current);
@@ -11220,6 +11240,11 @@ async function frameEvidence(selector) {
11220
11240
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
11221
11241
  if (contained) return true;
11222
11242
  }
11243
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
11244
+ const currentRect = current.getBoundingClientRect();
11245
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
11246
+ if (clippedByAncestor) return true;
11247
+ }
11223
11248
  current = current.parentElement;
11224
11249
  }
11225
11250
  return false;
@@ -11233,7 +11258,7 @@ async function frameEvidence(selector) {
11233
11258
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
11234
11259
  const overflow = Math.max(leftOverflow, rightOverflow);
11235
11260
  if (overflow <= 0.5) continue;
11236
- if (isContainedByHorizontalScroller(element)) continue;
11261
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
11237
11262
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
11238
11263
  const id = element.id ? "#" + element.id : "";
11239
11264
  const className = typeof element.className === "string"
@@ -11613,7 +11638,7 @@ async function captureViewport(viewport) {
11613
11638
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
11614
11639
  const viewportWidth = clientWidth || window.innerWidth;
11615
11640
  const overflowOffenders = [];
11616
- function isContainedByHorizontalScroller(element) {
11641
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
11617
11642
  let current = element.parentElement;
11618
11643
  while (current && current !== body && current !== documentElement) {
11619
11644
  const style = window.getComputedStyle(current);
@@ -11623,6 +11648,11 @@ async function captureViewport(viewport) {
11623
11648
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
11624
11649
  if (contained) return true;
11625
11650
  }
11651
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
11652
+ const currentRect = current.getBoundingClientRect();
11653
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
11654
+ if (clippedByAncestor) return true;
11655
+ }
11626
11656
  current = current.parentElement;
11627
11657
  }
11628
11658
  return false;
@@ -11636,7 +11666,7 @@ async function captureViewport(viewport) {
11636
11666
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
11637
11667
  const overflow = Math.max(leftOverflow, rightOverflow);
11638
11668
  if (overflow <= 0.5) continue;
11639
- if (isContainedByHorizontalScroller(element)) continue;
11669
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
11640
11670
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
11641
11671
  const id = element.id ? "#" + element.id : "";
11642
11672
  const className = typeof element.className === "string"
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-4S6RC5IJ.js";
61
+ } from "./chunk-H3DOYKAQ.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -263,6 +263,14 @@ function normalizeSetupActionArgs(input, index) {
263
263
  }
264
264
  return argsInput.map(toJsonValue);
265
265
  }
266
+ function normalizeSetupActionRepeat(input, index) {
267
+ const repeat = numberValue(valueFromOwn(input, "repeat", "repeat_count", "repeatCount", "times"));
268
+ if (repeat === void 0) return void 0;
269
+ if (!Number.isInteger(repeat) || repeat < 1 || repeat > 100) {
270
+ throw new Error(`target.setup_actions[${index}].repeat must be an integer from 1 to 100.`);
271
+ }
272
+ return repeat;
273
+ }
266
274
  function normalizeSetupAction(input, index) {
267
275
  if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
268
276
  const type = normalizeSetupActionType(stringValue(input.type), index);
@@ -321,6 +329,7 @@ function normalizeSetupAction(input, index) {
321
329
  ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
322
330
  timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
323
331
  after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
332
+ repeat: normalizeSetupActionRepeat(input, index),
324
333
  reload: input.reload === true,
325
334
  storage: normalizeSetupActionStorage(input.storage, index),
326
335
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
@@ -2469,11 +2478,22 @@ async function executeSetupActions(actions) {
2469
2478
  const results = [];
2470
2479
  for (let index = 0; index < (actions || []).length; index += 1) {
2471
2480
  const action = actions[index] || {};
2472
- const result = await executeSetupAction(action, index);
2473
- results.push(result);
2474
- const afterMs = setupNumber(action.after_ms, 0);
2475
- if (afterMs) await page.waitForTimeout(afterMs);
2476
- if (result.ok === false && action.continue_on_failure !== true) break;
2481
+ const requestedRepeat = setupNumber(action.repeat, 1);
2482
+ const repeatCount = Math.min(100, Math.max(1, Math.floor(requestedRepeat || 1)));
2483
+ let shouldStop = false;
2484
+ for (let repeatIndex = 0; repeatIndex < repeatCount; repeatIndex += 1) {
2485
+ const result = await executeSetupAction(action, index);
2486
+ results.push(repeatCount > 1
2487
+ ? { ...result, repeat_index: repeatIndex, repeat_count: repeatCount }
2488
+ : result);
2489
+ const afterMs = setupNumber(action.after_ms, 0);
2490
+ if (afterMs) await page.waitForTimeout(afterMs);
2491
+ if (result.ok === false && action.continue_on_failure !== true) {
2492
+ shouldStop = true;
2493
+ break;
2494
+ }
2495
+ }
2496
+ if (shouldStop) break;
2477
2497
  }
2478
2498
  return results;
2479
2499
  }
@@ -2539,7 +2559,7 @@ async function frameEvidence(selector) {
2539
2559
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
2540
2560
  const viewportWidth = clientWidth || window.innerWidth;
2541
2561
  const overflowOffenders = [];
2542
- function isContainedByHorizontalScroller(element) {
2562
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
2543
2563
  let current = element.parentElement;
2544
2564
  while (current && current !== body && current !== documentElement) {
2545
2565
  const style = window.getComputedStyle(current);
@@ -2549,6 +2569,11 @@ async function frameEvidence(selector) {
2549
2569
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
2550
2570
  if (contained) return true;
2551
2571
  }
2572
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
2573
+ const currentRect = current.getBoundingClientRect();
2574
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
2575
+ if (clippedByAncestor) return true;
2576
+ }
2552
2577
  current = current.parentElement;
2553
2578
  }
2554
2579
  return false;
@@ -2562,7 +2587,7 @@ async function frameEvidence(selector) {
2562
2587
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
2563
2588
  const overflow = Math.max(leftOverflow, rightOverflow);
2564
2589
  if (overflow <= 0.5) continue;
2565
- if (isContainedByHorizontalScroller(element)) continue;
2590
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
2566
2591
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
2567
2592
  const id = element.id ? "#" + element.id : "";
2568
2593
  const className = typeof element.className === "string"
@@ -2942,7 +2967,7 @@ async function captureViewport(viewport) {
2942
2967
  const scrollWidth = documentElement ? documentElement.scrollWidth : 0;
2943
2968
  const viewportWidth = clientWidth || window.innerWidth;
2944
2969
  const overflowOffenders = [];
2945
- function isContainedByHorizontalScroller(element) {
2970
+ function isHandledByHorizontalOverflowAncestor(element, rect) {
2946
2971
  let current = element.parentElement;
2947
2972
  while (current && current !== body && current !== documentElement) {
2948
2973
  const style = window.getComputedStyle(current);
@@ -2952,6 +2977,11 @@ async function captureViewport(viewport) {
2952
2977
  const contained = currentRect.left >= -0.5 && currentRect.right <= viewportWidth + 0.5;
2953
2978
  if (contained) return true;
2954
2979
  }
2980
+ if (overflowX === "hidden" || overflowX === "clip" || style.overflow === "hidden" || style.overflow === "clip") {
2981
+ const currentRect = current.getBoundingClientRect();
2982
+ const clippedByAncestor = rect.left < currentRect.left - 0.5 || rect.right > currentRect.right + 0.5;
2983
+ if (clippedByAncestor) return true;
2984
+ }
2955
2985
  current = current.parentElement;
2956
2986
  }
2957
2987
  return false;
@@ -2965,7 +2995,7 @@ async function captureViewport(viewport) {
2965
2995
  const rightOverflow = Math.max(0, rect.right - viewportWidth);
2966
2996
  const overflow = Math.max(leftOverflow, rightOverflow);
2967
2997
  if (overflow <= 0.5) continue;
2968
- if (isContainedByHorizontalScroller(element)) continue;
2998
+ if (isHandledByHorizontalOverflowAncestor(element, rect)) continue;
2969
2999
  const tag = element.tagName ? element.tagName.toLowerCase() : "element";
2970
3000
  const id = element.id ? "#" + element.id : "";
2971
3001
  const className = typeof element.className === "string"
@@ -36,6 +36,7 @@ interface RiddleProofProfileSetupAction {
36
36
  ms?: number;
37
37
  timeout_ms?: number;
38
38
  after_ms?: number;
39
+ repeat?: number;
39
40
  reload?: boolean;
40
41
  storage?: "local" | "session" | "both";
41
42
  continue_on_failure?: boolean;
package/dist/profile.d.ts CHANGED
@@ -36,6 +36,7 @@ interface RiddleProofProfileSetupAction {
36
36
  ms?: number;
37
37
  timeout_ms?: number;
38
38
  after_ms?: number;
39
+ repeat?: number;
39
40
  reload?: boolean;
40
41
  storage?: "local" | "session" | "both";
41
42
  continue_on_failure?: boolean;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-4S6RC5IJ.js";
22
+ } from "./chunk-H3DOYKAQ.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.52",
3
+ "version": "0.7.54",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",