@riddledc/riddle-proof 0.7.144 → 0.7.146

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.
@@ -2030,11 +2030,17 @@ function summarizeRouteInventory(viewport, inventory) {
2030
2030
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
2031
2031
  const sourceLinkCount = numberValue(inventory.source_link_count) ?? numberValue(inventory.home_game_link_count) ?? null;
2032
2032
  const sourceUniqueLinkCount = numberValue(inventory.source_unique_link_count) ?? numberValue(inventory.home_unique_game_link_count) ?? null;
2033
+ const sourceCandidateCount = numberValue(inventory.source_candidate_count);
2034
+ const sourceCandidateUniqueLinkCount = numberValue(inventory.source_candidate_unique_link_count);
2035
+ const sourceLinkScope = stringValue(inventory.source_link_scope);
2033
2036
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
2034
2037
  const duplicateSourceLinkCount = numberValue(inventory.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
2035
2038
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
2036
2039
  return {
2037
2040
  viewport,
2041
+ source_link_scope: sourceLinkScope ?? null,
2042
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
2043
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
2038
2044
  source_link_count: sourceLinkCount,
2039
2045
  source_unique_link_count: sourceUniqueLinkCount,
2040
2046
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -2673,6 +2679,9 @@ function assessCheckFromEvidence(check, evidence) {
2673
2679
  const clickthroughs = Array.isArray(first?.clickthroughs) ? first.clickthroughs : [];
2674
2680
  const sourceLinkCount = numberValue(first?.source_link_count) ?? numberValue(first?.home_game_link_count) ?? null;
2675
2681
  const sourceUniqueLinkCount = numberValue(first?.source_unique_link_count) ?? numberValue(first?.home_unique_game_link_count) ?? null;
2682
+ const sourceCandidateCount = numberValue(first?.source_candidate_count);
2683
+ const sourceCandidateUniqueLinkCount = numberValue(first?.source_candidate_unique_link_count);
2684
+ const sourceLinkScope = stringValue(first?.source_link_scope);
2676
2685
  const duplicateSourceLinks = Array.isArray(first?.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
2677
2686
  const duplicateSourceLinkCount = numberValue(first?.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
2678
2687
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first?.expected_routes, check.expected_routes);
@@ -2683,6 +2692,9 @@ function assessCheckFromEvidence(check, evidence) {
2683
2692
  evidence: {
2684
2693
  expected_count: check.expected_routes?.length || 0,
2685
2694
  expected_routes: expectedRoutes,
2695
+ source_link_scope: sourceLinkScope ?? null,
2696
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
2697
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
2686
2698
  source_link_count: sourceLinkCount,
2687
2699
  source_unique_link_count: sourceUniqueLinkCount,
2688
2700
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -3675,11 +3687,17 @@ function summarizeRouteInventory(viewport, inventory) {
3675
3687
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
3676
3688
  const sourceLinkCount = typeof inventory.source_link_count === "number" ? inventory.source_link_count : typeof inventory.home_game_link_count === "number" ? inventory.home_game_link_count : null;
3677
3689
  const sourceUniqueLinkCount = typeof inventory.source_unique_link_count === "number" ? inventory.source_unique_link_count : typeof inventory.home_unique_game_link_count === "number" ? inventory.home_unique_game_link_count : null;
3690
+ const sourceCandidateCount = typeof inventory.source_candidate_count === "number" ? inventory.source_candidate_count : null;
3691
+ const sourceCandidateUniqueLinkCount = typeof inventory.source_candidate_unique_link_count === "number" ? inventory.source_candidate_unique_link_count : null;
3692
+ const sourceLinkScope = typeof inventory.source_link_scope === "string" ? inventory.source_link_scope : null;
3678
3693
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
3679
3694
  const duplicateSourceLinkCount = typeof inventory.duplicate_source_link_count === "number" ? inventory.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
3680
3695
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
3681
3696
  return {
3682
3697
  viewport,
3698
+ source_link_scope: sourceLinkScope,
3699
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
3700
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
3683
3701
  source_link_count: sourceLinkCount,
3684
3702
  source_unique_link_count: sourceUniqueLinkCount,
3685
3703
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -4550,6 +4568,9 @@ function assessProfile(profile, evidence) {
4550
4568
  const clickthroughs = Array.isArray(first.clickthroughs) ? first.clickthroughs : [];
4551
4569
  const sourceLinkCount = typeof first.source_link_count === "number" ? first.source_link_count : typeof first.home_game_link_count === "number" ? first.home_game_link_count : null;
4552
4570
  const sourceUniqueLinkCount = typeof first.source_unique_link_count === "number" ? first.source_unique_link_count : typeof first.home_unique_game_link_count === "number" ? first.home_unique_game_link_count : null;
4571
+ const sourceCandidateCount = typeof first.source_candidate_count === "number" ? first.source_candidate_count : null;
4572
+ const sourceCandidateUniqueLinkCount = typeof first.source_candidate_unique_link_count === "number" ? first.source_candidate_unique_link_count : null;
4573
+ const sourceLinkScope = typeof first.source_link_scope === "string" ? first.source_link_scope : null;
4553
4574
  const duplicateSourceLinks = Array.isArray(first.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
4554
4575
  const duplicateSourceLinkCount = typeof first.duplicate_source_link_count === "number" ? first.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
4555
4576
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first.expected_routes, check.expected_routes);
@@ -4560,6 +4581,9 @@ function assessProfile(profile, evidence) {
4560
4581
  evidence: {
4561
4582
  expected_count: (check.expected_routes || []).length,
4562
4583
  expected_routes: expectedRoutes,
4584
+ source_link_scope: sourceLinkScope,
4585
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
4586
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
4563
4587
  source_link_count: sourceLinkCount,
4564
4588
  source_unique_link_count: sourceUniqueLinkCount,
4565
4589
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -6731,9 +6755,15 @@ async function collectInventoryHomeLinks(check) {
6731
6755
  app_path: appPath,
6732
6756
  };
6733
6757
  });
6734
- return links.filter((link) => (
6758
+ const selectedLinks = links.filter((link) => (
6735
6759
  routePathPrefix ? link.app_path.startsWith(routePathPrefix) : expectedSet.has(link.app_path)
6736
6760
  ));
6761
+ return {
6762
+ links: selectedLinks,
6763
+ candidate_count: links.length,
6764
+ candidate_unique_link_count: Array.from(new Set(links.map((link) => link.app_path))).length,
6765
+ source_link_scope: routePathPrefix ? "route_path_prefix" : "expected_routes",
6766
+ };
6737
6767
  }, { linkSelector, expectedPaths, routePathPrefix, targetUrl });
6738
6768
  }
6739
6769
  async function waitForInventoryRouteHealth(check, expectedPath) {
@@ -6874,7 +6904,11 @@ async function collectRouteInventory(check, viewport) {
6874
6904
  const expectedPaths = expectedRoutes.map((route) => normalizeRoutePath(route.path));
6875
6905
  const expectedSet = new Set(expectedPaths);
6876
6906
  const failures = [];
6877
- const homeLinks = await collectInventoryHomeLinks(check);
6907
+ const homeLinkCapture = await collectInventoryHomeLinks(check);
6908
+ const homeLinks = Array.isArray(homeLinkCapture) ? homeLinkCapture : Array.isArray(homeLinkCapture && homeLinkCapture.links) ? homeLinkCapture.links : [];
6909
+ const sourceCandidateCount = typeof homeLinkCapture?.candidate_count === "number" ? homeLinkCapture.candidate_count : homeLinks.length;
6910
+ const sourceCandidateUniqueLinkCount = typeof homeLinkCapture?.candidate_unique_link_count === "number" ? homeLinkCapture.candidate_unique_link_count : new Set(homeLinks.map((link) => link.app_path)).size;
6911
+ const sourceLinkScope = typeof homeLinkCapture?.source_link_scope === "string" ? homeLinkCapture.source_link_scope : check.route_path_prefix ? "route_path_prefix" : "expected_routes";
6878
6912
  const homeLinkPaths = homeLinks.map((link) => link.app_path);
6879
6913
  const uniqueHomeLinkPaths = Array.from(new Set(homeLinkPaths));
6880
6914
  const duplicateHomeLinkPaths = homeLinkPaths.filter((path, index) => homeLinkPaths.indexOf(path) !== index);
@@ -6956,6 +6990,9 @@ async function collectRouteInventory(check, viewport) {
6956
6990
  expected_routes: expectedRoutes,
6957
6991
  link_selector: check.link_selector || "a[href]",
6958
6992
  source_selector: check.source_selector || null,
6993
+ source_link_scope: sourceLinkScope,
6994
+ source_candidate_count: sourceCandidateCount,
6995
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount,
6959
6996
  source_link_count: homeLinkPaths.length,
6960
6997
  source_unique_link_count: uniqueHomeLinkPaths.length,
6961
6998
  duplicate_source_link_count: duplicateHomeLinkPaths.length,
@@ -7152,6 +7189,9 @@ async function captureViewport(viewport) {
7152
7189
  expected_routes: routeInventoryCheck.expected_routes || [],
7153
7190
  link_selector: routeInventoryCheck.link_selector || "a[href]",
7154
7191
  source_selector: routeInventoryCheck.source_selector || null,
7192
+ source_link_scope: routeInventoryCheck.route_path_prefix ? "route_path_prefix" : "expected_routes",
7193
+ source_candidate_count: 0,
7194
+ source_candidate_unique_link_count: 0,
7155
7195
  source_link_count: 0,
7156
7196
  source_unique_link_count: 0,
7157
7197
  duplicate_source_link_count: 0,
@@ -7278,6 +7318,9 @@ function buildProfileEvidence(currentViewports) {
7278
7318
  .map((viewport) => ({
7279
7319
  viewport: viewport.name,
7280
7320
  expected_count: (viewport.route_inventory.expected_routes || []).length,
7321
+ source_link_scope: viewport.route_inventory.source_link_scope,
7322
+ source_candidate_count: viewport.route_inventory.source_candidate_count,
7323
+ source_candidate_unique_link_count: viewport.route_inventory.source_candidate_unique_link_count,
7281
7324
  source_link_count: viewport.route_inventory.source_link_count == null ? viewport.route_inventory.home_game_link_count : viewport.route_inventory.source_link_count,
7282
7325
  source_unique_link_count: viewport.route_inventory.source_unique_link_count == null ? viewport.route_inventory.home_unique_game_link_count : viewport.route_inventory.source_unique_link_count,
7283
7326
  duplicate_source_link_count: viewport.route_inventory.duplicate_source_link_count,
package/dist/cli.cjs CHANGED
@@ -6938,6 +6938,7 @@ function createRiddleApiClient(config = {}) {
6938
6938
 
6939
6939
  // src/profile.ts
6940
6940
  var RIDDLE_PROOF_PROFILE_VERSION = "riddle-proof.profile.v1";
6941
+ var RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION = "riddle-proof.profile-evidence.v1";
6941
6942
  var RIDDLE_PROOF_PROFILE_RESULT_VERSION = "riddle-proof.profile-result.v1";
6942
6943
  var RIDDLE_PROOF_PROFILE_STATUSES = [
6943
6944
  "passed",
@@ -8967,11 +8968,17 @@ function summarizeRouteInventory(viewport, inventory) {
8967
8968
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
8968
8969
  const sourceLinkCount = numberValue(inventory.source_link_count) ?? numberValue(inventory.home_game_link_count) ?? null;
8969
8970
  const sourceUniqueLinkCount = numberValue(inventory.source_unique_link_count) ?? numberValue(inventory.home_unique_game_link_count) ?? null;
8971
+ const sourceCandidateCount = numberValue(inventory.source_candidate_count);
8972
+ const sourceCandidateUniqueLinkCount = numberValue(inventory.source_candidate_unique_link_count);
8973
+ const sourceLinkScope = stringValue2(inventory.source_link_scope);
8970
8974
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path7) => String(path7)) : [];
8971
8975
  const duplicateSourceLinkCount = numberValue(inventory.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
8972
8976
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
8973
8977
  return {
8974
8978
  viewport,
8979
+ source_link_scope: sourceLinkScope ?? null,
8980
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
8981
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
8975
8982
  source_link_count: sourceLinkCount,
8976
8983
  source_unique_link_count: sourceUniqueLinkCount,
8977
8984
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -9610,6 +9617,9 @@ function assessCheckFromEvidence(check, evidence) {
9610
9617
  const clickthroughs = Array.isArray(first?.clickthroughs) ? first.clickthroughs : [];
9611
9618
  const sourceLinkCount = numberValue(first?.source_link_count) ?? numberValue(first?.home_game_link_count) ?? null;
9612
9619
  const sourceUniqueLinkCount = numberValue(first?.source_unique_link_count) ?? numberValue(first?.home_unique_game_link_count) ?? null;
9620
+ const sourceCandidateCount = numberValue(first?.source_candidate_count);
9621
+ const sourceCandidateUniqueLinkCount = numberValue(first?.source_candidate_unique_link_count);
9622
+ const sourceLinkScope = stringValue2(first?.source_link_scope);
9613
9623
  const duplicateSourceLinks = Array.isArray(first?.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path7) => String(path7)) : [];
9614
9624
  const duplicateSourceLinkCount = numberValue(first?.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
9615
9625
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first?.expected_routes, check.expected_routes);
@@ -9620,6 +9630,9 @@ function assessCheckFromEvidence(check, evidence) {
9620
9630
  evidence: {
9621
9631
  expected_count: check.expected_routes?.length || 0,
9622
9632
  expected_routes: expectedRoutes,
9633
+ source_link_scope: sourceLinkScope ?? null,
9634
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
9635
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
9623
9636
  source_link_count: sourceLinkCount,
9624
9637
  source_unique_link_count: sourceUniqueLinkCount,
9625
9638
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -10596,11 +10609,17 @@ function summarizeRouteInventory(viewport, inventory) {
10596
10609
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
10597
10610
  const sourceLinkCount = typeof inventory.source_link_count === "number" ? inventory.source_link_count : typeof inventory.home_game_link_count === "number" ? inventory.home_game_link_count : null;
10598
10611
  const sourceUniqueLinkCount = typeof inventory.source_unique_link_count === "number" ? inventory.source_unique_link_count : typeof inventory.home_unique_game_link_count === "number" ? inventory.home_unique_game_link_count : null;
10612
+ const sourceCandidateCount = typeof inventory.source_candidate_count === "number" ? inventory.source_candidate_count : null;
10613
+ const sourceCandidateUniqueLinkCount = typeof inventory.source_candidate_unique_link_count === "number" ? inventory.source_candidate_unique_link_count : null;
10614
+ const sourceLinkScope = typeof inventory.source_link_scope === "string" ? inventory.source_link_scope : null;
10599
10615
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
10600
10616
  const duplicateSourceLinkCount = typeof inventory.duplicate_source_link_count === "number" ? inventory.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
10601
10617
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
10602
10618
  return {
10603
10619
  viewport,
10620
+ source_link_scope: sourceLinkScope,
10621
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
10622
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
10604
10623
  source_link_count: sourceLinkCount,
10605
10624
  source_unique_link_count: sourceUniqueLinkCount,
10606
10625
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -11471,6 +11490,9 @@ function assessProfile(profile, evidence) {
11471
11490
  const clickthroughs = Array.isArray(first.clickthroughs) ? first.clickthroughs : [];
11472
11491
  const sourceLinkCount = typeof first.source_link_count === "number" ? first.source_link_count : typeof first.home_game_link_count === "number" ? first.home_game_link_count : null;
11473
11492
  const sourceUniqueLinkCount = typeof first.source_unique_link_count === "number" ? first.source_unique_link_count : typeof first.home_unique_game_link_count === "number" ? first.home_unique_game_link_count : null;
11493
+ const sourceCandidateCount = typeof first.source_candidate_count === "number" ? first.source_candidate_count : null;
11494
+ const sourceCandidateUniqueLinkCount = typeof first.source_candidate_unique_link_count === "number" ? first.source_candidate_unique_link_count : null;
11495
+ const sourceLinkScope = typeof first.source_link_scope === "string" ? first.source_link_scope : null;
11474
11496
  const duplicateSourceLinks = Array.isArray(first.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
11475
11497
  const duplicateSourceLinkCount = typeof first.duplicate_source_link_count === "number" ? first.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
11476
11498
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first.expected_routes, check.expected_routes);
@@ -11481,6 +11503,9 @@ function assessProfile(profile, evidence) {
11481
11503
  evidence: {
11482
11504
  expected_count: (check.expected_routes || []).length,
11483
11505
  expected_routes: expectedRoutes,
11506
+ source_link_scope: sourceLinkScope,
11507
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
11508
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
11484
11509
  source_link_count: sourceLinkCount,
11485
11510
  source_unique_link_count: sourceUniqueLinkCount,
11486
11511
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -13652,9 +13677,15 @@ async function collectInventoryHomeLinks(check) {
13652
13677
  app_path: appPath,
13653
13678
  };
13654
13679
  });
13655
- return links.filter((link) => (
13680
+ const selectedLinks = links.filter((link) => (
13656
13681
  routePathPrefix ? link.app_path.startsWith(routePathPrefix) : expectedSet.has(link.app_path)
13657
13682
  ));
13683
+ return {
13684
+ links: selectedLinks,
13685
+ candidate_count: links.length,
13686
+ candidate_unique_link_count: Array.from(new Set(links.map((link) => link.app_path))).length,
13687
+ source_link_scope: routePathPrefix ? "route_path_prefix" : "expected_routes",
13688
+ };
13658
13689
  }, { linkSelector, expectedPaths, routePathPrefix, targetUrl });
13659
13690
  }
13660
13691
  async function waitForInventoryRouteHealth(check, expectedPath) {
@@ -13795,7 +13826,11 @@ async function collectRouteInventory(check, viewport) {
13795
13826
  const expectedPaths = expectedRoutes.map((route) => normalizeRoutePath(route.path));
13796
13827
  const expectedSet = new Set(expectedPaths);
13797
13828
  const failures = [];
13798
- const homeLinks = await collectInventoryHomeLinks(check);
13829
+ const homeLinkCapture = await collectInventoryHomeLinks(check);
13830
+ const homeLinks = Array.isArray(homeLinkCapture) ? homeLinkCapture : Array.isArray(homeLinkCapture && homeLinkCapture.links) ? homeLinkCapture.links : [];
13831
+ const sourceCandidateCount = typeof homeLinkCapture?.candidate_count === "number" ? homeLinkCapture.candidate_count : homeLinks.length;
13832
+ const sourceCandidateUniqueLinkCount = typeof homeLinkCapture?.candidate_unique_link_count === "number" ? homeLinkCapture.candidate_unique_link_count : new Set(homeLinks.map((link) => link.app_path)).size;
13833
+ const sourceLinkScope = typeof homeLinkCapture?.source_link_scope === "string" ? homeLinkCapture.source_link_scope : check.route_path_prefix ? "route_path_prefix" : "expected_routes";
13799
13834
  const homeLinkPaths = homeLinks.map((link) => link.app_path);
13800
13835
  const uniqueHomeLinkPaths = Array.from(new Set(homeLinkPaths));
13801
13836
  const duplicateHomeLinkPaths = homeLinkPaths.filter((path, index) => homeLinkPaths.indexOf(path) !== index);
@@ -13877,6 +13912,9 @@ async function collectRouteInventory(check, viewport) {
13877
13912
  expected_routes: expectedRoutes,
13878
13913
  link_selector: check.link_selector || "a[href]",
13879
13914
  source_selector: check.source_selector || null,
13915
+ source_link_scope: sourceLinkScope,
13916
+ source_candidate_count: sourceCandidateCount,
13917
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount,
13880
13918
  source_link_count: homeLinkPaths.length,
13881
13919
  source_unique_link_count: uniqueHomeLinkPaths.length,
13882
13920
  duplicate_source_link_count: duplicateHomeLinkPaths.length,
@@ -14073,6 +14111,9 @@ async function captureViewport(viewport) {
14073
14111
  expected_routes: routeInventoryCheck.expected_routes || [],
14074
14112
  link_selector: routeInventoryCheck.link_selector || "a[href]",
14075
14113
  source_selector: routeInventoryCheck.source_selector || null,
14114
+ source_link_scope: routeInventoryCheck.route_path_prefix ? "route_path_prefix" : "expected_routes",
14115
+ source_candidate_count: 0,
14116
+ source_candidate_unique_link_count: 0,
14076
14117
  source_link_count: 0,
14077
14118
  source_unique_link_count: 0,
14078
14119
  duplicate_source_link_count: 0,
@@ -14199,6 +14240,9 @@ function buildProfileEvidence(currentViewports) {
14199
14240
  .map((viewport) => ({
14200
14241
  viewport: viewport.name,
14201
14242
  expected_count: (viewport.route_inventory.expected_routes || []).length,
14243
+ source_link_scope: viewport.route_inventory.source_link_scope,
14244
+ source_candidate_count: viewport.route_inventory.source_candidate_count,
14245
+ source_candidate_unique_link_count: viewport.route_inventory.source_candidate_unique_link_count,
14202
14246
  source_link_count: viewport.route_inventory.source_link_count == null ? viewport.route_inventory.home_game_link_count : viewport.route_inventory.source_link_count,
14203
14247
  source_unique_link_count: viewport.route_inventory.source_unique_link_count == null ? viewport.route_inventory.home_unique_game_link_count : viewport.route_inventory.source_unique_link_count,
14204
14248
  duplicate_source_link_count: viewport.route_inventory.duplicate_source_link_count,
@@ -14337,7 +14381,7 @@ function usage() {
14337
14381
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
14338
14382
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
14339
14383
  " riddle-proof-loop status --state-path <path>",
14340
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
14384
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--split-viewports true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
14341
14385
  " riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
14342
14386
  " riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
14343
14387
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
@@ -14394,6 +14438,9 @@ function optionBoolean(options, key) {
14394
14438
  function runProfileStrictOption(options) {
14395
14439
  return optionBoolean(options, "strict") ?? false;
14396
14440
  }
14441
+ function runProfileSplitViewportsOption(options) {
14442
+ return optionBoolean(options, "splitViewports") ?? false;
14443
+ }
14397
14444
  function optionNumber(options, ...keys) {
14398
14445
  for (const key of keys) {
14399
14446
  const value = optionString(options, key);
@@ -14706,6 +14753,8 @@ function profileRiddleJobMarkdown(result) {
14706
14753
  const riddle = cliRecord(result.riddle);
14707
14754
  if (!riddle) return [];
14708
14755
  const jobId = cliString(riddle.job_id);
14756
+ const mode = cliString(riddle.mode);
14757
+ const jobCount = cliFiniteNumber(riddle.job_count);
14709
14758
  const status = cliString(riddle.status);
14710
14759
  const terminal = typeof riddle.terminal === "boolean" ? riddle.terminal : void 0;
14711
14760
  const queueElapsedMs = cliFiniteNumber(riddle.queue_elapsed_ms);
@@ -14715,6 +14764,8 @@ function profileRiddleJobMarkdown(result) {
14715
14764
  const submittedAt = cliString(riddle.submitted_at);
14716
14765
  const completedAt = cliString(riddle.completed_at);
14717
14766
  const parts = [
14767
+ mode ? `mode ${markdownInlineCode(mode)}` : "",
14768
+ jobCount === void 0 ? "" : `jobs ${jobCount}`,
14718
14769
  jobId ? `job ${markdownInlineCode(jobId)}` : "",
14719
14770
  status ? `status ${markdownInlineCode(status)}` : "",
14720
14771
  terminal === void 0 ? "" : `terminal ${terminal ? "true" : "false"}`
@@ -14728,6 +14779,21 @@ function profileRiddleJobMarkdown(result) {
14728
14779
  if (submittedAt || completedAt) {
14729
14780
  lines.push(`- timing:${submittedAt ? ` submitted ${markdownInlineCode(submittedAt)}` : ""}${completedAt ? ` completed ${markdownInlineCode(completedAt)}` : ""}`);
14730
14781
  }
14782
+ const splitJobs = Array.isArray(riddle.split_jobs) ? riddle.split_jobs.map(cliRecord).filter((job) => Boolean(job)) : [];
14783
+ for (const job of splitJobs.slice(0, 12)) {
14784
+ const viewport = cliString(job.viewport) || "viewport";
14785
+ const splitJobId = cliString(job.job_id);
14786
+ const splitStatus = cliString(job.status);
14787
+ const splitTerminal = typeof job.terminal === "boolean" ? job.terminal : void 0;
14788
+ lines.push(
14789
+ `- ${viewport}: ${[
14790
+ splitJobId ? `job ${markdownInlineCode(splitJobId)}` : "",
14791
+ splitStatus ? `status ${markdownInlineCode(splitStatus)}` : "",
14792
+ splitTerminal === void 0 ? "" : `terminal ${splitTerminal ? "true" : "false"}`
14793
+ ].filter(Boolean).join(", ") || "job metadata unavailable"}`
14794
+ );
14795
+ }
14796
+ if (splitJobs.length > 12) lines.push(`- ${splitJobs.length - 12} additional split job(s) omitted.`);
14731
14797
  return lines;
14732
14798
  }
14733
14799
  function markdownInlineCode(value, maxLength = 80) {
@@ -14881,6 +14947,12 @@ function cliRouteInventoryRouteList(routes) {
14881
14947
  const omitted = routes.length > 12 ? `; ${routes.length - 12} more` : "";
14882
14948
  return `${visible.join("; ")}${omitted}`;
14883
14949
  }
14950
+ function cliRouteInventorySourceScopeLabel(value) {
14951
+ const scope = cliString(value);
14952
+ if (scope === "expected_routes") return "expected routes";
14953
+ if (scope === "route_path_prefix") return "route path prefix";
14954
+ return scope;
14955
+ }
14884
14956
  function profileEnvironmentBlockerMarkdown(result) {
14885
14957
  const blocker = cliRecord(result.environment_blocker);
14886
14958
  if (!blocker) return [];
@@ -15109,6 +15181,9 @@ function profileRouteInventorySummaryMarkdown(result) {
15109
15181
  const expectedCount = cliFiniteNumber(evidence.expected_count);
15110
15182
  const sourceLinkCount = cliFiniteNumber(evidence.source_link_count);
15111
15183
  const sourceUniqueLinkCount = cliFiniteNumber(evidence.source_unique_link_count);
15184
+ const sourceCandidateCount = cliFiniteNumber(evidence.source_candidate_count);
15185
+ const sourceCandidateUniqueLinkCount = cliFiniteNumber(evidence.source_candidate_unique_link_count);
15186
+ const sourceScopeLabel = cliRouteInventorySourceScopeLabel(evidence.source_link_scope);
15112
15187
  const directRouteCount = cliFiniteNumber(evidence.direct_route_count);
15113
15188
  const clickthroughCount = cliFiniteNumber(evidence.clickthrough_count);
15114
15189
  const topLevelFailures = Array.isArray(evidence.failures) ? evidence.failures.length : void 0;
@@ -15128,15 +15203,21 @@ function profileRouteInventorySummaryMarkdown(result) {
15128
15203
  if (expectedRoutes.length) {
15129
15204
  lines.push(`- ${label} expected routes: ${cliRouteInventoryRouteList(expectedRoutes)}`);
15130
15205
  }
15206
+ if (sourceScopeLabel || sourceCandidateCount !== void 0) {
15207
+ const candidateText = sourceCandidateCount === void 0 ? "" : `; selector candidates ${sourceCandidateCount}${sourceCandidateUniqueLinkCount === void 0 ? "" : ` (${sourceCandidateUniqueLinkCount} unique)`}`;
15208
+ lines.push(`- ${label} source scope: ${sourceScopeLabel || "unknown"}${candidateText}`);
15209
+ }
15131
15210
  for (const viewport of viewports.slice(0, 8)) {
15132
15211
  const viewportName = cliString(viewport.viewport) || cliString(viewport.name) || "viewport";
15133
15212
  const viewportSourceLinkCount = cliFiniteNumber(viewport.source_link_count);
15134
15213
  const viewportSourceUniqueLinkCount = cliFiniteNumber(viewport.source_unique_link_count);
15214
+ const viewportSourceCandidateCount = cliFiniteNumber(viewport.source_candidate_count);
15215
+ const viewportSourceCandidateUniqueLinkCount = cliFiniteNumber(viewport.source_candidate_unique_link_count);
15135
15216
  const viewportDirectRouteCount = cliFiniteNumber(viewport.direct_route_count);
15136
15217
  const viewportClickthroughCount = cliFiniteNumber(viewport.clickthrough_count);
15137
15218
  const viewportFailureCount = cliFiniteNumber(viewport.failure_count) || 0;
15138
15219
  lines.push(
15139
- `- ${label} ${viewportName}: source ${viewportSourceLinkCount ?? "unknown"}${viewportSourceUniqueLinkCount === void 0 ? "" : ` (${viewportSourceUniqueLinkCount} unique)`}, direct ${viewportDirectRouteCount ?? "unknown"}, clickthrough ${viewportClickthroughCount ?? "unknown"}, failures ${viewportFailureCount}`
15220
+ `- ${label} ${viewportName}: source ${viewportSourceLinkCount ?? "unknown"}${viewportSourceUniqueLinkCount === void 0 ? "" : ` (${viewportSourceUniqueLinkCount} unique)`}${viewportSourceCandidateCount === void 0 ? "" : `, selector candidates ${viewportSourceCandidateCount}${viewportSourceCandidateUniqueLinkCount === void 0 ? "" : ` (${viewportSourceCandidateUniqueLinkCount} unique)`}`}, direct ${viewportDirectRouteCount ?? "unknown"}, clickthrough ${viewportClickthroughCount ?? "unknown"}, failures ${viewportFailureCount}`
15140
15221
  );
15141
15222
  }
15142
15223
  if (viewports.length > 8) lines.push(`- ${label}: ${viewports.length - 8} additional viewport(s) omitted from route inventory summary.`);
@@ -15338,13 +15419,146 @@ function riddleMetadataFromPoll(jobId, poll) {
15338
15419
  timed_out: poll.poll?.timed_out
15339
15420
  };
15340
15421
  }
15341
- async function runProfileForCli(profile, options) {
15342
- const runner = optionString(options, "runner") || "riddle";
15343
- if (runner !== "riddle") {
15344
- throw new Error(`Unsupported --runner ${runner}. The current CLI supports --runner riddle.`);
15422
+ function profileForSplitViewport(profile, viewport) {
15423
+ return {
15424
+ ...profile,
15425
+ name: `${profile.name}-${viewport.name || `${viewport.width}x${viewport.height}`}`,
15426
+ target: {
15427
+ ...profile.target,
15428
+ viewports: [viewport]
15429
+ },
15430
+ metadata: {
15431
+ ...profile.metadata || {},
15432
+ split_parent_profile: profile.name,
15433
+ split_viewport: viewport.name
15434
+ }
15435
+ };
15436
+ }
15437
+ function safeProfileOutputSegment(value) {
15438
+ const safe = value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
15439
+ return safe || "viewport";
15440
+ }
15441
+ function splitViewportOutputDir(outputDir, viewportName, seen) {
15442
+ const base = safeProfileOutputSegment(viewportName);
15443
+ const count = seen.get(base) || 0;
15444
+ seen.set(base, count + 1);
15445
+ return import_node_path6.default.join(outputDir, count ? `${base}-${count + 1}` : base);
15446
+ }
15447
+ function splitViewportArtifactRefs(input) {
15448
+ return (input.result.artifacts.riddle_artifacts || []).map((artifact) => ({
15449
+ ...artifact,
15450
+ name: `${safeProfileOutputSegment(input.viewport.name)}/${artifact.name || artifact.kind || "artifact"}`
15451
+ }));
15452
+ }
15453
+ function sumDefinedNumbers(values) {
15454
+ const numbers = values.filter((value) => typeof value === "number" && Number.isFinite(value));
15455
+ return numbers.length ? numbers.reduce((sum, value) => sum + value, 0) : void 0;
15456
+ }
15457
+ function splitViewportRiddleMetadata(childRuns) {
15458
+ const splitJobs = childRuns.map(({ viewport, result }) => ({
15459
+ viewport: viewport.name,
15460
+ job_id: result.riddle?.job_id,
15461
+ status: result.riddle?.status,
15462
+ terminal: result.riddle?.terminal,
15463
+ queue_elapsed_ms: result.riddle?.queue_elapsed_ms,
15464
+ elapsed_ms: result.riddle?.elapsed_ms,
15465
+ attempt: result.riddle?.attempt,
15466
+ attempts: result.riddle?.attempts,
15467
+ timed_out: result.riddle?.timed_out
15468
+ }));
15469
+ return {
15470
+ mode: "split-viewports",
15471
+ job_count: childRuns.length,
15472
+ status: "split-viewports",
15473
+ terminal: childRuns.every(({ result }) => result.riddle?.terminal !== false),
15474
+ queue_elapsed_ms: sumDefinedNumbers(splitJobs.map((job) => job.queue_elapsed_ms)),
15475
+ elapsed_ms: sumDefinedNumbers(splitJobs.map((job) => job.elapsed_ms)),
15476
+ split_jobs: splitJobs
15477
+ };
15478
+ }
15479
+ function latestCapturedAt(evidences) {
15480
+ let latest = "";
15481
+ let latestMs = Number.NEGATIVE_INFINITY;
15482
+ for (const evidence of evidences) {
15483
+ const parsed = Date.parse(evidence.captured_at);
15484
+ if (Number.isFinite(parsed) && parsed >= latestMs) {
15485
+ latest = evidence.captured_at;
15486
+ latestMs = parsed;
15487
+ }
15345
15488
  }
15489
+ return latest || (/* @__PURE__ */ new Date()).toISOString();
15490
+ }
15491
+ function splitViewportDomSummary(profile, childRuns, evidence) {
15492
+ return {
15493
+ split_viewports: true,
15494
+ expected_viewport_count: profile.target.viewports.length,
15495
+ viewport_count: evidence.viewports.length,
15496
+ child_result_count: childRuns.length,
15497
+ child_statuses: childRuns.map(({ viewport, result }) => ({
15498
+ viewport: viewport.name,
15499
+ profile_name: result.profile_name,
15500
+ status: result.status,
15501
+ job_id: result.riddle?.job_id || null
15502
+ })),
15503
+ routes: evidence.viewports.map((viewport) => ({
15504
+ viewport: viewport.name,
15505
+ requested: viewport.route.requested,
15506
+ observed: viewport.route.observed,
15507
+ matched: viewport.route.matched,
15508
+ http_status: viewport.route.http_status ?? null
15509
+ })),
15510
+ titles: evidence.viewports.map((viewport) => viewport.title).filter((title) => Boolean(title)),
15511
+ overflow_px: evidence.viewports.map((viewport) => viewport.overflow_px ?? null),
15512
+ bounds_overflow_px: evidence.viewports.map((viewport) => viewport.bounds_overflow_px ?? null),
15513
+ overflow_offender_counts: evidence.viewports.map((viewport) => (viewport.overflow_offenders || []).length),
15514
+ console_event_count: evidence.console.events.length,
15515
+ console_fatal_count: evidence.console.fatal_count,
15516
+ page_error_count: evidence.page_errors.length,
15517
+ network_mock_count: (profile.target.network_mocks || []).length,
15518
+ network_mock_hit_count: (evidence.network_mocks || []).filter((event) => event.ok !== false).length
15519
+ };
15520
+ }
15521
+ function aggregateSplitViewportEvidence(profile, childRuns) {
15522
+ const evidences = childRuns.map(({ result }) => result.evidence).filter((evidence2) => Boolean(evidence2));
15523
+ const viewports = evidences.flatMap((evidence2) => evidence2.viewports || []);
15524
+ const consoleEvents = evidences.flatMap((evidence2) => evidence2.console?.events || []);
15525
+ const pageErrors = evidences.flatMap((evidence2) => evidence2.page_errors || []);
15526
+ const networkMocks = evidences.flatMap((evidence2) => evidence2.network_mocks || []);
15527
+ const evidence = {
15528
+ version: RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
15529
+ profile_name: profile.name,
15530
+ target_url: resolveRiddleProofProfileTargetUrl(profile),
15531
+ baseline_policy: profile.baseline_policy,
15532
+ captured_at: latestCapturedAt(evidences),
15533
+ viewports,
15534
+ console: {
15535
+ events: consoleEvents,
15536
+ fatal_count: evidences.reduce((sum, item) => sum + (item.console?.fatal_count || 0), 0)
15537
+ },
15538
+ page_errors: pageErrors,
15539
+ network_mocks: networkMocks.length ? networkMocks : void 0
15540
+ };
15541
+ evidence.dom_summary = splitViewportDomSummary(profile, childRuns, evidence);
15542
+ return evidence;
15543
+ }
15544
+ function splitViewportBlockedMessage(childRuns) {
15545
+ const blocked = childRuns.filter(({ result }) => !result.evidence || result.status === "environment_blocked" || result.status === "configuration_error").map(({ viewport, result }) => `${viewport.name}: ${result.status}${result.error ? ` (${result.error})` : ""}`);
15546
+ return `Split viewport run did not produce reliable evidence for ${blocked.join("; ")}.`;
15547
+ }
15548
+ function withSplitViewportWarnings(profile, result) {
15549
+ const warnings = [];
15550
+ if (profile.target.network_mocks?.length) {
15551
+ warnings.push("Split viewport mode runs each viewport in a separate Riddle job; global network mock sequencing is assessed from aggregated events.");
15552
+ }
15553
+ if (!warnings.length) return result;
15554
+ return {
15555
+ ...result,
15556
+ warnings: [.../* @__PURE__ */ new Set([...result.warnings || [], ...warnings])]
15557
+ };
15558
+ }
15559
+ async function runSingleRiddleProfileForCli(profile, options, input) {
15560
+ const { client, runner } = input;
15346
15561
  const targetUrl = resolveRiddleProofProfileTargetUrl(profile);
15347
- const client = createRiddleApiClient(riddleClientConfig(options));
15348
15562
  let created;
15349
15563
  try {
15350
15564
  created = await client.runScript({
@@ -15403,6 +15617,48 @@ async function runProfileForCli(profile, options) {
15403
15617
  artifacts
15404
15618
  });
15405
15619
  }
15620
+ async function runSplitViewportProfileForCli(profile, options, input) {
15621
+ const outputDir = profileOutputDirOption(options);
15622
+ const seenOutputNames = /* @__PURE__ */ new Map();
15623
+ const childRuns = [];
15624
+ for (const viewport of profile.target.viewports) {
15625
+ const childProfile = profileForSplitViewport(profile, viewport);
15626
+ const result2 = await runSingleRiddleProfileForCli(childProfile, options, input);
15627
+ if (outputDir) {
15628
+ writeProfileOutput(splitViewportOutputDir(outputDir, viewport.name, seenOutputNames), result2);
15629
+ }
15630
+ childRuns.push({ viewport, profile: childProfile, result: result2 });
15631
+ }
15632
+ const artifacts = childRuns.flatMap(splitViewportArtifactRefs);
15633
+ const blocked = childRuns.filter(({ result: result2 }) => !result2.evidence || result2.status === "environment_blocked" || result2.status === "configuration_error");
15634
+ if (blocked.length) {
15635
+ return createRiddleProofProfileEnvironmentBlockedResult({
15636
+ profile,
15637
+ runner: input.runner,
15638
+ error: splitViewportBlockedMessage(childRuns),
15639
+ riddle: splitViewportRiddleMetadata(childRuns),
15640
+ artifacts
15641
+ });
15642
+ }
15643
+ const evidence = aggregateSplitViewportEvidence(profile, childRuns);
15644
+ const result = assessRiddleProofProfileEvidence(profile, evidence, {
15645
+ runner: input.runner,
15646
+ riddle: splitViewportRiddleMetadata(childRuns),
15647
+ artifacts
15648
+ });
15649
+ return withSplitViewportWarnings(profile, result);
15650
+ }
15651
+ async function runProfileForCli(profile, options) {
15652
+ const runner = optionString(options, "runner") || "riddle";
15653
+ if (runner !== "riddle") {
15654
+ throw new Error(`Unsupported --runner ${runner}. The current CLI supports --runner riddle.`);
15655
+ }
15656
+ const client = createRiddleApiClient(riddleClientConfig(options));
15657
+ if (runProfileSplitViewportsOption(options) && profile.target.viewports.length > 1) {
15658
+ return runSplitViewportProfileForCli(profile, options, { client, runner });
15659
+ }
15660
+ return runSingleRiddleProfileForCli(profile, options, { client, runner });
15661
+ }
15406
15662
  function requestForRun(options) {
15407
15663
  const statePath = optionString(options, "statePath");
15408
15664
  const withEngineModuleUrl = (request) => {
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
3
4
  assessRiddleProofProfileEvidence,
4
5
  buildRiddleProofProfileScript,
5
6
  collectRiddleProfileArtifactRefs,
@@ -12,7 +13,7 @@ import {
12
13
  profileStatusExitCode,
13
14
  resolveRiddleProofProfileTargetUrl,
14
15
  resolveRiddleProofProfileTimeoutSec
15
- } from "./chunk-LFFTWXLB.js";
16
+ } from "./chunk-ZC6AK3D3.js";
16
17
  import {
17
18
  createRiddleApiClient,
18
19
  parseRiddleViewport
@@ -46,7 +47,7 @@ function usage() {
46
47
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
47
48
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
48
49
  " riddle-proof-loop status --state-path <path>",
49
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
50
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--strict true|false; default false] [--split-viewports true|false; default false] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--quiet]",
50
51
  " riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
51
52
  " riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
52
53
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
@@ -103,6 +104,9 @@ function optionBoolean(options, key) {
103
104
  function runProfileStrictOption(options) {
104
105
  return optionBoolean(options, "strict") ?? false;
105
106
  }
107
+ function runProfileSplitViewportsOption(options) {
108
+ return optionBoolean(options, "splitViewports") ?? false;
109
+ }
106
110
  function optionNumber(options, ...keys) {
107
111
  for (const key of keys) {
108
112
  const value = optionString(options, key);
@@ -415,6 +419,8 @@ function profileRiddleJobMarkdown(result) {
415
419
  const riddle = cliRecord(result.riddle);
416
420
  if (!riddle) return [];
417
421
  const jobId = cliString(riddle.job_id);
422
+ const mode = cliString(riddle.mode);
423
+ const jobCount = cliFiniteNumber(riddle.job_count);
418
424
  const status = cliString(riddle.status);
419
425
  const terminal = typeof riddle.terminal === "boolean" ? riddle.terminal : void 0;
420
426
  const queueElapsedMs = cliFiniteNumber(riddle.queue_elapsed_ms);
@@ -424,6 +430,8 @@ function profileRiddleJobMarkdown(result) {
424
430
  const submittedAt = cliString(riddle.submitted_at);
425
431
  const completedAt = cliString(riddle.completed_at);
426
432
  const parts = [
433
+ mode ? `mode ${markdownInlineCode(mode)}` : "",
434
+ jobCount === void 0 ? "" : `jobs ${jobCount}`,
427
435
  jobId ? `job ${markdownInlineCode(jobId)}` : "",
428
436
  status ? `status ${markdownInlineCode(status)}` : "",
429
437
  terminal === void 0 ? "" : `terminal ${terminal ? "true" : "false"}`
@@ -437,6 +445,21 @@ function profileRiddleJobMarkdown(result) {
437
445
  if (submittedAt || completedAt) {
438
446
  lines.push(`- timing:${submittedAt ? ` submitted ${markdownInlineCode(submittedAt)}` : ""}${completedAt ? ` completed ${markdownInlineCode(completedAt)}` : ""}`);
439
447
  }
448
+ const splitJobs = Array.isArray(riddle.split_jobs) ? riddle.split_jobs.map(cliRecord).filter((job) => Boolean(job)) : [];
449
+ for (const job of splitJobs.slice(0, 12)) {
450
+ const viewport = cliString(job.viewport) || "viewport";
451
+ const splitJobId = cliString(job.job_id);
452
+ const splitStatus = cliString(job.status);
453
+ const splitTerminal = typeof job.terminal === "boolean" ? job.terminal : void 0;
454
+ lines.push(
455
+ `- ${viewport}: ${[
456
+ splitJobId ? `job ${markdownInlineCode(splitJobId)}` : "",
457
+ splitStatus ? `status ${markdownInlineCode(splitStatus)}` : "",
458
+ splitTerminal === void 0 ? "" : `terminal ${splitTerminal ? "true" : "false"}`
459
+ ].filter(Boolean).join(", ") || "job metadata unavailable"}`
460
+ );
461
+ }
462
+ if (splitJobs.length > 12) lines.push(`- ${splitJobs.length - 12} additional split job(s) omitted.`);
440
463
  return lines;
441
464
  }
442
465
  function markdownInlineCode(value, maxLength = 80) {
@@ -590,6 +613,12 @@ function cliRouteInventoryRouteList(routes) {
590
613
  const omitted = routes.length > 12 ? `; ${routes.length - 12} more` : "";
591
614
  return `${visible.join("; ")}${omitted}`;
592
615
  }
616
+ function cliRouteInventorySourceScopeLabel(value) {
617
+ const scope = cliString(value);
618
+ if (scope === "expected_routes") return "expected routes";
619
+ if (scope === "route_path_prefix") return "route path prefix";
620
+ return scope;
621
+ }
593
622
  function profileEnvironmentBlockerMarkdown(result) {
594
623
  const blocker = cliRecord(result.environment_blocker);
595
624
  if (!blocker) return [];
@@ -818,6 +847,9 @@ function profileRouteInventorySummaryMarkdown(result) {
818
847
  const expectedCount = cliFiniteNumber(evidence.expected_count);
819
848
  const sourceLinkCount = cliFiniteNumber(evidence.source_link_count);
820
849
  const sourceUniqueLinkCount = cliFiniteNumber(evidence.source_unique_link_count);
850
+ const sourceCandidateCount = cliFiniteNumber(evidence.source_candidate_count);
851
+ const sourceCandidateUniqueLinkCount = cliFiniteNumber(evidence.source_candidate_unique_link_count);
852
+ const sourceScopeLabel = cliRouteInventorySourceScopeLabel(evidence.source_link_scope);
821
853
  const directRouteCount = cliFiniteNumber(evidence.direct_route_count);
822
854
  const clickthroughCount = cliFiniteNumber(evidence.clickthrough_count);
823
855
  const topLevelFailures = Array.isArray(evidence.failures) ? evidence.failures.length : void 0;
@@ -837,15 +869,21 @@ function profileRouteInventorySummaryMarkdown(result) {
837
869
  if (expectedRoutes.length) {
838
870
  lines.push(`- ${label} expected routes: ${cliRouteInventoryRouteList(expectedRoutes)}`);
839
871
  }
872
+ if (sourceScopeLabel || sourceCandidateCount !== void 0) {
873
+ const candidateText = sourceCandidateCount === void 0 ? "" : `; selector candidates ${sourceCandidateCount}${sourceCandidateUniqueLinkCount === void 0 ? "" : ` (${sourceCandidateUniqueLinkCount} unique)`}`;
874
+ lines.push(`- ${label} source scope: ${sourceScopeLabel || "unknown"}${candidateText}`);
875
+ }
840
876
  for (const viewport of viewports.slice(0, 8)) {
841
877
  const viewportName = cliString(viewport.viewport) || cliString(viewport.name) || "viewport";
842
878
  const viewportSourceLinkCount = cliFiniteNumber(viewport.source_link_count);
843
879
  const viewportSourceUniqueLinkCount = cliFiniteNumber(viewport.source_unique_link_count);
880
+ const viewportSourceCandidateCount = cliFiniteNumber(viewport.source_candidate_count);
881
+ const viewportSourceCandidateUniqueLinkCount = cliFiniteNumber(viewport.source_candidate_unique_link_count);
844
882
  const viewportDirectRouteCount = cliFiniteNumber(viewport.direct_route_count);
845
883
  const viewportClickthroughCount = cliFiniteNumber(viewport.clickthrough_count);
846
884
  const viewportFailureCount = cliFiniteNumber(viewport.failure_count) || 0;
847
885
  lines.push(
848
- `- ${label} ${viewportName}: source ${viewportSourceLinkCount ?? "unknown"}${viewportSourceUniqueLinkCount === void 0 ? "" : ` (${viewportSourceUniqueLinkCount} unique)`}, direct ${viewportDirectRouteCount ?? "unknown"}, clickthrough ${viewportClickthroughCount ?? "unknown"}, failures ${viewportFailureCount}`
886
+ `- ${label} ${viewportName}: source ${viewportSourceLinkCount ?? "unknown"}${viewportSourceUniqueLinkCount === void 0 ? "" : ` (${viewportSourceUniqueLinkCount} unique)`}${viewportSourceCandidateCount === void 0 ? "" : `, selector candidates ${viewportSourceCandidateCount}${viewportSourceCandidateUniqueLinkCount === void 0 ? "" : ` (${viewportSourceCandidateUniqueLinkCount} unique)`}`}, direct ${viewportDirectRouteCount ?? "unknown"}, clickthrough ${viewportClickthroughCount ?? "unknown"}, failures ${viewportFailureCount}`
849
887
  );
850
888
  }
851
889
  if (viewports.length > 8) lines.push(`- ${label}: ${viewports.length - 8} additional viewport(s) omitted from route inventory summary.`);
@@ -1047,13 +1085,146 @@ function riddleMetadataFromPoll(jobId, poll) {
1047
1085
  timed_out: poll.poll?.timed_out
1048
1086
  };
1049
1087
  }
1050
- async function runProfileForCli(profile, options) {
1051
- const runner = optionString(options, "runner") || "riddle";
1052
- if (runner !== "riddle") {
1053
- throw new Error(`Unsupported --runner ${runner}. The current CLI supports --runner riddle.`);
1088
+ function profileForSplitViewport(profile, viewport) {
1089
+ return {
1090
+ ...profile,
1091
+ name: `${profile.name}-${viewport.name || `${viewport.width}x${viewport.height}`}`,
1092
+ target: {
1093
+ ...profile.target,
1094
+ viewports: [viewport]
1095
+ },
1096
+ metadata: {
1097
+ ...profile.metadata || {},
1098
+ split_parent_profile: profile.name,
1099
+ split_viewport: viewport.name
1100
+ }
1101
+ };
1102
+ }
1103
+ function safeProfileOutputSegment(value) {
1104
+ const safe = value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
1105
+ return safe || "viewport";
1106
+ }
1107
+ function splitViewportOutputDir(outputDir, viewportName, seen) {
1108
+ const base = safeProfileOutputSegment(viewportName);
1109
+ const count = seen.get(base) || 0;
1110
+ seen.set(base, count + 1);
1111
+ return path.join(outputDir, count ? `${base}-${count + 1}` : base);
1112
+ }
1113
+ function splitViewportArtifactRefs(input) {
1114
+ return (input.result.artifacts.riddle_artifacts || []).map((artifact) => ({
1115
+ ...artifact,
1116
+ name: `${safeProfileOutputSegment(input.viewport.name)}/${artifact.name || artifact.kind || "artifact"}`
1117
+ }));
1118
+ }
1119
+ function sumDefinedNumbers(values) {
1120
+ const numbers = values.filter((value) => typeof value === "number" && Number.isFinite(value));
1121
+ return numbers.length ? numbers.reduce((sum, value) => sum + value, 0) : void 0;
1122
+ }
1123
+ function splitViewportRiddleMetadata(childRuns) {
1124
+ const splitJobs = childRuns.map(({ viewport, result }) => ({
1125
+ viewport: viewport.name,
1126
+ job_id: result.riddle?.job_id,
1127
+ status: result.riddle?.status,
1128
+ terminal: result.riddle?.terminal,
1129
+ queue_elapsed_ms: result.riddle?.queue_elapsed_ms,
1130
+ elapsed_ms: result.riddle?.elapsed_ms,
1131
+ attempt: result.riddle?.attempt,
1132
+ attempts: result.riddle?.attempts,
1133
+ timed_out: result.riddle?.timed_out
1134
+ }));
1135
+ return {
1136
+ mode: "split-viewports",
1137
+ job_count: childRuns.length,
1138
+ status: "split-viewports",
1139
+ terminal: childRuns.every(({ result }) => result.riddle?.terminal !== false),
1140
+ queue_elapsed_ms: sumDefinedNumbers(splitJobs.map((job) => job.queue_elapsed_ms)),
1141
+ elapsed_ms: sumDefinedNumbers(splitJobs.map((job) => job.elapsed_ms)),
1142
+ split_jobs: splitJobs
1143
+ };
1144
+ }
1145
+ function latestCapturedAt(evidences) {
1146
+ let latest = "";
1147
+ let latestMs = Number.NEGATIVE_INFINITY;
1148
+ for (const evidence of evidences) {
1149
+ const parsed = Date.parse(evidence.captured_at);
1150
+ if (Number.isFinite(parsed) && parsed >= latestMs) {
1151
+ latest = evidence.captured_at;
1152
+ latestMs = parsed;
1153
+ }
1054
1154
  }
1155
+ return latest || (/* @__PURE__ */ new Date()).toISOString();
1156
+ }
1157
+ function splitViewportDomSummary(profile, childRuns, evidence) {
1158
+ return {
1159
+ split_viewports: true,
1160
+ expected_viewport_count: profile.target.viewports.length,
1161
+ viewport_count: evidence.viewports.length,
1162
+ child_result_count: childRuns.length,
1163
+ child_statuses: childRuns.map(({ viewport, result }) => ({
1164
+ viewport: viewport.name,
1165
+ profile_name: result.profile_name,
1166
+ status: result.status,
1167
+ job_id: result.riddle?.job_id || null
1168
+ })),
1169
+ routes: evidence.viewports.map((viewport) => ({
1170
+ viewport: viewport.name,
1171
+ requested: viewport.route.requested,
1172
+ observed: viewport.route.observed,
1173
+ matched: viewport.route.matched,
1174
+ http_status: viewport.route.http_status ?? null
1175
+ })),
1176
+ titles: evidence.viewports.map((viewport) => viewport.title).filter((title) => Boolean(title)),
1177
+ overflow_px: evidence.viewports.map((viewport) => viewport.overflow_px ?? null),
1178
+ bounds_overflow_px: evidence.viewports.map((viewport) => viewport.bounds_overflow_px ?? null),
1179
+ overflow_offender_counts: evidence.viewports.map((viewport) => (viewport.overflow_offenders || []).length),
1180
+ console_event_count: evidence.console.events.length,
1181
+ console_fatal_count: evidence.console.fatal_count,
1182
+ page_error_count: evidence.page_errors.length,
1183
+ network_mock_count: (profile.target.network_mocks || []).length,
1184
+ network_mock_hit_count: (evidence.network_mocks || []).filter((event) => event.ok !== false).length
1185
+ };
1186
+ }
1187
+ function aggregateSplitViewportEvidence(profile, childRuns) {
1188
+ const evidences = childRuns.map(({ result }) => result.evidence).filter((evidence2) => Boolean(evidence2));
1189
+ const viewports = evidences.flatMap((evidence2) => evidence2.viewports || []);
1190
+ const consoleEvents = evidences.flatMap((evidence2) => evidence2.console?.events || []);
1191
+ const pageErrors = evidences.flatMap((evidence2) => evidence2.page_errors || []);
1192
+ const networkMocks = evidences.flatMap((evidence2) => evidence2.network_mocks || []);
1193
+ const evidence = {
1194
+ version: RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
1195
+ profile_name: profile.name,
1196
+ target_url: resolveRiddleProofProfileTargetUrl(profile),
1197
+ baseline_policy: profile.baseline_policy,
1198
+ captured_at: latestCapturedAt(evidences),
1199
+ viewports,
1200
+ console: {
1201
+ events: consoleEvents,
1202
+ fatal_count: evidences.reduce((sum, item) => sum + (item.console?.fatal_count || 0), 0)
1203
+ },
1204
+ page_errors: pageErrors,
1205
+ network_mocks: networkMocks.length ? networkMocks : void 0
1206
+ };
1207
+ evidence.dom_summary = splitViewportDomSummary(profile, childRuns, evidence);
1208
+ return evidence;
1209
+ }
1210
+ function splitViewportBlockedMessage(childRuns) {
1211
+ const blocked = childRuns.filter(({ result }) => !result.evidence || result.status === "environment_blocked" || result.status === "configuration_error").map(({ viewport, result }) => `${viewport.name}: ${result.status}${result.error ? ` (${result.error})` : ""}`);
1212
+ return `Split viewport run did not produce reliable evidence for ${blocked.join("; ")}.`;
1213
+ }
1214
+ function withSplitViewportWarnings(profile, result) {
1215
+ const warnings = [];
1216
+ if (profile.target.network_mocks?.length) {
1217
+ warnings.push("Split viewport mode runs each viewport in a separate Riddle job; global network mock sequencing is assessed from aggregated events.");
1218
+ }
1219
+ if (!warnings.length) return result;
1220
+ return {
1221
+ ...result,
1222
+ warnings: [.../* @__PURE__ */ new Set([...result.warnings || [], ...warnings])]
1223
+ };
1224
+ }
1225
+ async function runSingleRiddleProfileForCli(profile, options, input) {
1226
+ const { client, runner } = input;
1055
1227
  const targetUrl = resolveRiddleProofProfileTargetUrl(profile);
1056
- const client = createRiddleApiClient(riddleClientConfig(options));
1057
1228
  let created;
1058
1229
  try {
1059
1230
  created = await client.runScript({
@@ -1112,6 +1283,48 @@ async function runProfileForCli(profile, options) {
1112
1283
  artifacts
1113
1284
  });
1114
1285
  }
1286
+ async function runSplitViewportProfileForCli(profile, options, input) {
1287
+ const outputDir = profileOutputDirOption(options);
1288
+ const seenOutputNames = /* @__PURE__ */ new Map();
1289
+ const childRuns = [];
1290
+ for (const viewport of profile.target.viewports) {
1291
+ const childProfile = profileForSplitViewport(profile, viewport);
1292
+ const result2 = await runSingleRiddleProfileForCli(childProfile, options, input);
1293
+ if (outputDir) {
1294
+ writeProfileOutput(splitViewportOutputDir(outputDir, viewport.name, seenOutputNames), result2);
1295
+ }
1296
+ childRuns.push({ viewport, profile: childProfile, result: result2 });
1297
+ }
1298
+ const artifacts = childRuns.flatMap(splitViewportArtifactRefs);
1299
+ const blocked = childRuns.filter(({ result: result2 }) => !result2.evidence || result2.status === "environment_blocked" || result2.status === "configuration_error");
1300
+ if (blocked.length) {
1301
+ return createRiddleProofProfileEnvironmentBlockedResult({
1302
+ profile,
1303
+ runner: input.runner,
1304
+ error: splitViewportBlockedMessage(childRuns),
1305
+ riddle: splitViewportRiddleMetadata(childRuns),
1306
+ artifacts
1307
+ });
1308
+ }
1309
+ const evidence = aggregateSplitViewportEvidence(profile, childRuns);
1310
+ const result = assessRiddleProofProfileEvidence(profile, evidence, {
1311
+ runner: input.runner,
1312
+ riddle: splitViewportRiddleMetadata(childRuns),
1313
+ artifacts
1314
+ });
1315
+ return withSplitViewportWarnings(profile, result);
1316
+ }
1317
+ async function runProfileForCli(profile, options) {
1318
+ const runner = optionString(options, "runner") || "riddle";
1319
+ if (runner !== "riddle") {
1320
+ throw new Error(`Unsupported --runner ${runner}. The current CLI supports --runner riddle.`);
1321
+ }
1322
+ const client = createRiddleApiClient(riddleClientConfig(options));
1323
+ if (runProfileSplitViewportsOption(options) && profile.target.viewports.length > 1) {
1324
+ return runSplitViewportProfileForCli(profile, options, { client, runner });
1325
+ }
1326
+ return runSingleRiddleProfileForCli(profile, options, { client, runner });
1327
+ }
1115
1328
  function requestForRun(options) {
1116
1329
  const statePath = optionString(options, "statePath");
1117
1330
  const withEngineModuleUrl = (request) => {
package/dist/index.cjs CHANGED
@@ -10763,11 +10763,17 @@ function summarizeRouteInventory(viewport, inventory) {
10763
10763
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
10764
10764
  const sourceLinkCount = numberValue3(inventory.source_link_count) ?? numberValue3(inventory.home_game_link_count) ?? null;
10765
10765
  const sourceUniqueLinkCount = numberValue3(inventory.source_unique_link_count) ?? numberValue3(inventory.home_unique_game_link_count) ?? null;
10766
+ const sourceCandidateCount = numberValue3(inventory.source_candidate_count);
10767
+ const sourceCandidateUniqueLinkCount = numberValue3(inventory.source_candidate_unique_link_count);
10768
+ const sourceLinkScope = stringValue5(inventory.source_link_scope);
10766
10769
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path6) => String(path6)) : [];
10767
10770
  const duplicateSourceLinkCount = numberValue3(inventory.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
10768
10771
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
10769
10772
  return {
10770
10773
  viewport,
10774
+ source_link_scope: sourceLinkScope ?? null,
10775
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
10776
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
10771
10777
  source_link_count: sourceLinkCount,
10772
10778
  source_unique_link_count: sourceUniqueLinkCount,
10773
10779
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -11406,6 +11412,9 @@ function assessCheckFromEvidence(check, evidence) {
11406
11412
  const clickthroughs = Array.isArray(first?.clickthroughs) ? first.clickthroughs : [];
11407
11413
  const sourceLinkCount = numberValue3(first?.source_link_count) ?? numberValue3(first?.home_game_link_count) ?? null;
11408
11414
  const sourceUniqueLinkCount = numberValue3(first?.source_unique_link_count) ?? numberValue3(first?.home_unique_game_link_count) ?? null;
11415
+ const sourceCandidateCount = numberValue3(first?.source_candidate_count);
11416
+ const sourceCandidateUniqueLinkCount = numberValue3(first?.source_candidate_unique_link_count);
11417
+ const sourceLinkScope = stringValue5(first?.source_link_scope);
11409
11418
  const duplicateSourceLinks = Array.isArray(first?.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path6) => String(path6)) : [];
11410
11419
  const duplicateSourceLinkCount = numberValue3(first?.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
11411
11420
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first?.expected_routes, check.expected_routes);
@@ -11416,6 +11425,9 @@ function assessCheckFromEvidence(check, evidence) {
11416
11425
  evidence: {
11417
11426
  expected_count: check.expected_routes?.length || 0,
11418
11427
  expected_routes: expectedRoutes,
11428
+ source_link_scope: sourceLinkScope ?? null,
11429
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
11430
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
11419
11431
  source_link_count: sourceLinkCount,
11420
11432
  source_unique_link_count: sourceUniqueLinkCount,
11421
11433
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -12408,11 +12420,17 @@ function summarizeRouteInventory(viewport, inventory) {
12408
12420
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
12409
12421
  const sourceLinkCount = typeof inventory.source_link_count === "number" ? inventory.source_link_count : typeof inventory.home_game_link_count === "number" ? inventory.home_game_link_count : null;
12410
12422
  const sourceUniqueLinkCount = typeof inventory.source_unique_link_count === "number" ? inventory.source_unique_link_count : typeof inventory.home_unique_game_link_count === "number" ? inventory.home_unique_game_link_count : null;
12423
+ const sourceCandidateCount = typeof inventory.source_candidate_count === "number" ? inventory.source_candidate_count : null;
12424
+ const sourceCandidateUniqueLinkCount = typeof inventory.source_candidate_unique_link_count === "number" ? inventory.source_candidate_unique_link_count : null;
12425
+ const sourceLinkScope = typeof inventory.source_link_scope === "string" ? inventory.source_link_scope : null;
12411
12426
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
12412
12427
  const duplicateSourceLinkCount = typeof inventory.duplicate_source_link_count === "number" ? inventory.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
12413
12428
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
12414
12429
  return {
12415
12430
  viewport,
12431
+ source_link_scope: sourceLinkScope,
12432
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
12433
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
12416
12434
  source_link_count: sourceLinkCount,
12417
12435
  source_unique_link_count: sourceUniqueLinkCount,
12418
12436
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -13283,6 +13301,9 @@ function assessProfile(profile, evidence) {
13283
13301
  const clickthroughs = Array.isArray(first.clickthroughs) ? first.clickthroughs : [];
13284
13302
  const sourceLinkCount = typeof first.source_link_count === "number" ? first.source_link_count : typeof first.home_game_link_count === "number" ? first.home_game_link_count : null;
13285
13303
  const sourceUniqueLinkCount = typeof first.source_unique_link_count === "number" ? first.source_unique_link_count : typeof first.home_unique_game_link_count === "number" ? first.home_unique_game_link_count : null;
13304
+ const sourceCandidateCount = typeof first.source_candidate_count === "number" ? first.source_candidate_count : null;
13305
+ const sourceCandidateUniqueLinkCount = typeof first.source_candidate_unique_link_count === "number" ? first.source_candidate_unique_link_count : null;
13306
+ const sourceLinkScope = typeof first.source_link_scope === "string" ? first.source_link_scope : null;
13286
13307
  const duplicateSourceLinks = Array.isArray(first.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
13287
13308
  const duplicateSourceLinkCount = typeof first.duplicate_source_link_count === "number" ? first.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
13288
13309
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first.expected_routes, check.expected_routes);
@@ -13293,6 +13314,9 @@ function assessProfile(profile, evidence) {
13293
13314
  evidence: {
13294
13315
  expected_count: (check.expected_routes || []).length,
13295
13316
  expected_routes: expectedRoutes,
13317
+ source_link_scope: sourceLinkScope,
13318
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
13319
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
13296
13320
  source_link_count: sourceLinkCount,
13297
13321
  source_unique_link_count: sourceUniqueLinkCount,
13298
13322
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -15464,9 +15488,15 @@ async function collectInventoryHomeLinks(check) {
15464
15488
  app_path: appPath,
15465
15489
  };
15466
15490
  });
15467
- return links.filter((link) => (
15491
+ const selectedLinks = links.filter((link) => (
15468
15492
  routePathPrefix ? link.app_path.startsWith(routePathPrefix) : expectedSet.has(link.app_path)
15469
15493
  ));
15494
+ return {
15495
+ links: selectedLinks,
15496
+ candidate_count: links.length,
15497
+ candidate_unique_link_count: Array.from(new Set(links.map((link) => link.app_path))).length,
15498
+ source_link_scope: routePathPrefix ? "route_path_prefix" : "expected_routes",
15499
+ };
15470
15500
  }, { linkSelector, expectedPaths, routePathPrefix, targetUrl });
15471
15501
  }
15472
15502
  async function waitForInventoryRouteHealth(check, expectedPath) {
@@ -15607,7 +15637,11 @@ async function collectRouteInventory(check, viewport) {
15607
15637
  const expectedPaths = expectedRoutes.map((route) => normalizeRoutePath(route.path));
15608
15638
  const expectedSet = new Set(expectedPaths);
15609
15639
  const failures = [];
15610
- const homeLinks = await collectInventoryHomeLinks(check);
15640
+ const homeLinkCapture = await collectInventoryHomeLinks(check);
15641
+ const homeLinks = Array.isArray(homeLinkCapture) ? homeLinkCapture : Array.isArray(homeLinkCapture && homeLinkCapture.links) ? homeLinkCapture.links : [];
15642
+ const sourceCandidateCount = typeof homeLinkCapture?.candidate_count === "number" ? homeLinkCapture.candidate_count : homeLinks.length;
15643
+ const sourceCandidateUniqueLinkCount = typeof homeLinkCapture?.candidate_unique_link_count === "number" ? homeLinkCapture.candidate_unique_link_count : new Set(homeLinks.map((link) => link.app_path)).size;
15644
+ const sourceLinkScope = typeof homeLinkCapture?.source_link_scope === "string" ? homeLinkCapture.source_link_scope : check.route_path_prefix ? "route_path_prefix" : "expected_routes";
15611
15645
  const homeLinkPaths = homeLinks.map((link) => link.app_path);
15612
15646
  const uniqueHomeLinkPaths = Array.from(new Set(homeLinkPaths));
15613
15647
  const duplicateHomeLinkPaths = homeLinkPaths.filter((path, index) => homeLinkPaths.indexOf(path) !== index);
@@ -15689,6 +15723,9 @@ async function collectRouteInventory(check, viewport) {
15689
15723
  expected_routes: expectedRoutes,
15690
15724
  link_selector: check.link_selector || "a[href]",
15691
15725
  source_selector: check.source_selector || null,
15726
+ source_link_scope: sourceLinkScope,
15727
+ source_candidate_count: sourceCandidateCount,
15728
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount,
15692
15729
  source_link_count: homeLinkPaths.length,
15693
15730
  source_unique_link_count: uniqueHomeLinkPaths.length,
15694
15731
  duplicate_source_link_count: duplicateHomeLinkPaths.length,
@@ -15885,6 +15922,9 @@ async function captureViewport(viewport) {
15885
15922
  expected_routes: routeInventoryCheck.expected_routes || [],
15886
15923
  link_selector: routeInventoryCheck.link_selector || "a[href]",
15887
15924
  source_selector: routeInventoryCheck.source_selector || null,
15925
+ source_link_scope: routeInventoryCheck.route_path_prefix ? "route_path_prefix" : "expected_routes",
15926
+ source_candidate_count: 0,
15927
+ source_candidate_unique_link_count: 0,
15888
15928
  source_link_count: 0,
15889
15929
  source_unique_link_count: 0,
15890
15930
  duplicate_source_link_count: 0,
@@ -16011,6 +16051,9 @@ function buildProfileEvidence(currentViewports) {
16011
16051
  .map((viewport) => ({
16012
16052
  viewport: viewport.name,
16013
16053
  expected_count: (viewport.route_inventory.expected_routes || []).length,
16054
+ source_link_scope: viewport.route_inventory.source_link_scope,
16055
+ source_candidate_count: viewport.route_inventory.source_candidate_count,
16056
+ source_candidate_unique_link_count: viewport.route_inventory.source_candidate_unique_link_count,
16014
16057
  source_link_count: viewport.route_inventory.source_link_count == null ? viewport.route_inventory.home_game_link_count : viewport.route_inventory.source_link_count,
16015
16058
  source_unique_link_count: viewport.route_inventory.source_unique_link_count == null ? viewport.route_inventory.home_unique_game_link_count : viewport.route_inventory.source_unique_link_count,
16016
16059
  duplicate_source_link_count: viewport.route_inventory.duplicate_source_link_count,
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-LFFTWXLB.js";
65
+ } from "./chunk-ZC6AK3D3.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -2077,11 +2077,17 @@ function summarizeRouteInventory(viewport, inventory) {
2077
2077
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
2078
2078
  const sourceLinkCount = numberValue(inventory.source_link_count) ?? numberValue(inventory.home_game_link_count) ?? null;
2079
2079
  const sourceUniqueLinkCount = numberValue(inventory.source_unique_link_count) ?? numberValue(inventory.home_unique_game_link_count) ?? null;
2080
+ const sourceCandidateCount = numberValue(inventory.source_candidate_count);
2081
+ const sourceCandidateUniqueLinkCount = numberValue(inventory.source_candidate_unique_link_count);
2082
+ const sourceLinkScope = stringValue(inventory.source_link_scope);
2080
2083
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
2081
2084
  const duplicateSourceLinkCount = numberValue(inventory.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
2082
2085
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
2083
2086
  return {
2084
2087
  viewport,
2088
+ source_link_scope: sourceLinkScope ?? null,
2089
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
2090
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
2085
2091
  source_link_count: sourceLinkCount,
2086
2092
  source_unique_link_count: sourceUniqueLinkCount,
2087
2093
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -2720,6 +2726,9 @@ function assessCheckFromEvidence(check, evidence) {
2720
2726
  const clickthroughs = Array.isArray(first?.clickthroughs) ? first.clickthroughs : [];
2721
2727
  const sourceLinkCount = numberValue(first?.source_link_count) ?? numberValue(first?.home_game_link_count) ?? null;
2722
2728
  const sourceUniqueLinkCount = numberValue(first?.source_unique_link_count) ?? numberValue(first?.home_unique_game_link_count) ?? null;
2729
+ const sourceCandidateCount = numberValue(first?.source_candidate_count);
2730
+ const sourceCandidateUniqueLinkCount = numberValue(first?.source_candidate_unique_link_count);
2731
+ const sourceLinkScope = stringValue(first?.source_link_scope);
2723
2732
  const duplicateSourceLinks = Array.isArray(first?.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
2724
2733
  const duplicateSourceLinkCount = numberValue(first?.duplicate_source_link_count) ?? (sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null);
2725
2734
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first?.expected_routes, check.expected_routes);
@@ -2730,6 +2739,9 @@ function assessCheckFromEvidence(check, evidence) {
2730
2739
  evidence: {
2731
2740
  expected_count: check.expected_routes?.length || 0,
2732
2741
  expected_routes: expectedRoutes,
2742
+ source_link_scope: sourceLinkScope ?? null,
2743
+ source_candidate_count: sourceCandidateCount ?? sourceLinkCount,
2744
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount ?? sourceUniqueLinkCount,
2733
2745
  source_link_count: sourceLinkCount,
2734
2746
  source_unique_link_count: sourceUniqueLinkCount,
2735
2747
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -3722,11 +3734,17 @@ function summarizeRouteInventory(viewport, inventory) {
3722
3734
  const clickthroughs = Array.isArray(inventory.clickthroughs) ? inventory.clickthroughs : [];
3723
3735
  const sourceLinkCount = typeof inventory.source_link_count === "number" ? inventory.source_link_count : typeof inventory.home_game_link_count === "number" ? inventory.home_game_link_count : null;
3724
3736
  const sourceUniqueLinkCount = typeof inventory.source_unique_link_count === "number" ? inventory.source_unique_link_count : typeof inventory.home_unique_game_link_count === "number" ? inventory.home_unique_game_link_count : null;
3737
+ const sourceCandidateCount = typeof inventory.source_candidate_count === "number" ? inventory.source_candidate_count : null;
3738
+ const sourceCandidateUniqueLinkCount = typeof inventory.source_candidate_unique_link_count === "number" ? inventory.source_candidate_unique_link_count : null;
3739
+ const sourceLinkScope = typeof inventory.source_link_scope === "string" ? inventory.source_link_scope : null;
3725
3740
  const duplicateSourceLinks = Array.isArray(inventory.duplicate_source_link_paths) ? inventory.duplicate_source_link_paths.map((path) => String(path)) : [];
3726
3741
  const duplicateSourceLinkCount = typeof inventory.duplicate_source_link_count === "number" ? inventory.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
3727
3742
  const failures = Array.isArray(inventory.failures) ? inventory.failures : [];
3728
3743
  return {
3729
3744
  viewport,
3745
+ source_link_scope: sourceLinkScope,
3746
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
3747
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
3730
3748
  source_link_count: sourceLinkCount,
3731
3749
  source_unique_link_count: sourceUniqueLinkCount,
3732
3750
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -4597,6 +4615,9 @@ function assessProfile(profile, evidence) {
4597
4615
  const clickthroughs = Array.isArray(first.clickthroughs) ? first.clickthroughs : [];
4598
4616
  const sourceLinkCount = typeof first.source_link_count === "number" ? first.source_link_count : typeof first.home_game_link_count === "number" ? first.home_game_link_count : null;
4599
4617
  const sourceUniqueLinkCount = typeof first.source_unique_link_count === "number" ? first.source_unique_link_count : typeof first.home_unique_game_link_count === "number" ? first.home_unique_game_link_count : null;
4618
+ const sourceCandidateCount = typeof first.source_candidate_count === "number" ? first.source_candidate_count : null;
4619
+ const sourceCandidateUniqueLinkCount = typeof first.source_candidate_unique_link_count === "number" ? first.source_candidate_unique_link_count : null;
4620
+ const sourceLinkScope = typeof first.source_link_scope === "string" ? first.source_link_scope : null;
4600
4621
  const duplicateSourceLinks = Array.isArray(first.duplicate_source_link_paths) ? first.duplicate_source_link_paths.map((path) => String(path)) : [];
4601
4622
  const duplicateSourceLinkCount = typeof first.duplicate_source_link_count === "number" ? first.duplicate_source_link_count : sourceLinkCount !== null && sourceUniqueLinkCount !== null ? Math.max(0, sourceLinkCount - sourceUniqueLinkCount) : null;
4602
4623
  const expectedRoutes = routeInventoryExpectedRouteSummaries(first.expected_routes, check.expected_routes);
@@ -4607,6 +4628,9 @@ function assessProfile(profile, evidence) {
4607
4628
  evidence: {
4608
4629
  expected_count: (check.expected_routes || []).length,
4609
4630
  expected_routes: expectedRoutes,
4631
+ source_link_scope: sourceLinkScope,
4632
+ source_candidate_count: sourceCandidateCount == null ? sourceLinkCount : sourceCandidateCount,
4633
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount == null ? sourceUniqueLinkCount : sourceCandidateUniqueLinkCount,
4610
4634
  source_link_count: sourceLinkCount,
4611
4635
  source_unique_link_count: sourceUniqueLinkCount,
4612
4636
  duplicate_source_link_count: duplicateSourceLinkCount,
@@ -6778,9 +6802,15 @@ async function collectInventoryHomeLinks(check) {
6778
6802
  app_path: appPath,
6779
6803
  };
6780
6804
  });
6781
- return links.filter((link) => (
6805
+ const selectedLinks = links.filter((link) => (
6782
6806
  routePathPrefix ? link.app_path.startsWith(routePathPrefix) : expectedSet.has(link.app_path)
6783
6807
  ));
6808
+ return {
6809
+ links: selectedLinks,
6810
+ candidate_count: links.length,
6811
+ candidate_unique_link_count: Array.from(new Set(links.map((link) => link.app_path))).length,
6812
+ source_link_scope: routePathPrefix ? "route_path_prefix" : "expected_routes",
6813
+ };
6784
6814
  }, { linkSelector, expectedPaths, routePathPrefix, targetUrl });
6785
6815
  }
6786
6816
  async function waitForInventoryRouteHealth(check, expectedPath) {
@@ -6921,7 +6951,11 @@ async function collectRouteInventory(check, viewport) {
6921
6951
  const expectedPaths = expectedRoutes.map((route) => normalizeRoutePath(route.path));
6922
6952
  const expectedSet = new Set(expectedPaths);
6923
6953
  const failures = [];
6924
- const homeLinks = await collectInventoryHomeLinks(check);
6954
+ const homeLinkCapture = await collectInventoryHomeLinks(check);
6955
+ const homeLinks = Array.isArray(homeLinkCapture) ? homeLinkCapture : Array.isArray(homeLinkCapture && homeLinkCapture.links) ? homeLinkCapture.links : [];
6956
+ const sourceCandidateCount = typeof homeLinkCapture?.candidate_count === "number" ? homeLinkCapture.candidate_count : homeLinks.length;
6957
+ const sourceCandidateUniqueLinkCount = typeof homeLinkCapture?.candidate_unique_link_count === "number" ? homeLinkCapture.candidate_unique_link_count : new Set(homeLinks.map((link) => link.app_path)).size;
6958
+ const sourceLinkScope = typeof homeLinkCapture?.source_link_scope === "string" ? homeLinkCapture.source_link_scope : check.route_path_prefix ? "route_path_prefix" : "expected_routes";
6925
6959
  const homeLinkPaths = homeLinks.map((link) => link.app_path);
6926
6960
  const uniqueHomeLinkPaths = Array.from(new Set(homeLinkPaths));
6927
6961
  const duplicateHomeLinkPaths = homeLinkPaths.filter((path, index) => homeLinkPaths.indexOf(path) !== index);
@@ -7003,6 +7037,9 @@ async function collectRouteInventory(check, viewport) {
7003
7037
  expected_routes: expectedRoutes,
7004
7038
  link_selector: check.link_selector || "a[href]",
7005
7039
  source_selector: check.source_selector || null,
7040
+ source_link_scope: sourceLinkScope,
7041
+ source_candidate_count: sourceCandidateCount,
7042
+ source_candidate_unique_link_count: sourceCandidateUniqueLinkCount,
7006
7043
  source_link_count: homeLinkPaths.length,
7007
7044
  source_unique_link_count: uniqueHomeLinkPaths.length,
7008
7045
  duplicate_source_link_count: duplicateHomeLinkPaths.length,
@@ -7199,6 +7236,9 @@ async function captureViewport(viewport) {
7199
7236
  expected_routes: routeInventoryCheck.expected_routes || [],
7200
7237
  link_selector: routeInventoryCheck.link_selector || "a[href]",
7201
7238
  source_selector: routeInventoryCheck.source_selector || null,
7239
+ source_link_scope: routeInventoryCheck.route_path_prefix ? "route_path_prefix" : "expected_routes",
7240
+ source_candidate_count: 0,
7241
+ source_candidate_unique_link_count: 0,
7202
7242
  source_link_count: 0,
7203
7243
  source_unique_link_count: 0,
7204
7244
  duplicate_source_link_count: 0,
@@ -7325,6 +7365,9 @@ function buildProfileEvidence(currentViewports) {
7325
7365
  .map((viewport) => ({
7326
7366
  viewport: viewport.name,
7327
7367
  expected_count: (viewport.route_inventory.expected_routes || []).length,
7368
+ source_link_scope: viewport.route_inventory.source_link_scope,
7369
+ source_candidate_count: viewport.route_inventory.source_candidate_count,
7370
+ source_candidate_unique_link_count: viewport.route_inventory.source_candidate_unique_link_count,
7328
7371
  source_link_count: viewport.route_inventory.source_link_count == null ? viewport.route_inventory.home_game_link_count : viewport.route_inventory.source_link_count,
7329
7372
  source_unique_link_count: viewport.route_inventory.source_unique_link_count == null ? viewport.route_inventory.home_unique_game_link_count : viewport.route_inventory.source_unique_link_count,
7330
7373
  duplicate_source_link_count: viewport.route_inventory.duplicate_source_link_count,
@@ -376,7 +376,9 @@ interface RiddleProofProfileResult {
376
376
  warnings?: string[];
377
377
  evidence?: RiddleProofProfileEvidence;
378
378
  riddle?: {
379
+ mode?: "split-viewports" | (string & {});
379
380
  job_id?: string;
381
+ job_count?: number;
380
382
  status?: string | null;
381
383
  terminal?: boolean;
382
384
  created_at?: string | null;
@@ -387,6 +389,17 @@ interface RiddleProofProfileResult {
387
389
  attempt?: number;
388
390
  attempts?: number;
389
391
  timed_out?: boolean;
392
+ split_jobs?: Array<{
393
+ viewport: string;
394
+ job_id?: string;
395
+ status?: string | null;
396
+ terminal?: boolean;
397
+ queue_elapsed_ms?: number | null;
398
+ elapsed_ms?: number;
399
+ attempt?: number;
400
+ attempts?: number;
401
+ timed_out?: boolean;
402
+ }>;
390
403
  };
391
404
  environment_blocker?: Record<string, JsonValue>;
392
405
  error?: string;
package/dist/profile.d.ts CHANGED
@@ -376,7 +376,9 @@ interface RiddleProofProfileResult {
376
376
  warnings?: string[];
377
377
  evidence?: RiddleProofProfileEvidence;
378
378
  riddle?: {
379
+ mode?: "split-viewports" | (string & {});
379
380
  job_id?: string;
381
+ job_count?: number;
380
382
  status?: string | null;
381
383
  terminal?: boolean;
382
384
  created_at?: string | null;
@@ -387,6 +389,17 @@ interface RiddleProofProfileResult {
387
389
  attempt?: number;
388
390
  attempts?: number;
389
391
  timed_out?: boolean;
392
+ split_jobs?: Array<{
393
+ viewport: string;
394
+ job_id?: string;
395
+ status?: string | null;
396
+ terminal?: boolean;
397
+ queue_elapsed_ms?: number | null;
398
+ elapsed_ms?: number;
399
+ attempt?: number;
400
+ attempts?: number;
401
+ timed_out?: boolean;
402
+ }>;
390
403
  };
391
404
  environment_blocker?: Record<string, JsonValue>;
392
405
  error?: string;
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-LFFTWXLB.js";
26
+ } from "./chunk-ZC6AK3D3.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.144",
3
+ "version": "0.7.146",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",