sdr-visualizer 1.2.4__tar.gz → 1.2.6__tar.gz

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.
Files changed (181) hide show
  1. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/CHANGELOG.md +33 -2
  2. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/PKG-INFO +5 -4
  3. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/README.md +4 -3
  4. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/ADAPTER_GUIDE.md +30 -0
  5. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/PERFORMANCE.md +32 -7
  6. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/PRODUCT_CONTRACT.md +2 -2
  7. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/pyproject.toml +1 -1
  8. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/perf_browser_check.py +2 -2
  9. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/perf_check.py +49 -32
  10. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/__init__.py +1 -1
  11. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/adapters/aa.py +6 -5
  12. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/adapters/cja.py +6 -5
  13. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/lineage_layout.py +1 -1
  14. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/lineage_output.py +1 -1
  15. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/lineage_payload.py +1 -1
  16. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/collector.py +8 -1
  17. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/sdk_worker.py +7 -1
  18. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_adapters_aa.py +2 -2
  19. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_adapters_cja.py +3 -3
  20. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_cli.py +4 -4
  21. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_perf.py +65 -0
  22. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_perf_browser_check.py +16 -0
  23. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_release_documentation.py +9 -0
  24. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_collection.py +34 -7
  25. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_sdk.py +72 -8
  26. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/.gitignore +0 -0
  27. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/AGENTS.md +0 -0
  28. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/CODE_OF_CONDUCT.md +0 -0
  29. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/CONTRIBUTING.md +0 -0
  30. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/LICENSE +0 -0
  31. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/SECURITY.md +0 -0
  32. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/THIRD_PARTY_LICENSES +0 -0
  33. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/ADAPTER_CORRECTNESS_1.1.2.md +0 -0
  34. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/ARCHITECTURE.md +0 -0
  35. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/DEPENDABOT_AUTOMATION.md +0 -0
  36. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/EMBEDDED_DATA_FORMAT.md +0 -0
  37. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/LINEAGE.md +0 -0
  38. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/RELEASE_EVIDENCE_TEMPLATE.md +0 -0
  39. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/RELEASING.md +0 -0
  40. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/SHOWCASE.md +0 -0
  41. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/WORKSPACE_USAGE.md +0 -0
  42. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/payload-schema.json +0 -0
  43. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/docs/workspace-usage-schema.json +0 -0
  44. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/capture_screenshot.py +0 -0
  45. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/check_color_pack_parity.py +0 -0
  46. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/check_markdown_links.py +0 -0
  47. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/check_workflow_policy.py +0 -0
  48. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/corpus_check.py +0 -0
  49. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/dependabot_review.py +0 -0
  50. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/generate_aa_large_fixture.py +0 -0
  51. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/generate_cja_lineage_poc.py +0 -0
  52. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/generate_examples.py +0 -0
  53. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/generate_large_fixture.py +0 -0
  54. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/mutate_fixture.py +0 -0
  55. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/package_smoke_check.py +0 -0
  56. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/perf_lineage_poc.py +0 -0
  57. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/scripts/workspace_usage_fixture.py +0 -0
  58. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/__main__.py +0 -0
  59. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/adapters/__init__.py +0 -0
  60. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/adapters/base.py +0 -0
  61. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/adapters/cja_lineage.py +0 -0
  62. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/__init__.py +0 -0
  63. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/diff.py +0 -0
  64. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/formula_tree.py +0 -0
  65. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/references.py +0 -0
  66. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/segment_tree.py +0 -0
  67. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/analysis/trend.py +0 -0
  68. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/__init__.py +0 -0
  69. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/exit_codes.py +0 -0
  70. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/lineage.py +0 -0
  71. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/main.py +0 -0
  72. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/output_safety.py +0 -0
  73. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/cli/workspace_usage.py +0 -0
  74. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/__init__.py +0 -0
  75. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/exceptions.py +0 -0
  76. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/lineage.py +0 -0
  77. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/models.py +0 -0
  78. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/structure_limits.py +0 -0
  79. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/visualizer.py +0 -0
  80. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/core/workspace_usage.py +0 -0
  81. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/__init__.py +0 -0
  82. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/detect.py +0 -0
  83. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/lineage_discovery.py +0 -0
  84. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/loader.py +0 -0
  85. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/series.py +0 -0
  86. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/shell_out.py +0 -0
  87. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/input/workspace_usage.py +0 -0
  88. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/__init__.py +0 -0
  89. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/color_packs.py +0 -0
  90. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/data_payload.py +0 -0
  91. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/lineage_renderer.py +0 -0
  92. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/renderer.py +0 -0
  93. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/cja_lineage.css +0 -0
  94. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/cja_lineage.js +0 -0
  95. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/cja_lineage_graph.js +0 -0
  96. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/cja_lineage_roles.js +0 -0
  97. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/d3.min.js +0 -0
  98. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/visualizer.css +0 -0
  99. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/visualizer.js +0 -0
  100. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/static/visualizer_trend.js +0 -0
  101. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/catalog.html.j2 +0 -0
  102. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/changes.html.j2 +0 -0
  103. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/cja_lineage.html.j2 +0 -0
  104. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/graph.html.j2 +0 -0
  105. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/index.html.j2 +0 -0
  106. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/templates/trend.html.j2 +0 -0
  107. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/trend_charts.py +0 -0
  108. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/render/workspace_usage.py +0 -0
  109. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/__init__.py +0 -0
  110. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/aa_api.py +0 -0
  111. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/aa_sdk.py +0 -0
  112. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/auth.py +0 -0
  113. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/cja_api.py +0 -0
  114. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/cja_sdk.py +0 -0
  115. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/normalize.py +0 -0
  116. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/src/sdr_visualizer/usage/transport.py +0 -0
  117. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/__init__.py +0 -0
  118. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/adapter_cases.py +0 -0
  119. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/browser_support.py +0 -0
  120. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/conftest.py +0 -0
  121. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/__init__.py +0 -0
  122. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/aa_snapshot_clean.json +0 -0
  123. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/aa_snapshot_messy.json +0 -0
  124. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_lineage_degraded.json +0 -0
  125. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_lineage_enriched.json +0 -0
  126. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_lineage_hostile.json +0 -0
  127. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_lineage_shared.json +0 -0
  128. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_snapshot_clean.json +0 -0
  129. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_snapshot_hostile.json +0 -0
  130. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_snapshot_messy.json +0 -0
  131. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/cja_snapshot_minimal.json +0 -0
  132. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/workspace_usage_aa_all_types.json +0 -0
  133. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/fixtures/workspace_usage_cja_all_types.json +0 -0
  134. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_adapter_correctness.py +0 -0
  135. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_adapter_fuzz.py +0 -0
  136. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_analysis_diff.py +0 -0
  137. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_analysis_formula_tree.py +0 -0
  138. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_analysis_references.py +0 -0
  139. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_analysis_segment_tree.py +0 -0
  140. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_analysis_trend.py +0 -0
  141. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_browser_functional.py +0 -0
  142. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_browser_support.py +0 -0
  143. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_cja_lineage.py +0 -0
  144. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_cja_lineage_driver.py +0 -0
  145. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_cli_flags.py +0 -0
  146. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_color_pack_parity.py +0 -0
  147. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_color_packs.py +0 -0
  148. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_corpus_check.py +0 -0
  149. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_data_payload.py +0 -0
  150. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_dependabot_review.py +0 -0
  151. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_entrypoint.py +0 -0
  152. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_generate_examples.py +0 -0
  153. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_input_modes.py +0 -0
  154. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_input_series.py +0 -0
  155. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_lineage_browser.py +0 -0
  156. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_lineage_cli.py +0 -0
  157. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_lineage_discovery.py +0 -0
  158. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_lineage_performance.py +0 -0
  159. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_lineage_renderer.py +0 -0
  160. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_markdown_links.py +0 -0
  161. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_minimal_fixture.py +0 -0
  162. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_mutate_fixture.py +0 -0
  163. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_output_safety.py +0 -0
  164. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_package_smoke_check.py +0 -0
  165. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_payload_schema.py +0 -0
  166. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_renderer.py +0 -0
  167. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_renderer_anatomy.py +0 -0
  168. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_renderer_graph.py +0 -0
  169. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_semantic_properties.py +0 -0
  170. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_structure_limits.py +0 -0
  171. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_trend_charts.py +0 -0
  172. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workflow_policy.py +0 -0
  173. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage.py +0 -0
  174. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_aa_sdk.py +0 -0
  175. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_auth.py +0 -0
  176. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_cja_sdk.py +0 -0
  177. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_cli.py +0 -0
  178. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_offline.py +0 -0
  179. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_payload.py +0 -0
  180. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_perf.py +0 -0
  181. {sdr_visualizer-1.2.4 → sdr_visualizer-1.2.6}/tests/test_workspace_usage_transport.py +0 -0
