@riddledc/riddle-proof 0.7.9 → 0.7.10

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
@@ -150,7 +150,9 @@ appears only after a picker, tab, login stub, transport control, or other
150
150
  bounded interaction. Supported setup actions are `click`, `wait`,
151
151
  `wait_for_selector`, and `wait_for_text`; a failed setup action is recorded as
152
152
  a failed `setup_actions_succeeded` check so the profile cannot pass without
153
- reaching the intended state.
153
+ reaching the intended state. Text-matched `click` actions prefer visible
154
+ matching elements, which keeps responsive layouts from selecting hidden desktop
155
+ or mobile-only links.
154
156
 
155
157
  The result uses `riddle-proof.profile-result.v1` and separates product failures
156
158
  from weak proof and environment blockers:
@@ -199,7 +199,13 @@ function resolveRiddleProofProfileTargetUrl(profile) {
199
199
  throw new Error("profile target URL could not be resolved.");
200
200
  }
201
201
  function routeForViewport(viewport) {
202
- return viewport?.route || {
202
+ if (viewport?.route) {
203
+ return {
204
+ ...viewport.route,
205
+ matched: viewport.route.matched || routePathMatches(viewport.route.observed, viewport.route.expected_path)
206
+ };
207
+ }
208
+ return {
203
209
  requested: "",
204
210
  observed: "",
205
211
  matched: false,
@@ -225,8 +231,17 @@ function matchText(sample, check) {
225
231
  }
226
232
  return sample.includes(check.text || "");
227
233
  }
234
+ function normalizeRoutePath(path) {
235
+ const value = path || "/";
236
+ if (value === "/") return "/";
237
+ return value.replace(/\/+$/, "") || "/";
238
+ }
239
+ function routePathMatches(observed, expected) {
240
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
241
+ }
228
242
  function successfulRoute(route) {
229
- return route.matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
243
+ const matched = route.matched || routePathMatches(route.observed, route.expected_path);
244
+ return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
230
245
  }
231
246
  function assessCheckFromEvidence(check, evidence) {
232
247
  const viewports = evidence.viewports || [];
@@ -244,7 +259,7 @@ function assessCheckFromEvidence(check, evidence) {
244
259
  const failed = viewports.filter((viewport) => !successfulRoute({
245
260
  ...viewport.route,
246
261
  expected_path: expectedPath,
247
- matched: viewport.route.observed === expectedPath || viewport.route.matched
262
+ matched: routePathMatches(viewport.route.observed, expectedPath) || viewport.route.matched
248
263
  }));
249
264
  return {
250
265
  type: check.type,
@@ -512,8 +527,16 @@ function createRiddleProofProfileInsufficientResult(input) {
512
527
  }
513
528
  function runtimeScriptAssessmentSource() {
514
529
  return String.raw`
530
+ function normalizeRoutePath(path) {
531
+ const value = path || "/";
532
+ if (value === "/") return "/";
533
+ return value.replace(/\/+$/, "") || "/";
534
+ }
535
+ function routePathMatches(observed, expected) {
536
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
537
+ }
515
538
  function routeOk(route) {
516
- return Boolean(route && route.matched && !route.error && (route.http_status == null || route.http_status < 400));
539
+ return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path)) && !route.error && (route.http_status == null || route.http_status < 400));
517
540
  }
518
541
  function textMatches(sample, check) {
519
542
  if (check.pattern) {
@@ -570,7 +593,7 @@ function assessProfile(profile, evidence) {
570
593
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
571
594
  const failed = viewports.filter((viewport) => {
572
595
  const route = { ...(viewport.route || {}), expected_path: expectedPath };
573
- route.matched = route.observed === expectedPath || route.matched;
596
+ route.matched = routePathMatches(route.observed, expectedPath) || route.matched;
574
597
  return !routeOk(route);
575
598
  });
576
599
  checks.push({
@@ -743,6 +766,9 @@ function setupTextMatches(sample, action) {
743
766
  async function setupLocatorText(locator, index) {
744
767
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
745
768
  }
769
+ async function setupLocatorVisible(locator, index) {
770
+ return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
771
+ }
746
772
  async function executeSetupAction(action, ordinal) {
747
773
  const type = setupActionType(action);
748
774
  const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
@@ -763,16 +789,26 @@ async function executeSetupAction(action, ordinal) {
763
789
  if (!count) return { ...base, reason: "selector_not_found", count };
764
790
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
765
791
  let matchedText = null;
792
+ let hiddenMatchIndex = -1;
793
+ let hiddenMatchedText = null;
766
794
  if (action.text || action.pattern) {
767
795
  targetIndex = -1;
768
796
  for (let index = 0; index < count; index += 1) {
769
797
  const text = await setupLocatorText(locator, index);
770
798
  if (setupTextMatches(text, action)) {
771
- targetIndex = index;
772
- matchedText = text;
773
- break;
799
+ const visible = await setupLocatorVisible(locator, index);
800
+ if (visible) {
801
+ targetIndex = index;
802
+ matchedText = text;
803
+ break;
804
+ }
805
+ if (hiddenMatchIndex < 0) {
806
+ hiddenMatchIndex = index;
807
+ hiddenMatchedText = text;
808
+ }
774
809
  }
775
810
  }
811
+ if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
776
812
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
777
813
  }
778
814
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
@@ -899,7 +935,7 @@ async function captureViewport(viewport) {
899
935
  requested: targetUrl,
900
936
  observed: dom.pathname,
901
937
  expected_path: expectedPath,
902
- matched: dom.pathname === expectedPath,
938
+ matched: routePathMatches(dom.pathname, expectedPath),
903
939
  http_status: httpStatus,
904
940
  error: navigationError || waitError || undefined,
905
941
  },
package/dist/cli.cjs CHANGED
@@ -6978,7 +6978,13 @@ function resolveRiddleProofProfileTargetUrl(profile) {
6978
6978
  throw new Error("profile target URL could not be resolved.");
6979
6979
  }
6980
6980
  function routeForViewport(viewport) {
6981
- return viewport?.route || {
6981
+ if (viewport?.route) {
6982
+ return {
6983
+ ...viewport.route,
6984
+ matched: viewport.route.matched || routePathMatches(viewport.route.observed, viewport.route.expected_path)
6985
+ };
6986
+ }
6987
+ return {
6982
6988
  requested: "",
6983
6989
  observed: "",
6984
6990
  matched: false,
@@ -7004,8 +7010,17 @@ function matchText(sample, check) {
7004
7010
  }
7005
7011
  return sample.includes(check.text || "");
7006
7012
  }
7013
+ function normalizeRoutePath(path7) {
7014
+ const value = path7 || "/";
7015
+ if (value === "/") return "/";
7016
+ return value.replace(/\/+$/, "") || "/";
7017
+ }
7018
+ function routePathMatches(observed, expected) {
7019
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
7020
+ }
7007
7021
  function successfulRoute(route) {
7008
- return route.matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
7022
+ const matched = route.matched || routePathMatches(route.observed, route.expected_path);
7023
+ return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
7009
7024
  }
7010
7025
  function assessCheckFromEvidence(check, evidence) {
7011
7026
  const viewports = evidence.viewports || [];
@@ -7023,7 +7038,7 @@ function assessCheckFromEvidence(check, evidence) {
7023
7038
  const failed = viewports.filter((viewport) => !successfulRoute({
7024
7039
  ...viewport.route,
7025
7040
  expected_path: expectedPath,
7026
- matched: viewport.route.observed === expectedPath || viewport.route.matched
7041
+ matched: routePathMatches(viewport.route.observed, expectedPath) || viewport.route.matched
7027
7042
  }));
7028
7043
  return {
7029
7044
  type: check.type,
@@ -7275,8 +7290,16 @@ function createRiddleProofProfileInsufficientResult(input) {
7275
7290
  }
7276
7291
  function runtimeScriptAssessmentSource() {
7277
7292
  return String.raw`
7293
+ function normalizeRoutePath(path) {
7294
+ const value = path || "/";
7295
+ if (value === "/") return "/";
7296
+ return value.replace(/\/+$/, "") || "/";
7297
+ }
7298
+ function routePathMatches(observed, expected) {
7299
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
7300
+ }
7278
7301
  function routeOk(route) {
7279
- return Boolean(route && route.matched && !route.error && (route.http_status == null || route.http_status < 400));
7302
+ return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path)) && !route.error && (route.http_status == null || route.http_status < 400));
7280
7303
  }
7281
7304
  function textMatches(sample, check) {
7282
7305
  if (check.pattern) {
@@ -7333,7 +7356,7 @@ function assessProfile(profile, evidence) {
7333
7356
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
7334
7357
  const failed = viewports.filter((viewport) => {
7335
7358
  const route = { ...(viewport.route || {}), expected_path: expectedPath };
7336
- route.matched = route.observed === expectedPath || route.matched;
7359
+ route.matched = routePathMatches(route.observed, expectedPath) || route.matched;
7337
7360
  return !routeOk(route);
7338
7361
  });
7339
7362
  checks.push({
@@ -7506,6 +7529,9 @@ function setupTextMatches(sample, action) {
7506
7529
  async function setupLocatorText(locator, index) {
7507
7530
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
7508
7531
  }
7532
+ async function setupLocatorVisible(locator, index) {
7533
+ return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
7534
+ }
7509
7535
  async function executeSetupAction(action, ordinal) {
7510
7536
  const type = setupActionType(action);
7511
7537
  const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
@@ -7526,16 +7552,26 @@ async function executeSetupAction(action, ordinal) {
7526
7552
  if (!count) return { ...base, reason: "selector_not_found", count };
7527
7553
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
7528
7554
  let matchedText = null;
7555
+ let hiddenMatchIndex = -1;
7556
+ let hiddenMatchedText = null;
7529
7557
  if (action.text || action.pattern) {
7530
7558
  targetIndex = -1;
7531
7559
  for (let index = 0; index < count; index += 1) {
7532
7560
  const text = await setupLocatorText(locator, index);
7533
7561
  if (setupTextMatches(text, action)) {
7534
- targetIndex = index;
7535
- matchedText = text;
7536
- break;
7562
+ const visible = await setupLocatorVisible(locator, index);
7563
+ if (visible) {
7564
+ targetIndex = index;
7565
+ matchedText = text;
7566
+ break;
7567
+ }
7568
+ if (hiddenMatchIndex < 0) {
7569
+ hiddenMatchIndex = index;
7570
+ hiddenMatchedText = text;
7571
+ }
7537
7572
  }
7538
7573
  }
7574
+ if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
7539
7575
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
7540
7576
  }
7541
7577
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
@@ -7662,7 +7698,7 @@ async function captureViewport(viewport) {
7662
7698
  requested: targetUrl,
7663
7699
  observed: dom.pathname,
7664
7700
  expected_path: expectedPath,
7665
- matched: dom.pathname === expectedPath,
7701
+ matched: routePathMatches(dom.pathname, expectedPath),
7666
7702
  http_status: httpStatus,
7667
7703
  error: navigationError || waitError || undefined,
7668
7704
  },
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  normalizeRiddleProofProfile,
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl
12
- } from "./chunk-NUSUGO2P.js";
12
+ } from "./chunk-A7RJZD4I.js";
13
13
  import {
14
14
  createRiddleApiClient,
15
15
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8705,7 +8705,13 @@ function resolveRiddleProofProfileTargetUrl(profile) {
8705
8705
  throw new Error("profile target URL could not be resolved.");
8706
8706
  }
8707
8707
  function routeForViewport(viewport) {
8708
- return viewport?.route || {
8708
+ if (viewport?.route) {
8709
+ return {
8710
+ ...viewport.route,
8711
+ matched: viewport.route.matched || routePathMatches(viewport.route.observed, viewport.route.expected_path)
8712
+ };
8713
+ }
8714
+ return {
8709
8715
  requested: "",
8710
8716
  observed: "",
8711
8717
  matched: false,
@@ -8731,8 +8737,17 @@ function matchText(sample, check) {
8731
8737
  }
8732
8738
  return sample.includes(check.text || "");
8733
8739
  }
8740
+ function normalizeRoutePath(path6) {
8741
+ const value = path6 || "/";
8742
+ if (value === "/") return "/";
8743
+ return value.replace(/\/+$/, "") || "/";
8744
+ }
8745
+ function routePathMatches(observed, expected) {
8746
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
8747
+ }
8734
8748
  function successfulRoute(route) {
8735
- return route.matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
8749
+ const matched = route.matched || routePathMatches(route.observed, route.expected_path);
8750
+ return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
8736
8751
  }
8737
8752
  function assessCheckFromEvidence(check, evidence) {
8738
8753
  const viewports = evidence.viewports || [];
@@ -8750,7 +8765,7 @@ function assessCheckFromEvidence(check, evidence) {
8750
8765
  const failed = viewports.filter((viewport) => !successfulRoute({
8751
8766
  ...viewport.route,
8752
8767
  expected_path: expectedPath,
8753
- matched: viewport.route.observed === expectedPath || viewport.route.matched
8768
+ matched: routePathMatches(viewport.route.observed, expectedPath) || viewport.route.matched
8754
8769
  }));
8755
8770
  return {
8756
8771
  type: check.type,
@@ -9018,8 +9033,16 @@ function createRiddleProofProfileInsufficientResult(input) {
9018
9033
  }
9019
9034
  function runtimeScriptAssessmentSource() {
9020
9035
  return String.raw`
9036
+ function normalizeRoutePath(path) {
9037
+ const value = path || "/";
9038
+ if (value === "/") return "/";
9039
+ return value.replace(/\/+$/, "") || "/";
9040
+ }
9041
+ function routePathMatches(observed, expected) {
9042
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
9043
+ }
9021
9044
  function routeOk(route) {
9022
- return Boolean(route && route.matched && !route.error && (route.http_status == null || route.http_status < 400));
9045
+ return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path)) && !route.error && (route.http_status == null || route.http_status < 400));
9023
9046
  }
9024
9047
  function textMatches(sample, check) {
9025
9048
  if (check.pattern) {
@@ -9076,7 +9099,7 @@ function assessProfile(profile, evidence) {
9076
9099
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
9077
9100
  const failed = viewports.filter((viewport) => {
9078
9101
  const route = { ...(viewport.route || {}), expected_path: expectedPath };
9079
- route.matched = route.observed === expectedPath || route.matched;
9102
+ route.matched = routePathMatches(route.observed, expectedPath) || route.matched;
9080
9103
  return !routeOk(route);
9081
9104
  });
9082
9105
  checks.push({
@@ -9249,6 +9272,9 @@ function setupTextMatches(sample, action) {
9249
9272
  async function setupLocatorText(locator, index) {
9250
9273
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
9251
9274
  }
9275
+ async function setupLocatorVisible(locator, index) {
9276
+ return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
9277
+ }
9252
9278
  async function executeSetupAction(action, ordinal) {
9253
9279
  const type = setupActionType(action);
9254
9280
  const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
@@ -9269,16 +9295,26 @@ async function executeSetupAction(action, ordinal) {
9269
9295
  if (!count) return { ...base, reason: "selector_not_found", count };
9270
9296
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
9271
9297
  let matchedText = null;
9298
+ let hiddenMatchIndex = -1;
9299
+ let hiddenMatchedText = null;
9272
9300
  if (action.text || action.pattern) {
9273
9301
  targetIndex = -1;
9274
9302
  for (let index = 0; index < count; index += 1) {
9275
9303
  const text = await setupLocatorText(locator, index);
9276
9304
  if (setupTextMatches(text, action)) {
9277
- targetIndex = index;
9278
- matchedText = text;
9279
- break;
9305
+ const visible = await setupLocatorVisible(locator, index);
9306
+ if (visible) {
9307
+ targetIndex = index;
9308
+ matchedText = text;
9309
+ break;
9310
+ }
9311
+ if (hiddenMatchIndex < 0) {
9312
+ hiddenMatchIndex = index;
9313
+ hiddenMatchedText = text;
9314
+ }
9280
9315
  }
9281
9316
  }
9317
+ if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
9282
9318
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
9283
9319
  }
9284
9320
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
@@ -9405,7 +9441,7 @@ async function captureViewport(viewport) {
9405
9441
  requested: targetUrl,
9406
9442
  observed: dom.pathname,
9407
9443
  expected_path: expectedPath,
9408
- matched: dom.pathname === expectedPath,
9444
+ matched: routePathMatches(dom.pathname, expectedPath),
9409
9445
  http_status: httpStatus,
9410
9446
  error: navigationError || waitError || undefined,
9411
9447
  },
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ import {
56
56
  resolveRiddleProofProfileTargetUrl,
57
57
  slugifyRiddleProofProfileName,
58
58
  summarizeRiddleProofProfileResult
59
- } from "./chunk-NUSUGO2P.js";
59
+ } from "./chunk-A7RJZD4I.js";
60
60
  import {
61
61
  DEFAULT_RIDDLE_API_BASE_URL,
62
62
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -240,7 +240,13 @@ function resolveRiddleProofProfileTargetUrl(profile) {
240
240
  throw new Error("profile target URL could not be resolved.");
241
241
  }
242
242
  function routeForViewport(viewport) {
243
- return viewport?.route || {
243
+ if (viewport?.route) {
244
+ return {
245
+ ...viewport.route,
246
+ matched: viewport.route.matched || routePathMatches(viewport.route.observed, viewport.route.expected_path)
247
+ };
248
+ }
249
+ return {
244
250
  requested: "",
245
251
  observed: "",
246
252
  matched: false,
@@ -266,8 +272,17 @@ function matchText(sample, check) {
266
272
  }
267
273
  return sample.includes(check.text || "");
268
274
  }
275
+ function normalizeRoutePath(path) {
276
+ const value = path || "/";
277
+ if (value === "/") return "/";
278
+ return value.replace(/\/+$/, "") || "/";
279
+ }
280
+ function routePathMatches(observed, expected) {
281
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
282
+ }
269
283
  function successfulRoute(route) {
270
- return route.matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
284
+ const matched = route.matched || routePathMatches(route.observed, route.expected_path);
285
+ return matched && !route.error && (route.http_status === null || route.http_status === void 0 || route.http_status < 400);
271
286
  }
272
287
  function assessCheckFromEvidence(check, evidence) {
273
288
  const viewports = evidence.viewports || [];
@@ -285,7 +300,7 @@ function assessCheckFromEvidence(check, evidence) {
285
300
  const failed = viewports.filter((viewport) => !successfulRoute({
286
301
  ...viewport.route,
287
302
  expected_path: expectedPath,
288
- matched: viewport.route.observed === expectedPath || viewport.route.matched
303
+ matched: routePathMatches(viewport.route.observed, expectedPath) || viewport.route.matched
289
304
  }));
290
305
  return {
291
306
  type: check.type,
@@ -553,8 +568,16 @@ function createRiddleProofProfileInsufficientResult(input) {
553
568
  }
554
569
  function runtimeScriptAssessmentSource() {
555
570
  return String.raw`
571
+ function normalizeRoutePath(path) {
572
+ const value = path || "/";
573
+ if (value === "/") return "/";
574
+ return value.replace(/\/+$/, "") || "/";
575
+ }
576
+ function routePathMatches(observed, expected) {
577
+ return normalizeRoutePath(observed) === normalizeRoutePath(expected);
578
+ }
556
579
  function routeOk(route) {
557
- return Boolean(route && route.matched && !route.error && (route.http_status == null || route.http_status < 400));
580
+ return Boolean(route && (route.matched || routePathMatches(route.observed, route.expected_path)) && !route.error && (route.http_status == null || route.http_status < 400));
558
581
  }
559
582
  function textMatches(sample, check) {
560
583
  if (check.pattern) {
@@ -611,7 +634,7 @@ function assessProfile(profile, evidence) {
611
634
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
612
635
  const failed = viewports.filter((viewport) => {
613
636
  const route = { ...(viewport.route || {}), expected_path: expectedPath };
614
- route.matched = route.observed === expectedPath || route.matched;
637
+ route.matched = routePathMatches(route.observed, expectedPath) || route.matched;
615
638
  return !routeOk(route);
616
639
  });
617
640
  checks.push({
@@ -784,6 +807,9 @@ function setupTextMatches(sample, action) {
784
807
  async function setupLocatorText(locator, index) {
785
808
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
786
809
  }
810
+ async function setupLocatorVisible(locator, index) {
811
+ return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
812
+ }
787
813
  async function executeSetupAction(action, ordinal) {
788
814
  const type = setupActionType(action);
789
815
  const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null };
@@ -804,16 +830,26 @@ async function executeSetupAction(action, ordinal) {
804
830
  if (!count) return { ...base, reason: "selector_not_found", count };
805
831
  let targetIndex = Number.isInteger(action.index) ? action.index : 0;
806
832
  let matchedText = null;
833
+ let hiddenMatchIndex = -1;
834
+ let hiddenMatchedText = null;
807
835
  if (action.text || action.pattern) {
808
836
  targetIndex = -1;
809
837
  for (let index = 0; index < count; index += 1) {
810
838
  const text = await setupLocatorText(locator, index);
811
839
  if (setupTextMatches(text, action)) {
812
- targetIndex = index;
813
- matchedText = text;
814
- break;
840
+ const visible = await setupLocatorVisible(locator, index);
841
+ if (visible) {
842
+ targetIndex = index;
843
+ matchedText = text;
844
+ break;
845
+ }
846
+ if (hiddenMatchIndex < 0) {
847
+ hiddenMatchIndex = index;
848
+ hiddenMatchedText = text;
849
+ }
815
850
  }
816
851
  }
852
+ if (targetIndex < 0 && hiddenMatchIndex >= 0) return { ...base, reason: "matching_element_not_visible", count, target_index: hiddenMatchIndex, text: hiddenMatchedText };
817
853
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
818
854
  }
819
855
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
@@ -940,7 +976,7 @@ async function captureViewport(viewport) {
940
976
  requested: targetUrl,
941
977
  observed: dom.pathname,
942
978
  expected_path: expectedPath,
943
- matched: dom.pathname === expectedPath,
979
+ matched: routePathMatches(dom.pathname, expectedPath),
944
980
  http_status: httpStatus,
945
981
  error: navigationError || waitError || undefined,
946
982
  },
package/dist/profile.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  resolveRiddleProofProfileTargetUrl,
18
18
  slugifyRiddleProofProfileName,
19
19
  summarizeRiddleProofProfileResult
20
- } from "./chunk-NUSUGO2P.js";
20
+ } from "./chunk-A7RJZD4I.js";
21
21
  export {
22
22
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
23
23
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.9",
3
+ "version": "0.7.10",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",