@riddledc/riddle-proof 0.7.93 → 0.7.94

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
@@ -163,6 +163,7 @@ or as a stronger proof base before a change loop.
163
163
  { "type": "selector_visible", "selector": "[data-testid='pricing-cards']" },
164
164
  { "type": "selector_absent", "selector": "[data-testid='loading-spinner']" },
165
165
  { "type": "selector_count_equals", "selector": "[data-testid='pricing-card']", "expected_count": 3 },
166
+ { "type": "selector_text_visible", "selector": "[data-testid='pricing-cards']", "text": "Pro" },
166
167
  { "type": "text_visible", "text": "Start building" },
167
168
  { "type": "text_visible", "text": "Compare plans", "viewports": ["desktop"] },
168
169
  { "type": "no_mobile_horizontal_overflow" },
@@ -417,6 +418,22 @@ The check records the visible text sequence for the selector and passes when
417
418
  the expected texts appear in that order as a subsequence. This is less brittle
418
419
  than matching one large body-text regex when only row or card order matters.
419
420
 
421
+ Use `selector_text_visible` and `selector_text_absent` when the durable
422
+ assertion belongs to one panel, code sample, result area, or card group rather
423
+ than the whole page:
424
+
425
+ ```json
426
+ {
427
+ "type": "selector_text_visible",
428
+ "selector": ".result-state",
429
+ "text": "\"sync\": false"
430
+ }
431
+ ```
432
+
433
+ The check records visible text for the selector in each viewport and reports
434
+ matched counts plus short samples, which makes generated-command and evidence
435
+ card audits easier to diagnose than global `text_visible` checks.
436
+
420
437
  Use `frame_text_visible` and `frame_no_horizontal_overflow` for embedded app,
421
438
  game, or preview surfaces that render inside iframes:
422
439
 
@@ -20,6 +20,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
20
20
  "selector_count_equals",
21
21
  "selector_count_equal",
22
22
  "selector_count_eq",
23
+ "selector_text_visible",
24
+ "selector_text_absent",
23
25
  "selector_text_order",
24
26
  "frame_text_visible",
25
27
  "frame_url_equals",
@@ -733,7 +735,7 @@ function normalizeCheck(input, index) {
733
735
  if (!isSupportedCheckType(type)) {
734
736
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
735
737
  }
736
- if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue(input.selector)) {
738
+ if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue(input.selector)) {
737
739
  throw new Error(`checks[${index}] ${type} requires selector.`);
738
740
  }
739
741
  if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue(input.selector)) {
@@ -749,7 +751,7 @@ function normalizeCheck(input, index) {
749
751
  if (type === "frame_url_matches" && !stringValue(input.pattern)) {
750
752
  throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
751
753
  }
752
- if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
754
+ if ((type === "text_visible" || type === "text_absent" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
753
755
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
754
756
  }
755
757
  if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
@@ -1015,9 +1017,11 @@ function textSequenceForCheck(viewport, check) {
1015
1017
  const key = selectorKey(check);
1016
1018
  const sequence = viewport.text_sequences?.[key];
1017
1019
  if (isRecord(sequence)) {
1020
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
1021
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
1018
1022
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
1019
1023
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
1020
- const candidates = visibleTexts.length ? visibleTexts : texts;
1024
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
1021
1025
  return candidates.map((text) => String(text).replace(/\s+/g, " ").trim()).filter(Boolean);
1022
1026
  }
1023
1027
  return [];
@@ -1351,6 +1355,35 @@ function assessCheckFromEvidence(check, evidence) {
1351
1355
  message: failed.length ? `Selector ${key} count did not equal ${expectedCount} in ${failed.length} viewport(s).` : void 0
1352
1356
  };
1353
1357
  }
1358
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
1359
+ const key = selectorKey(check);
1360
+ const expectedVisible = check.type === "selector_text_visible";
1361
+ const results = viewports.map((viewport) => {
1362
+ const texts = textSequenceForCheck(viewport, check);
1363
+ const matches = texts.filter((text) => matchText(text, check));
1364
+ return {
1365
+ viewport: viewport.name,
1366
+ selector_count: viewport.selectors?.[key]?.count || 0,
1367
+ visible_count: viewport.selectors?.[key]?.visible_count || 0,
1368
+ matched_count: matches.length,
1369
+ matched: matches.length > 0,
1370
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240))
1371
+ };
1372
+ });
1373
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
1374
+ return {
1375
+ type: check.type,
1376
+ label: checkLabel(check),
1377
+ status: failed ? "failed" : "passed",
1378
+ evidence: {
1379
+ selector: key,
1380
+ text: check.text || null,
1381
+ pattern: check.pattern || null,
1382
+ viewports: results.map((result) => toJsonValue(result))
1383
+ },
1384
+ message: failed ? `Selector ${key} text assertion failed in ${failed} viewport(s).` : void 0
1385
+ };
1386
+ }
1354
1387
  if (check.type === "selector_text_order") {
1355
1388
  const key = selectorKey(check);
1356
1389
  const expectedTexts = check.expected_texts || [];
@@ -1361,7 +1394,7 @@ function assessCheckFromEvidence(check, evidence) {
1361
1394
  viewport: viewport.name,
1362
1395
  matched: match.matched,
1363
1396
  matched_positions: match.positions,
1364
- visible_texts: texts.slice(0, 20)
1397
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240))
1365
1398
  };
