@riddledc/riddle-proof 0.7.114 → 0.7.115

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
@@ -406,6 +406,19 @@ These checks are useful for audit/no-diff profiles where the product should
406
406
  show a fallback state and avoid rendering stale loaders, duplicate rows, or
407
407
  missing-resource iframes.
408
408
 
409
+ Use `dialog_count_equals`, `dialog_accept_count_equals`, and
410
+ `dialog_dismiss_count_equals` when destructive-action profiles need to prove
411
+ browser confirm/prompt handling directly. The counts come from the captured
412
+ dialog summary and use `expected_count`:
413
+
414
+ ```json
415
+ [
416
+ { "type": "dialog_count_equals", "expected_count": 2 },
417
+ { "type": "dialog_accept_count_equals", "expected_count": 1 },
418
+ { "type": "dialog_dismiss_count_equals", "expected_count": 1 }
419
+ ]
420
+ ```
421
+
409
422
  Use `url_search_param_equals` and `url_search_param_absent` when the final URL
410
423
  is part of the contract, such as deep-link recovery that must drop a stale
411
424
  local identifier while preserving shareable query state:
@@ -20,6 +20,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
20
20
  "selector_count_equals",
21
21
  "selector_count_equal",
22
22
  "selector_count_eq",
23
+ "dialog_count_equals",
24
+ "dialog_accept_count_equals",
25
+ "dialog_dismiss_count_equals",
23
26
  "selector_text_visible",
24
27
  "selector_text_absent",
25
28
  "selector_text_order",
@@ -772,6 +775,14 @@ function validateRegexPatterns(patterns, label) {
772
775
  }
773
776
  }
774
777
  }
778
+ function isDialogCountCheckType(type) {
779
+ return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
780
+ }
781
+ function dialogCountFieldForCheckType(type) {
782
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
783
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
784
+ return "dialog_count";
785
+ }
775
786
  function normalizeCheck(input, index) {
776
787
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
777
788
  const type = stringValue(input.type);
@@ -779,6 +790,7 @@ function normalizeCheck(input, index) {
779
790
  if (!isSupportedCheckType(type)) {
780
791
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
781
792
  }
793
+ const isDialogCountCheck = isDialogCountCheckType(type);
782
794
  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)) {
783
795
  throw new Error(`checks[${index}] ${type} requires selector.`);
784
796
  }
@@ -810,9 +822,12 @@ function normalizeCheck(input, index) {
810
822
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
811
823
  }
812
824
  const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
813
- if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
825
+ if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
814
826
  throw new Error(`checks[${index}] ${type} requires expected_count.`);
815
827
  }
828
+ if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
829
+ throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
830
+ }
816
831
  const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
817
832
  if (type === "selector_text_order") {
818
833
  if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
@@ -1482,6 +1497,22 @@ function assessCheckFromEvidence(check, evidence) {
1482
1497
  message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
1483
1498
  };
1484
1499
  }