@@ -4,6 +4,32 @@ All notable changes to `sdr-visualizer` will be documented here. The format foll
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.2.6] - 2026-10-27
8
+
9
+ ### Changed
10
+
11
+ - Advance the catalog tested-through generator markers to `cja_auto_sdr`
12
+ 3.13.2 and `aa_auto_sdr` 1.24.1. Snapshots that declare those versions no
13
+ longer print a newer-than-tested warning. Later versions are still accepted
14
+ with a compatibility warning. The separate lineage allowlist is unchanged.
15
+
16
+ ## [1.2.5] - 2026-10-17
17
+
18
+ ### Fixed
19
+
20
+ - Kill a Workspace worker directly when it rejects process-group cleanup and
21
+ stays running, then report the original cleanup error, so collection no
22
+ longer waits on a worker that ignored the group signal.
23
+ - Fail the Python performance gate when any published tier fixture is missing,
24
+ warn when a report reaches 90% of its size budget, and treat a Workspace
25
+ interaction of exactly 100 ms as over budget, matching the published limit.
26
+
27
+ ### Changed
28
+
29
+ - Document CJA catalog generator-version provenance, correct adapter
30
+ tested-through marker guidance, and remove obsolete lineage POC/private
31
+ module descriptions.
32
+
7
33
  ## [1.2.4] - 2026-10-17
8
34
 
9
35
  ### Changed
@@ -12,6 +38,8 @@ All notable changes to `sdr-visualizer` will be documented here. The format foll
12
38
  3.12.12 and `aa_auto_sdr` 1.21.24. Snapshots declaring those versions no
13
39
  longer raise a newer-than-tested warning; later versions remain accepted
14
40
  with a compatibility warning. The separate lineage allowlist is unchanged.
41
+ - Clarify release retention-setting versus artifact-expiry checks and the
42
+ marker-only sibling review disposition.
15
43
 
16
44
  ### Fixed
17
45
 
@@ -34,7 +62,6 @@ All notable changes to `sdr-visualizer` will be documented here. The format foll
34
62
  - Make live AA Workspace collection and manual assistive-technology testing
35
63
  optional release evidence, retain automated accessibility and keyboard checks,
36
64
  and scope release license signoff to project and vendored D3 notices.
37
-
38
65
  - Update the optional AA Workspace SDK to `aanalytics2==0.5.5.post2` and align
39
66
  its collection version guard with the package pin.
40
67
  - Automatically review and merge verified, lockfile-only patch updates to
@@ -42,6 +69,8 @@ All notable changes to `sdr-visualizer` will be documented here. The format foll
42
69
  dependency changes on the manual-review path.
43
70
  - Replace the README catalog screenshot with a feature slideshow covering search,
44
71
  references, anatomy, comparisons, trends, and offline reports across AA and CJA.