1366
1399
  });
1367
1400
  const failed = results.filter((result) => !result.matched).length;
@@ -2071,9 +2104,11 @@ function textSequenceForCheck(viewport, check) {
2071
2104
  const key = check.selector || "";
2072
2105
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
2073
2106
  if (sequence && typeof sequence === "object") {
2107
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
2108
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
2074
2109
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
2075
2110
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
2076
- const candidates = visibleTexts.length ? visibleTexts : texts;
2111
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
2077
2112
  return candidates.map((text) => String(text || "").replace(/\s+/g, " ").trim()).filter(Boolean);
2078
2113
  }
2079
2114
  return [];
@@ -2711,6 +2746,31 @@ function assessProfile(profile, evidence) {
2711
2746
  });
2712
2747
  continue;
2713
2748
  }
2749
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
2750
+ const selector = check.selector || "";
2751
+ const expectedVisible = check.type === "selector_text_visible";
2752
+ const results = checkViewports.map((viewport) => {
2753
+ const texts = textSequenceForCheck(viewport, check);
2754
+ const matches = texts.filter((text) => textMatches(text, check));
2755
+ return {
2756
+ viewport: viewport.name,
2757
+ selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
2758
+ visible_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].visible_count : 0,
2759
+ matched_count: matches.length,
2760
+ matched: matches.length > 0,
2761
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240)),
2762
+ };
2763
+ });
2764
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
2765
+ checks.push({
2766
+ type: check.type,
2767
+ label: check.label || check.type,
2768
+ status: failed ? "failed" : "passed",
2769
+ evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
2770
+ message: failed ? "Selector " + selector + " text assertion failed in " + failed + " viewport(s)." : undefined,
2771
+ });
2772
+ continue;
2773
+ }
2714
2774
  if (check.type === "selector_text_order") {
2715
2775
  const selector = check.selector || "";
2716
2776
  const expectedTexts = check.expected_texts || [];
@@ -2721,7 +2781,7 @@ function assessProfile(profile, evidence) {
2721
2781
  viewport: viewport.name,
2722
2782
  matched: match.matched,
2723
2783
  matched_positions: match.positions,
2724
- visible_texts: texts.slice(0, 20),
2784
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240)),
2725
2785
  };
2726
2786
  });
2727
2787
  const failed = results.filter((result) => !result.matched).length;