1500
+ if (isDialogCountCheckType(check.type)) {
1501
+ const field = dialogCountFieldForCheckType(check.type);
1502
+ const expectedCount = check.expected_count ?? 0;
1503
+ const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
1504
+ return {
1505
+ type: check.type,
1506
+ label: checkLabel(check),
1507
+ status: actualCount === expectedCount ? "passed" : "failed",
1508
+ evidence: {
1509
+ field,
1510
+ expected_count: expectedCount,
1511
+ count: actualCount
1512
+ },
1513
+ message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
1514
+ };
1515
+ }
1485
1516
  if (check.type === "route_loaded") {
1486
1517
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
1487
1518
  const failed = viewports.filter((viewport) => !successfulRoute({
@@ -2733,6 +2764,16 @@ function summarizeRouteInventory(viewport, inventory) {
2733
2764
  function numberValue(value) {
2734
2765
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2735
2766
  }
2767
+ function isDialogCountCheckType(type) {
2768
+ return type === "dialog_count_equals"
2769
+ || type === "dialog_accept_count_equals"
2770
+ || type === "dialog_dismiss_count_equals";
2771
+ }
2772
+ function dialogCountFieldForCheckType(type) {
2773
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
2774
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
2775
+ return "dialog_count";
2776
+ }
2736
2777
  function maxPositiveNumber() {
2737
2778
  let max = 0;
2738
2779
  for (const value of arguments) {
@@ -3104,6 +3145,19 @@ function assessProfile(profile, evidence) {
3104
3145
  });
3105
3146
  continue;
3106
3147
  }
3148
+ if (isDialogCountCheckType(check.type)) {
3149
+ const field = dialogCountFieldForCheckType(check.type);
3150
+ const expectedCount = check.expected_count == null ? 0 : check.expected_count;
3151
+ const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
3152
+ checks.push({
3153
+ type: check.type,
3154
+ label: check.label || check.type,
3155
+ status: actualCount === expectedCount ? "passed" : "failed",
3156
+ evidence: { field, expected_count: expectedCount, count: actualCount },
3157
+ message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
3158
+ });
3159
+ continue;
3160
+ }
3107
3161
  if (check.type === "route_loaded") {
3108
3162
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
3109
3163
  const failed = checkViewports.filter((viewport) => {
package/dist/cli.cjs CHANGED
@@ -6957,6 +6957,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
6957
6957
  "selector_count_equals",
6958
6958
  "selector_count_equal",
6959
6959
  "selector_count_eq",
6960
+ "dialog_count_equals",
6961
+ "dialog_accept_count_equals",
6962
+ "dialog_dismiss_count_equals",
6960
6963
  "selector_text_visible",
6961
6964
  "selector_text_absent",
6962
6965
  "selector_text_order",
@@ -7709,6 +7712,14 @@ function validateRegexPatterns(patterns, label) {
7709
7712
  }
7710
7713
  }
7711
7714
  }
7715
+ function isDialogCountCheckType(type) {
7716
+ return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
7717
+ }
7718
+ function dialogCountFieldForCheckType(type) {
7719
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
7720
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
7721
+ return "dialog_count";
7722
+ }
7712
7723
  function normalizeCheck(input, index) {
7713
7724
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
7714
7725
  const type = stringValue2(input.type);
@@ -7716,6 +7727,7 @@ function normalizeCheck(input, index) {
7716
7727
  if (!isSupportedCheckType(type)) {
7717
7728
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
7718
7729
  }
7730
+ const isDialogCountCheck = isDialogCountCheckType(type);
7719
7731
  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)) {
7720
7732
  throw new Error(`checks[${index}] ${type} requires selector.`);
7721
7733
  }
@@ -7747,9 +7759,12 @@ function normalizeCheck(input, index) {
7747
7759
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
7748
7760
  }
7749
7761
  const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
7750
- if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
7762
+ if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
7751
7763
  throw new Error(`checks[${index}] ${type} requires expected_count.`);
7752
7764
  }
7765
+ if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
7766
+ throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
7767
+ }
7753
7768
  const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
7754
7769
  if (type === "selector_text_order") {
7755
7770
  if (!stringValue2(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
@@ -8419,6 +8434,22 @@ function assessCheckFromEvidence(check, evidence) {
8419
8434
  message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
8420
8435
  };
8421
8436
  }
8437
+ if (isDialogCountCheckType(check.type)) {
8438
+ const field = dialogCountFieldForCheckType(check.type);
8439
+ const expectedCount = check.expected_count ?? 0;
8440
+ const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
8441
+ return {
8442
+ type: check.type,
8443
+ label: checkLabel(check),
8444
+ status: actualCount === expectedCount ? "passed" : "failed",
8445
+ evidence: {
8446
+ field,
8447
+ expected_count: expectedCount,
8448
+ count: actualCount
8449
+ },
8450
+ message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
8451
+ };
8452
+ }
8422
8453
  if (check.type === "route_loaded") {
8423
8454
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
8424
8455
  const failed = viewports.filter((viewport) => !successfulRoute({
@@ -9654,6 +9685,16 @@ function summarizeRouteInventory(viewport, inventory) {
9654
9685
  function numberValue(value) {
9655
9686
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
9656
9687
  }
9688
+ function isDialogCountCheckType(type) {
9689
+ return type === "dialog_count_equals"
9690
+ || type === "dialog_accept_count_equals"
9691
+ || type === "dialog_dismiss_count_equals";
9692
+ }
9693
+ function dialogCountFieldForCheckType(type) {
9694
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
9695
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
9696
+ return "dialog_count";
9697
+ }
9657
9698
  function maxPositiveNumber() {
9658
9699
  let max = 0;
9659
9700
  for (const value of arguments) {
@@ -10025,6 +10066,19 @@ function assessProfile(profile, evidence) {
10025
10066
  });
10026
10067
  continue;
10027
10068
  }
10069
+ if (isDialogCountCheckType(check.type)) {
10070
+ const field = dialogCountFieldForCheckType(check.type);
10071
+ const expectedCount = check.expected_count == null ? 0 : check.expected_count;
10072
+ const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
10073
+ checks.push({
10074
+ type: check.type,
10075
+ label: check.label || check.type,
10076
+ status: actualCount === expectedCount ? "passed" : "failed",
10077
+ evidence: { field, expected_count: expectedCount, count: actualCount },
10078
+ message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
10079
+ });
10080
+ continue;
10081
+ }
10028
10082
  if (check.type === "route_loaded") {
10029
10083
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
10030
10084
  const failed = checkViewports.filter((viewport) => {
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-3CND75DM.js";
13
+ } from "./chunk-QOOPPRYK.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8750,6 +8750,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8750
8750
  "selector_count_equals",
8751
8751
  "selector_count_equal",
8752
8752
  "selector_count_eq",
8753
+ "dialog_count_equals",
8754
+ "dialog_accept_count_equals",
8755
+ "dialog_dismiss_count_equals",
8753
8756
  "selector_text_visible",
8754
8757
  "selector_text_absent",
8755
8758
  "selector_text_order",
@@ -9502,6 +9505,14 @@ function validateRegexPatterns(patterns, label) {
9502
9505
  }
9503
9506
  }
9504
9507
  }
9508
+ function isDialogCountCheckType(type) {
9509
+ return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
9510
+ }
9511
+ function dialogCountFieldForCheckType(type) {
9512
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
9513
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
9514
+ return "dialog_count";
9515
+ }
9505
9516
  function normalizeCheck(input, index) {
9506
9517
  if (!isRecord2(input)) throw new Error(`checks[${index}] must be an object.`);
9507
9518
  const type = stringValue5(input.type);
@@ -9509,6 +9520,7 @@ function normalizeCheck(input, index) {
9509
9520
  if (!isSupportedCheckType(type)) {
9510
9521
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
9511
9522
  }
9523
+ const isDialogCountCheck = isDialogCountCheckType(type);
9512
9524
  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)) {
9513
9525
  throw new Error(`checks[${index}] ${type} requires selector.`);
9514
9526
  }
@@ -9540,9 +9552,12 @@ function normalizeCheck(input, index) {
9540
9552
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
9541
9553
  }
9542
9554
  const expectedCount = numberValue3(input.expected_count) ?? numberValue3(input.expectedCount) ?? numberValue3(input.count);
9543
- if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
9555
+ if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
9544
9556
  throw new Error(`checks[${index}] ${type} requires expected_count.`);
9545
9557
  }
9558
+ if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
9559
+ throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
9560
+ }
9546
9561
  const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
9547
9562
  if (type === "selector_text_order") {
9548
9563
  if (!stringValue5(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
@@ -10212,6 +10227,22 @@ function assessCheckFromEvidence(check, evidence) {
10212
10227
  message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
10213
10228
  };
10214
10229
  }
10230
+ if (isDialogCountCheckType(check.type)) {
10231
+ const field = dialogCountFieldForCheckType(check.type);
10232
+ const expectedCount = check.expected_count ?? 0;
10233
+ const actualCount = numberValue3(evidence.dom_summary?.[field]) ?? 0;
10234
+ return {
10235
+ type: check.type,
10236
+ label: checkLabel(check),
10237
+ status: actualCount === expectedCount ? "passed" : "failed",
10238
+ evidence: {
10239
+ field,
10240
+ expected_count: expectedCount,
10241
+ count: actualCount
10242
+ },
10243
+ message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
10244
+ };
10245
+ }
10215
10246
  if (check.type === "route_loaded") {
10216
10247
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
10217
10248
  const failed = viewports.filter((viewport) => !successfulRoute({
@@ -11463,6 +11494,16 @@ function summarizeRouteInventory(viewport, inventory) {
11463
11494
  function numberValue(value) {
11464
11495
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
11465
11496
  }
11497
+ function isDialogCountCheckType(type) {
11498
+ return type === "dialog_count_equals"
11499
+ || type === "dialog_accept_count_equals"
11500
+ || type === "dialog_dismiss_count_equals";
11501
+ }
11502
+ function dialogCountFieldForCheckType(type) {
11503
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
11504
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
11505
+ return "dialog_count";
11506
+ }
11466
11507
  function maxPositiveNumber() {
11467
11508
  let max = 0;
11468
11509
  for (const value of arguments) {
@@ -11834,6 +11875,19 @@ function assessProfile(profile, evidence) {
11834
11875
  });
11835
11876
  continue;
11836
11877
  }
11878
+ if (isDialogCountCheckType(check.type)) {
11879
+ const field = dialogCountFieldForCheckType(check.type);
11880
+ const expectedCount = check.expected_count == null ? 0 : check.expected_count;
11881
+ const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
11882
+ checks.push({
11883
+ type: check.type,
11884
+ label: check.label || check.type,
11885
+ status: actualCount === expectedCount ? "passed" : "failed",
11886
+ evidence: { field, expected_count: expectedCount, count: actualCount },
11887
+ message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
11888
+ });
11889
+ continue;
11890
+ }
11837
11891
  if (check.type === "route_loaded") {
11838
11892
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
11839
11893
  const failed = checkViewports.filter((viewport) => {
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ import {
59
59
  resolveRiddleProofProfileTimeoutSec,
60
60
  slugifyRiddleProofProfileName,
61
61
  summarizeRiddleProofProfileResult
62
- } from "./chunk-3CND75DM.js";
62
+ } from "./chunk-QOOPPRYK.js";
63
63
  import {
64
64
  DEFAULT_RIDDLE_API_BASE_URL,
65
65
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -64,6 +64,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
64
64
  "selector_count_equals",
65
65
  "selector_count_equal",
66
66
  "selector_count_eq",
67
+ "dialog_count_equals",
68
+ "dialog_accept_count_equals",
69
+ "dialog_dismiss_count_equals",
67
70
  "selector_text_visible",
68
71
  "selector_text_absent",
69
72
  "selector_text_order",
@@ -816,6 +819,14 @@ function validateRegexPatterns(patterns, label) {
816
819
  }
817
820
  }
818
821
  }
822
+ function isDialogCountCheckType(type) {
823
+ return type === "dialog_count_equals" || type === "dialog_accept_count_equals" || type === "dialog_dismiss_count_equals";
824
+ }
825
+ function dialogCountFieldForCheckType(type) {
826
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
827
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
828
+ return "dialog_count";
829
+ }
819
830
  function normalizeCheck(input, index) {
820
831
  if (!isRecord(input)) throw new Error(`checks[${index}] must be an object.`);
821
832
  const type = stringValue(input.type);
@@ -823,6 +834,7 @@ function normalizeCheck(input, index) {
823
834
  if (!isSupportedCheckType(type)) {
824
835
  throw new Error(`checks[${index}].type ${type} is not supported. Supported checks: ${RIDDLE_PROOF_PROFILE_CHECK_TYPES.join(", ")}`);
825
836
  }
837
+ const isDialogCountCheck = isDialogCountCheckType(type);
826
838
  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)) {
827
839
  throw new Error(`checks[${index}] ${type} requires selector.`);
828
840
  }
@@ -854,9 +866,12 @@ function normalizeCheck(input, index) {
854
866
  throw new Error(`checks[${index}] selector_count_at_least requires min_count.`);
855
867
  }
856
868
  const expectedCount = numberValue(input.expected_count) ?? numberValue(input.expectedCount) ?? numberValue(input.count);
857
- if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && expectedCount === void 0) {
869
+ if ((type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq" || isDialogCountCheck) && expectedCount === void 0) {
858
870
  throw new Error(`checks[${index}] ${type} requires expected_count.`);
859
871
  }
872
+ if (isDialogCountCheck && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
873
+ throw new Error(`checks[${index}] ${type} expected_count must be a non-negative integer.`);
874
+ }
860
875
  const expectedTexts = normalizeExpectedTexts(input.expected_texts ?? input.expectedTexts, index);
861
876
  if (type === "selector_text_order") {
862
877
  if (!stringValue(input.selector)) throw new Error(`checks[${index}] selector_text_order requires selector.`);
@@ -1526,6 +1541,22 @@ function assessCheckFromEvidence(check, evidence) {
1526
1541
  message: check.viewports?.length ? `No matching viewport evidence was captured for ${check.viewports.join(", ")}.` : "No viewport evidence was captured."
1527
1542
  };
1528
1543
  }
1544
+ if (isDialogCountCheckType(check.type)) {
1545
+ const field = dialogCountFieldForCheckType(check.type);
1546
+ const expectedCount = check.expected_count ?? 0;
1547
+ const actualCount = numberValue(evidence.dom_summary?.[field]) ?? 0;
1548
+ return {
1549
+ type: check.type,
1550
+ label: checkLabel(check),
1551
+ status: actualCount === expectedCount ? "passed" : "failed",
1552
+ evidence: {
1553
+ field,
1554
+ expected_count: expectedCount,
1555
+ count: actualCount
1556
+ },
1557
+ message: actualCount === expectedCount ? void 0 : `${field} did not equal ${expectedCount}; observed ${actualCount}.`
1558
+ };
1559
+ }
1529
1560
  if (check.type === "route_loaded") {
1530
1561
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
1531
1562
  const failed = viewports.filter((viewport) => !successfulRoute({
@@ -2777,6 +2808,16 @@ function summarizeRouteInventory(viewport, inventory) {
2777
2808
  function numberValue(value) {
2778
2809
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2779
2810
  }
2811
+ function isDialogCountCheckType(type) {
2812
+ return type === "dialog_count_equals"
2813
+ || type === "dialog_accept_count_equals"
2814
+ || type === "dialog_dismiss_count_equals";
2815
+ }
2816
+ function dialogCountFieldForCheckType(type) {
2817
+ if (type === "dialog_accept_count_equals") return "dialog_accept_count";
2818
+ if (type === "dialog_dismiss_count_equals") return "dialog_dismiss_count";
2819
+ return "dialog_count";
2820
+ }
2780
2821
  function maxPositiveNumber() {
2781
2822
  let max = 0;
2782
2823
  for (const value of arguments) {
@@ -3148,6 +3189,19 @@ function assessProfile(profile, evidence) {
3148
3189
  });
3149
3190
  continue;
3150
3191
  }
3192
+ if (isDialogCountCheckType(check.type)) {
3193
+ const field = dialogCountFieldForCheckType(check.type);
3194
+ const expectedCount = check.expected_count == null ? 0 : check.expected_count;
3195
+ const actualCount = numberValue(evidence.dom_summary && evidence.dom_summary[field]) ?? 0;
3196
+ checks.push({
3197
+ type: check.type,
3198
+ label: check.label || check.type,
3199
+ status: actualCount === expectedCount ? "passed" : "failed",
3200
+ evidence: { field, expected_count: expectedCount, count: actualCount },
3201
+ message: actualCount === expectedCount ? undefined : field + " did not equal " + expectedCount + "; observed " + actualCount + ".",
3202
+ });
3203
+ continue;
3204
+ }
3151
3205
  if (check.type === "route_loaded") {
3152
3206
  const expectedPath = check.expected_path || new URL(evidence.target_url).pathname || "/";
3153
3207
  const failed = checkViewports.filter((viewport) => {
@@ -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_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
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", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "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", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
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_visible", "selector_text_absent", "selector_text_order", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
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", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "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", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
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
@@ -20,7 +20,7 @@ import {
20
20
  resolveRiddleProofProfileTimeoutSec,
21
21
  slugifyRiddleProofProfileName,
22
22
  summarizeRiddleProofProfileResult
23
- } from "./chunk-3CND75DM.js";
23
+ } from "./chunk-QOOPPRYK.js";
24
24
  export {
25
25
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
26
26
  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.114",
3
+ "version": "0.7.115",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",