@riddledc/riddle-proof 0.7.82 → 0.7.84

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
@@ -59,7 +59,7 @@ without depending on another plugin runtime.
59
59
  ## Durable Loop CLI
60
60
 
61
61
  The package publishes `riddle-proof-loop` as a host-agnostic runner surface for
62
- Codex/CLI-style testing:
62
+ CLI-style and sole-agent testing:
63
63
 
64
64
  ```sh
65
65
  riddle-proof-loop run --request-json request.json --checkpoint-mode yield
@@ -88,9 +88,9 @@ Flag-based `respond` refuses to submit generated placeholder payloads. If the
88
88
  checkpoint template includes `TODO` fields, provide a real `--payload-json`
89
89
  file/object before resuming the run.
90
90
 
91
- `--agent local` is the generic CLI executor slot. The current implementation
92
- uses the local Codex CLI adapter underneath, but the loop contract and CLI
93
- surface are intentionally not Codex-specific.
91
+ `--agent local` is the generic CLI executor slot. A host can wire that slot to
92
+ Codex, Claude Code, another local CLI, or a managed worker without changing the
93
+ checkpoint, evidence, or proof-assessment contract.
94
94
 
95
95
  Visual/UI proof runs can pass `viewport_matrix` / `viewport_matrix_json` to the
96
96
  base loop. The runtime records the requested matrix, captures per-viewport
@@ -676,7 +676,7 @@ terminal proof failure. If `--wait` exhausts its attempts before a terminal job
676
676
  status, the command exits non-zero and the result explains the last observed
677
677
  status and `submitted_at` state.
678
678
 
679
- ## OpenClaw Adapter Boundary
679
+ ## Base vs OpenClaw Wrapper Boundary
680
680
 
681
681
  `@riddledc/riddle-proof/openclaw` translates OpenClaw Riddle Proof tool params
682
682
  into generic `RiddleProofRunParams`.
@@ -689,6 +689,27 @@ Generic authenticated proof inputs are preserved as pass-through JSON strings:
689
689
  those for public integrations; reserve `use_auth` for a configured, site-specific
690
690
  auth helper.
691
691
 
692
+ Keep behavior in base `@riddledc/riddle-proof` when it changes the portable run
693
+ contract or evidence semantics:
694
+
695
+ - checkpoint packets and responses
696
+ - profile, audit/no-diff, and proof-of-change run modes
697
+ - viewport matrices and per-viewport artifact metadata
698
+ - visual-delta thresholds, changed-region evidence, and evidence recovery gates
699
+ - run state, run cards, result objects, proof sessions, and evidence bundles
700
+ - generic auth/header/local storage inputs
701
+
702
+ Keep behavior in the OpenClaw wrapper when it only concerns OpenClaw hosting or
703
+ presentation:
704
+
705
+ - OpenClaw tool registration and schema wording
706
+ - Discord thread/status formatting
707
+ - OpenClaw workflow labels such as interactive, background PR, and continuous
708
+ - PR handoff/status phrasing such as `ship_mode=none`
709
+ - checkpoint packet display and review UX
710
+ - configured site-specific auth helpers
711
+ - wrapper deployment, hot reload, and notification adapters
712
+
692
713
  The adapter does not invoke another OpenClaw plugin and does not supply a
693
714
  coding agent. It is the reusable mapping layer a future OpenClaw wrapper can
694
715
  call before handing the request to its configured implementation, judge, ship,
@@ -226,11 +226,12 @@ function profileScreenshotLabels(viewports) {
226
226
  }
227
227
  return labels;
228
228
  }
229
- function profileSetupSummary(viewports, actionCount) {
229
+ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport) {
230
230
  return toJsonValue({
231
231
  viewport_count: viewports.length,
232
232
  action_count: actionCount ?? null,
233
233
  viewports: viewports.map((viewport) => {
234
+ const expectedActionCount = expectedActionCountByViewport?.get(viewport.name) ?? actionCount;
234
235
  const results = viewport.setup_action_results || [];
235
236
  const failed = results.filter((result) => result.ok === false);
236
237
  const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -254,7 +255,8 @@ function profileSetupSummary(viewports, actionCount) {
254
255
  })).filter((item) => item.text).slice(-6);
255
256
  return {
256
257
  name: viewport.name,
257
- ok: (actionCount === void 0 ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
258
+ expected_action_count: expectedActionCount ?? null,
259
+ ok: (expectedActionCount === void 0 ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
258
260
  result_count: results.length,
259
261
  observed_path: viewport.route?.observed ?? null,
260
262
  final_url: viewport.url ?? null,
@@ -491,6 +493,7 @@ function normalizeSetupAction(input, index) {
491
493
  repeat: normalizeSetupActionRepeat(input, index),
492
494
  reload: input.reload === true,
493
495
  storage: normalizeSetupActionStorage(input.storage, index),
496
+ viewports: normalizeStringList(input.viewports ?? input.viewport_names ?? input.viewportNames, `target.setup_actions[${index}] viewports`),
494
497
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
495
498
  };
496
499
  }
@@ -1063,6 +1066,13 @@ function viewportsForCheck(check, viewports) {
1063
1066
  const names = new Set(check.viewports);
1064
1067
  return viewports.filter((viewport) => names.has(viewport.name));
1065
1068
  }
1069
+ function setupActionAppliesToViewport(action, viewportName) {
1070
+ if (!action.viewports?.length) return true;
1071
+ return Boolean(viewportName && action.viewports.includes(viewportName));
1072
+ }
1073
+ function setupActionsForViewport(actions, viewportName) {
1074
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
1075
+ }
1066
1076
  function assessCheckFromEvidence(check, evidence) {
1067
1077
  const viewports = viewportsForCheck(check, evidence.viewports || []);
1068
1078
  if (!viewports.length) {
@@ -1443,7 +1453,21 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1443
1453
  const actionCount = profile.target.setup_actions.length;
1444
1454
  const failed = [];
1445
1455
  const viewports = evidence.viewports || [];
1456
+ const expectedActionCountByViewport = /* @__PURE__ */ new Map();
1457
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
1458
+ for (const action of profile.target.setup_actions) {
1459
+ if (action.viewports?.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
1460
+ failed.push({
1461
+ viewport: null,
1462
+ action: action.type,
1463
+ selector: action.selector ?? null,
1464
+ reason: `setup action scoped to missing viewport(s): ${action.viewports.join(", ")}`
1465
+ });
1466
+ }
1467
+ }
1446
1468
  for (const viewport of viewports) {
1469
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
1470
+ expectedActionCountByViewport.set(viewport.name, expectedActionCount);
1447
1471
  const results = viewport.setup_action_results || [];
1448
1472
  for (const result of results) {
1449
1473
  if (result.ok === false) {
@@ -1457,12 +1481,12 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1457
1481
  });
1458
1482
  }
1459
1483
  }
1460
- if (results.length < actionCount && results.every((result) => result.ok !== false)) {
1484
+ if (results.length < expectedActionCount && results.every((result) => result.ok !== false)) {
1461
1485
  failed.push({
1462
1486
  viewport: viewport.name,
1463
1487
  action: "setup_actions",
1464
1488
  selector: null,
1465
- reason: `missing setup action results: ${results.length}/${actionCount}`
1489
+ reason: `missing setup action results: ${results.length}/${expectedActionCount}`
1466
1490
  });
1467
1491
  }
1468
1492
  }
@@ -1474,10 +1498,11 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1474
1498
  action_count: actionCount,
1475
1499
  viewports: viewports.map((viewport) => ({
1476
1500
  name: viewport.name,
1477
- ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
1501
+ expected_action_count: expectedActionCountByViewport.get(viewport.name) ?? actionCount,
1502
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountByViewport.get(viewport.name) ?? actionCount) && (viewport.setup_action_results || []).every((result) => result.ok !== false),
1478
1503
  result_count: (viewport.setup_action_results || []).length
1479
1504
  })),
1480
- setup_summary: profileSetupSummary(viewports, actionCount),
1505
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport),
1481
1506
  failed
1482
1507
  },
1483
1508
  message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
@@ -1863,6 +1888,13 @@ function viewportsForCheck(check, viewports) {
1863
1888
  const names = new Set(check.viewports);
1864
1889
  return viewports.filter((viewport) => names.has(viewport.name));
1865
1890
  }
1891
+ function setupActionAppliesToViewport(action, viewportName) {
1892
+ if (!Array.isArray(action.viewports) || !action.viewports.length) return true;
1893
+ return Boolean(viewportName && action.viewports.includes(viewportName));
1894
+ }
1895
+ function setupActionsForViewport(actions, viewportName) {
1896
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
1897
+ }
1866
1898
  function summarizeRouteInventory(viewport, inventory) {
1867
1899
  const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
1868
1900
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
@@ -2011,11 +2043,14 @@ function profileScreenshotLabels(viewports) {
2011
2043
  }
2012
2044
  return labels;
2013
2045
  }
2014
- function profileSetupSummary(viewports, actionCount) {
2046
+ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport) {
2015
2047
  return {
2016
2048
  viewport_count: (viewports || []).length,
2017
2049
  action_count: actionCount ?? null,
2018
2050
  viewports: (viewports || []).map((viewport) => {
2051
+ const expectedActionCount = expectedActionCountsByViewport && expectedActionCountsByViewport[viewport.name] !== undefined
2052
+ ? expectedActionCountsByViewport[viewport.name]
2053
+ : actionCount;
2019
2054
  const results = viewport.setup_action_results || [];
2020
2055
  const failed = results.filter((result) => result && result.ok === false);
2021
2056
  const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -2051,7 +2086,8 @@ function profileSetupSummary(viewports, actionCount) {
2051
2086
  .slice(-6);
2052
2087
  return {
2053
2088
  name: viewport.name,
2054
- ok: (actionCount === undefined ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
2089
+ expected_action_count: expectedActionCount ?? null,
2090
+ ok: (expectedActionCount === undefined ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
2055
2091
  result_count: results.length,
2056
2092
  observed_path: viewport.route && viewport.route.observed || null,
2057
2093
  final_url: viewport.url || null,
@@ -2174,7 +2210,21 @@ function assessProfile(profile, evidence) {
2174
2210
  if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
2175
2211
  const actionCount = profile.target.setup_actions.length;
2176
2212
  const failed = [];
2213
+ const expectedActionCountsByViewport = {};
2214
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
2215
+ for (const action of profile.target.setup_actions) {
2216
+ if (Array.isArray(action.viewports) && action.viewports.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
2217
+ failed.push({
2218
+ viewport: null,
2219
+ action: action.type,
2220
+ selector: action.selector || null,
2221
+ reason: "setup action scoped to missing viewport(s): " + action.viewports.join(", "),
2222
+ });
2223
+ }
2224
+ }
2177
2225
  for (const viewport of viewports) {
2226
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
2227
+ expectedActionCountsByViewport[viewport.name] = expectedActionCount;
2178
2228
  const results = viewport.setup_action_results || [];
2179
2229
  for (const result of results) {
2180
2230
  if (result && result.ok === false) {
@@ -2188,12 +2238,12 @@ function assessProfile(profile, evidence) {
2188
2238
  });
2189
2239
  }
2190
2240
  }
2191
- if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
2241
+ if (results.length < expectedActionCount && results.every((result) => !result || result.ok !== false)) {
2192
2242
  failed.push({
2193
2243
  viewport: viewport.name,
2194
2244
  action: "setup_actions",
2195
2245
  selector: null,
2196
- reason: "missing setup action results: " + results.length + "/" + actionCount,
2246
+ reason: "missing setup action results: " + results.length + "/" + expectedActionCount,
2197
2247
  });
2198
2248
  }
2199
2249
  }
@@ -2205,11 +2255,12 @@ function assessProfile(profile, evidence) {
2205
2255
  action_count: actionCount,
2206
2256
  viewports: viewports.map((viewport) => ({
2207
2257
  name: viewport.name,
2208
- ok: (viewport.setup_action_results || []).length >= actionCount
2258
+ expected_action_count: expectedActionCountsByViewport[viewport.name] ?? actionCount,
2259
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountsByViewport[viewport.name] ?? actionCount)
2209
2260
  && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
2210
2261
  result_count: (viewport.setup_action_results || []).length,
2211
2262
  })),
2212
- setup_summary: profileSetupSummary(viewports, actionCount),
2263
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport),
2213
2264
  failed,
2214
2265
  },
2215
2266
  message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
@@ -3946,7 +3997,7 @@ async function captureViewport(viewport) {
3946
3997
  await page.waitForTimeout(profile.target.wait_ms);
3947
3998
  }
3948
3999
  const setupActionResults = (!navigationError && !waitError)
3949
- ? await executeSetupActions(profile.target.setup_actions || [], viewport)
4000
+ ? await executeSetupActions(setupActionsForViewport(profile.target.setup_actions || [], viewport.name), viewport)
3950
4001
  : [];
3951
4002
  const dom = await page.evaluate(() => {
3952
4003
  const body = document.body;
package/dist/cli.cjs CHANGED
@@ -7113,11 +7113,12 @@ function profileScreenshotLabels(viewports) {
7113
7113
  }
7114
7114
  return labels;
7115
7115
  }
7116
- function profileSetupSummary(viewports, actionCount) {
7116
+ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport) {
7117
7117
  return toJsonValue({
7118
7118
  viewport_count: viewports.length,
7119
7119
  action_count: actionCount ?? null,
7120
7120
  viewports: viewports.map((viewport) => {
7121
+ const expectedActionCount = expectedActionCountByViewport?.get(viewport.name) ?? actionCount;
7121
7122
  const results = viewport.setup_action_results || [];
7122
7123
  const failed = results.filter((result) => result.ok === false);
7123
7124
  const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -7141,7 +7142,8 @@ function profileSetupSummary(viewports, actionCount) {
7141
7142
  })).filter((item) => item.text).slice(-6);
7142
7143
  return {
7143
7144
  name: viewport.name,
7144
- ok: (actionCount === void 0 ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
7145
+ expected_action_count: expectedActionCount ?? null,
7146
+ ok: (expectedActionCount === void 0 ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
7145
7147
  result_count: results.length,
7146
7148
  observed_path: viewport.route?.observed ?? null,
7147
7149
  final_url: viewport.url ?? null,
@@ -7378,6 +7380,7 @@ function normalizeSetupAction(input, index) {
7378
7380
  repeat: normalizeSetupActionRepeat(input, index),
7379
7381
  reload: input.reload === true,
7380
7382
  storage: normalizeSetupActionStorage(input.storage, index),
7383
+ viewports: normalizeStringList(input.viewports ?? input.viewport_names ?? input.viewportNames, `target.setup_actions[${index}] viewports`),
7381
7384
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
7382
7385
  };
7383
7386
  }
@@ -7950,6 +7953,13 @@ function viewportsForCheck(check, viewports) {
7950
7953
  const names = new Set(check.viewports);
7951
7954
  return viewports.filter((viewport) => names.has(viewport.name));
7952
7955
  }
7956
+ function setupActionAppliesToViewport(action, viewportName) {
7957
+ if (!action.viewports?.length) return true;
7958
+ return Boolean(viewportName && action.viewports.includes(viewportName));
7959
+ }
7960
+ function setupActionsForViewport(actions, viewportName) {
7961
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
7962
+ }
7953
7963
  function assessCheckFromEvidence(check, evidence) {
7954
7964
  const viewports = viewportsForCheck(check, evidence.viewports || []);
7955
7965
  if (!viewports.length) {
@@ -8330,7 +8340,21 @@ function assessSetupActionsFromEvidence(profile, evidence) {
8330
8340
  const actionCount = profile.target.setup_actions.length;
8331
8341
  const failed = [];
8332
8342
  const viewports = evidence.viewports || [];
8343
+ const expectedActionCountByViewport = /* @__PURE__ */ new Map();
8344
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
8345
+ for (const action of profile.target.setup_actions) {
8346
+ if (action.viewports?.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
8347
+ failed.push({
8348
+ viewport: null,
8349
+ action: action.type,
8350
+ selector: action.selector ?? null,
8351
+ reason: `setup action scoped to missing viewport(s): ${action.viewports.join(", ")}`
8352
+ });
8353
+ }
8354
+ }
8333
8355
  for (const viewport of viewports) {
8356
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
8357
+ expectedActionCountByViewport.set(viewport.name, expectedActionCount);
8334
8358
  const results = viewport.setup_action_results || [];
8335
8359
  for (const result of results) {
8336
8360
  if (result.ok === false) {
@@ -8344,12 +8368,12 @@ function assessSetupActionsFromEvidence(profile, evidence) {
8344
8368
  });
8345
8369
  }
8346
8370
  }
8347
- if (results.length < actionCount && results.every((result) => result.ok !== false)) {
8371
+ if (results.length < expectedActionCount && results.every((result) => result.ok !== false)) {
8348
8372
  failed.push({
8349
8373
  viewport: viewport.name,
8350
8374
  action: "setup_actions",
8351
8375
  selector: null,
8352
- reason: `missing setup action results: ${results.length}/${actionCount}`
8376
+ reason: `missing setup action results: ${results.length}/${expectedActionCount}`
8353
8377
  });
8354
8378
  }
8355
8379
  }
@@ -8361,10 +8385,11 @@ function assessSetupActionsFromEvidence(profile, evidence) {
8361
8385
  action_count: actionCount,
8362
8386
  viewports: viewports.map((viewport) => ({
8363
8387
  name: viewport.name,
8364
- ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
8388
+ expected_action_count: expectedActionCountByViewport.get(viewport.name) ?? actionCount,
8389
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountByViewport.get(viewport.name) ?? actionCount) && (viewport.setup_action_results || []).every((result) => result.ok !== false),
8365
8390
  result_count: (viewport.setup_action_results || []).length
8366
8391
  })),
8367
- setup_summary: profileSetupSummary(viewports, actionCount),
8392
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport),
8368
8393
  failed
8369
8394
  },
8370
8395
  message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
@@ -8734,6 +8759,13 @@ function viewportsForCheck(check, viewports) {
8734
8759
  const names = new Set(check.viewports);
8735
8760
  return viewports.filter((viewport) => names.has(viewport.name));
8736
8761
  }
8762
+ function setupActionAppliesToViewport(action, viewportName) {
8763
+ if (!Array.isArray(action.viewports) || !action.viewports.length) return true;
8764
+ return Boolean(viewportName && action.viewports.includes(viewportName));
8765
+ }
8766
+ function setupActionsForViewport(actions, viewportName) {
8767
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
8768
+ }
8737
8769
  function summarizeRouteInventory(viewport, inventory) {
8738
8770
  const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
8739
8771
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
@@ -8882,11 +8914,14 @@ function profileScreenshotLabels(viewports) {
8882
8914
  }
8883
8915
  return labels;
8884
8916
  }
8885
- function profileSetupSummary(viewports, actionCount) {
8917
+ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport) {
8886
8918
  return {
8887
8919
  viewport_count: (viewports || []).length,
8888
8920
  action_count: actionCount ?? null,
8889
8921
  viewports: (viewports || []).map((viewport) => {
8922
+ const expectedActionCount = expectedActionCountsByViewport && expectedActionCountsByViewport[viewport.name] !== undefined
8923
+ ? expectedActionCountsByViewport[viewport.name]
8924
+ : actionCount;
8890
8925
  const results = viewport.setup_action_results || [];
8891
8926
  const failed = results.filter((result) => result && result.ok === false);
8892
8927
  const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -8922,7 +8957,8 @@ function profileSetupSummary(viewports, actionCount) {
8922
8957
  .slice(-6);
8923
8958
  return {
8924
8959
  name: viewport.name,
8925
- ok: (actionCount === undefined ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
8960
+ expected_action_count: expectedActionCount ?? null,
8961
+ ok: (expectedActionCount === undefined ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
8926
8962
  result_count: results.length,
8927
8963
  observed_path: viewport.route && viewport.route.observed || null,
8928
8964
  final_url: viewport.url || null,
@@ -9045,7 +9081,21 @@ function assessProfile(profile, evidence) {
9045
9081
  if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
9046
9082
  const actionCount = profile.target.setup_actions.length;
9047
9083
  const failed = [];
9084
+ const expectedActionCountsByViewport = {};
9085
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
9086
+ for (const action of profile.target.setup_actions) {
9087
+ if (Array.isArray(action.viewports) && action.viewports.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
9088
+ failed.push({
9089
+ viewport: null,
9090
+ action: action.type,
9091
+ selector: action.selector || null,
9092
+ reason: "setup action scoped to missing viewport(s): " + action.viewports.join(", "),
9093
+ });
9094
+ }
9095
+ }
9048
9096
  for (const viewport of viewports) {
9097
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
9098
+ expectedActionCountsByViewport[viewport.name] = expectedActionCount;
9049
9099
  const results = viewport.setup_action_results || [];
9050
9100
  for (const result of results) {
9051
9101
  if (result && result.ok === false) {
@@ -9059,12 +9109,12 @@ function assessProfile(profile, evidence) {
9059
9109
  });
9060
9110
  }
9061
9111
  }
9062
- if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
9112
+ if (results.length < expectedActionCount && results.every((result) => !result || result.ok !== false)) {
9063
9113
  failed.push({
9064
9114
  viewport: viewport.name,
9065
9115
  action: "setup_actions",
9066
9116
  selector: null,
9067
- reason: "missing setup action results: " + results.length + "/" + actionCount,
9117
+ reason: "missing setup action results: " + results.length + "/" + expectedActionCount,
9068
9118
  });
9069
9119
  }
9070
9120
  }
@@ -9076,11 +9126,12 @@ function assessProfile(profile, evidence) {
9076
9126
  action_count: actionCount,
9077
9127
  viewports: viewports.map((viewport) => ({
9078
9128
  name: viewport.name,
9079
- ok: (viewport.setup_action_results || []).length >= actionCount
9129
+ expected_action_count: expectedActionCountsByViewport[viewport.name] ?? actionCount,
9130
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountsByViewport[viewport.name] ?? actionCount)
9080
9131
  && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
9081
9132
  result_count: (viewport.setup_action_results || []).length,
9082
9133
  })),
9083
- setup_summary: profileSetupSummary(viewports, actionCount),
9134
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport),
9084
9135
  failed,
9085
9136
  },
9086
9137
  message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
@@ -10817,7 +10868,7 @@ async function captureViewport(viewport) {
10817
10868
  await page.waitForTimeout(profile.target.wait_ms);
10818
10869
  }
10819
10870
  const setupActionResults = (!navigationError && !waitError)
10820
- ? await executeSetupActions(profile.target.setup_actions || [], viewport)
10871
+ ? await executeSetupActions(setupActionsForViewport(profile.target.setup_actions || [], viewport.name), viewport)
10821
10872
  : [];
10822
10873
  const dom = await page.evaluate(() => {
10823
10874
  const body = document.body;
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-3RUIKF4C.js";
13
+ } from "./chunk-QC42KDBD.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8954,11 +8954,12 @@ function profileScreenshotLabels(viewports) {
8954
8954
  }
8955
8955
  return labels;
8956
8956
  }
8957
- function profileSetupSummary(viewports, actionCount) {
8957
+ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport) {
8958
8958
  return toJsonValue({
8959
8959
  viewport_count: viewports.length,
8960
8960
  action_count: actionCount ?? null,
8961
8961
  viewports: viewports.map((viewport) => {
8962
+ const expectedActionCount = expectedActionCountByViewport?.get(viewport.name) ?? actionCount;
8962
8963
  const results = viewport.setup_action_results || [];
8963
8964
  const failed = results.filter((result) => result.ok === false);
8964
8965
  const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -8982,7 +8983,8 @@ function profileSetupSummary(viewports, actionCount) {
8982
8983
  })).filter((item) => item.text).slice(-6);
8983
8984
  return {
8984
8985
  name: viewport.name,
8985
- ok: (actionCount === void 0 ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
8986
+ expected_action_count: expectedActionCount ?? null,
8987
+ ok: (expectedActionCount === void 0 ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
8986
8988
  result_count: results.length,
8987
8989
  observed_path: viewport.route?.observed ?? null,
8988
8990
  final_url: viewport.url ?? null,
@@ -9219,6 +9221,7 @@ function normalizeSetupAction(input, index) {
9219
9221
  repeat: normalizeSetupActionRepeat(input, index),
9220
9222
  reload: input.reload === true,
9221
9223
  storage: normalizeSetupActionStorage(input.storage, index),
9224
+ viewports: normalizeStringList(input.viewports ?? input.viewport_names ?? input.viewportNames, `target.setup_actions[${index}] viewports`),
9222
9225
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
9223
9226
  };
9224
9227
  }
@@ -9791,6 +9794,13 @@ function viewportsForCheck(check, viewports) {
9791
9794
  const names = new Set(check.viewports);
9792
9795
  return viewports.filter((viewport) => names.has(viewport.name));
9793
9796
  }
9797
+ function setupActionAppliesToViewport(action, viewportName) {
9798
+ if (!action.viewports?.length) return true;
9799
+ return Boolean(viewportName && action.viewports.includes(viewportName));
9800
+ }
9801
+ function setupActionsForViewport(actions, viewportName) {
9802
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
9803
+ }
9794
9804
  function assessCheckFromEvidence(check, evidence) {
9795
9805
  const viewports = viewportsForCheck(check, evidence.viewports || []);
9796
9806
  if (!viewports.length) {
@@ -10171,7 +10181,21 @@ function assessSetupActionsFromEvidence(profile, evidence) {
10171
10181
  const actionCount = profile.target.setup_actions.length;
10172
10182
  const failed = [];
10173
10183
  const viewports = evidence.viewports || [];
10184
+ const expectedActionCountByViewport = /* @__PURE__ */ new Map();
10185
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
10186
+ for (const action of profile.target.setup_actions) {
10187
+ if (action.viewports?.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
10188
+ failed.push({
10189
+ viewport: null,
10190
+ action: action.type,
10191
+ selector: action.selector ?? null,
10192
+ reason: `setup action scoped to missing viewport(s): ${action.viewports.join(", ")}`
10193
+ });
10194
+ }
10195
+ }
10174
10196
  for (const viewport of viewports) {
10197
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
10198
+ expectedActionCountByViewport.set(viewport.name, expectedActionCount);
10175
10199
  const results = viewport.setup_action_results || [];
10176
10200
  for (const result of results) {
10177
10201
  if (result.ok === false) {
@@ -10185,12 +10209,12 @@ function assessSetupActionsFromEvidence(profile, evidence) {
10185
10209
  });
10186
10210
  }
10187
10211
  }
10188
- if (results.length < actionCount && results.every((result) => result.ok !== false)) {
10212
+ if (results.length < expectedActionCount && results.every((result) => result.ok !== false)) {
10189
10213
  failed.push({
10190
10214
  viewport: viewport.name,
10191
10215
  action: "setup_actions",
10192
10216
  selector: null,
10193
- reason: `missing setup action results: ${results.length}/${actionCount}`
10217
+ reason: `missing setup action results: ${results.length}/${expectedActionCount}`
10194
10218
  });
10195
10219
  }
10196
10220
  }
@@ -10202,10 +10226,11 @@ function assessSetupActionsFromEvidence(profile, evidence) {
10202
10226
  action_count: actionCount,
10203
10227
  viewports: viewports.map((viewport) => ({
10204
10228
  name: viewport.name,
10205
- ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
10229
+ expected_action_count: expectedActionCountByViewport.get(viewport.name) ?? actionCount,
10230
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountByViewport.get(viewport.name) ?? actionCount) && (viewport.setup_action_results || []).every((result) => result.ok !== false),
10206
10231
  result_count: (viewport.setup_action_results || []).length
10207
10232
  })),
10208
- setup_summary: profileSetupSummary(viewports, actionCount),
10233
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport),
10209
10234
  failed
10210
10235
  },
10211
10236
  message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
@@ -10591,6 +10616,13 @@ function viewportsForCheck(check, viewports) {
10591
10616
  const names = new Set(check.viewports);
10592
10617
  return viewports.filter((viewport) => names.has(viewport.name));
10593
10618
  }
10619
+ function setupActionAppliesToViewport(action, viewportName) {
10620
+ if (!Array.isArray(action.viewports) || !action.viewports.length) return true;
10621
+ return Boolean(viewportName && action.viewports.includes(viewportName));
10622
+ }
10623
+ function setupActionsForViewport(actions, viewportName) {
10624
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
10625
+ }
10594
10626
  function summarizeRouteInventory(viewport, inventory) {
10595
10627
  const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
10596
10628
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
@@ -10739,11 +10771,14 @@ function profileScreenshotLabels(viewports) {
10739
10771
  }
10740
10772
  return labels;
10741
10773
  }
10742
- function profileSetupSummary(viewports, actionCount) {
10774
+ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport) {
10743
10775
  return {
10744
10776
  viewport_count: (viewports || []).length,
10745
10777
  action_count: actionCount ?? null,
10746
10778
  viewports: (viewports || []).map((viewport) => {
10779
+ const expectedActionCount = expectedActionCountsByViewport && expectedActionCountsByViewport[viewport.name] !== undefined
10780
+ ? expectedActionCountsByViewport[viewport.name]
10781
+ : actionCount;
10747
10782
  const results = viewport.setup_action_results || [];
10748
10783
  const failed = results.filter((result) => result && result.ok === false);
10749
10784
  const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -10779,7 +10814,8 @@ function profileSetupSummary(viewports, actionCount) {
10779
10814
  .slice(-6);
10780
10815
  return {
10781
10816
  name: viewport.name,
10782
- ok: (actionCount === undefined ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
10817
+ expected_action_count: expectedActionCount ?? null,
10818
+ ok: (expectedActionCount === undefined ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
10783
10819
  result_count: results.length,
10784
10820
  observed_path: viewport.route && viewport.route.observed || null,
10785
10821
  final_url: viewport.url || null,
@@ -10902,7 +10938,21 @@ function assessProfile(profile, evidence) {
10902
10938
  if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
10903
10939
  const actionCount = profile.target.setup_actions.length;
10904
10940
  const failed = [];
10941
+ const expectedActionCountsByViewport = {};
10942
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
10943
+ for (const action of profile.target.setup_actions) {
10944
+ if (Array.isArray(action.viewports) && action.viewports.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
10945
+ failed.push({
10946
+ viewport: null,
10947
+ action: action.type,
10948
+ selector: action.selector || null,
10949
+ reason: "setup action scoped to missing viewport(s): " + action.viewports.join(", "),
10950
+ });
10951
+ }
10952
+ }
10905
10953
  for (const viewport of viewports) {
10954
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
10955
+ expectedActionCountsByViewport[viewport.name] = expectedActionCount;
10906
10956
  const results = viewport.setup_action_results || [];
10907
10957
  for (const result of results) {
10908
10958
  if (result && result.ok === false) {
@@ -10916,12 +10966,12 @@ function assessProfile(profile, evidence) {
10916
10966
  });
10917
10967
  }
10918
10968
  }
10919
- if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
10969
+ if (results.length < expectedActionCount && results.every((result) => !result || result.ok !== false)) {
10920
10970
  failed.push({
10921
10971
  viewport: viewport.name,
10922
10972
  action: "setup_actions",
10923
10973
  selector: null,
10924
- reason: "missing setup action results: " + results.length + "/" + actionCount,
10974
+ reason: "missing setup action results: " + results.length + "/" + expectedActionCount,
10925
10975
  });
10926
10976
  }
10927
10977
  }
@@ -10933,11 +10983,12 @@ function assessProfile(profile, evidence) {
10933
10983
  action_count: actionCount,
10934
10984
  viewports: viewports.map((viewport) => ({
10935
10985
  name: viewport.name,
10936
- ok: (viewport.setup_action_results || []).length >= actionCount
10986
+ expected_action_count: expectedActionCountsByViewport[viewport.name] ?? actionCount,
10987
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountsByViewport[viewport.name] ?? actionCount)
10937
10988
  && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
10938
10989
  result_count: (viewport.setup_action_results || []).length,
10939
10990
  })),
10940
- setup_summary: profileSetupSummary(viewports, actionCount),
10991
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport),
10941
10992
  failed,
10942
10993
  },
10943
10994
  message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
@@ -12674,7 +12725,7 @@ async function captureViewport(viewport) {
12674
12725
  await page.waitForTimeout(profile.target.wait_ms);
12675
12726
  }
12676
12727
  const setupActionResults = (!navigationError && !waitError)
12677
- ? await executeSetupActions(profile.target.setup_actions || [], viewport)
12728
+ ? await executeSetupActions(setupActionsForViewport(profile.target.setup_actions || [], viewport.name), viewport)
12678
12729
  : [];
12679
12730
  const dom = await page.evaluate(() => {
12680
12731
  const body = document.body;
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-3RUIKF4C.js";
61
+ } from "./chunk-QC42KDBD.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -269,11 +269,12 @@ function profileScreenshotLabels(viewports) {
269
269
  }
270
270
  return labels;
271
271
  }
272
- function profileSetupSummary(viewports, actionCount) {
272
+ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewport) {
273
273
  return toJsonValue({
274
274
  viewport_count: viewports.length,
275
275
  action_count: actionCount ?? null,
276
276
  viewports: viewports.map((viewport) => {
277
+ const expectedActionCount = expectedActionCountByViewport?.get(viewport.name) ?? actionCount;
277
278
  const results = viewport.setup_action_results || [];
278
279
  const failed = results.filter((result) => result.ok === false);
279
280
  const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -297,7 +298,8 @@ function profileSetupSummary(viewports, actionCount) {
297
298
  })).filter((item) => item.text).slice(-6);
298
299
  return {
299
300
  name: viewport.name,
300
- ok: (actionCount === void 0 ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
301
+ expected_action_count: expectedActionCount ?? null,
302
+ ok: (expectedActionCount === void 0 ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
301
303
  result_count: results.length,
302
304
  observed_path: viewport.route?.observed ?? null,
303
305
  final_url: viewport.url ?? null,
@@ -534,6 +536,7 @@ function normalizeSetupAction(input, index) {
534
536
  repeat: normalizeSetupActionRepeat(input, index),
535
537
  reload: input.reload === true,
536
538
  storage: normalizeSetupActionStorage(input.storage, index),
539
+ viewports: normalizeStringList(input.viewports ?? input.viewport_names ?? input.viewportNames, `target.setup_actions[${index}] viewports`),
537
540
  continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
538
541
  };
539
542
  }
@@ -1106,6 +1109,13 @@ function viewportsForCheck(check, viewports) {
1106
1109
  const names = new Set(check.viewports);
1107
1110
  return viewports.filter((viewport) => names.has(viewport.name));
1108
1111
  }
1112
+ function setupActionAppliesToViewport(action, viewportName) {
1113
+ if (!action.viewports?.length) return true;
1114
+ return Boolean(viewportName && action.viewports.includes(viewportName));
1115
+ }
1116
+ function setupActionsForViewport(actions, viewportName) {
1117
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
1118
+ }
1109
1119
  function assessCheckFromEvidence(check, evidence) {
1110
1120
  const viewports = viewportsForCheck(check, evidence.viewports || []);
1111
1121
  if (!viewports.length) {
@@ -1486,7 +1496,21 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1486
1496
  const actionCount = profile.target.setup_actions.length;
1487
1497
  const failed = [];
1488
1498
  const viewports = evidence.viewports || [];
1499
+ const expectedActionCountByViewport = /* @__PURE__ */ new Map();
1500
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
1501
+ for (const action of profile.target.setup_actions) {
1502
+ if (action.viewports?.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
1503
+ failed.push({
1504
+ viewport: null,
1505
+ action: action.type,
1506
+ selector: action.selector ?? null,
1507
+ reason: `setup action scoped to missing viewport(s): ${action.viewports.join(", ")}`
1508
+ });
1509
+ }
1510
+ }
1489
1511
  for (const viewport of viewports) {
1512
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
1513
+ expectedActionCountByViewport.set(viewport.name, expectedActionCount);
1490
1514
  const results = viewport.setup_action_results || [];
1491
1515
  for (const result of results) {
1492
1516
  if (result.ok === false) {
@@ -1500,12 +1524,12 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1500
1524
  });
1501
1525
  }
1502
1526
  }
1503
- if (results.length < actionCount && results.every((result) => result.ok !== false)) {
1527
+ if (results.length < expectedActionCount && results.every((result) => result.ok !== false)) {
1504
1528
  failed.push({
1505
1529
  viewport: viewport.name,
1506
1530
  action: "setup_actions",
1507
1531
  selector: null,
1508
- reason: `missing setup action results: ${results.length}/${actionCount}`
1532
+ reason: `missing setup action results: ${results.length}/${expectedActionCount}`
1509
1533
  });
1510
1534
  }
1511
1535
  }
@@ -1517,10 +1541,11 @@ function assessSetupActionsFromEvidence(profile, evidence) {
1517
1541
  action_count: actionCount,
1518
1542
  viewports: viewports.map((viewport) => ({
1519
1543
  name: viewport.name,
1520
- ok: (viewport.setup_action_results || []).length >= actionCount && (viewport.setup_action_results || []).every((result) => result.ok !== false),
1544
+ expected_action_count: expectedActionCountByViewport.get(viewport.name) ?? actionCount,
1545
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountByViewport.get(viewport.name) ?? actionCount) && (viewport.setup_action_results || []).every((result) => result.ok !== false),
1521
1546
  result_count: (viewport.setup_action_results || []).length
1522
1547
  })),
1523
- setup_summary: profileSetupSummary(viewports, actionCount),
1548
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountByViewport),
1524
1549
  failed
1525
1550
  },
1526
1551
  message: failed.length ? `Setup actions failed in ${failed.length} viewport action(s).` : void 0
@@ -1906,6 +1931,13 @@ function viewportsForCheck(check, viewports) {
1906
1931
  const names = new Set(check.viewports);
1907
1932
  return viewports.filter((viewport) => names.has(viewport.name));
1908
1933
  }
1934
+ function setupActionAppliesToViewport(action, viewportName) {
1935
+ if (!Array.isArray(action.viewports) || !action.viewports.length) return true;
1936
+ return Boolean(viewportName && action.viewports.includes(viewportName));
1937
+ }
1938
+ function setupActionsForViewport(actions, viewportName) {
1939
+ return (actions || []).filter((action) => setupActionAppliesToViewport(action, viewportName));
1940
+ }
1909
1941
  function summarizeRouteInventory(viewport, inventory) {
1910
1942
  const directRoutes = Array.isArray(inventory.direct_routes) ? inventory.direct_routes : [];
1911
1943
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
@@ -2054,11 +2086,14 @@ function profileScreenshotLabels(viewports) {
2054
2086
  }
2055
2087
  return labels;
2056
2088
  }
2057
- function profileSetupSummary(viewports, actionCount) {
2089
+ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport) {
2058
2090
  return {
2059
2091
  viewport_count: (viewports || []).length,
2060
2092
  action_count: actionCount ?? null,
2061
2093
  viewports: (viewports || []).map((viewport) => {
2094
+ const expectedActionCount = expectedActionCountsByViewport && expectedActionCountsByViewport[viewport.name] !== undefined
2095
+ ? expectedActionCountsByViewport[viewport.name]
2096
+ : actionCount;
2062
2097
  const results = viewport.setup_action_results || [];
2063
2098
  const failed = results.filter((result) => result && result.ok === false);
2064
2099
  const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
@@ -2094,7 +2129,8 @@ function profileSetupSummary(viewports, actionCount) {
2094
2129
  .slice(-6);
2095
2130
  return {
2096
2131
  name: viewport.name,
2097
- ok: (actionCount === undefined ? results.length > 0 : results.length >= actionCount) && failed.length === 0,
2132
+ expected_action_count: expectedActionCount ?? null,
2133
+ ok: (expectedActionCount === undefined ? results.length > 0 : results.length >= expectedActionCount) && failed.length === 0,
2098
2134
  result_count: results.length,
2099
2135
  observed_path: viewport.route && viewport.route.observed || null,
2100
2136
  final_url: viewport.url || null,
@@ -2217,7 +2253,21 @@ function assessProfile(profile, evidence) {
2217
2253
  if (profile.target && Array.isArray(profile.target.setup_actions) && profile.target.setup_actions.length) {
2218
2254
  const actionCount = profile.target.setup_actions.length;
2219
2255
  const failed = [];
2256
+ const expectedActionCountsByViewport = {};
2257
+ const capturedViewportNames = new Set(viewports.map((viewport) => viewport.name));
2258
+ for (const action of profile.target.setup_actions) {
2259
+ if (Array.isArray(action.viewports) && action.viewports.length && !action.viewports.some((name) => capturedViewportNames.has(name))) {
2260
+ failed.push({
2261
+ viewport: null,
2262
+ action: action.type,
2263
+ selector: action.selector || null,
2264
+ reason: "setup action scoped to missing viewport(s): " + action.viewports.join(", "),
2265
+ });
2266
+ }
2267
+ }
2220
2268
  for (const viewport of viewports) {
2269
+ const expectedActionCount = setupActionsForViewport(profile.target.setup_actions, viewport.name).length;
2270
+ expectedActionCountsByViewport[viewport.name] = expectedActionCount;
2221
2271
  const results = viewport.setup_action_results || [];
2222
2272
  for (const result of results) {
2223
2273
  if (result && result.ok === false) {
@@ -2231,12 +2281,12 @@ function assessProfile(profile, evidence) {
2231
2281
  });
2232
2282
  }
2233
2283
  }
2234
- if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
2284
+ if (results.length < expectedActionCount && results.every((result) => !result || result.ok !== false)) {
2235
2285
  failed.push({
2236
2286
  viewport: viewport.name,
2237
2287
  action: "setup_actions",
2238
2288
  selector: null,
2239
- reason: "missing setup action results: " + results.length + "/" + actionCount,
2289
+ reason: "missing setup action results: " + results.length + "/" + expectedActionCount,
2240
2290
  });
2241
2291
  }
2242
2292
  }
@@ -2248,11 +2298,12 @@ function assessProfile(profile, evidence) {
2248
2298
  action_count: actionCount,
2249
2299
  viewports: viewports.map((viewport) => ({
2250
2300
  name: viewport.name,
2251
- ok: (viewport.setup_action_results || []).length >= actionCount
2301
+ expected_action_count: expectedActionCountsByViewport[viewport.name] ?? actionCount,
2302
+ ok: (viewport.setup_action_results || []).length >= (expectedActionCountsByViewport[viewport.name] ?? actionCount)
2252
2303
  && (viewport.setup_action_results || []).every((result) => !result || result.ok !== false),
2253
2304
  result_count: (viewport.setup_action_results || []).length,
2254
2305
  })),
2255
- setup_summary: profileSetupSummary(viewports, actionCount),
2306
+ setup_summary: profileSetupSummary(viewports, actionCount, expectedActionCountsByViewport),
2256
2307
  failed,
2257
2308
  },
2258
2309
  message: failed.length ? "Setup actions failed in " + failed.length + " viewport action(s)." : undefined,
@@ -3989,7 +4040,7 @@ async function captureViewport(viewport) {
3989
4040
  await page.waitForTimeout(profile.target.wait_ms);
3990
4041
  }
3991
4042
  const setupActionResults = (!navigationError && !waitError)
3992
- ? await executeSetupActions(profile.target.setup_actions || [], viewport)
4043
+ ? await executeSetupActions(setupActionsForViewport(profile.target.setup_actions || [], viewport.name), viewport)
3993
4044
  : [];
3994
4045
  const dom = await page.evaluate(() => {
3995
4046
  const body = document.body;
@@ -56,6 +56,7 @@ interface RiddleProofProfileSetupAction {
56
56
  repeat?: number;
57
57
  reload?: boolean;
58
58
  storage?: "local" | "session" | "both";
59
+ viewports?: string[];
59
60
  continue_on_failure?: boolean;
60
61
  }
61
62
  interface RiddleProofProfileNetworkMockResponse {
package/dist/profile.d.ts CHANGED
@@ -56,6 +56,7 @@ interface RiddleProofProfileSetupAction {
56
56
  repeat?: number;
57
57
  reload?: boolean;
58
58
  storage?: "local" | "session" | "both";
59
+ viewports?: string[];
59
60
  continue_on_failure?: boolean;
60
61
  }
61
62
  interface RiddleProofProfileNetworkMockResponse {
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-3RUIKF4C.js";
22
+ } from "./chunk-QC42KDBD.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.82",
3
+ "version": "0.7.84",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",