@@ -3925,6 +3985,7 @@ async function selectorStats(selector) {
3925
3985
  async function selectorTextSequence(selector) {
3926
3986
  return page.locator(selector).evaluateAll((elements) => {
3927
3987
  const compact = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 240);
3988
+ const matchText = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 8000);
3928
3989
  const isVisible = (element) => {
3929
3990
  const style = window.getComputedStyle(element);
3930
3991
  const rect = element.getBoundingClientRect();
@@ -3933,6 +3994,7 @@ async function selectorTextSequence(selector) {
3933
3994
  const rows = elements.map((element, index) => ({
3934
3995
  index,
3935
3996
  text: compact(element.innerText || element.textContent || ""),
3997
+ match_text: matchText(element.innerText || element.textContent || ""),
3936
3998
  visible: isVisible(element),
3937
3999
  }));
3938
4000
  return {
@@ -3940,8 +4002,10 @@ async function selectorTextSequence(selector) {
3940
4002
  visible_count: rows.filter((row) => row.visible).length,
3941
4003
  texts: rows.map((row) => row.text).filter(Boolean).slice(0, 40),
3942
4004
  visible_texts: rows.filter((row) => row.visible).map((row) => row.text).filter(Boolean).slice(0, 40),
4005
+ match_texts: rows.map((row) => row.match_text).filter(Boolean).slice(0, 40),
4006
+ visible_match_texts: rows.filter((row) => row.visible).map((row) => row.match_text).filter(Boolean).slice(0, 40),
3943
4007
  };
3944
- }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
4008
+ }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], match_texts: [], visible_match_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
3945
4009
  }
3946
4010
  function linkProbeMaxLinks(check) {
3947
4011
  const value = Number(check.max_links || check.maxLinks || check.limit || 100);
@@ -4677,7 +4741,7 @@ async function captureViewport(viewport) {
4677
4741
  ) {
4678
4742
  selectors[check.selector] = await selectorStats(check.selector);
4679
4743
  }
4680
- if (check.type === "selector_text_order" && check.selector) {
4744
+ if ((check.type === "selector_text_order" || check.type === "selector_text_visible" || check.type === "selector_text_absent") && check.selector) {
4681
4745
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
4682
4746
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
4683
4747
  }
package/dist/cli.cjs CHANGED
@@ -6913,6 +6913,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
6913
6913
  "selector_count_equals",
6914
6914
  "selector_count_equal",
6915
6915
  "selector_count_eq",
6916
+ "selector_text_visible",
6917
+ "selector_text_absent",
6916
6918
  "selector_text_order",
6917
6919
  "frame_text_visible",
6918
6920
  "frame_url_equals",
@@ -7626,7 +7628,7 @@ function normalizeCheck(input, index) {
7626
7628
  if (!isSupportedCheckType(type)) {
7627
7629
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
7628
7630
  }
7629
- if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue2(input.selector)) {
7631
+ if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue2(input.selector)) {
7630
7632
  throw new Error(`checks[${index}] ${type} requires selector.`);
7631
7633
  }
7632
7634
  if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue2(input.selector)) {
@@ -7642,7 +7644,7 @@ function normalizeCheck(input, index) {
7642
7644
  if (type === "frame_url_matches" && !stringValue2(input.pattern)) {
7643
7645
  throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
7644
7646
  }
7645
- if ((type === "text_visible" || type === "text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
7647
+ if ((type === "text_visible" || type === "text_absent" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
7646
7648
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
7647
7649
  }
7648
7650
  if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue2(input.param) && !stringValue2(input.search_param) && !stringValue2(input.searchParam) && !stringValue2(input.key)) {
@@ -7908,9 +7910,11 @@ function textSequenceForCheck(viewport, check) {
7908
7910
  const key = selectorKey(check);
7909
7911
  const sequence = viewport.text_sequences?.[key];
7910
7912
  if (isRecord(sequence)) {
7913
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
7914
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
7911
7915
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
7912
7916
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
7913
- const candidates = visibleTexts.length ? visibleTexts : texts;
7917
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
7914
7918
  return candidates.map((text) => String(text).replace(/\s+/g, " ").trim()).filter(Boolean);
7915
7919
  }
7916
7920
  return [];
@@ -8244,6 +8248,35 @@ function assessCheckFromEvidence(check, evidence) {
8244
8248
  message: failed.length ? `Selector ${key} count did not equal ${expectedCount} in ${failed.length} viewport(s).` : void 0
8245
8249
  };
8246
8250
  }
8251
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
8252
+ const key = selectorKey(check);
8253
+ const expectedVisible = check.type === "selector_text_visible";
8254
+ const results = viewports.map((viewport) => {
8255
+ const texts = textSequenceForCheck(viewport, check);
8256
+ const matches = texts.filter((text) => matchText(text, check));
8257
+ return {
8258
+ viewport: viewport.name,
8259
+ selector_count: viewport.selectors?.[key]?.count || 0,
8260
+ visible_count: viewport.selectors?.[key]?.visible_count || 0,
8261
+ matched_count: matches.length,
8262
+ matched: matches.length > 0,
8263
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240))
8264
+ };
8265
+ });
8266
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
8267
+ return {
8268
+ type: check.type,
8269
+ label: checkLabel(check),
8270
+ status: failed ? "failed" : "passed",
8271
+ evidence: {
8272
+ selector: key,
8273
+ text: check.text || null,
8274
+ pattern: check.pattern || null,
8275
+ viewports: results.map((result) => toJsonValue(result))
8276
+ },
8277
+ message: failed ? `Selector ${key} text assertion failed in ${failed} viewport(s).` : void 0
8278
+ };
8279
+ }
8247
8280
  if (check.type === "selector_text_order") {
8248
8281
  const key = selectorKey(check);
8249
8282
  const expectedTexts = check.expected_texts || [];
@@ -8254,7 +8287,7 @@ function assessCheckFromEvidence(check, evidence) {
8254
8287
  viewport: viewport.name,
8255
8288
  matched: match.matched,
8256
8289
  matched_positions: match.positions,
8257
- visible_texts: texts.slice(0, 20)
8290
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240))
8258
8291
  };
8259
8292
  });
8260
8293
  const failed = results.filter((result) => !result.matched).length;
@@ -8948,9 +8981,11 @@ function textSequenceForCheck(viewport, check) {
8948
8981
  const key = check.selector || "";
8949
8982
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
8950
8983
  if (sequence && typeof sequence === "object") {
8984
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
8985
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
8951
8986
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
8952
8987
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
8953
- const candidates = visibleTexts.length ? visibleTexts : texts;
8988
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
8954
8989
  return candidates.map((text) => String(text || "").replace(/\s+/g, " ").trim()).filter(Boolean);
8955
8990
  }
8956
8991
  return [];
@@ -9588,6 +9623,31 @@ function assessProfile(profile, evidence) {
9588
9623
  });
9589
9624
  continue;
9590
9625
  }