72
+ - Add canonical `AGENTS.md` contributor guidance and ship it in the source
73
+ distribution.
45
74
 
46
75
  ## [1.2.2] - 2026-09-21
47
76
 
@@ -752,7 +781,9 @@ The following are explicitly internal and may change without notice:
752
781
  - Workspace project visualization (v0.4)
753
782
  - Schema map view (v0.5)
754
783
 
755
- [Unreleased]: https://github.com/brian-a-au/sdr-visualizer/compare/v1.2.4...HEAD
784
+ [Unreleased]: https://github.com/brian-a-au/sdr-visualizer/compare/v1.2.6...HEAD
785
+ [1.2.6]: https://github.com/brian-a-au/sdr-visualizer/releases/tag/v1.2.6
786
+ [1.2.5]: https://github.com/brian-a-au/sdr-visualizer/releases/tag/v1.2.5
756
787
  [1.2.4]: https://github.com/brian-a-au/sdr-visualizer/releases/tag/v1.2.4
757
788
  [1.2.3]: https://github.com/brian-a-au/sdr-visualizer/releases/tag/v1.2.3
758
789
  [1.2.2]: https://github.com/brian-a-au/sdr-visualizer/releases/tag/v1.2.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sdr-visualizer
3
- Version: 1.2.4
3
+ Version: 1.2.6
4
4
  Summary: Static-output visual catalog generator for Adobe Customer Journey Analytics and Adobe Analytics implementations.
5
5
  Project-URL: Homepage, https://brian-a-au.github.io/sdr-visualizer/
6
6
  Project-URL: Documentation, https://github.com/brian-a-au/sdr-visualizer#documentation
@@ -280,8 +280,9 @@ the trend is the newest usable snapshot in the directory.
280
280
  The output is CI-gated against the budgets in
281
281
  [`docs/PERFORMANCE.md`](https://github.com/brian-a-au/sdr-visualizer/blob/main/docs/PERFORMANCE.md).
282
282
  Build time and HTML size are enforced at every published tier (100 / 500 / 1,000 / 2,000
283
- components). Browser-measured budgets are enforced at the 1,000-component tier
284
- (initial render < 1s, filter/search < 150ms) and the 2,000-component tier
283
+ components). Browser-measured budgets for initial render and filter/search are
284
+ enforced at all four tiers, from 100 components (< 200ms, < 50ms) and 500
285
+ components (< 500ms, < 100ms) up to 1,000 (< 1s, < 150ms) and 2,000
285
286
  (< 2s, < 300ms), plus a 700ms cap on the graph view's main-thread block.
286
287
  These guarantees cover up to 8,000 reference edges. Denser valid reports use an
287
288
  explicit graph opt-in and sit outside the published size and latency limits.
@@ -334,7 +335,7 @@ arguments and exit codes are described in the
334
335
  Its embedded payload and Python modules are internal and do not extend the
335
336
  catalog schema or JSON sidecar contract.
336
337
 
