@riddledc/riddle-proof 0.7.162 → 0.7.164

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.
@@ -571,6 +571,41 @@ function profileSetupCanvasSignatureReceipts(results) {
571
571
  reason: result.reason ?? result.error ?? null
572
572
  }));
573
573
  }
574
+ function profileSetupCanvasSignatureStableHashGroups(results) {
575
+ const groups = /* @__PURE__ */ new Map();
576
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
577
+ if (receipt.ok === false) continue;
578
+ const hash = stringValue(receipt.hash);
579
+ if (!hash) continue;
580
+ const selector = stringValue(receipt.selector) || "canvas";
581
+ const frameSelector = stringValue(receipt.frame_selector);
582
+ const key = String(frameSelector || "") + "\n" + selector;
583
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
584
+ const ordinal = numberValue(receipt.ordinal);
585
+ const label = stringValue(receipt.label) || (ordinal === void 0 ? `capture-${group.receipts.length + 1}` : `#${ordinal}`);
586
+ group.receipts.push({ hash, label, ordinal });
587
+ groups.set(key, group);
588
+ }
589
+ const warnings = [];
590
+ for (const group of groups.values()) {
591
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
592
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
593
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
594
+ const visibleLabels = labels.slice(0, 8);
595
+ warnings.push({
596
+ selector: group.selector,
597
+ frame_selector: group.frame_selector ?? null,
598
+ hash: group.receipts[0].hash,
599
+ count: group.receipts.length,
600
+ label_count: labels.length,
601
+ labels: visibleLabels,
602
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
603
+ ordinals: group.receipts.map((receipt) => receipt.ordinal).filter((value) => value !== void 0).slice(0, 12),
604
+ reason: "stable_canvas_signature_hash"
605
+ });
606
+ }
607
+ return warnings;
608
+ }
574
609
  function sampleProfileSetupSummaryItems(items, limit) {
575
610
  if (items.length <= limit) return items;
576
611
  const firstCount = Math.floor(limit / 2);
@@ -671,6 +706,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
671
706
  canvas_signature_total: canvasSignatureReceipts.length,
672
707
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
673
708
  canvas_signature: sampledCanvasSignatureReceipts,
709
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
674
710
  clicked,
675
711
  text_samples,
676
712
  failed: failed.map((result) => ({
@@ -4152,6 +4188,48 @@ function profileSetupCanvasSignatureReceipts(results) {
4152
4188
  reason: result.reason || result.error || null,
4153
4189
  }));
4154
4190
  }
4191
+ function profileSetupCanvasSignatureStableHashGroups(results) {
4192
+ const groups = new Map();
4193
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
4194
+ if (receipt.ok === false) continue;
4195
+ const hash = typeof receipt.hash === "string" && receipt.hash.trim() ? receipt.hash.trim() : undefined;
4196
+ if (!hash) continue;
4197
+ const selector = typeof receipt.selector === "string" && receipt.selector.trim() ? receipt.selector.trim() : "canvas";
4198
+ const frameSelector = typeof receipt.frame_selector === "string" && receipt.frame_selector.trim() ? receipt.frame_selector.trim() : undefined;
4199
+ const key = String(frameSelector || "") + "\\n" + selector;
4200
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
4201
+ const ordinal = typeof receipt.ordinal === "number" && Number.isFinite(receipt.ordinal) ? receipt.ordinal : undefined;
4202
+ const label = typeof receipt.label === "string" && receipt.label.trim()
4203
+ ? receipt.label.trim()
4204
+ : ordinal === undefined
4205
+ ? "capture-" + (group.receipts.length + 1)
4206
+ : "#" + ordinal;
4207
+ group.receipts.push({ hash, label, ordinal });
4208
+ groups.set(key, group);
4209
+ }
4210
+ const warnings = [];
4211
+ for (const group of groups.values()) {
4212
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
4213
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
4214
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
4215
+ const visibleLabels = labels.slice(0, 8);
4216
+ warnings.push({
4217
+ selector: group.selector,
4218
+ frame_selector: group.frame_selector || null,
4219
+ hash: group.receipts[0].hash,
4220
+ count: group.receipts.length,
4221
+ label_count: labels.length,
4222
+ labels: visibleLabels,
4223
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
4224
+ ordinals: group.receipts
4225
+ .map((receipt) => receipt.ordinal)
4226
+ .filter((value) => value !== undefined)
4227
+ .slice(0, 12),
4228
+ reason: "stable_canvas_signature_hash",
4229
+ });
4230
+ }
4231
+ return warnings;
4232
+ }
4155
4233
  function sampleProfileSetupSummaryItems(items, limit) {
4156
4234
  if ((items || []).length <= limit) return items || [];
4157
4235
  const firstCount = Math.floor(limit / 2);
@@ -4276,6 +4354,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
4276
4354
  canvas_signature_total: canvasSignatureReceipts.length,
4277
4355
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
4278
4356
  canvas_signature: sampledCanvasSignatureReceipts,
4357
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
4279
4358
  clicked,
4280
4359
  text_samples: textSamples,
4281
4360
  failed: failed.map((result) => ({
package/dist/cli.cjs CHANGED
@@ -7528,6 +7528,41 @@ function profileSetupCanvasSignatureReceipts(results) {
7528
7528
  reason: result.reason ?? result.error ?? null
7529
7529
  }));
7530
7530
  }
7531
+ function profileSetupCanvasSignatureStableHashGroups(results) {
7532
+ const groups = /* @__PURE__ */ new Map();
7533
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
7534
+ if (receipt.ok === false) continue;
7535
+ const hash = stringValue2(receipt.hash);
7536
+ if (!hash) continue;
7537
+ const selector = stringValue2(receipt.selector) || "canvas";
7538
+ const frameSelector = stringValue2(receipt.frame_selector);
7539
+ const key = String(frameSelector || "") + "\n" + selector;
7540
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
7541
+ const ordinal = numberValue(receipt.ordinal);
7542
+ const label = stringValue2(receipt.label) || (ordinal === void 0 ? `capture-${group.receipts.length + 1}` : `#${ordinal}`);
7543
+ group.receipts.push({ hash, label, ordinal });
7544
+ groups.set(key, group);
7545
+ }
7546
+ const warnings = [];
7547
+ for (const group of groups.values()) {
7548
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
7549
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
7550
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
7551
+ const visibleLabels = labels.slice(0, 8);
7552
+ warnings.push({
7553
+ selector: group.selector,
7554
+ frame_selector: group.frame_selector ?? null,
7555
+ hash: group.receipts[0].hash,
7556
+ count: group.receipts.length,
7557
+ label_count: labels.length,
7558
+ labels: visibleLabels,
7559
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
7560
+ ordinals: group.receipts.map((receipt) => receipt.ordinal).filter((value) => value !== void 0).slice(0, 12),
7561
+ reason: "stable_canvas_signature_hash"
7562
+ });
7563
+ }
7564
+ return warnings;
7565
+ }
7531
7566
  function sampleProfileSetupSummaryItems(items, limit) {
7532
7567
  if (items.length <= limit) return items;
7533
7568
  const firstCount = Math.floor(limit / 2);
@@ -7628,6 +7663,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
7628
7663
  canvas_signature_total: canvasSignatureReceipts.length,
7629
7664
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
7630
7665
  canvas_signature: sampledCanvasSignatureReceipts,
7666
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
7631
7667
  clicked,
7632
7668
  text_samples,
7633
7669
  failed: failed.map((result) => ({
@@ -11093,6 +11129,48 @@ function profileSetupCanvasSignatureReceipts(results) {
11093
11129
  reason: result.reason || result.error || null,
11094
11130
  }));
11095
11131
  }
11132
+ function profileSetupCanvasSignatureStableHashGroups(results) {
11133
+ const groups = new Map();
11134
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
11135
+ if (receipt.ok === false) continue;
11136
+ const hash = typeof receipt.hash === "string" && receipt.hash.trim() ? receipt.hash.trim() : undefined;
11137
+ if (!hash) continue;
11138
+ const selector = typeof receipt.selector === "string" && receipt.selector.trim() ? receipt.selector.trim() : "canvas";
11139
+ const frameSelector = typeof receipt.frame_selector === "string" && receipt.frame_selector.trim() ? receipt.frame_selector.trim() : undefined;
11140
+ const key = String(frameSelector || "") + "\\n" + selector;
11141
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
11142
+ const ordinal = typeof receipt.ordinal === "number" && Number.isFinite(receipt.ordinal) ? receipt.ordinal : undefined;
11143
+ const label = typeof receipt.label === "string" && receipt.label.trim()
11144
+ ? receipt.label.trim()
11145
+ : ordinal === undefined
11146
+ ? "capture-" + (group.receipts.length + 1)
11147
+ : "#" + ordinal;
11148
+ group.receipts.push({ hash, label, ordinal });
11149
+ groups.set(key, group);
11150
+ }
11151
+ const warnings = [];
11152
+ for (const group of groups.values()) {
11153
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
11154
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
11155
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
11156
+ const visibleLabels = labels.slice(0, 8);
11157
+ warnings.push({
11158
+ selector: group.selector,
11159
+ frame_selector: group.frame_selector || null,
11160
+ hash: group.receipts[0].hash,
11161
+ count: group.receipts.length,
11162
+ label_count: labels.length,
11163
+ labels: visibleLabels,
11164
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
11165
+ ordinals: group.receipts
11166
+ .map((receipt) => receipt.ordinal)
11167
+ .filter((value) => value !== undefined)
11168
+ .slice(0, 12),
11169
+ reason: "stable_canvas_signature_hash",
11170
+ });
11171
+ }
11172
+ return warnings;
11173
+ }
11096
11174
  function sampleProfileSetupSummaryItems(items, limit) {
11097
11175
  if ((items || []).length <= limit) return items || [];
11098
11176
  const firstCount = Math.floor(limit / 2);
@@ -11217,6 +11295,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
11217
11295
  canvas_signature_total: canvasSignatureReceipts.length,
11218
11296
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
11219
11297
  canvas_signature: sampledCanvasSignatureReceipts,
11298
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
11220
11299
  clicked,
11221
11300
  text_samples: textSamples,
11222
11301
  failed: failed.map((result) => ({
@@ -15858,6 +15937,25 @@ function profileSetupSummaryMarkdown(result) {
15858
15937
  lines.push(`- ${name} canvas_signature: ${ok}, ${markdownInlineCode(selector)}${label ? ` ${markdownInlineCode(label, 80)}` : ""}${hash ? ` hash ${markdownInlineCode(hash, 80)}` : ""}${sizeText}${cssSizeText}${dataLength === void 0 ? "" : `, data chars ${dataLength}`}${compareTo ? `, compared ${markdownInlineCode(compareTo)}` : ""}${previousHash ? ` previous ${markdownInlineCode(previousHash, 80)}` : ""}${changed === void 0 ? "" : `, changed ${changed}`}${storedTo ? `, stored ${markdownInlineCode(storedTo)}` : ""}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
15859
15938
  }
15860
15939
  if (canvasSignatureDetails.length > sampledCanvasSignatureDetails.length) lines.push(`- ${canvasSignatureDetails.length - sampledCanvasSignatureDetails.length} additional canvas_signature receipt(s) omitted.`);
15940
+ const canvasSignatureWarningGroups = viewports.map((viewport) => {
15941
+ const name = cliString(viewport.name) || "viewport";
15942
+ const warnings = Array.isArray(viewport.canvas_signature_stable_hash_groups) ? viewport.canvas_signature_stable_hash_groups.map(cliRecord).filter((item) => Boolean(item)) : [];
15943
+ return warnings.map((warning) => ({ name, receipt: warning }));
15944
+ });
15945
+ const canvasSignatureWarnings = canvasSignatureWarningGroups.flat();
15946
+ const sampledCanvasSignatureWarnings = balancedSetupReceiptDetails(canvasSignatureWarningGroups, 12);
15947
+ for (const { name, receipt } of sampledCanvasSignatureWarnings) {
15948
+ const selector = cliString(receipt.selector) || "canvas";
15949
+ const frameSelector = cliString(receipt.frame_selector);
15950
+ const hash = cliString(receipt.hash);
15951
+ const count = cliFiniteNumber(receipt.count);
15952
+ const labelCount = cliFiniteNumber(receipt.label_count);
15953
+ const labels = cliStringArray(receipt.labels);
15954
+ const omittedLabelCount = cliFiniteNumber(receipt.omitted_label_count) || 0;
15955
+ const labelText = labels.length ? ` across ${labels.map((label) => markdownInlineCode(label, 60)).join(", ")}${omittedLabelCount ? `, plus ${omittedLabelCount} more` : ""}` : "";
15956
+ lines.push(`- ${name} canvas_signature warning: ${markdownInlineCode(selector)}${frameSelector ? ` in frame ${markdownInlineCode(frameSelector)}` : ""} returned the same hash${hash ? ` ${markdownInlineCode(hash, 80)}` : ""} for ${count ?? labelCount ?? "multiple"} labeled capture(s)${labelText}; treat canvas signatures as diagnostic when runtime evidence or screenshots show state changes.`);
15957
+ }
15958
+ if (canvasSignatureWarnings.length > sampledCanvasSignatureWarnings.length) lines.push(`- ${canvasSignatureWarnings.length - sampledCanvasSignatureWarnings.length} additional canvas_signature warning(s) omitted.`);
15861
15959
  const rangeValueGroups = viewports.map((viewport) => {
15862
15960
  const name = cliString(viewport.name) || "viewport";
15863
15961
  const receipts = Array.isArray(viewport.set_range_value) ? viewport.set_range_value.map(cliRecord).filter((item) => Boolean(item)) : [];
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  profileStatusExitCode,
14
14
  resolveRiddleProofProfileTargetUrl,
15
15
  resolveRiddleProofProfileTimeoutSec
16
- } from "./chunk-ZLNPYVMJ.js";
16
+ } from "./chunk-RXJ7YQBJ.js";
17
17
  import {
18
18
  createRiddleApiClient,
19
19
  isTerminalRiddleJobStatus,
@@ -860,6 +860,25 @@ function profileSetupSummaryMarkdown(result) {
860
860
  lines.push(`- ${name} canvas_signature: ${ok}, ${markdownInlineCode(selector)}${label ? ` ${markdownInlineCode(label, 80)}` : ""}${hash ? ` hash ${markdownInlineCode(hash, 80)}` : ""}${sizeText}${cssSizeText}${dataLength === void 0 ? "" : `, data chars ${dataLength}`}${compareTo ? `, compared ${markdownInlineCode(compareTo)}` : ""}${previousHash ? ` previous ${markdownInlineCode(previousHash, 80)}` : ""}${changed === void 0 ? "" : `, changed ${changed}`}${storedTo ? `, stored ${markdownInlineCode(storedTo)}` : ""}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
861
861
  }
862
862
  if (canvasSignatureDetails.length > sampledCanvasSignatureDetails.length) lines.push(`- ${canvasSignatureDetails.length - sampledCanvasSignatureDetails.length} additional canvas_signature receipt(s) omitted.`);
863
+ const canvasSignatureWarningGroups = viewports.map((viewport) => {
864
+ const name = cliString(viewport.name) || "viewport";
865
+ const warnings = Array.isArray(viewport.canvas_signature_stable_hash_groups) ? viewport.canvas_signature_stable_hash_groups.map(cliRecord).filter((item) => Boolean(item)) : [];
866
+ return warnings.map((warning) => ({ name, receipt: warning }));
867
+ });
868
+ const canvasSignatureWarnings = canvasSignatureWarningGroups.flat();
869
+ const sampledCanvasSignatureWarnings = balancedSetupReceiptDetails(canvasSignatureWarningGroups, 12);
870
+ for (const { name, receipt } of sampledCanvasSignatureWarnings) {
871
+ const selector = cliString(receipt.selector) || "canvas";
872
+ const frameSelector = cliString(receipt.frame_selector);
873
+ const hash = cliString(receipt.hash);
874
+ const count = cliFiniteNumber(receipt.count);
875
+ const labelCount = cliFiniteNumber(receipt.label_count);
876
+ const labels = cliStringArray(receipt.labels);
877
+ const omittedLabelCount = cliFiniteNumber(receipt.omitted_label_count) || 0;
878
+ const labelText = labels.length ? ` across ${labels.map((label) => markdownInlineCode(label, 60)).join(", ")}${omittedLabelCount ? `, plus ${omittedLabelCount} more` : ""}` : "";
879
+ lines.push(`- ${name} canvas_signature warning: ${markdownInlineCode(selector)}${frameSelector ? ` in frame ${markdownInlineCode(frameSelector)}` : ""} returned the same hash${hash ? ` ${markdownInlineCode(hash, 80)}` : ""} for ${count ?? labelCount ?? "multiple"} labeled capture(s)${labelText}; treat canvas signatures as diagnostic when runtime evidence or screenshots show state changes.`);
880
+ }
881
+ if (canvasSignatureWarnings.length > sampledCanvasSignatureWarnings.length) lines.push(`- ${canvasSignatureWarnings.length - sampledCanvasSignatureWarnings.length} additional canvas_signature warning(s) omitted.`);
863
882
  const rangeValueGroups = viewports.map((viewport) => {
864
883
  const name = cliString(viewport.name) || "viewport";
865
884
  const receipts = Array.isArray(viewport.set_range_value) ? viewport.set_range_value.map(cliRecord).filter((item) => Boolean(item)) : [];
package/dist/index.cjs CHANGED
@@ -9304,6 +9304,41 @@ function profileSetupCanvasSignatureReceipts(results) {
9304
9304
  reason: result.reason ?? result.error ?? null
9305
9305
  }));
9306
9306
  }
9307
+ function profileSetupCanvasSignatureStableHashGroups(results) {
9308
+ const groups = /* @__PURE__ */ new Map();
9309
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
9310
+ if (receipt.ok === false) continue;
9311
+ const hash = stringValue5(receipt.hash);
9312
+ if (!hash) continue;
9313
+ const selector = stringValue5(receipt.selector) || "canvas";
9314
+ const frameSelector = stringValue5(receipt.frame_selector);
9315
+ const key = String(frameSelector || "") + "\n" + selector;
9316
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
9317
+ const ordinal = numberValue3(receipt.ordinal);
9318
+ const label = stringValue5(receipt.label) || (ordinal === void 0 ? `capture-${group.receipts.length + 1}` : `#${ordinal}`);
9319
+ group.receipts.push({ hash, label, ordinal });
9320
+ groups.set(key, group);
9321
+ }
9322
+ const warnings = [];
9323
+ for (const group of groups.values()) {
9324
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
9325
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
9326
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
9327
+ const visibleLabels = labels.slice(0, 8);
9328
+ warnings.push({
9329
+ selector: group.selector,
9330
+ frame_selector: group.frame_selector ?? null,
9331
+ hash: group.receipts[0].hash,
9332
+ count: group.receipts.length,
9333
+ label_count: labels.length,
9334
+ labels: visibleLabels,
9335
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
9336
+ ordinals: group.receipts.map((receipt) => receipt.ordinal).filter((value) => value !== void 0).slice(0, 12),
9337
+ reason: "stable_canvas_signature_hash"
9338
+ });
9339
+ }
9340
+ return warnings;
9341
+ }
9307
9342
  function sampleProfileSetupSummaryItems(items, limit) {
9308
9343
  if (items.length <= limit) return items;
9309
9344
  const firstCount = Math.floor(limit / 2);
@@ -9404,6 +9439,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9404
9439
  canvas_signature_total: canvasSignatureReceipts.length,
9405
9440
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
9406
9441
  canvas_signature: sampledCanvasSignatureReceipts,
9442
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
9407
9443
  clicked,
9408
9444
  text_samples,
9409
9445
  failed: failed.map((result) => ({
@@ -12885,6 +12921,48 @@ function profileSetupCanvasSignatureReceipts(results) {
12885
12921
  reason: result.reason || result.error || null,
12886
12922
  }));
12887
12923
  }
12924
+ function profileSetupCanvasSignatureStableHashGroups(results) {
12925
+ const groups = new Map();
12926
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
12927
+ if (receipt.ok === false) continue;
12928
+ const hash = typeof receipt.hash === "string" && receipt.hash.trim() ? receipt.hash.trim() : undefined;
12929
+ if (!hash) continue;
12930
+ const selector = typeof receipt.selector === "string" && receipt.selector.trim() ? receipt.selector.trim() : "canvas";
12931
+ const frameSelector = typeof receipt.frame_selector === "string" && receipt.frame_selector.trim() ? receipt.frame_selector.trim() : undefined;
12932
+ const key = String(frameSelector || "") + "\\n" + selector;
12933
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
12934
+ const ordinal = typeof receipt.ordinal === "number" && Number.isFinite(receipt.ordinal) ? receipt.ordinal : undefined;
12935
+ const label = typeof receipt.label === "string" && receipt.label.trim()
12936
+ ? receipt.label.trim()
12937
+ : ordinal === undefined
12938
+ ? "capture-" + (group.receipts.length + 1)
12939
+ : "#" + ordinal;
12940
+ group.receipts.push({ hash, label, ordinal });
12941
+ groups.set(key, group);
12942
+ }
12943
+ const warnings = [];
12944
+ for (const group of groups.values()) {
12945
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
12946
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
12947
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
12948
+ const visibleLabels = labels.slice(0, 8);
12949
+ warnings.push({
12950
+ selector: group.selector,
12951
+ frame_selector: group.frame_selector || null,
12952
+ hash: group.receipts[0].hash,
12953
+ count: group.receipts.length,
12954
+ label_count: labels.length,
12955
+ labels: visibleLabels,
12956
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
12957
+ ordinals: group.receipts
12958
+ .map((receipt) => receipt.ordinal)
12959
+ .filter((value) => value !== undefined)
12960
+ .slice(0, 12),
12961
+ reason: "stable_canvas_signature_hash",
12962
+ });
12963
+ }
12964
+ return warnings;
12965
+ }
12888
12966
  function sampleProfileSetupSummaryItems(items, limit) {
12889
12967
  if ((items || []).length <= limit) return items || [];
12890
12968
  const firstCount = Math.floor(limit / 2);
@@ -13009,6 +13087,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
13009
13087
  canvas_signature_total: canvasSignatureReceipts.length,
13010
13088
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
13011
13089
  canvas_signature: sampledCanvasSignatureReceipts,
13090
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
13012
13091
  clicked,
13013
13092
  text_samples: textSamples,
13014
13093
  failed: failed.map((result) => ({
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-ZLNPYVMJ.js";
65
+ } from "./chunk-RXJ7YQBJ.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -618,6 +618,41 @@ function profileSetupCanvasSignatureReceipts(results) {
618
618
  reason: result.reason ?? result.error ?? null
619
619
  }));
620
620
  }
621
+ function profileSetupCanvasSignatureStableHashGroups(results) {
622
+ const groups = /* @__PURE__ */ new Map();
623
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
624
+ if (receipt.ok === false) continue;
625
+ const hash = stringValue(receipt.hash);
626
+ if (!hash) continue;
627
+ const selector = stringValue(receipt.selector) || "canvas";
628
+ const frameSelector = stringValue(receipt.frame_selector);
629
+ const key = String(frameSelector || "") + "\n" + selector;
630
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
631
+ const ordinal = numberValue(receipt.ordinal);
632
+ const label = stringValue(receipt.label) || (ordinal === void 0 ? `capture-${group.receipts.length + 1}` : `#${ordinal}`);
633
+ group.receipts.push({ hash, label, ordinal });
634
+ groups.set(key, group);
635
+ }
636
+ const warnings = [];
637
+ for (const group of groups.values()) {
638
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
639
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
640
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
641
+ const visibleLabels = labels.slice(0, 8);
642
+ warnings.push({
643
+ selector: group.selector,
644
+ frame_selector: group.frame_selector ?? null,
645
+ hash: group.receipts[0].hash,
646
+ count: group.receipts.length,
647
+ label_count: labels.length,
648
+ labels: visibleLabels,
649
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
650
+ ordinals: group.receipts.map((receipt) => receipt.ordinal).filter((value) => value !== void 0).slice(0, 12),
651
+ reason: "stable_canvas_signature_hash"
652
+ });
653
+ }
654
+ return warnings;
655
+ }
621
656
  function sampleProfileSetupSummaryItems(items, limit) {
622
657
  if (items.length <= limit) return items;
623
658
  const firstCount = Math.floor(limit / 2);
@@ -718,6 +753,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
718
753
  canvas_signature_total: canvasSignatureReceipts.length,
719
754
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
720
755
  canvas_signature: sampledCanvasSignatureReceipts,
756
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
721
757
  clicked,
722
758
  text_samples,
723
759
  failed: failed.map((result) => ({
@@ -4199,6 +4235,48 @@ function profileSetupCanvasSignatureReceipts(results) {
4199
4235
  reason: result.reason || result.error || null,
4200
4236
  }));
4201
4237
  }
4238
+ function profileSetupCanvasSignatureStableHashGroups(results) {
4239
+ const groups = new Map();
4240
+ for (const receipt of profileSetupCanvasSignatureReceipts(results)) {
4241
+ if (receipt.ok === false) continue;
4242
+ const hash = typeof receipt.hash === "string" && receipt.hash.trim() ? receipt.hash.trim() : undefined;
4243
+ if (!hash) continue;
4244
+ const selector = typeof receipt.selector === "string" && receipt.selector.trim() ? receipt.selector.trim() : "canvas";
4245
+ const frameSelector = typeof receipt.frame_selector === "string" && receipt.frame_selector.trim() ? receipt.frame_selector.trim() : undefined;
4246
+ const key = String(frameSelector || "") + "\\n" + selector;
4247
+ const group = groups.get(key) || { selector, frame_selector: frameSelector, receipts: [] };
4248
+ const ordinal = typeof receipt.ordinal === "number" && Number.isFinite(receipt.ordinal) ? receipt.ordinal : undefined;
4249
+ const label = typeof receipt.label === "string" && receipt.label.trim()
4250
+ ? receipt.label.trim()
4251
+ : ordinal === undefined
4252
+ ? "capture-" + (group.receipts.length + 1)
4253
+ : "#" + ordinal;
4254
+ group.receipts.push({ hash, label, ordinal });
4255
+ groups.set(key, group);
4256
+ }
4257
+ const warnings = [];
4258
+ for (const group of groups.values()) {
4259
+ const hashes = new Set(group.receipts.map((receipt) => receipt.hash));
4260
+ const labels = [...new Set(group.receipts.map((receipt) => receipt.label))];
4261
+ if (group.receipts.length < 2 || labels.length < 2 || hashes.size !== 1) continue;
4262
+ const visibleLabels = labels.slice(0, 8);
4263
+ warnings.push({
4264
+ selector: group.selector,
4265
+ frame_selector: group.frame_selector || null,
4266
+ hash: group.receipts[0].hash,
4267
+ count: group.receipts.length,
4268
+ label_count: labels.length,
4269
+ labels: visibleLabels,
4270
+ omitted_label_count: Math.max(0, labels.length - visibleLabels.length),
4271
+ ordinals: group.receipts
4272
+ .map((receipt) => receipt.ordinal)
4273
+ .filter((value) => value !== undefined)
4274
+ .slice(0, 12),
4275
+ reason: "stable_canvas_signature_hash",
4276
+ });
4277
+ }
4278
+ return warnings;
4279
+ }
4202
4280
  function sampleProfileSetupSummaryItems(items, limit) {
4203
4281
  if ((items || []).length <= limit) return items || [];
4204
4282
  const firstCount = Math.floor(limit / 2);
@@ -4323,6 +4401,7 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
4323
4401
  canvas_signature_total: canvasSignatureReceipts.length,
4324
4402
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
4325
4403
  canvas_signature: sampledCanvasSignatureReceipts,
4404
+ canvas_signature_stable_hash_groups: profileSetupCanvasSignatureStableHashGroups(results),
4326
4405
  clicked,
4327
4406
  text_samples: textSamples,
4328
4407
  failed: failed.map((result) => ({
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-ZLNPYVMJ.js";
26
+ } from "./chunk-RXJ7YQBJ.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.162",
3
+ "version": "0.7.164",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",