9626
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
9627
+ const selector = check.selector || "";
9628
+ const expectedVisible = check.type === "selector_text_visible";
9629
+ const results = checkViewports.map((viewport) => {
9630
+ const texts = textSequenceForCheck(viewport, check);
9631
+ const matches = texts.filter((text) => textMatches(text, check));
9632
+ return {
9633
+ viewport: viewport.name,
9634
+ selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
9635
+ visible_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].visible_count : 0,
9636
+ matched_count: matches.length,
9637
+ matched: matches.length > 0,
9638
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240)),
9639
+ };
9640
+ });
9641
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
9642
+ checks.push({
9643
+ type: check.type,
9644
+ label: check.label || check.type,
9645
+ status: failed ? "failed" : "passed",
9646
+ evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
9647
+ message: failed ? "Selector " + selector + " text assertion failed in " + failed + " viewport(s)." : undefined,
9648
+ });
9649
+ continue;
9650
+ }
9591
9651
  if (check.type === "selector_text_order") {
9592
9652
  const selector = check.selector || "";
9593
9653
  const expectedTexts = check.expected_texts || [];
@@ -9598,7 +9658,7 @@ function assessProfile(profile, evidence) {
9598
9658
  viewport: viewport.name,
9599
9659
  matched: match.matched,
9600
9660
  matched_positions: match.positions,
9601
- visible_texts: texts.slice(0, 20),
9661
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240)),
9602
9662
  };
9603
9663
  });
9604
9664
  const failed = results.filter((result) => !result.matched).length;
@@ -10802,6 +10862,7 @@ async function selectorStats(selector) {
10802
10862
  async function selectorTextSequence(selector) {
10803
10863
  return page.locator(selector).evaluateAll((elements) => {
10804
10864
  const compact = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 240);
10865
+ const matchText = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 8000);
10805
10866
  const isVisible = (element) => {
10806
10867
  const style = window.getComputedStyle(element);
10807
10868
  const rect = element.getBoundingClientRect();
@@ -10810,6 +10871,7 @@ async function selectorTextSequence(selector) {
10810
10871
  const rows = elements.map((element, index) => ({
10811
10872
  index,
10812
10873
  text: compact(element.innerText || element.textContent || ""),
10874
+ match_text: matchText(element.innerText || element.textContent || ""),
10813
10875
  visible: isVisible(element),
10814
10876
  }));
10815
10877
  return {
@@ -10817,8 +10879,10 @@ async function selectorTextSequence(selector) {
10817
10879
  visible_count: rows.filter((row) => row.visible).length,
10818
10880
  texts: rows.map((row) => row.text).filter(Boolean).slice(0, 40),
10819
10881
  visible_texts: rows.filter((row) => row.visible).map((row) => row.text).filter(Boolean).slice(0, 40),
10882
+ match_texts: rows.map((row) => row.match_text).filter(Boolean).slice(0, 40),
10883
+ visible_match_texts: rows.filter((row) => row.visible).map((row) => row.match_text).filter(Boolean).slice(0, 40),
10820
10884
  };
10821
- }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
10885
+ }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], match_texts: [], visible_match_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
10822
10886
  }
10823
10887
  function linkProbeMaxLinks(check) {
10824
10888
  const value = Number(check.max_links || check.maxLinks || check.limit || 100);
@@ -11554,7 +11618,7 @@ async function captureViewport(viewport) {
11554
11618
  ) {
11555
11619
  selectors[check.selector] = await selectorStats(check.selector);
11556
11620
  }
11557
- if (check.type === "selector_text_order" && check.selector) {
11621
+ if ((check.type === "selector_text_order" || check.type === "selector_text_visible" || check.type === "selector_text_absent") && check.selector) {
11558
11622
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
11559
11623
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
11560
11624
  }
@@ -12181,6 +12245,11 @@ function profileCheckMarkdownTarget(check) {
12181
12245
  const expectedCount = cliFiniteNumber(evidence.expected_count);
12182
12246
  return selector && expectedCount !== void 0 ? `${markdownInlineCode(selector)} = ${expectedCount}` : void 0;
12183
12247
  }
12248
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
12249
+ const textTarget = profileCheckTextTarget(evidence);
12250
+ if (selector && textTarget) return `${markdownInlineCode(selector)} contains ${textTarget}`;
12251
+ return selector ? markdownInlineCode(selector) : textTarget;
12252
+ }
12184
12253
  if (check.type === "selector_text_order") {
12185
12254
  return selector ? `${markdownInlineCode(selector)} text order` : void 0;
12186
12255
  }
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-QLBOFUON.js";
13
+ } from "./chunk-FQ4QBY2N.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
@@ -389,6 +389,11 @@ function profileCheckMarkdownTarget(check) {
389
389
  const expectedCount = cliFiniteNumber(evidence.expected_count);
390
390
  return selector && expectedCount !== void 0 ? `${markdownInlineCode(selector)} = ${expectedCount}` : void 0;
391
391
  }
392
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
393
+ const textTarget = profileCheckTextTarget(evidence);
394
+ if (selector && textTarget) return `${markdownInlineCode(selector)} contains ${textTarget}`;
395
+ return selector ? markdownInlineCode(selector) : textTarget;
396
+ }
392
397
  if (check.type === "selector_text_order") {
393
398
  return selector ? `${markdownInlineCode(selector)} text order` : void 0;
394
399
  }
