@riddledc/riddle-proof 0.7.128 → 0.7.129

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.
@@ -1854,6 +1854,49 @@ function matchText(sample, check) {
1854
1854
  }
1855
1855
  return sample.includes(check.text || "");
1856
1856
  }
1857
+ function compactTextEvidenceSample(value) {
1858
+ return String(value || "").replace(/\s+/g, " ").trim();
1859
+ }
1860
+ function textSampleAroundMatch(sample, index, length) {
1861
+ if (index < 0) return void 0;
1862
+ const source = String(sample || "");
1863
+ const context = 120;
1864
+ const start = Math.max(0, index - context);
1865
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
1866
+ const prefix = start > 0 ? "..." : "";
1867
+ const suffix = end < source.length ? "..." : "";
1868
+ const compacted = compactTextEvidenceSample(`${prefix}${source.slice(start, end)}${suffix}`);
1869
+ return compacted ? compacted.slice(0, 240) : void 0;
1870
+ }
1871
+ function textMatchSamples(sample, check) {
1872
+ const source = String(sample || "");
1873
+ if (!source) return [];
1874
+ if (check.pattern) {
1875
+ try {
1876
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
1877
+ const match = new RegExp(check.pattern, flags).exec(source);
1878
+ const sampleText2 = match ? textSampleAroundMatch(source, match.index, match[0]?.length || 1) : void 0;
1879
+ return sampleText2 ? [sampleText2] : [];
1880
+ } catch {
1881
+ return [];
1882
+ }
1883
+ }
1884
+ const text = check.text || "";
1885
+ if (!text) return [];
1886
+ const index = source.indexOf(text);
1887
+ const sampleText = textSampleAroundMatch(source, index, text.length);
1888
+ return sampleText ? [sampleText] : [];
1889
+ }
1890
+ function textCheckFailureSamples(viewport, check) {
1891
+ const key = textKey(check);
1892
+ const captured = viewport.text_match_samples?.[key] || [];
1893
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
1894
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
1895
+ const matchedSamples = textMatchSamples(viewport.body_text_sample || "", check);
1896
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
1897
+ const fallback = compactTextEvidenceSample(viewport.body_text_sample || "").slice(0, 240);
1898
+ return fallback ? [fallback] : [];
1899
+ }
1857
1900
  function allowedMessageSample(input) {
1858
1901
  if (!isRecord(input)) return String(input || "");
1859
1902
  const parts = [
@@ -2298,10 +2341,17 @@ function assessCheckFromEvidence(check, evidence) {
2298
2341
  if (check.type === "text_visible" || check.type === "text_absent") {
2299
2342
  const key = textKey(check);
2300
2343
  const expectedVisible = check.type === "text_visible";
2301
- const matches = viewports.map((viewport) => {
2344
+ const results = viewports.map((viewport) => {
2302
2345
  const fromEvidence = viewport.text_matches?.[key];
2303
- return typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
2346
+ const matched = typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
2347
+ const failedAgainstExpectation = matched !== expectedVisible;
2348
+ return {
2349
+ viewport: viewport.name,
2350
+ matched,
2351
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
2352
+ };
2304
2353
  });
2354
+ const matches = results.map((result) => result.matched);
2305
2355
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
2306
2356
  return {
2307
2357
  type: check.type,
@@ -2310,7 +2360,8 @@ function assessCheckFromEvidence(check, evidence) {
2310
2360
  evidence: {
2311
2361
  text: check.text || null,
2312
2362
  pattern: check.pattern || null,
2313
- matches
2363
+ matches,
2364
+ viewports: results.map((result) => toJsonValue(result))
2314
2365
  },
2315
2366
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
2316
2367
  };
@@ -2897,6 +2948,48 @@ function textMatches(sample, check) {
2897
2948
  }
2898
2949
  return String(sample || "").includes(check.text || "");
2899
2950
  }
2951
+ function compactTextEvidenceSample(value) {
2952
+ return String(value || "").replace(/\s+/g, " ").trim();
2953
+ }
2954
+ function textSampleAroundMatch(sample, index, length) {
2955
+ if (index < 0) return undefined;
2956
+ const source = String(sample || "");
2957
+ const context = 120;
2958
+ const start = Math.max(0, index - context);
2959
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
2960
+ const prefix = start > 0 ? "..." : "";
2961
+ const suffix = end < source.length ? "..." : "";
2962
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
2963
+ return compacted ? compacted.slice(0, 240) : undefined;
2964
+ }
2965
+ function textMatchSamples(sample, check) {
2966
+ const source = String(sample || "");
2967
+ if (!source) return [];
2968
+ if (check.pattern) {
2969
+ try {
2970
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
2971
+ const match = new RegExp(check.pattern, flags).exec(source);
2972
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
2973
+ return sampleText ? [sampleText] : [];
2974
+ } catch { return []; }
2975
+ }
2976
+ const text = check.text || "";
2977
+ if (!text) return [];
2978
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
2979
+ return sampleText ? [sampleText] : [];
2980
+ }
2981
+ function textCheckFailureSamples(viewport, check) {
2982
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
2983
+ const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
2984
+ const capturedSamples = captured
2985
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
2986
+ .filter(Boolean);
2987
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
2988
+ const matchedSamples = textMatchSamples(viewport && viewport.body_text_sample || "", check);
2989
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
2990
+ const fallback = compactTextEvidenceSample(viewport && viewport.body_text_sample || "").slice(0, 240);
2991
+ return fallback ? [fallback] : [];
2992
+ }
2900
2993
  function allowedMessageSample(input) {
2901
2994
  if (!input || typeof input !== "object" || Array.isArray(input)) return String(input || "");
2902
2995
  const parts = [
@@ -3974,13 +4067,22 @@ function assessProfile(profile, evidence) {
3974
4067
  if (check.type === "text_visible" || check.type === "text_absent") {
3975
4068
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
3976
4069
  const expectedVisible = check.type === "text_visible";
3977
- const matches = checkViewports.map((viewport) => viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check));
4070
+ const results = checkViewports.map((viewport) => {
4071
+ const matched = viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check);
4072
+ const failedAgainstExpectation = matched !== expectedVisible;
4073
+ return {
4074
+ viewport: viewport.name,
4075
+ matched,
4076
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
4077
+ };
4078
+ });
4079
+ const matches = results.map((result) => result.matched);
3978
4080
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
3979
4081
  checks.push({
3980
4082
  type: check.type,
3981
4083
  label: check.label || check.type,
3982
4084
  status: failed ? "failed" : "passed",
3983
- evidence: { text: check.text, pattern: check.pattern, matches },
4085
+ evidence: { text: check.text, pattern: check.pattern, matches, viewports: results },
3984
4086
  message: failed ? "Text assertion failed in " + failed + " viewport(s)." : undefined,
3985
4087
  });
3986
4088
  continue;
@@ -4300,6 +4402,36 @@ function textMatches(sample, check) {
4300
4402
  }
4301
4403
  return String(sample || "").includes(check.text || "");
4302
4404
  }
4405
+ function compactTextEvidenceSample(value) {
4406
+ return String(value || "").replace(/\s+/g, " ").trim();
4407
+ }
4408
+ function textSampleAroundMatch(sample, index, length) {
4409
+ if (index < 0) return undefined;
4410
+ const source = String(sample || "");
4411
+ const context = 120;
4412
+ const start = Math.max(0, index - context);
4413
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
4414
+ const prefix = start > 0 ? "..." : "";
4415
+ const suffix = end < source.length ? "..." : "";
4416
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
4417
+ return compacted ? compacted.slice(0, 240) : undefined;
4418
+ }
4419
+ function textMatchSamples(sample, check) {
4420
+ const source = String(sample || "");
4421
+ if (!source) return [];
4422
+ if (check.pattern) {
4423
+ try {
4424
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
4425
+ const match = new RegExp(check.pattern, flags).exec(source);
4426
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
4427
+ return sampleText ? [sampleText] : [];
4428
+ } catch { return []; }
4429
+ }
4430
+ const text = check.text || "";
4431
+ if (!text) return [];
4432
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
4433
+ return sampleText ? [sampleText] : [];
4434
+ }
4303
4435
  function profileCheckAppliesToViewport(check, viewport) {
4304
4436
  if (!Array.isArray(check.viewports) || !check.viewports.length) return true;
4305
4437
  return Boolean(viewport && viewport.name && check.viewports.includes(viewport.name));
@@ -6251,6 +6383,7 @@ async function captureViewport(viewport) {
6251
6383
  const frames = {};
6252
6384
  const text_sequences = {};
6253
6385
  const text_matches = {};
6386
+ const text_match_samples = {};
6254
6387
  const http_statuses = {};
6255
6388
  const link_statuses = {};
6256
6389
  for (const check of profile.checks || []) {
@@ -6272,7 +6405,10 @@ async function captureViewport(viewport) {
6272
6405
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
6273
6406
  }
6274
6407
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
6275
- text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
6408
+ const key = textKey(check);
6409
+ const sample = dom.body_text || dom.body_text_sample || "";
6410
+ text_matches[key] = textMatches(sample, check);
6411
+ text_match_samples[key] = textMatchSamples(sample, check);
6276
6412
  }
6277
6413
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
6278
6414
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -6349,6 +6485,7 @@ async function captureViewport(viewport) {
6349
6485
  frames,
6350
6486
  text_sequences,
6351
6487
  text_matches,
6488
+ text_match_samples,
6352
6489
  http_statuses,
6353
6490
  link_statuses,
6354
6491
  route_inventory: routeInventory,
package/dist/cli.cjs CHANGED
@@ -8791,6 +8791,49 @@ function matchText(sample, check) {
8791
8791
  }
8792
8792
  return sample.includes(check.text || "");
8793
8793
  }
8794
+ function compactTextEvidenceSample(value) {
8795
+ return String(value || "").replace(/\s+/g, " ").trim();
8796
+ }
8797
+ function textSampleAroundMatch(sample, index, length) {
8798
+ if (index < 0) return void 0;
8799
+ const source = String(sample || "");
8800
+ const context = 120;
8801
+ const start = Math.max(0, index - context);
8802
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
8803
+ const prefix = start > 0 ? "..." : "";
8804
+ const suffix = end < source.length ? "..." : "";
8805
+ const compacted = compactTextEvidenceSample(`${prefix}${source.slice(start, end)}${suffix}`);
8806
+ return compacted ? compacted.slice(0, 240) : void 0;
8807
+ }
8808
+ function textMatchSamples(sample, check) {
8809
+ const source = String(sample || "");
8810
+ if (!source) return [];
8811
+ if (check.pattern) {
8812
+ try {
8813
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
8814
+ const match = new RegExp(check.pattern, flags).exec(source);
8815
+ const sampleText2 = match ? textSampleAroundMatch(source, match.index, match[0]?.length || 1) : void 0;
8816
+ return sampleText2 ? [sampleText2] : [];
8817
+ } catch {
8818
+ return [];
8819
+ }
8820
+ }
8821
+ const text = check.text || "";
8822
+ if (!text) return [];
8823
+ const index = source.indexOf(text);
8824
+ const sampleText = textSampleAroundMatch(source, index, text.length);
8825
+ return sampleText ? [sampleText] : [];
8826
+ }
8827
+ function textCheckFailureSamples(viewport, check) {
8828
+ const key = textKey(check);
8829
+ const captured = viewport.text_match_samples?.[key] || [];
8830
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
8831
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
8832
+ const matchedSamples = textMatchSamples(viewport.body_text_sample || "", check);
8833
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
8834
+ const fallback = compactTextEvidenceSample(viewport.body_text_sample || "").slice(0, 240);
8835
+ return fallback ? [fallback] : [];
8836
+ }
8794
8837
  function allowedMessageSample(input) {
8795
8838
  if (!isRecord(input)) return String(input || "");
8796
8839
  const parts = [
@@ -9235,10 +9278,17 @@ function assessCheckFromEvidence(check, evidence) {
9235
9278
  if (check.type === "text_visible" || check.type === "text_absent") {
9236
9279
  const key = textKey(check);
9237
9280
  const expectedVisible = check.type === "text_visible";
9238
- const matches = viewports.map((viewport) => {
9281
+ const results = viewports.map((viewport) => {
9239
9282
  const fromEvidence = viewport.text_matches?.[key];
9240
- return typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
9283
+ const matched = typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
9284
+ const failedAgainstExpectation = matched !== expectedVisible;
9285
+ return {
9286
+ viewport: viewport.name,
9287
+ matched,
9288
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
9289
+ };
9241
9290
  });
9291
+ const matches = results.map((result) => result.matched);
9242
9292
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
9243
9293
  return {
9244
9294
  type: check.type,
@@ -9247,7 +9297,8 @@ function assessCheckFromEvidence(check, evidence) {
9247
9297
  evidence: {
9248
9298
  text: check.text || null,
9249
9299
  pattern: check.pattern || null,
9250
- matches
9300
+ matches,
9301
+ viewports: results.map((result) => toJsonValue(result))
9251
9302
  },
9252
9303
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
9253
9304
  };
@@ -9818,6 +9869,48 @@ function textMatches(sample, check) {
9818
9869
  }
9819
9870
  return String(sample || "").includes(check.text || "");
9820
9871
  }
9872
+ function compactTextEvidenceSample(value) {
9873
+ return String(value || "").replace(/\s+/g, " ").trim();
9874
+ }
9875
+ function textSampleAroundMatch(sample, index, length) {
9876
+ if (index < 0) return undefined;
9877
+ const source = String(sample || "");
9878
+ const context = 120;
9879
+ const start = Math.max(0, index - context);
9880
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
9881
+ const prefix = start > 0 ? "..." : "";
9882
+ const suffix = end < source.length ? "..." : "";
9883
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
9884
+ return compacted ? compacted.slice(0, 240) : undefined;
9885
+ }
9886
+ function textMatchSamples(sample, check) {
9887
+ const source = String(sample || "");
9888
+ if (!source) return [];
9889
+ if (check.pattern) {
9890
+ try {
9891
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
9892
+ const match = new RegExp(check.pattern, flags).exec(source);
9893
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
9894
+ return sampleText ? [sampleText] : [];
9895
+ } catch { return []; }
9896
+ }
9897
+ const text = check.text || "";
9898
+ if (!text) return [];
9899
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
9900
+ return sampleText ? [sampleText] : [];
9901
+ }
9902
+ function textCheckFailureSamples(viewport, check) {
9903
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
9904
+ const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
9905
+ const capturedSamples = captured
9906
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
9907
+ .filter(Boolean);
9908
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
9909
+ const matchedSamples = textMatchSamples(viewport && viewport.body_text_sample || "", check);
9910
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
9911
+ const fallback = compactTextEvidenceSample(viewport && viewport.body_text_sample || "").slice(0, 240);
9912
+ return fallback ? [fallback] : [];
9913
+ }
9821
9914
  function allowedMessageSample(input) {
9822
9915
  if (!input || typeof input !== "object" || Array.isArray(input)) return String(input || "");
9823
9916
  const parts = [
@@ -10895,13 +10988,22 @@ function assessProfile(profile, evidence) {
10895
10988
  if (check.type === "text_visible" || check.type === "text_absent") {
10896
10989
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
10897
10990
  const expectedVisible = check.type === "text_visible";
10898
- const matches = checkViewports.map((viewport) => viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check));
10991
+ const results = checkViewports.map((viewport) => {
10992
+ const matched = viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check);
10993
+ const failedAgainstExpectation = matched !== expectedVisible;
10994
+ return {
10995
+ viewport: viewport.name,
10996
+ matched,
10997
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
10998
+ };
10999
+ });
11000
+ const matches = results.map((result) => result.matched);
10899
11001
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
10900
11002
  checks.push({
10901
11003
  type: check.type,
10902
11004
  label: check.label || check.type,
10903
11005
  status: failed ? "failed" : "passed",
10904
- evidence: { text: check.text, pattern: check.pattern, matches },
11006
+ evidence: { text: check.text, pattern: check.pattern, matches, viewports: results },
10905
11007
  message: failed ? "Text assertion failed in " + failed + " viewport(s)." : undefined,
10906
11008
  });
10907
11009
  continue;
@@ -11221,6 +11323,36 @@ function textMatches(sample, check) {
11221
11323
  }
11222
11324
  return String(sample || "").includes(check.text || "");
11223
11325
  }
11326
+ function compactTextEvidenceSample(value) {
11327
+ return String(value || "").replace(/\s+/g, " ").trim();
11328
+ }
11329
+ function textSampleAroundMatch(sample, index, length) {
11330
+ if (index < 0) return undefined;
11331
+ const source = String(sample || "");
11332
+ const context = 120;
11333
+ const start = Math.max(0, index - context);
11334
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
11335
+ const prefix = start > 0 ? "..." : "";
11336
+ const suffix = end < source.length ? "..." : "";
11337
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
11338
+ return compacted ? compacted.slice(0, 240) : undefined;
11339
+ }
11340
+ function textMatchSamples(sample, check) {
11341
+ const source = String(sample || "");
11342
+ if (!source) return [];
11343
+ if (check.pattern) {
11344
+ try {
11345
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
11346
+ const match = new RegExp(check.pattern, flags).exec(source);
11347
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
11348
+ return sampleText ? [sampleText] : [];
11349
+ } catch { return []; }
11350
+ }
11351
+ const text = check.text || "";
11352
+ if (!text) return [];
11353
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
11354
+ return sampleText ? [sampleText] : [];
11355
+ }
11224
11356
  function profileCheckAppliesToViewport(check, viewport) {
11225
11357
  if (!Array.isArray(check.viewports) || !check.viewports.length) return true;
11226
11358
  return Boolean(viewport && viewport.name && check.viewports.includes(viewport.name));
@@ -13172,6 +13304,7 @@ async function captureViewport(viewport) {
13172
13304
  const frames = {};
13173
13305
  const text_sequences = {};
13174
13306
  const text_matches = {};
13307
+ const text_match_samples = {};
13175
13308
  const http_statuses = {};
13176
13309
  const link_statuses = {};
13177
13310
  for (const check of profile.checks || []) {
@@ -13193,7 +13326,10 @@ async function captureViewport(viewport) {
13193
13326
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
13194
13327
  }
13195
13328
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
13196
- text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
13329
+ const key = textKey(check);
13330
+ const sample = dom.body_text || dom.body_text_sample || "";
13331
+ text_matches[key] = textMatches(sample, check);
13332
+ text_match_samples[key] = textMatchSamples(sample, check);
13197
13333
  }
13198
13334
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
13199
13335
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -13270,6 +13406,7 @@ async function captureViewport(viewport) {
13270
13406
  frames,
13271
13407
  text_sequences,
13272
13408
  text_matches,
13409
+ text_match_samples,
13273
13410
  http_statuses,
13274
13411
  link_statuses,
13275
13412
  route_inventory: routeInventory,
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  profileStatusExitCode,
13
13
  resolveRiddleProofProfileTargetUrl,
14
14
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-TO3FVF5S.js";
15
+ } from "./chunk-TDK6WFH3.js";
16
16
  import {
17
17
  createRiddleApiClient,
18
18
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -10587,6 +10587,49 @@ function matchText(sample, check) {
10587
10587
  }
10588
10588
  return sample.includes(check.text || "");
10589
10589
  }
10590
+ function compactTextEvidenceSample(value) {
10591
+ return String(value || "").replace(/\s+/g, " ").trim();
10592
+ }
10593
+ function textSampleAroundMatch(sample, index, length) {
10594
+ if (index < 0) return void 0;
10595
+ const source = String(sample || "");
10596
+ const context = 120;
10597
+ const start = Math.max(0, index - context);
10598
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
10599
+ const prefix = start > 0 ? "..." : "";
10600
+ const suffix = end < source.length ? "..." : "";
10601
+ const compacted = compactTextEvidenceSample(`${prefix}${source.slice(start, end)}${suffix}`);
10602
+ return compacted ? compacted.slice(0, 240) : void 0;
10603
+ }
10604
+ function textMatchSamples(sample, check) {
10605
+ const source = String(sample || "");
10606
+ if (!source) return [];
10607
+ if (check.pattern) {
10608
+ try {
10609
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
10610
+ const match = new RegExp(check.pattern, flags).exec(source);
10611
+ const sampleText2 = match ? textSampleAroundMatch(source, match.index, match[0]?.length || 1) : void 0;
10612
+ return sampleText2 ? [sampleText2] : [];
10613
+ } catch {
10614
+ return [];
10615
+ }
10616
+ }
10617
+ const text = check.text || "";
10618
+ if (!text) return [];
10619
+ const index = source.indexOf(text);
10620
+ const sampleText = textSampleAroundMatch(source, index, text.length);
10621
+ return sampleText ? [sampleText] : [];
10622
+ }
10623
+ function textCheckFailureSamples(viewport, check) {
10624
+ const key = textKey(check);
10625
+ const captured = viewport.text_match_samples?.[key] || [];
10626
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
10627
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
10628
+ const matchedSamples = textMatchSamples(viewport.body_text_sample || "", check);
10629
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
10630
+ const fallback = compactTextEvidenceSample(viewport.body_text_sample || "").slice(0, 240);
10631
+ return fallback ? [fallback] : [];
10632
+ }
10590
10633
  function allowedMessageSample(input) {
10591
10634
  if (!isRecord2(input)) return String(input || "");
10592
10635
  const parts = [
@@ -11031,10 +11074,17 @@ function assessCheckFromEvidence(check, evidence) {
11031
11074
  if (check.type === "text_visible" || check.type === "text_absent") {
11032
11075
  const key = textKey(check);
11033
11076
  const expectedVisible = check.type === "text_visible";
11034
- const matches = viewports.map((viewport) => {
11077
+ const results = viewports.map((viewport) => {
11035
11078
  const fromEvidence = viewport.text_matches?.[key];
11036
- return typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
11079
+ const matched = typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
11080
+ const failedAgainstExpectation = matched !== expectedVisible;
11081
+ return {
11082
+ viewport: viewport.name,
11083
+ matched,
11084
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
11085
+ };
11037
11086
  });
11087
+ const matches = results.map((result) => result.matched);
11038
11088
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
11039
11089
  return {
11040
11090
  type: check.type,
@@ -11043,7 +11093,8 @@ function assessCheckFromEvidence(check, evidence) {
11043
11093
  evidence: {
11044
11094
  text: check.text || null,
11045
11095
  pattern: check.pattern || null,
11046
- matches
11096
+ matches,
11097
+ viewports: results.map((result) => toJsonValue(result))
11047
11098
  },
11048
11099
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
11049
11100
  };
@@ -11630,6 +11681,48 @@ function textMatches(sample, check) {
11630
11681
  }
11631
11682
  return String(sample || "").includes(check.text || "");
11632
11683
  }
11684
+ function compactTextEvidenceSample(value) {
11685
+ return String(value || "").replace(/\s+/g, " ").trim();
11686
+ }
11687
+ function textSampleAroundMatch(sample, index, length) {
11688
+ if (index < 0) return undefined;
11689
+ const source = String(sample || "");
11690
+ const context = 120;
11691
+ const start = Math.max(0, index - context);
11692
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
11693
+ const prefix = start > 0 ? "..." : "";
11694
+ const suffix = end < source.length ? "..." : "";
11695
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
11696
+ return compacted ? compacted.slice(0, 240) : undefined;
11697
+ }
11698
+ function textMatchSamples(sample, check) {
11699
+ const source = String(sample || "");
11700
+ if (!source) return [];
11701
+ if (check.pattern) {
11702
+ try {
11703
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
11704
+ const match = new RegExp(check.pattern, flags).exec(source);
11705
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
11706
+ return sampleText ? [sampleText] : [];
11707
+ } catch { return []; }
11708
+ }
11709
+ const text = check.text || "";
11710
+ if (!text) return [];
11711
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
11712
+ return sampleText ? [sampleText] : [];
11713
+ }
11714
+ function textCheckFailureSamples(viewport, check) {
11715
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
11716
+ const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
11717
+ const capturedSamples = captured
11718
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
11719
+ .filter(Boolean);
11720
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
11721
+ const matchedSamples = textMatchSamples(viewport && viewport.body_text_sample || "", check);
11722
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
11723
+ const fallback = compactTextEvidenceSample(viewport && viewport.body_text_sample || "").slice(0, 240);
11724
+ return fallback ? [fallback] : [];
11725
+ }
11633
11726
  function allowedMessageSample(input) {
11634
11727
  if (!input || typeof input !== "object" || Array.isArray(input)) return String(input || "");
11635
11728
  const parts = [
@@ -12707,13 +12800,22 @@ function assessProfile(profile, evidence) {
12707
12800
  if (check.type === "text_visible" || check.type === "text_absent") {
12708
12801
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
12709
12802
  const expectedVisible = check.type === "text_visible";
12710
- const matches = checkViewports.map((viewport) => viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check));
12803
+ const results = checkViewports.map((viewport) => {
12804
+ const matched = viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check);
12805
+ const failedAgainstExpectation = matched !== expectedVisible;
12806
+ return {
12807
+ viewport: viewport.name,
12808
+ matched,
12809
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
12810
+ };
12811
+ });
12812
+ const matches = results.map((result) => result.matched);
12711
12813
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
12712
12814
  checks.push({
12713
12815
  type: check.type,
12714
12816
  label: check.label || check.type,
12715
12817
  status: failed ? "failed" : "passed",
12716
- evidence: { text: check.text, pattern: check.pattern, matches },
12818
+ evidence: { text: check.text, pattern: check.pattern, matches, viewports: results },
12717
12819
  message: failed ? "Text assertion failed in " + failed + " viewport(s)." : undefined,
12718
12820
  });
12719
12821
  continue;
@@ -13033,6 +13135,36 @@ function textMatches(sample, check) {
13033
13135
  }
13034
13136
  return String(sample || "").includes(check.text || "");
13035
13137
  }
13138
+ function compactTextEvidenceSample(value) {
13139
+ return String(value || "").replace(/\s+/g, " ").trim();
13140
+ }
13141
+ function textSampleAroundMatch(sample, index, length) {
13142
+ if (index < 0) return undefined;
13143
+ const source = String(sample || "");
13144
+ const context = 120;
13145
+ const start = Math.max(0, index - context);
13146
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
13147
+ const prefix = start > 0 ? "..." : "";
13148
+ const suffix = end < source.length ? "..." : "";
13149
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
13150
+ return compacted ? compacted.slice(0, 240) : undefined;
13151
+ }
13152
+ function textMatchSamples(sample, check) {
13153
+ const source = String(sample || "");
13154
+ if (!source) return [];
13155
+ if (check.pattern) {
13156
+ try {
13157
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
13158
+ const match = new RegExp(check.pattern, flags).exec(source);
13159
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
13160
+ return sampleText ? [sampleText] : [];
13161
+ } catch { return []; }
13162
+ }
13163
+ const text = check.text || "";
13164
+ if (!text) return [];
13165
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
13166
+ return sampleText ? [sampleText] : [];
13167
+ }
13036
13168
  function profileCheckAppliesToViewport(check, viewport) {
13037
13169
  if (!Array.isArray(check.viewports) || !check.viewports.length) return true;
13038
13170
  return Boolean(viewport && viewport.name && check.viewports.includes(viewport.name));
@@ -14984,6 +15116,7 @@ async function captureViewport(viewport) {
14984
15116
  const frames = {};
14985
15117
  const text_sequences = {};
14986
15118
  const text_matches = {};
15119
+ const text_match_samples = {};
14987
15120
  const http_statuses = {};
14988
15121
  const link_statuses = {};
14989
15122
  for (const check of profile.checks || []) {
@@ -15005,7 +15138,10 @@ async function captureViewport(viewport) {
15005
15138
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
15006
15139
  }
15007
15140
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
15008
- text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
15141
+ const key = textKey(check);
15142
+ const sample = dom.body_text || dom.body_text_sample || "";
15143
+ text_matches[key] = textMatches(sample, check);
15144
+ text_match_samples[key] = textMatchSamples(sample, check);
15009
15145
  }
15010
15146
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
15011
15147
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -15082,6 +15218,7 @@ async function captureViewport(viewport) {
15082
15218
  frames,
15083
15219
  text_sequences,
15084
15220
  text_matches,
15221
+ text_match_samples,
15085
15222
  http_statuses,
15086
15223
  link_statuses,
15087
15224
  route_inventory: routeInventory,
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-TO3FVF5S.js";
65
+ } from "./chunk-TDK6WFH3.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -1901,6 +1901,49 @@ function matchText(sample, check) {
1901
1901
  }
1902
1902
  return sample.includes(check.text || "");
1903
1903
  }
1904
+ function compactTextEvidenceSample(value) {
1905
+ return String(value || "").replace(/\s+/g, " ").trim();
1906
+ }
1907
+ function textSampleAroundMatch(sample, index, length) {
1908
+ if (index < 0) return void 0;
1909
+ const source = String(sample || "");
1910
+ const context = 120;
1911
+ const start = Math.max(0, index - context);
1912
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
1913
+ const prefix = start > 0 ? "..." : "";
1914
+ const suffix = end < source.length ? "..." : "";
1915
+ const compacted = compactTextEvidenceSample(`${prefix}${source.slice(start, end)}${suffix}`);
1916
+ return compacted ? compacted.slice(0, 240) : void 0;
1917
+ }
1918
+ function textMatchSamples(sample, check) {
1919
+ const source = String(sample || "");
1920
+ if (!source) return [];
1921
+ if (check.pattern) {
1922
+ try {
1923
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
1924
+ const match = new RegExp(check.pattern, flags).exec(source);
1925
+ const sampleText2 = match ? textSampleAroundMatch(source, match.index, match[0]?.length || 1) : void 0;
1926
+ return sampleText2 ? [sampleText2] : [];
1927
+ } catch {
1928
+ return [];
1929
+ }
1930
+ }
1931
+ const text = check.text || "";
1932
+ if (!text) return [];
1933
+ const index = source.indexOf(text);
1934
+ const sampleText = textSampleAroundMatch(source, index, text.length);
1935
+ return sampleText ? [sampleText] : [];
1936
+ }
1937
+ function textCheckFailureSamples(viewport, check) {
1938
+ const key = textKey(check);
1939
+ const captured = viewport.text_match_samples?.[key] || [];
1940
+ const capturedSamples = captured.map((sample) => compactTextEvidenceSample(sample).slice(0, 240)).filter(Boolean);
1941
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
1942
+ const matchedSamples = textMatchSamples(viewport.body_text_sample || "", check);
1943
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
1944
+ const fallback = compactTextEvidenceSample(viewport.body_text_sample || "").slice(0, 240);
1945
+ return fallback ? [fallback] : [];
1946
+ }
1904
1947
  function allowedMessageSample(input) {
1905
1948
  if (!isRecord(input)) return String(input || "");
1906
1949
  const parts = [
@@ -2345,10 +2388,17 @@ function assessCheckFromEvidence(check, evidence) {
2345
2388
  if (check.type === "text_visible" || check.type === "text_absent") {
2346
2389
  const key = textKey(check);
2347
2390
  const expectedVisible = check.type === "text_visible";
2348
- const matches = viewports.map((viewport) => {
2391
+ const results = viewports.map((viewport) => {
2349
2392
  const fromEvidence = viewport.text_matches?.[key];
2350
- return typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
2393
+ const matched = typeof fromEvidence === "boolean" ? fromEvidence : matchText(viewport.body_text_sample || "", check);
2394
+ const failedAgainstExpectation = matched !== expectedVisible;
2395
+ return {
2396
+ viewport: viewport.name,
2397
+ matched,
2398
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : []
2399
+ };
2351
2400
  });
2401
+ const matches = results.map((result) => result.matched);
2352
2402
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
2353
2403
  return {
2354
2404
  type: check.type,
@@ -2357,7 +2407,8 @@ function assessCheckFromEvidence(check, evidence) {
2357
2407
  evidence: {
2358
2408
  text: check.text || null,
2359
2409
  pattern: check.pattern || null,
2360
- matches
2410
+ matches,
2411
+ viewports: results.map((result) => toJsonValue(result))
2361
2412
  },
2362
2413
  message: failed ? `Text assertion failed in ${failed} viewport(s).` : void 0
2363
2414
  };
@@ -2944,6 +2995,48 @@ function textMatches(sample, check) {
2944
2995
  }
2945
2996
  return String(sample || "").includes(check.text || "");
2946
2997
  }
2998
+ function compactTextEvidenceSample(value) {
2999
+ return String(value || "").replace(/\s+/g, " ").trim();
3000
+ }
3001
+ function textSampleAroundMatch(sample, index, length) {
3002
+ if (index < 0) return undefined;
3003
+ const source = String(sample || "");
3004
+ const context = 120;
3005
+ const start = Math.max(0, index - context);
3006
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
3007
+ const prefix = start > 0 ? "..." : "";
3008
+ const suffix = end < source.length ? "..." : "";
3009
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
3010
+ return compacted ? compacted.slice(0, 240) : undefined;
3011
+ }
3012
+ function textMatchSamples(sample, check) {
3013
+ const source = String(sample || "");
3014
+ if (!source) return [];
3015
+ if (check.pattern) {
3016
+ try {
3017
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
3018
+ const match = new RegExp(check.pattern, flags).exec(source);
3019
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
3020
+ return sampleText ? [sampleText] : [];
3021
+ } catch { return []; }
3022
+ }
3023
+ const text = check.text || "";
3024
+ if (!text) return [];
3025
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
3026
+ return sampleText ? [sampleText] : [];
3027
+ }
3028
+ function textCheckFailureSamples(viewport, check) {
3029
+ const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
3030
+ const captured = viewport && viewport.text_match_samples && Array.isArray(viewport.text_match_samples[key]) ? viewport.text_match_samples[key] : [];
3031
+ const capturedSamples = captured
3032
+ .map((sample) => compactTextEvidenceSample(sample).slice(0, 240))
3033
+ .filter(Boolean);
3034
+ if (capturedSamples.length) return capturedSamples.slice(0, 3);
3035
+ const matchedSamples = textMatchSamples(viewport && viewport.body_text_sample || "", check);
3036
+ if (matchedSamples.length) return matchedSamples.slice(0, 3);
3037
+ const fallback = compactTextEvidenceSample(viewport && viewport.body_text_sample || "").slice(0, 240);
3038
+ return fallback ? [fallback] : [];
3039
+ }
2947
3040
  function allowedMessageSample(input) {
2948
3041
  if (!input || typeof input !== "object" || Array.isArray(input)) return String(input || "");
2949
3042
  const parts = [
@@ -4021,13 +4114,22 @@ function assessProfile(profile, evidence) {
4021
4114
  if (check.type === "text_visible" || check.type === "text_absent") {
4022
4115
  const key = check.pattern ? "pattern:" + check.pattern + "/" + (check.flags || "") : "text:" + (check.text || "");
4023
4116
  const expectedVisible = check.type === "text_visible";
4024
- const matches = checkViewports.map((viewport) => viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check));
4117
+ const results = checkViewports.map((viewport) => {
4118
+ const matched = viewport.text_matches && typeof viewport.text_matches[key] === "boolean" ? viewport.text_matches[key] : textMatches(viewport.body_text_sample || "", check);
4119
+ const failedAgainstExpectation = matched !== expectedVisible;
4120
+ return {
4121
+ viewport: viewport.name,
4122
+ matched,
4123
+ samples: failedAgainstExpectation ? textCheckFailureSamples(viewport, check) : [],
4124
+ };
4125
+ });
4126
+ const matches = results.map((result) => result.matched);
4025
4127
  const failed = matches.filter((matched) => matched !== expectedVisible).length;
4026
4128
  checks.push({
4027
4129
  type: check.type,
4028
4130
  label: check.label || check.type,
4029
4131
  status: failed ? "failed" : "passed",
4030
- evidence: { text: check.text, pattern: check.pattern, matches },
4132
+ evidence: { text: check.text, pattern: check.pattern, matches, viewports: results },
4031
4133
  message: failed ? "Text assertion failed in " + failed + " viewport(s)." : undefined,
4032
4134
  });
4033
4135
  continue;
@@ -4347,6 +4449,36 @@ function textMatches(sample, check) {
4347
4449
  }
4348
4450
  return String(sample || "").includes(check.text || "");
4349
4451
  }
4452
+ function compactTextEvidenceSample(value) {
4453
+ return String(value || "").replace(/\s+/g, " ").trim();
4454
+ }
4455
+ function textSampleAroundMatch(sample, index, length) {
4456
+ if (index < 0) return undefined;
4457
+ const source = String(sample || "");
4458
+ const context = 120;
4459
+ const start = Math.max(0, index - context);
4460
+ const end = Math.min(source.length, index + Math.max(length, 1) + context);
4461
+ const prefix = start > 0 ? "..." : "";
4462
+ const suffix = end < source.length ? "..." : "";
4463
+ const compacted = compactTextEvidenceSample(prefix + source.slice(start, end) + suffix);
4464
+ return compacted ? compacted.slice(0, 240) : undefined;
4465
+ }
4466
+ function textMatchSamples(sample, check) {
4467
+ const source = String(sample || "");
4468
+ if (!source) return [];
4469
+ if (check.pattern) {
4470
+ try {
4471
+ const flags = Array.from(new Set(String(check.flags || "").replace(/[gy]/g, "").split(""))).join("");
4472
+ const match = new RegExp(check.pattern, flags).exec(source);
4473
+ const sampleText = match ? textSampleAroundMatch(source, match.index, match[0] ? match[0].length : 1) : undefined;
4474
+ return sampleText ? [sampleText] : [];
4475
+ } catch { return []; }
4476
+ }
4477
+ const text = check.text || "";
4478
+ if (!text) return [];
4479
+ const sampleText = textSampleAroundMatch(source, source.indexOf(text), text.length);
4480
+ return sampleText ? [sampleText] : [];
4481
+ }
4350
4482
  function profileCheckAppliesToViewport(check, viewport) {
4351
4483
  if (!Array.isArray(check.viewports) || !check.viewports.length) return true;
4352
4484
  return Boolean(viewport && viewport.name && check.viewports.includes(viewport.name));
@@ -6298,6 +6430,7 @@ async function captureViewport(viewport) {
6298
6430
  const frames = {};
6299
6431
  const text_sequences = {};
6300
6432
  const text_matches = {};
6433
+ const text_match_samples = {};
6301
6434
  const http_statuses = {};
6302
6435
  const link_statuses = {};
6303
6436
  for (const check of profile.checks || []) {
@@ -6319,7 +6452,10 @@ async function captureViewport(viewport) {
6319
6452
  text_sequences[check.selector] = await selectorTextSequence(check.selector);
6320
6453
  }
6321
6454
  if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
6322
- text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
6455
+ const key = textKey(check);
6456
+ const sample = dom.body_text || dom.body_text_sample || "";
6457
+ text_matches[key] = textMatches(sample, check);
6458
+ text_match_samples[key] = textMatchSamples(sample, check);
6323
6459
  }
6324
6460
  if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
6325
6461
  selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
@@ -6396,6 +6532,7 @@ async function captureViewport(viewport) {
6396
6532
  frames,
6397
6533
  text_sequences,
6398
6534
  text_matches,
6535
+ text_match_samples,
6399
6536
  http_statuses,
6400
6537
  link_statuses,
6401
6538
  route_inventory: routeInventory,
@@ -307,6 +307,7 @@ interface RiddleProofProfileViewportEvidence {
307
307
  frames?: Record<string, Record<string, JsonValue>>;
308
308
  text_sequences?: Record<string, Record<string, JsonValue>>;
309
309
  text_matches?: Record<string, boolean>;
310
+ text_match_samples?: Record<string, string[]>;
310
311
  http_statuses?: Record<string, Record<string, JsonValue>>;
311
312
  link_statuses?: Record<string, Record<string, JsonValue>>;
312
313
  route_inventory?: Record<string, JsonValue>;
package/dist/profile.d.ts CHANGED
@@ -307,6 +307,7 @@ interface RiddleProofProfileViewportEvidence {
307
307
  frames?: Record<string, Record<string, JsonValue>>;
308
308
  text_sequences?: Record<string, Record<string, JsonValue>>;
309
309
  text_matches?: Record<string, boolean>;
310
+ text_match_samples?: Record<string, string[]>;
310
311
  http_statuses?: Record<string, Record<string, JsonValue>>;
311
312
  link_statuses?: Record<string, Record<string, JsonValue>>;
312
313
  route_inventory?: Record<string, JsonValue>;
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-TO3FVF5S.js";
26
+ } from "./chunk-TDK6WFH3.js";
27
27
  export {
28
28
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
29
29
  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.128",
3
+ "version": "0.7.129",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",