337
- **Performance budgets.** The tier table above is a guarantee, not a goal: loosening a budget is a breaking change; tightening one is minor.
338
+ **Performance budgets.** The tier table in [`docs/PERFORMANCE.md`](https://github.com/brian-a-au/sdr-visualizer/blob/main/docs/PERFORMANCE.md) is a guarantee, not a goal: loosening a budget is a breaking change; tightening one is minor.
338
339
 
339
340
  Warnings (snapshot generator newer than the tested version; 5,000+ component reports) are informational and never make a valid snapshot fail.
340
341
 
@@ -257,8 +257,9 @@ the trend is the newest usable snapshot in the directory.
257
257
  The output is CI-gated against the budgets in
258
258
  [`docs/PERFORMANCE.md`](https://github.com/brian-a-au/sdr-visualizer/blob/main/docs/PERFORMANCE.md).
259
259
  Build time and HTML size are enforced at every published tier (100 / 500 / 1,000 / 2,000
260
- components). Browser-measured budgets are enforced at the 1,000-component tier
261
- (initial render < 1s, filter/search < 150ms) and the 2,000-component tier
260
+ components). Browser-measured budgets for initial render and filter/search are
261
+ enforced at all four tiers, from 100 components (< 200ms, < 50ms) and 500
262
+ components (< 500ms, < 100ms) up to 1,000 (< 1s, < 150ms) and 2,000
262
263
  (< 2s, < 300ms), plus a 700ms cap on the graph view's main-thread block.
263
264
  These guarantees cover up to 8,000 reference edges. Denser valid reports use an
264
265
  explicit graph opt-in and sit outside the published size and latency limits.
@@ -311,7 +312,7 @@ arguments and exit codes are described in the
311
312
  Its embedded payload and Python modules are internal and do not extend the
312
313
  catalog schema or JSON sidecar contract.
313
314
 
314
- **Performance budgets.** The tier table above is a guarantee, not a goal: loosening a budget is a breaking change; tightening one is minor.
315
+ **Performance budgets.** The tier table in [`docs/PERFORMANCE.md`](https://github.com/brian-a-au/sdr-visualizer/blob/main/docs/PERFORMANCE.md) is a guarantee, not a goal: loosening a budget is a breaking change; tightening one is minor.
315
316
 
316
317
  Warnings (snapshot generator newer than the tested version; 5,000+ component reports) are informational and never make a valid snapshot fail.
317
318
 
@@ -37,6 +37,36 @@ Reads the JSON output of [`cja_auto_sdr`](https://github.com/brian-a-au/cja_auto
37
37
  - Calc metrics ship `metric_references` and `segment_references` arrays; the adapter merges these and de-dupes.
38
38
  - Derived fields appear only in CJA — there's no AA equivalent.
39
39
 
40
+ ### CJA generator version provenance
41
+
42
+ The adapter reads `metadata["Tool Version"]` or `metadata["tool_version"]`
43
+ when declared; otherwise `adapter_version` is `unknown` and no
44
+ newer-than-tested warning is possible. The example above illustrates accepted
45
+ version metadata, not a field guaranteed by the exporter.
46
+
47
+ Public source inspection at `cja_auto_sdr` **v3.12.12**, commit
48
+ `73c3f60e531358d339828abbbb94bbb0afb69b0b`, confirms that its
49
+ [catalog metadata builder](https://github.com/brian-a-au/cja_auto_sdr/blob/73c3f60e531358d339828abbbb94bbb0afb69b0b/src/cja_auto_sdr/generator.py#L1160-L1308)
50
+ omits the generator version. The
51
+ [JSON payload builder](https://github.com/brian-a-au/cja_auto_sdr/blob/73c3f60e531358d339828abbbb94bbb0afb69b0b/src/cja_auto_sdr/output/sdr/__init__.py#L507-L575)
52
+ passes that metadata through without adding a version. There is no additional
53
+ catalog field for the adapter to read in this version.
54
+
55
+ The separate
56
+ [run summary](https://github.com/brian-a-au/cja_auto_sdr/blob/73c3f60e531358d339828abbbb94bbb0afb69b0b/src/cja_auto_sdr/generator.py#L2516-L2530)
57
+ and
58
+ [diff snapshot format](https://github.com/brian-a-au/cja_auto_sdr/blob/73c3f60e531358d339828abbbb94bbb0afb69b0b/src/cja_auto_sdr/diff/models.py#L300-L375)
59
+ record `tool_version`, but those are different artifacts. The catalog adapter
60
+ does not join external provenance or infer a version from the locally installed
61
+ exporter, timestamps, or inventory schema versions. Existing undeclared catalog
62
+ snapshots remain `unknown`; exporter-side version metadata would be needed to
63
+ make their generator version available at export time.
64
+
65
+ The tested-through marker comes from recorded validation with an exact upstream
66
+ version and the historical compatibility corpus, as required by the
67
+ [compatibility policy](PRODUCT_CONTRACT.md#compatibility-policy). Taking the
68
+ highest version string found in fixtures or old snapshots is insufficient.
69
+
40
70
  ### CJA component mappings
41
71
 
42
72
  | CJA input | Normalized collection | Embedded type |
@@ -191,19 +191,44 @@ uv run python scripts/perf_browser_check.py
191
191
 
192
192
  CI runs `perf_check.py` after `pytest` in the test job. The browser gate runs in
193
193
  the separate `browser-perf` job after browser functional tests. A regression
194
- that exceeds any budget fails the build.
194
+ that exceeds any budget fails the build. `perf_check.py` fails when any tier
195
+ fixture is missing and prints a non-failing warning when an HTML size reaches
196
+ 90% of its budget.
195
197
 
196
198
  ## What we measure
197
199
 
198
200
  One representative Python-side run looks like this:
199
201
 
200
202
  ```text
201
- [CJA] build time: 0.01s (budget 6.0s)
202
- [CJA] HTML size : 0.71MB (budget 4.0MB)
203
- [AA] build time: 0.01s (budget 6.0s)
204
- [AA] HTML size : 0.61MB (budget 4.0MB)
205
- [CJA-XL] build time: 0.01s (budget 12.0s)
206
- [CJA-XL] HTML size : 0.98MB (budget 8.0MB)
203
+ [CJA-100] build time: 0.01s (budget 1.0s, median of 3)
204
+ [CJA-100] HTML size : 0.43MB (budget 0.5MB)
205
+ [CJA-500] build time: 0.02s (budget 3.0s, median of 3)
206
+ [CJA-500] HTML size : 0.57MB (budget 2MB)
207
+ [CJA] build time: 0.06s (budget 6.0s, median of 3)
208
+ [CJA] HTML size : 0.81MB (budget 4MB)
209
+ [AA] build time: 0.04s (budget 6.0s, median of 3)
210
+ [AA] HTML size : 0.70MB (budget 4MB)
211
+ [CJA-dense] build time: 0.09s (budget 6.0s, median of 3)
212
+ [CJA-dense] HTML size : 1.42MB (budget 4MB)
213
+ [CJA-compare] build time: 0.07s (budget 9.0s, median of 3)
214
+ [CJA-compare] HTML size : 0.82MB (budget 4.5MB)
215
+ [CJA-trend] build time: 0.19s (budget 6.0s, median of 3, 6 snapshots)
216
+ [CJA-trend] HTML size : 0.82MB (budget 4.5MB)
217
+ [CJA-XL] build time: 0.08s (budget 12.0s, median of 3)
218
+ [CJA-XL] HTML size : 1.09MB (budget 8MB)
219
+ [cja_snapshot_small-usage] build time: 0.02s (budget 1.0s, median of 3)
220
+ [cja_snapshot_small-usage] HTML size : 0.48MB (budget 0.5MB)
221
+ warning: [cja_snapshot_small-usage] HTML size at 95% of budget
222
+ [cja_snapshot_medium-usage] build time: 0.24s (budget 3.0s, median of 3)
223
+ [cja_snapshot_medium-usage] HTML size : 1.18MB (budget 2MB)
224
+ [cja_snapshot_large-usage] build time: 0.30s (budget 6.0s, median of 3)
225
+ [cja_snapshot_large-usage] HTML size : 1.58MB (budget 4MB)
226
+ [aa_snapshot_large-usage] build time: 0.29s (budget 6.0s, median of 3)
227
+ [aa_snapshot_large-usage] HTML size : 1.40MB (budget 4MB)
228
+ [cja_snapshot_xl-usage] build time: 0.36s (budget 12.0s, median of 3)
229
+ [cja_snapshot_xl-usage] HTML size : 2.06MB (budget 8MB)
230
+ [CJA-usage-repeated] build time: 0.35s (budget 6.0s, median of 3)
231
+ [CJA-usage-repeated] HTML size : 1.78MB (budget 4MB)
207
232
  OK: all budgets met
208
233
  ```
209
234
 
@@ -207,8 +207,8 @@ unusable, and capped-out members do not warn. The current markers are:
207
207
 
208
208
  | Platform | Warning threshold |
209
209
  |---|---:|
210
- | CJA (`cja_auto_sdr`) | 3.12.12 |
211
- | AA (`aa_auto_sdr`) | 1.21.24 |
210
+ | CJA (`cja_auto_sdr`) | 3.13.2 |
211
+ | AA (`aa_auto_sdr`) | 1.24.1 |
212
212
 
213
213
  A marker is evidence of exercised compatibility, not a promise about every
214
214
  possible snapshot produced by that version. It may advance only after a
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sdr-visualizer"
3
- version = "1.2.4"
3
+ version = "1.2.6"
4
4
  description = "Static-output visual catalog generator for Adobe Customer Journey Analytics and Adobe Analytics implementations."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -313,8 +313,8 @@ def _workspace_failures(label: str, measured: dict, project_count: int) -> list[
313
313
  ):
314
314
  failures.append(f"[{label}] page replacement did not advance the project range")
315
315
  for field, action in (("openMs", "first open"), ("pageMs", "page replacement")):
316
- if measured[field] > WORKSPACE_INTERACTION_BUDGET_MS:
317
- failures.append(f"[{label}] Workspace {action} {measured[field]:.1f}ms > 100ms")
316
+ if measured[field] >= WORKSPACE_INTERACTION_BUDGET_MS:
317
+ failures.append(f"[{label}] Workspace {action} {measured[field]:.1f}ms >= 100ms")
318
318
  return failures
319
319
 
320
320
 
@@ -4,14 +4,14 @@ Renders fixtures and asserts the build-time + HTML-size budgets across all
4
4
  four documented tiers. CI runs this after pytest (see .github/workflows/test.yml).
5
5
 
6
6
  - CJA small (100 components, `generate_large_fixture.py --scale 0.083`):
7
- 100-component budgets (build < 1s, size < 0.5MB). Skipped when absent.
7
+ 100-component budgets (build < 1s, size < 0.5MB). Required.
8
8
  - CJA medium (~500 components, `--scale 0.417`): 500-component budgets
9
- (build < 3s, size < 2MB). Skipped when absent.
9
+ (build < 3s, size < 2MB). Required.
10
10
  - CJA / AA large (~1,200 / ~900 components): 1,000-component budgets
11
11
  (build < 6s, size < 4MB)
12
12
  - CJA XL (~2,000 components, generated on demand via
13
13
  `generate_large_fixture.py --scale 1.67 --output tests/fixtures/cja_snapshot_xl.json`):
14
- 2,000-component budgets (build < 12s, size < 8MB). Skipped when absent.
14
+ 2,000-component budgets (build < 12s, size < 8MB). Required.
15
15
 
16
16
  Build time is the median of 3 runs per fixture.
17
17
 
@@ -71,6 +71,25 @@ TREND_SERIES_LEN = 6
71
71
  TREND_BUILD_BUDGET_S = TREND_SERIES_LEN * 1.0
72
72
  TREND_SIZE_BUDGET_BYTES = SIZE_BUDGET_BYTES + 500_000
73
73
 
74
+ # Non-failing early warning for deterministic HTML size growth.
75
+ HEADROOM_WARNING_RATIO = 0.9
76
+
77
+ GENERATE = "uv run python scripts/generate_large_fixture.py"
78
+ REQUIRED_FIXTURES = [
79
+ ("CJA_SMALL", f"{GENERATE} --scale 0.083 --output tests/fixtures/cja_snapshot_small.json"),
80
+ ("CJA_MEDIUM", f"{GENERATE} --scale 0.417 --output tests/fixtures/cja_snapshot_medium.json"),
81
+ ("CJA_LARGE", GENERATE),
82
+ ("AA_LARGE", "uv run python scripts/generate_aa_large_fixture.py"),
83
+ ("CJA_XL", f"{GENERATE} --scale 1.67 --output tests/fixtures/cja_snapshot_xl.json"),
84
+ ]
85
+
86
+
87
+ def _headroom_note(label: str, size_bytes: int, budget_bytes: int) -> str | None:
88
+ if HEADROOM_WARNING_RATIO * budget_bytes <= size_bytes < budget_bytes:
89
+ pct = size_bytes * 100 // budget_bytes
90
+ return f"warning: [{label}] HTML size at {pct}% of budget"
91
+ return None
92
+
74
93
 
75
94
  def _load_usage_fixture():
76
95
  spec = importlib.util.spec_from_file_location(
@@ -118,6 +137,8 @@ def _measure_compare(old_snap: dict, new_snap: dict) -> tuple[list[str], str]:
118
137
  f"[CJA-compare] build time: {elapsed:.2f}s (budget {COMPARE_BUILD_BUDGET_S}s, median of 3)",
119
138
  f"[CJA-compare] HTML size : {size_mb:.2f}MB (budget {COMPARE_SIZE_BUDGET_BYTES / 1_000_000:g}MB)",
120
139
  ]
140
+ if note := _headroom_note("CJA-compare", size_bytes, COMPARE_SIZE_BUDGET_BYTES):
141
+ msgs.append(note)
121
142
  failures = []
122
143
  if elapsed >= COMPARE_BUILD_BUDGET_S:
123
144
  failures.append(
@@ -152,6 +173,8 @@ def _measure_trend(base_snap: dict, mutate) -> tuple[list[str], str]:
152
173
  f"median of 3, {TREND_SERIES_LEN} snapshots)",
153
174
  f"[CJA-trend] HTML size : {size_mb:.2f}MB (budget {TREND_SIZE_BUDGET_BYTES / 1_000_000:g}MB)",
154
175
  ]
176
+ if note := _headroom_note("CJA-trend", size_bytes, TREND_SIZE_BUDGET_BYTES):
177
+ msgs.append(note)
155
178
  failures = []
156
179
  if elapsed >= TREND_BUILD_BUDGET_S:
157
180
  failures.append(f"CJA-trend build time {elapsed:.2f}s over budget {TREND_BUILD_BUDGET_S}s")
@@ -187,6 +210,8 @@ def _measure(
187
210
  f"[{label}] build time: {elapsed:.2f}s (budget {build_budget_s}s, median of 3)",
188
211
  f"[{label}] HTML size : {size_mb:.2f}MB (budget {size_budget_bytes / 1_000_000:g}MB)",
189
212
  ]
213
+ if note := _headroom_note(label, size_bytes, size_budget_bytes):
214
+ msgs.append(note)
190
215
  failures = []
191
216
  if elapsed >= build_budget_s:
192
217
  failures.append(f"[{label}] build time {elapsed:.2f}s >= {build_budget_s}s budget")
@@ -198,17 +223,18 @@ def _measure(
198
223
 
199
224
 
200
225
  def main() -> int:
201
- for fixture, generator in [
202
- (CJA_LARGE, "scripts/generate_large_fixture.py"),
203
- (AA_LARGE, "scripts/generate_aa_large_fixture.py"),
204
- ]:
205
- if not fixture.exists():
206
- print(
207
- f"sdr-visualizer: fixture {fixture} missing; run "
208
- f"`uv run python {generator}` first.",
209
- file=sys.stderr,
210
- )
211
- return 2
226
+ missing = [
227
+ (globals()[name], command)
228
+ for name, command in REQUIRED_FIXTURES
229
+ if not globals()[name].exists()
230
+ ]
231
+ for fixture, command in missing:
232
+ print(
233
+ f"sdr-visualizer: fixture {fixture} missing; run `{command}` first.",
234
+ file=sys.stderr,
235
+ )
236
+ if missing:
237
+ return 2
212
238
 
213
239
  cja_snap = json.loads(CJA_LARGE.read_text(encoding="utf-8"))
214
240
  aa_snap = json.loads(AA_LARGE.read_text(encoding="utf-8"))
@@ -218,13 +244,10 @@ def main() -> int:
218
244
  (CJA_SMALL, "CJA-100", SMALL_BUILD_BUDGET_S, SMALL_SIZE_BUDGET_BYTES),
219
245
  (CJA_MEDIUM, "CJA-500", MEDIUM_BUILD_BUDGET_S, MEDIUM_SIZE_BUDGET_BYTES),
220
246
  ]:
221
- if path.exists():
222
- snap = json.loads(path.read_text(encoding="utf-8"))
223
- tier_failures, tier_report = _measure(label, snap, cja_adapt, build_b, size_b)
224
- small_failures += tier_failures
225
- print(tier_report)
226
- else:
227
- print(f"note: {path.name} not generated; skipping {label} gate")
247
+ snap = json.loads(path.read_text(encoding="utf-8"))
248
+ tier_failures, tier_report = _measure(label, snap, cja_adapt, build_b, size_b)
249
+ small_failures += tier_failures
250
+ print(tier_report)
228
251
 
229
252
  cja_failures, cja_report = _measure("CJA", cja_snap, cja_adapt)
230
253
  print(cja_report)
@@ -245,15 +268,11 @@ def main() -> int:
245
268
  trend_failures, trend_report = _measure_trend(cja_snap, mutate)
246
269
  print(trend_report)
247
270
 
248
- xl_failures: list[str] = []
249
- if CJA_XL.exists():
250
- xl_snap = json.loads(CJA_XL.read_text(encoding="utf-8"))
251
- xl_failures, xl_report = _measure(
252
- "CJA-XL", xl_snap, cja_adapt, XL_BUILD_BUDGET_S, XL_SIZE_BUDGET_BYTES
253
- )
254
- print(xl_report)
255
- else:
256
- print("note: cja_snapshot_xl.json not generated; skipping 2,000-component gate")
271
+ xl_snap = json.loads(CJA_XL.read_text(encoding="utf-8"))
272
+ xl_failures, xl_report = _measure(
273
+ "CJA-XL", xl_snap, cja_adapt, XL_BUILD_BUDGET_S, XL_SIZE_BUDGET_BYTES
274
+ )
275
+ print(xl_report)
257
276
 
258
277
  # Preserve every original gate, then repeat its tier with bounded evidence.
259
278
  # Small approaches the HTML cap; XL approaches the normalized 1 MiB cap.
@@ -266,8 +285,6 @@ def main() -> int:
266
285
  (AA_LARGE, aa_adapt, BUILD_BUDGET_S, SIZE_BUDGET_BYTES, 10_000),
267
286
  (CJA_XL, cja_adapt, XL_BUILD_BUDGET_S, XL_SIZE_BUDGET_BYTES, 10_000),
268
287
  ]:
269
- if not path.exists():
270
- continue # Same optional fixtures as the original Python matrix.
271
288
  snap = json.loads(path.read_text(encoding="utf-8"))
272
289
  encoded = usage_fixture.usage_json(adapter(snap), project_count=projects, pad_input=True)
273
290
  errors, report = _measure(
@@ -1,3 +1,3 @@
1
1
  """sdr-visualizer: visual catalog generator for CJA / AA implementations."""
2
2
 
3
- __version__ = "1.2.4"
3
+ __version__ = "1.2.6"
@@ -351,11 +351,12 @@ def _walk_segment_definition(definition: Any) -> tuple[int, list[str]]:
351
351
  # ---------------------------------------------------------------------------
352
352
 
353
353
 
354
- # The newest aa_auto_sdr version this release was validated against
355
- # (bundled fixtures + the private real corpus; re-derive at each release:
356
- # grep -rho '"Tool Version": "[^"]*"|"tool_version": "[^"]*"' over corpus
357
- # and fixtures, take the max). The compatibility policy warns — never refuses.
358
- TESTED_THROUGH_GENERATOR_VERSION = "1.21.24"
354
+ # The newest aa_auto_sdr version this release was validated against.
355
+ # Advance from recorded release validation with that exact generator version
356
+ # and the historical compatibility corpus; snapshot declarations alone do not
357
+ # establish this marker. Undeclared versions stay unknown and do not warn.
358
+ # The compatibility policy warns about newer declared versions, never refuses.
359
+ TESTED_THROUGH_GENERATOR_VERSION = "1.24.1"
359
360
 
360
361
 
361
362
  def generator_version_warning(adapter_version: str) -> str | None:
@@ -363,11 +363,12 @@ def _walk_for_contexts(node: Any, out: list[str]) -> None:
363
363
  # ---------------------------------------------------------------------------
364
364
 
365
365
 
366
- # The newest cja_auto_sdr version this release was validated against
367
- # (bundled fixtures + the private real corpus; re-derive at each release:
368
- # grep -rho '"Tool Version": "[^"]*"|"tool_version": "[^"]*"' over corpus
369
- # and fixtures, take the max). The compatibility policy warns — never refuses.
370
- TESTED_THROUGH_GENERATOR_VERSION = "3.12.12"
366
+ # The newest cja_auto_sdr version this release was validated against.
367
+ # Advance from recorded release validation with that exact generator version
368
+ # and the historical compatibility corpus; snapshot declarations alone do not
369
+ # establish this marker. Undeclared versions stay unknown and do not warn.
370
+ # The compatibility policy warns about newer declared versions, never refuses.
371
+ TESTED_THROUGH_GENERATOR_VERSION = "3.13.2"
371
372
 
372
373
 
373
374
  def generator_version_warning(adapter_version: str) -> str | None:
@@ -1,4 +1,4 @@
1
- """Deterministic, build-side geometry for the CJA lineage POC."""
1
+ """Deterministic, build-side geometry for the CJA lineage report."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,4 +1,4 @@
1
- """Private, content-free output boundary for the CJA lineage POC."""
1
+ """Content-free output boundary for the CJA lineage report."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -1,4 +1,4 @@
1
- """Build the private, source-faithful payload for the CJA lineage POC."""
1
+ """Build the source-faithful payload for the CJA lineage report."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import contextlib
5
6
  import importlib.metadata
6
7
  import os
7
8
  import selectors
@@ -416,10 +417,16 @@ def _stop(process):
416
417
  except PermissionError as error:
417
418
  # On macOS an exiting process group can reject a signal before
418
419
  # waitpid reports its leader's exit. Only accept cleanup once the
419
- # child has actually exited, within the existing wait bound.
420
+ # child has actually exited, within the existing wait bound;
421
+ # otherwise kill the leader directly so the Popen context can finish
422
+ # once it exits, then report the refused group signal.
420
423
  try:
421
424
  process.wait(timeout=2)
422
425
  except subprocess.TimeoutExpired:
426
+ with contextlib.suppress(OSError):
427
+ process.kill()
428
+ with contextlib.suppress(subprocess.TimeoutExpired):
429
+ process.wait(timeout=2)
423
430
  raise error from None
424
431
  return
425
432
  process.wait(timeout=2)
@@ -125,10 +125,16 @@ def _stop(process):
125
125
  pass
126
126
  except PermissionError as error:
127
127
  # An exiting process group can reject a signal before its leader is
128
- # reaped. Accept cleanup only after exit within the existing bound.
128
+ # reaped. Accept cleanup only after exit within the existing bound;
129
+ # otherwise kill the leader directly so the Popen context can finish
130
+ # once it exits, then report the refused group signal.
129
131
  try:
130
132
  process.wait(timeout=2)
131
133
  except subprocess.TimeoutExpired:
134
+ with contextlib.suppress(OSError):
135
+ process.kill()
136
+ with contextlib.suppress(subprocess.TimeoutExpired):
137
+ process.wait(timeout=2)
132
138
  raise error from None
133
139
  return
134
140
  process.wait(timeout=2)
@@ -521,5 +521,5 @@ def test_equal_older_or_unparseable_versions_do_not_warn():
521
521
  def test_tuple_length_mismatch_versions_compare_correctly():
522
522
  from sdr_visualizer.adapters.aa import generator_version_warning
523
523
 
524
- assert generator_version_warning("1.22") is not None
525
- assert generator_version_warning("1.21") is None
524
+ assert generator_version_warning("1.25") is not None
525
+ assert generator_version_warning("1.24") is None
@@ -858,12 +858,12 @@ def test_equal_older_or_unparseable_versions_do_not_warn():
858
858
 
859
859
 
860
860
  def test_tuple_length_mismatch_versions_compare_correctly():
861
- # (3, 13) > (3, 12, 4), while the shorter (3, 12) sorts below the
861
+ # (3, 14) > (3, 13, 2), while the shorter (3, 13) sorts below the
862
862
  # longer tested tuple. This pins Python tuple ordering as the contract.
863
863
  from sdr_visualizer.adapters.cja import generator_version_warning
864
864
 
865
- assert generator_version_warning("3.13") is not None
866
- assert generator_version_warning("3.12") is None
865
+ assert generator_version_warning("3.14") is not None
866
+ assert generator_version_warning("3.13") is None
867
867
 
868
868
 
869
869
  # ---------------------------------------------------------------------------
@@ -1101,10 +1101,10 @@ def test_tested_generator_version_does_not_warn(tmp_path, capsys):
1101
1101
  @pytest.mark.parametrize(
1102
1102
  ("platform", "version", "warns"),
1103
1103
  [
1104
- ("cja", "3.12.12", False),
1105
- ("cja", "3.12.13", True),
1106
- ("aa", "1.21.24", False),
1107
- ("aa", "1.21.25", True),
1104
+ ("cja", "3.13.2", False),
1105
+ ("cja", "3.13.3", True),
1106
+ ("aa", "1.24.1", False),
1107
+ ("aa", "1.24.2", True),
1108
1108
  ],
1109
1109
  )
1110
1110
  def test_catalog_generator_warning_boundary(platform, version, warns, tmp_path, capsys):
@@ -160,3 +160,68 @@ def test_fixture_and_corpus_tier_budgets_agree_exactly():
160
160
  assert corpus._tier_budget_bytes(2001) is None
161
161
  assert perf_check.COMPARE_SIZE_BUDGET_BYTES == 4_500_000
162
162
  assert perf_check.TREND_SIZE_BUDGET_BYTES == 4_500_000
163
+
164
+
165
+ @pytest.mark.parametrize("delta,expected", [(-1, None), (0, "90%"), (1, "90%")])
166
+ def test_headroom_note_boundary(delta, expected):
167
+ note = perf_check._headroom_note("CJA-100", 450_000 + delta, 500_000)
168
+ if expected is None:
169
+ assert note is None
170
+ else:
171
+ assert expected in note
172
+ assert "CJA-100" in note
173
+
174
+
175
+ def test_headroom_note_absent_at_or_over_budget():
176
+ assert perf_check._headroom_note("x", 500_000, 500_000) is None
177
+ assert perf_check._headroom_note("x", 500_001, 500_000) is None
178
+
179
+
180
+ def test_measure_report_includes_headroom_note_without_failing(monkeypatch):
181
+ monkeypatch.setattr(perf_check, "render", lambda impl: "x" * 460_000)
182
+ monkeypatch.setattr(perf_check.time, "perf_counter", lambda: 0)
183
+ failures, report = perf_check._measure(
184
+ "CJA-100", {}, lambda snap: None, size_budget_bytes=500_000
185
+ )
186
+ assert failures == []
187
+ assert "warning: [CJA-100] HTML size at 92% of budget" in report
188
+
189
+
190
+ @pytest.mark.parametrize("mode,label", [("compare", "CJA-compare"), ("trend", "CJA-trend")])
191
+ def test_comparative_report_includes_headroom_note_without_failing(monkeypatch, mode, label):
192
+ monkeypatch.setattr(perf_check, "cja_adapt", lambda snap: None)
193
+ monkeypatch.setattr(perf_check, "build_payload_with_options", lambda impl: {"meta": {}})
194
+ monkeypatch.setattr(perf_check, "diff_implementations", lambda *args: {"baseline": {}})
195
+ monkeypatch.setattr(perf_check, "build_trend", lambda *args, **kwargs: {})
196
+ monkeypatch.setattr(perf_check, "render_payload", lambda payload: "x" * 4_050_000)
197
+ monkeypatch.setattr(perf_check.time, "perf_counter", lambda: 0)
198
+ if mode == "compare":
199
+ failures, report = perf_check._measure_compare({}, {})
200
+ else:
201
+ failures, report = perf_check._measure_trend({}, lambda snap: snap)
202
+ assert failures == []
203
+ assert f"warning: [{label}] HTML size at 90% of budget" in report
204
+
205
+
206
+ def test_main_fails_when_any_tier_fixture_missing(tmp_path, monkeypatch, capsys):
207
+ for name in ("CJA_SMALL", "CJA_MEDIUM", "CJA_LARGE", "AA_LARGE", "CJA_XL"):
208
+ monkeypatch.setattr(perf_check, name, tmp_path / f"{name.lower()}.json")
209
+ assert perf_check.main() == 2
210
+ out = capsys.readouterr()
211
+ for flag in ("--scale 0.083", "--scale 0.417", "--scale 1.67", "generate_aa_large_fixture"):
212
+ assert flag in out.err
213
+ for name in ("cja_small", "cja_medium", "cja_large", "aa_large", "cja_xl"):
214
+ assert f"{name}.json missing" in out.err
215
+ assert "OK: all budgets met" not in out.out
216
+
217
+
218
+ def test_main_names_only_the_missing_tier(tmp_path, monkeypatch, capsys):
219
+ present = tmp_path / "present.json"
220
+ present.write_text("{}", encoding="utf-8")
221
+ for name in ("CJA_MEDIUM", "CJA_LARGE", "AA_LARGE", "CJA_XL"):
222
+ monkeypatch.setattr(perf_check, name, present)
223
+ monkeypatch.setattr(perf_check, "CJA_SMALL", tmp_path / "cja_snapshot_small.json")
224
+ assert perf_check.main() == 2
225
+ err = capsys.readouterr().err
226
+ assert "cja_snapshot_small.json" in err
227
+ assert "--scale 0.417" not in err
@@ -157,3 +157,19 @@ def test_comparative_browser_render_boundary(monkeypatch, mode, delta):
157
157
  page.evaluate.side_effect = [1, 0, 59, 0, 100]
158
158
  failures = perf_browser_check._check_trend(page, Path("/tmp/boundary.html"))
159
159
  assert bool(failures) == (delta >= 0)
160
+
161
+
162
+ @pytest.mark.parametrize("ms,fails", [(99.9, False), (100.0, True)])
163
+ def test_workspace_gate_rejects_exact_budget(ms, fails):
164
+ observations = {
165
+ "eager": 0,
166
+ "total": 10000,
167
+ "first": 50,
168
+ "second": 50,
169
+ "firstRange": "Showing 1–50 of 10000",
170
+ "secondRange": "Showing 51–100 of 10000",
171
+ "openMs": ms,
172
+ "pageMs": 3,
173
+ }
174
+ failures = perf_browser_check._workspace_failures("synthetic", observations, 10000)
175
+ assert bool(failures) == fails