package/dist/index.cjs CHANGED
@@ -8749,6 +8749,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8749
8749
  "selector_count_equals",
8750
8750
  "selector_count_equal",
8751
8751
  "selector_count_eq",
8752
+ "selector_text_visible",
8753
+ "selector_text_absent",
8752
8754
  "selector_text_order",
8753
8755
  "frame_text_visible",
8754
8756
  "frame_url_equals",
@@ -9462,7 +9464,7 @@ function normalizeCheck(input, index) {
9462
9464
  if (!isSupportedCheckType(type)) {
9463
9465
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
9464
9466
  }
9465
- if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue5(input.selector)) {
9467
+ if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue5(input.selector)) {
9466
9468
  throw new Error(`checks[${index}] ${type} requires selector.`);
9467
9469
  }
9468
9470
  if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue5(input.selector)) {
@@ -9478,7 +9480,7 @@ function normalizeCheck(input, index) {
9478
9480
  if (type === "frame_url_matches" && !stringValue5(input.pattern)) {
9479
9481
  throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
9480
9482
  }
9481
- if ((type === "text_visible" || type === "text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9483
+ if ((type === "text_visible" || type === "text_absent" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
9482
9484
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
9483
9485
  }
9484
9486
  if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue5(input.param) && !stringValue5(input.search_param) && !stringValue5(input.searchParam) && !stringValue5(input.key)) {
@@ -9744,9 +9746,11 @@ function textSequenceForCheck(viewport, check) {
9744
9746
  const key = selectorKey(check);
9745
9747
  const sequence = viewport.text_sequences?.[key];
9746
9748
  if (isRecord2(sequence)) {
9749
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
9750
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
9747
9751
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
9748
9752
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
9749
- const candidates = visibleTexts.length ? visibleTexts : texts;
9753
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
9750
9754
  return candidates.map((text) => String(text).replace(/\s+/g, " ").trim()).filter(Boolean);
9751
9755
  }
9752
9756
  return [];
@@ -10080,6 +10084,35 @@ function assessCheckFromEvidence(check, evidence) {
10080
10084
  message: failed.length ? `Selector ${key} count did not equal ${expectedCount} in ${failed.length} viewport(s).` : void 0
10081
10085
  };
10082
10086
  }
10087
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
10088
+ const key = selectorKey(check);
10089
+ const expectedVisible = check.type === "selector_text_visible";
10090
+ const results = viewports.map((viewport) => {
10091
+ const texts = textSequenceForCheck(viewport, check);
10092
+ const matches = texts.filter((text) => matchText(text, check));
10093
+ return {
10094
+ viewport: viewport.name,
10095
+ selector_count: viewport.selectors?.[key]?.count || 0,
10096
+ visible_count: viewport.selectors?.[key]?.visible_count || 0,
10097
+ matched_count: matches.length,
10098
+ matched: matches.length > 0,
10099
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240))
10100
+ };
10101
+ });
10102
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
10103
+ return {
10104
+ type: check.type,
10105
+ label: checkLabel(check),
10106
+ status: failed ? "failed" : "passed",
10107
+ evidence: {
10108
+ selector: key,
10109
+ text: check.text || null,
10110
+ pattern: check.pattern || null,
10111
+ viewports: results.map((result) => toJsonValue(result))
10112
+ },
10113
+ message: failed ? `Selector ${key} text assertion failed in ${failed} viewport(s).` : void 0
10114
+ };
10115
+ }
10083
10116
  if (check.type === "selector_text_order") {
10084
10117
  const key = selectorKey(check);
10085
10118
  const expectedTexts = check.expected_texts || [];
@@ -10090,7 +10123,7 @@ function assessCheckFromEvidence(check, evidence) {
10090
10123
  viewport: viewport.name,
10091
10124
  matched: match.matched,
10092
10125
  matched_positions: match.positions,
10093
- visible_texts: texts.slice(0, 20)
10126
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240))
10094
10127
  };
10095
10128
  });
10096
10129
  const failed = results.filter((result) => !result.matched).length;
@@ -10800,9 +10833,11 @@ function textSequenceForCheck(viewport, check) {
10800
10833
  const key = check.selector || "";
10801
10834
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
10802
10835
  if (sequence && typeof sequence === "object") {
10836
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
10837
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
10803
10838
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
10804
10839
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
10805
- const candidates = visibleTexts.length ? visibleTexts : texts;
10840
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
10806
10841
  return candidates.map((text) => String(text || "").replace(/\s+/g, " ").trim()).filter(Boolean);
10807
10842
  }
10808
10843
  return [];
@@ -11440,6 +11475,31 @@ function assessProfile(profile, evidence) {
11440
11475
  });
11441
11476
  continue;
11442
11477
  }
11478
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
11479
+ const selector = check.selector || "";
11480
+ const expectedVisible = check.type === "selector_text_visible";
11481
+ const results = checkViewports.map((viewport) => {
11482
+ const texts = textSequenceForCheck(viewport, check);
11483
+ const matches = texts.filter((text) => textMatches(text, check));
11484
+ return {
11485
+ viewport: viewport.name,
11486
+ selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
11487
+ visible_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].visible_count : 0,
11488
+ matched_count: matches.length,
11489
+ matched: matches.length > 0,
11490
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240)),
11491
+ };
11492
+ });
11493
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
11494
+ checks.push({
11495
+ type: check.type,
11496
+ label: check.label || check.type,
11497
+ status: failed ? "failed" : "passed",
11498
+ evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
11499
+ message: failed ? "Selector " + selector + " text assertion failed in " + failed + " viewport(s)." : undefined,
11500
+ });
11501
+ continue;
11502
+ }
11443
11503
  if (check.type === "selector_text_order") {
11444
11504
  const selector = check.selector || "";
11445
11505
  const expectedTexts = check.expected_texts || [];
@@ -11450,7 +11510,7 @@ function assessProfile(profile, evidence) {
11450
11510
  viewport: viewport.name,
11451
11511
  matched: match.matched,
11452
11512
  matched_positions: match.positions,
11453
- visible_texts: texts.slice(0, 20),
11513
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240)),
11454
11514
  };
11455
11515
  });
11456
11516
  const failed = results.filter((result) => !result.matched).length;
@@ -12654,6 +12714,7 @@ async function selectorStats(selector) {
12654
12714
  async function selectorTextSequence(selector) {
12655
12715
  return page.locator(selector).evaluateAll((elements) => {
12656
12716
  const compact = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 240);
12717
+ const matchText = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 8000);
12657
12718
  const isVisible = (element) => {
12658
12719
  const style = window.getComputedStyle(element);
12659
12720
  const rect = element.getBoundingClientRect();
@@ -12662,6 +12723,7 @@ async function selectorTextSequence(selector) {
12662
12723
  const rows = elements.map((element, index) => ({
12663
12724
  index,
12664
12725
  text: compact(element.innerText || element.textContent || ""),
12726
+ match_text: matchText(element.innerText || element.textContent || ""),
12665
12727
  visible: isVisible(element),
12666
12728
  }));
12667
12729
  return {
@@ -12669,8 +12731,10 @@ async function selectorTextSequence(selector) {
12669
12731
  visible_count: rows.filter((row) => row.visible).length,
12670
12732
  texts: rows.map((row) => row.text).filter(Boolean).slice(0, 40),
12671
12733
  visible_texts: rows.filter((row) => row.visible).map((row) => row.text).filter(Boolean).slice(0, 40),
12734
+ match_texts: rows.map((row) => row.match_text).filter(Boolean).slice(0, 40),
12735
+ visible_match_texts: rows.filter((row) => row.visible).map((row) => row.match_text).filter(Boolean).slice(0, 40),
12672
12736
  };
12673
- }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
12737
+ }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], match_texts: [], visible_match_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
12674
12738
  }
12675
12739
  function linkProbeMaxLinks(check) {
12676
12740
  const value = Number(check.max_links || check.maxLinks || check.limit || 100);
@@ -13406,7 +13470,7 @@ async function captureViewport(viewport) {
13406
13470
  ) {
13407
13471
  selectors[check.selector] = await selectorStats(check.selector);
13408
13472
  }
13409
- if (check.type === "selector_text_order" && check.selector) {
13473
+ if ((check.type === "selector_text_order" || check.type === "selector_text_visible" || check.type === "selector_text_absent") && check.selector) {
13410
13474
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
13411
13475
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
13412
13476
  }
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-QLBOFUON.js";
61
+ } from "./chunk-FQ4QBY2N.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -63,6 +63,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
63
63
  "selector_count_equals",
64
64
  "selector_count_equal",
65
65
  "selector_count_eq",
66
+ "selector_text_visible",
67
+ "selector_text_absent",
66
68
  "selector_text_order",
67
69
  "frame_text_visible",
68
70
  "frame_url_equals",
@@ -776,7 +778,7 @@ function normalizeCheck(input, index) {
776
778
  if (!isSupportedCheckType(type)) {
777
779
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
778
780
  }
779
- if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue(input.selector)) {
781
+ if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue(input.selector)) {
780
782
  throw new Error(`checks[${index}] ${type} requires selector.`);
781
783
  }
782
784
  if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue(input.selector)) {
@@ -792,7 +794,7 @@ function normalizeCheck(input, index) {
792
794
  if (type === "frame_url_matches" && !stringValue(input.pattern)) {
793
795
  throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
794
796
  }
795
- if ((type === "text_visible" || type === "text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
797
+ if ((type === "text_visible" || type === "text_absent" || type === "selector_text_visible" || type === "selector_text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
796
798
  throw new Error(`checks[${index}] ${type} requires text or pattern.`);
797
799
  }
798
800
  if ((type === "url_search_param_equals" || type === "url_search_param_absent") && !stringValue(input.param) && !stringValue(input.search_param) && !stringValue(input.searchParam) && !stringValue(input.key)) {
@@ -1058,9 +1060,11 @@ function textSequenceForCheck(viewport, check) {
1058
1060
  const key = selectorKey(check);
1059
1061
  const sequence = viewport.text_sequences?.[key];
1060
1062
  if (isRecord(sequence)) {
1063
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
1064
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
1061
1065
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
1062
1066
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
1063
- const candidates = visibleTexts.length ? visibleTexts : texts;
1067
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
1064
1068
  return candidates.map((text) => String(text).replace(/\s+/g, " ").trim()).filter(Boolean);
1065
1069
  }
1066
1070
  return [];
@@ -1394,6 +1398,35 @@ function assessCheckFromEvidence(check, evidence) {
1394
1398
  message: failed.length ? `Selector ${key} count did not equal ${expectedCount} in ${failed.length} viewport(s).` : void 0
1395
1399
  };
1396
1400
  }
1401
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
1402
+ const key = selectorKey(check);
1403
+ const expectedVisible = check.type === "selector_text_visible";
1404
+ const results = viewports.map((viewport) => {
1405
+ const texts = textSequenceForCheck(viewport, check);
1406
+ const matches = texts.filter((text) => matchText(text, check));
1407
+ return {
1408
+ viewport: viewport.name,
1409
+ selector_count: viewport.selectors?.[key]?.count || 0,
1410
+ visible_count: viewport.selectors?.[key]?.visible_count || 0,
1411
+ matched_count: matches.length,
1412
+ matched: matches.length > 0,
1413
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240))
1414
+ };
1415
+ });
1416
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
1417
+ return {
1418
+ type: check.type,
1419
+ label: checkLabel(check),
1420
+ status: failed ? "failed" : "passed",
1421
+ evidence: {
1422
+ selector: key,
1423
+ text: check.text || null,
1424
+ pattern: check.pattern || null,
1425
+ viewports: results.map((result) => toJsonValue(result))
1426
+ },
1427
+ message: failed ? `Selector ${key} text assertion failed in ${failed} viewport(s).` : void 0
1428
+ };
1429
+ }
1397
1430
  if (check.type === "selector_text_order") {
1398
1431
  const key = selectorKey(check);
1399
1432
  const expectedTexts = check.expected_texts || [];
@@ -1404,7 +1437,7 @@ function assessCheckFromEvidence(check, evidence) {
1404
1437
  viewport: viewport.name,
1405
1438
  matched: match.matched,
1406
1439
  matched_positions: match.positions,
1407
- visible_texts: texts.slice(0, 20)
1440
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240))
1408
1441
  };
1409
1442
  });
1410
1443
  const failed = results.filter((result) => !result.matched).length;
@@ -2114,9 +2147,11 @@ function textSequenceForCheck(viewport, check) {
2114
2147
  const key = check.selector || "";
2115
2148
  const sequence = viewport.text_sequences && viewport.text_sequences[key];
2116
2149
  if (sequence && typeof sequence === "object") {
2150
+ const visibleMatchTexts = Array.isArray(sequence.visible_match_texts) ? sequence.visible_match_texts : [];
2151
+ const matchTexts = Array.isArray(sequence.match_texts) ? sequence.match_texts : [];
2117
2152
  const visibleTexts = Array.isArray(sequence.visible_texts) ? sequence.visible_texts : [];
2118
2153
  const texts = Array.isArray(sequence.texts) ? sequence.texts : [];
2119
- const candidates = visibleTexts.length ? visibleTexts : texts;
2154
+ const candidates = visibleMatchTexts.length ? visibleMatchTexts : matchTexts.length ? matchTexts : visibleTexts.length ? visibleTexts : texts;
2120
2155
  return candidates.map((text) => String(text || "").replace(/\s+/g, " ").trim()).filter(Boolean);
2121
2156
  }
2122
2157
  return [];
@@ -2754,6 +2789,31 @@ function assessProfile(profile, evidence) {
2754
2789
  });
2755
2790
  continue;
2756
2791
  }
2792
+ if (check.type === "selector_text_visible" || check.type === "selector_text_absent") {
2793
+ const selector = check.selector || "";
2794
+ const expectedVisible = check.type === "selector_text_visible";
2795
+ const results = checkViewports.map((viewport) => {
2796
+ const texts = textSequenceForCheck(viewport, check);
2797
+ const matches = texts.filter((text) => textMatches(text, check));
2798
+ return {
2799
+ viewport: viewport.name,
2800
+ selector_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].count : 0,
2801
+ visible_count: viewport.selectors && viewport.selectors[selector] ? viewport.selectors[selector].visible_count : 0,
2802
+ matched_count: matches.length,
2803
+ matched: matches.length > 0,
2804
+ samples: matches.slice(0, 3).map((text) => text.slice(0, 240)),
2805
+ };
2806
+ });
2807
+ const failed = results.filter((result) => result.matched !== expectedVisible).length;
2808
+ checks.push({
2809
+ type: check.type,
2810
+ label: check.label || check.type,
2811
+ status: failed ? "failed" : "passed",
2812
+ evidence: { selector, text: check.text || null, pattern: check.pattern || null, viewports: results },
2813
+ message: failed ? "Selector " + selector + " text assertion failed in " + failed + " viewport(s)." : undefined,
2814
+ });
2815
+ continue;
2816
+ }
2757
2817
  if (check.type === "selector_text_order") {
2758
2818
  const selector = check.selector || "";
2759
2819
  const expectedTexts = check.expected_texts || [];
@@ -2764,7 +2824,7 @@ function assessProfile(profile, evidence) {
2764
2824
  viewport: viewport.name,
2765
2825
  matched: match.matched,
2766
2826
  matched_positions: match.positions,
2767
- visible_texts: texts.slice(0, 20),
2827
+ visible_texts: texts.slice(0, 20).map((text) => text.slice(0, 240)),
2768
2828
  };
2769
2829
  });
2770
2830
  const failed = results.filter((result) => !result.matched).length;
@@ -3968,6 +4028,7 @@ async function selectorStats(selector) {
3968
4028
  async function selectorTextSequence(selector) {
3969
4029
  return page.locator(selector).evaluateAll((elements) => {
3970
4030
  const compact = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 240);
4031
+ const matchText = (value) => String(value || "").replace(/\s+/g, " ").trim().slice(0, 8000);
3971
4032
  const isVisible = (element) => {
3972
4033
  const style = window.getComputedStyle(element);
3973
4034
  const rect = element.getBoundingClientRect();
@@ -3976,6 +4037,7 @@ async function selectorTextSequence(selector) {
3976
4037
  const rows = elements.map((element, index) => ({
3977
4038
  index,
3978
4039
  text: compact(element.innerText || element.textContent || ""),
4040
+ match_text: matchText(element.innerText || element.textContent || ""),
3979
4041
  visible: isVisible(element),
3980
4042
  }));
3981
4043
  return {
@@ -3983,8 +4045,10 @@ async function selectorTextSequence(selector) {
3983
4045
  visible_count: rows.filter((row) => row.visible).length,
3984
4046
  texts: rows.map((row) => row.text).filter(Boolean).slice(0, 40),
3985
4047
  visible_texts: rows.filter((row) => row.visible).map((row) => row.text).filter(Boolean).slice(0, 40),
4048
+ match_texts: rows.map((row) => row.match_text).filter(Boolean).slice(0, 40),
4049
+ visible_match_texts: rows.filter((row) => row.visible).map((row) => row.match_text).filter(Boolean).slice(0, 40),
3986
4050
  };
3987
- }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
4051
+ }).catch((error) => ({ count: 0, visible_count: 0, texts: [], visible_texts: [], match_texts: [], visible_match_texts: [], error: String(error && error.message ? error.message : error).slice(0, 500) }));
3988
4052
  }
3989
4053
  function linkProbeMaxLinks(check) {
3990
4054
  const value = Number(check.max_links || check.maxLinks || check.limit || 100);
@@ -4720,7 +4784,7 @@ async function captureViewport(viewport) {
4720
4784
  ) {
4721
4785
  selectors[check.selector] = await selectorStats(check.selector);
4722
4786
  }
4723
- if (check.type === "selector_text_order" && check.selector) {
4787
+ if ((check.type === "selector_text_order" || check.type === "selector_text_visible" || check.type === "selector_text_absent") && check.selector) {
4724
4788
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
4725
4789
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
4726
4790
  }
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
4
4
  declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
- declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
7
+ declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
8
  declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
package/dist/profile.d.ts CHANGED
@@ -4,7 +4,7 @@ declare const RIDDLE_PROOF_PROFILE_VERSION: "riddle-proof.profile.v1";
4
4
  declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evidence.v1";
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
- declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
7
+ declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
8
  declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_call"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-QLBOFUON.js";
22
+ } from "./chunk-FQ4QBY2N.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  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: "author" | "recon" | "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: "author" | "recon" | "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: "author" | "recon" | "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: "author" | "recon" | "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: "author" | "recon" | "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: "author" | "recon" | "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.93",
3
+ "version": "0.7.94",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",