roam-code 12.1.0__tar.gz → 12.3.0__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 (539) hide show
  1. {roam_code-12.1.0/src/roam_code.egg-info → roam_code-12.3.0}/PKG-INFO +24 -9
  2. {roam_code-12.1.0 → roam_code-12.3.0}/README.md +11 -7
  3. {roam_code-12.1.0 → roam_code-12.3.0}/pyproject.toml +46 -2
  4. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/attest/cga.py +34 -9
  5. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_cga.py +21 -4
  6. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_critique.py +63 -0
  7. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_dead.py +16 -0
  8. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_diagnose.py +9 -0
  9. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_entry_points.py +7 -1
  10. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_fan.py +41 -2
  11. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_health.py +30 -6
  12. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_mcp_setup.py +39 -2
  13. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_oracle.py +64 -22
  14. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_preflight.py +45 -0
  15. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_retrieve.py +96 -3
  16. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_rules.py +14 -1
  17. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_sbom.py +26 -2
  18. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_search.py +10 -1
  19. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_smells.py +77 -3
  20. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_taint.py +22 -1
  21. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_weather.py +12 -2
  22. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/metrics_history.py +16 -11
  23. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/resolve.py +58 -1
  24. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/competitor_site_data.py +1 -1
  25. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/config.py +4 -0
  26. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/clusters.py +63 -8
  27. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/pagerank.py +16 -6
  28. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/kotlin_lang.py +92 -1
  29. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_server.py +215 -2
  30. roam_code-12.3.0/src/roam/retrieve/learned_ranker.py +241 -0
  31. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/retrieve/pipeline.py +222 -7
  32. roam_code-12.3.0/src/roam/retrieve/rerank.py +510 -0
  33. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/retrieve/seeds.py +19 -13
  34. roam_code-12.3.0/src/roam/retrieve/semantic.py +194 -0
  35. roam_code-12.3.0/src/roam/runtime/daemon.py +100 -0
  36. roam_code-12.3.0/src/roam/runtime/graph_backend.py +92 -0
  37. roam_code-12.3.0/src/roam/runtime/lock_modes.py +50 -0
  38. roam_code-12.3.0/src/roam/runtime/lockmgr.py +136 -0
  39. roam_code-12.3.0/src/roam/security/aibom_extension.py +249 -0
  40. {roam_code-12.1.0 → roam_code-12.3.0/src/roam_code.egg-info}/PKG-INFO +24 -9
  41. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam_code.egg-info/SOURCES.txt +11 -0
  42. roam_code-12.3.0/src/roam_code.egg-info/requires.txt +34 -0
  43. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_batch_mcp.py +9 -1
  44. roam_code-12.3.0/tests/test_extractor_grammar_drift.py +171 -0
  45. roam_code-12.3.0/tests/test_fallback_contracts.py +225 -0
  46. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_mcp_server.py +14 -2
  47. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_readme_surface_consistency.py +7 -1
  48. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_retrieve.py +1 -0
  49. roam_code-12.3.0/tests/test_retrieve_cross_repo.py +249 -0
  50. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_retrieve_seeds.py +12 -4
  51. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_surface_counts.py +2 -0
  52. roam_code-12.3.0/tests/test_v12_2.py +300 -0
  53. roam_code-12.1.0/src/roam/retrieve/rerank.py +0 -266
  54. roam_code-12.1.0/src/roam_code.egg-info/requires.txt +0 -19
  55. {roam_code-12.1.0 → roam_code-12.3.0}/LICENSE +0 -0
  56. {roam_code-12.1.0 → roam_code-12.3.0}/setup.cfg +0 -0
  57. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/__init__.py +0 -0
  58. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/__main__.py +0 -0
  59. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/analysis/__init__.py +0 -0
  60. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/analysis/effects.py +0 -0
  61. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/analysis/taint.py +0 -0
  62. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/api.py +0 -0
  63. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/ask/__init__.py +0 -0
  64. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/ask/classifier.py +0 -0
  65. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/ask/recipes.py +0 -0
  66. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/ask/runner.py +0 -0
  67. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/attest/__init__.py +0 -0
  68. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/__init__.py +0 -0
  69. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/base.py +0 -0
  70. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_config.py +0 -0
  71. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_django.py +0 -0
  72. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_protobuf.py +0 -0
  73. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_rest_api.py +0 -0
  74. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_salesforce.py +0 -0
  75. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/bridge_template.py +0 -0
  76. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/bridges/registry.py +0 -0
  77. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/catalog/__init__.py +0 -0
  78. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/catalog/detectors.py +0 -0
  79. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/catalog/fixes.py +0 -0
  80. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/catalog/smells.py +0 -0
  81. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/catalog/tasks.py +0 -0
  82. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/cli.py +0 -0
  83. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/__init__.py +0 -0
  84. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/changed_files.py +0 -0
  85. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_adrs.py +0 -0
  86. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_adversarial.py +0 -0
  87. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_affected.py +0 -0
  88. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_affected_tests.py +0 -0
  89. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_agent_context.py +0 -0
  90. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_agent_export.py +0 -0
  91. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_agent_plan.py +0 -0
  92. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ai_ratio.py +0 -0
  93. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ai_readiness.py +0 -0
  94. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_alerts.py +0 -0
  95. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_annotate.py +0 -0
  96. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_api_changes.py +0 -0
  97. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_api_drift.py +0 -0
  98. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ask.py +0 -0
  99. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_attest.py +0 -0
  100. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_auth_gaps.py +0 -0
  101. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_bisect.py +0 -0
  102. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_breaking.py +0 -0
  103. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_budget.py +0 -0
  104. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_bus_factor.py +0 -0
  105. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_capsule.py +0 -0
  106. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_check_rules.py +0 -0
  107. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ci_setup.py +0 -0
  108. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_clean.py +0 -0
  109. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_clones.py +0 -0
  110. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_closure.py +0 -0
  111. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_clusters.py +0 -0
  112. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_codeowners.py +0 -0
  113. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_complexity.py +0 -0
  114. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_config.py +0 -0
  115. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_congestion.py +0 -0
  116. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_context.py +0 -0
  117. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_conventions.py +0 -0
  118. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_coupling.py +0 -0
  119. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_coverage_gaps.py +0 -0
  120. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_cut.py +0 -0
  121. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_dark_matter.py +0 -0
  122. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_dashboard.py +0 -0
  123. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_debt.py +0 -0
  124. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_deps.py +0 -0
  125. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_describe.py +0 -0
  126. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_dev_profile.py +0 -0
  127. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_diff.py +0 -0
  128. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_doc_staleness.py +0 -0
  129. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_docs_coverage.py +0 -0
  130. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_doctor.py +0 -0
  131. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_drift.py +0 -0
  132. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_duplicates.py +0 -0
  133. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_effects.py +0 -0
  134. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_endpoints.py +0 -0
  135. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_eval_retrieve.py +0 -0
  136. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_file.py +0 -0
  137. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_fingerprint.py +0 -0
  138. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_fitness.py +0 -0
  139. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_flag_dead.py +0 -0
  140. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_fleet.py +0 -0
  141. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_fn_coupling.py +0 -0
  142. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_forecast.py +0 -0
  143. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_grep.py +0 -0
  144. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_guard.py +0 -0
  145. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_hooks.py +0 -0
  146. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_hotspots.py +0 -0
  147. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_impact.py +0 -0
  148. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_index.py +0 -0
  149. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_index_bundle.py +0 -0
  150. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ingest_trace.py +0 -0
  151. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_init.py +0 -0
  152. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_intent.py +0 -0
  153. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_invariants.py +0 -0
  154. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_layers.py +0 -0
  155. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_map.py +0 -0
  156. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_math.py +0 -0
  157. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_metrics.py +0 -0
  158. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_migration_safety.py +0 -0
  159. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_minimap.py +0 -0
  160. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_missing_index.py +0 -0
  161. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_module.py +0 -0
  162. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_mutate.py +0 -0
  163. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_n1.py +0 -0
  164. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_orchestrate.py +0 -0
  165. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_orphan_routes.py +0 -0
  166. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_over_fetch.py +0 -0
  167. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_owner.py +0 -0
  168. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_partition.py +0 -0
  169. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_path_coverage.py +0 -0
  170. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_patterns.py +0 -0
  171. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_plan.py +0 -0
  172. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_plan_refactor.py +0 -0
  173. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_pr_diff.py +0 -0
  174. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_pr_risk.py +0 -0
  175. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_relate.py +0 -0
  176. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_report.py +0 -0
  177. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_reset.py +0 -0
  178. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_risk.py +0 -0
  179. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_safe_delete.py +0 -0
  180. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_safe_zones.py +0 -0
  181. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_schema.py +0 -0
  182. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_search_semantic.py +0 -0
  183. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_secrets.py +0 -0
  184. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_semantic_diff.py +0 -0
  185. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_simulate.py +0 -0
  186. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_simulate_departure.py +0 -0
  187. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_sketch.py +0 -0
  188. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_spectral.py +0 -0
  189. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_split.py +0 -0
  190. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
  191. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
  192. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_supply_chain.py +0 -0
  193. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_symbol.py +0 -0
  194. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_syntax_check.py +0 -0
  195. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_test_gaps.py +0 -0
  196. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_test_scaffold.py +0 -0
  197. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_testmap.py +0 -0
  198. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_tour.py +0 -0
  199. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_trace.py +0 -0
  200. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_trends.py +0 -0
  201. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_triage.py +0 -0
  202. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_understand.py +0 -0
  203. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_uses.py +0 -0
  204. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_verify.py +0 -0
  205. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_verify_imports.py +0 -0
  206. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_vibe_check.py +0 -0
  207. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_visualize.py +0 -0
  208. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_vuln_map.py +0 -0
  209. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_vuln_reach.py +0 -0
  210. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_vulns.py +0 -0
  211. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_watch.py +0 -0
  212. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_why.py +0 -0
  213. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_ws.py +0 -0
  214. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/cmd_xlang.py +0 -0
  215. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/codeowners_helpers.py +0 -0
  216. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/context_helpers.py +0 -0
  217. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/gate_presets.py +0 -0
  218. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/graph_helpers.py +0 -0
  219. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/next_steps.py +0 -0
  220. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/commands/suppression.py +0 -0
  221. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/coverage_reports.py +0 -0
  222. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/critique/__init__.py +0 -0
  223. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/critique/aggregator.py +0 -0
  224. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/critique/checks.py +0 -0
  225. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/db/__init__.py +0 -0
  226. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/db/connection.py +0 -0
  227. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/db/queries.py +0 -0
  228. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/db/schema.py +0 -0
  229. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/eval/__init__.py +0 -0
  230. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/eval/harness.py +0 -0
  231. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/exit_codes.py +0 -0
  232. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/fleet/__init__.py +0 -0
  233. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/fleet/adapters.py +0 -0
  234. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/fleet/manifest.py +0 -0
  235. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/git_utils.py +0 -0
  236. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/__init__.py +0 -0
  237. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/anomaly.py +0 -0
  238. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/builder.py +0 -0
  239. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/clone_detect.py +0 -0
  240. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/cycles.py +0 -0
  241. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/dark_matter.py +0 -0
  242. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/diff.py +0 -0
  243. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/fingerprint.py +0 -0
  244. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/layers.py +0 -0
  245. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/partition.py +0 -0
  246. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/pathfinding.py +0 -0
  247. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/propagation.py +0 -0
  248. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/simulate.py +0 -0
  249. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/spectral.py +0 -0
  250. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/graph/stats.py +0 -0
  251. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/__init__.py +0 -0
  252. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/complexity.py +0 -0
  253. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/discovery.py +0 -0
  254. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/django_post.py +0 -0
  255. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/file_roles.py +0 -0
  256. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/git_stats.py +0 -0
  257. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/gitignore.py +0 -0
  258. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/incremental.py +0 -0
  259. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/indexer.py +0 -0
  260. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/parser.py +0 -0
  261. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/relations.py +0 -0
  262. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/symbols.py +0 -0
  263. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/index/test_conventions.py +0 -0
  264. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/__init__.py +0 -0
  265. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/apex_lang.py +0 -0
  266. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/aura_lang.py +0 -0
  267. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/base.py +0 -0
  268. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/c_lang.py +0 -0
  269. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/csharp_lang.py +0 -0
  270. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/extractor_schema.py +0 -0
  271. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/foxpro_lang.py +0 -0
  272. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/generic_lang.py +0 -0
  273. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/go_lang.py +0 -0
  274. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/hcl_lang.py +0 -0
  275. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/java_lang.py +0 -0
  276. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/javascript_lang.py +0 -0
  277. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/php_lang.py +0 -0
  278. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/python_lang.py +0 -0
  279. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/query_engine.py +0 -0
  280. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/registry.py +0 -0
  281. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/ruby_lang.py +0 -0
  282. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/rust_lang.py +0 -0
  283. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/scala_lang.py +0 -0
  284. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/sfxml_lang.py +0 -0
  285. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/sql_lang.py +0 -0
  286. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/swift_lang.py +0 -0
  287. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/typescript_lang.py +0 -0
  288. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/visualforce_lang.py +0 -0
  289. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/languages/yaml_lang.py +0 -0
  290. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/__init__.py +0 -0
  291. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/completions.py +0 -0
  292. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/progress.py +0 -0
  293. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/sampling.py +0 -0
  294. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/session.py +0 -0
  295. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/mcp_extras/watcher.py +0 -0
  296. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/output/__init__.py +0 -0
  297. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/output/formatter.py +0 -0
  298. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/output/mermaid.py +0 -0
  299. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/output/sarif.py +0 -0
  300. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/output/schema_registry.py +0 -0
  301. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/plugins.py +0 -0
  302. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/refactor/__init__.py +0 -0
  303. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/refactor/codegen.py +0 -0
  304. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/refactor/transforms.py +0 -0
  305. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/retrieve/__init__.py +0 -0
  306. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/rules/__init__.py +0 -0
  307. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/rules/ast_match.py +0 -0
  308. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/rules/builtin.py +0 -0
  309. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/rules/dataflow.py +0 -0
  310. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/rules/engine.py +0 -0
  311. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/runtime/__init__.py +0 -0
  312. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/runtime/hotspots.py +0 -0
  313. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/runtime/trace_ingest.py +0 -0
  314. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/search/__init__.py +0 -0
  315. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/search/framework_packs.py +0 -0
  316. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/search/index_embeddings.py +0 -0
  317. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/search/onnx_embeddings.py +0 -0
  318. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/search/tfidf.py +0 -0
  319. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/security/__init__.py +0 -0
  320. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/security/taint_classifier.py +0 -0
  321. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/security/taint_engine.py +0 -0
  322. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/security/vuln_reach.py +0 -0
  323. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/security/vuln_store.py +0 -0
  324. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/surface_counts.py +0 -0
  325. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/templates/__init__.py +0 -0
  326. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/templates/ci/__init__.py +0 -0
  327. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/workspace/__init__.py +0 -0
  328. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/workspace/aggregator.py +0 -0
  329. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/workspace/api_scanner.py +0 -0
  330. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/workspace/config.py +0 -0
  331. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam/workspace/db.py +0 -0
  332. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam_code.egg-info/dependency_links.txt +0 -0
  333. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam_code.egg-info/entry_points.txt +0 -0
  334. {roam_code-12.1.0 → roam_code-12.3.0}/src/roam_code.egg-info/top_level.txt +0 -0
  335. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_adrs.py +0 -0
  336. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_adversarial.py +0 -0
  337. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_affected.py +0 -0
  338. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_agent_export.py +0 -0
  339. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_agent_mode.py +0 -0
  340. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_agent_plan_context.py +0 -0
  341. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ai_ratio.py +0 -0
  342. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ai_readiness.py +0 -0
  343. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_alerts_cmd.py +0 -0
  344. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_annotations.py +0 -0
  345. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_anomaly.py +0 -0
  346. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_api_changes.py +0 -0
  347. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_api_drift.py +0 -0
  348. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ask.py +0 -0
  349. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_attest.py +0 -0
  350. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_auth_gaps.py +0 -0
  351. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_backend_fixes_round2.py +0 -0
  352. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_backend_fixes_round3.py +0 -0
  353. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_basic.py +0 -0
  354. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_bisect.py +0 -0
  355. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_bridge_django.py +0 -0
  356. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_bridges.py +0 -0
  357. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_bridges_extended.py +0 -0
  358. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_budget.py +0 -0
  359. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_budget_flag.py +0 -0
  360. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_budget_phase2.py +0 -0
  361. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_bus_factor.py +0 -0
  362. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_capsule.py +0 -0
  363. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_cga.py +0 -0
  364. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_check_rules.py +0 -0
  365. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ci_gate_eval.py +0 -0
  366. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ci_sarif_guard.py +0 -0
  367. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ci_setup.py +0 -0
  368. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_clones.py +0 -0
  369. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_closure.py +0 -0
  370. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_codeowners.py +0 -0
  371. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_commands_architecture.py +0 -0
  372. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_commands_exploration.py +0 -0
  373. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_commands_health.py +0 -0
  374. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_commands_refactoring.py +0 -0
  375. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_commands_workflow.py +0 -0
  376. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_competitor_site_data.py +0 -0
  377. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_comprehensive.py +0 -0
  378. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_config.py +0 -0
  379. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_congestion.py +0 -0
  380. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_context_propagation.py +0 -0
  381. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_conventions_cmd.py +0 -0
  382. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_coverage_gaps_cmd.py +0 -0
  383. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_coverage_ingestion.py +0 -0
  384. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_critique.py +0 -0
  385. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_cut.py +0 -0
  386. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dark_matter.py +0 -0
  387. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dark_matter_helpers.py +0 -0
  388. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dashboard.py +0 -0
  389. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dataflow_dead.py +0 -0
  390. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dead_aging.py +0 -0
  391. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_defer_loading.py +0 -0
  392. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_demo_gif_asset.py +0 -0
  393. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_describe.py +0 -0
  394. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_detail_flag_hints.py +0 -0
  395. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_deterministic_output.py +0 -0
  396. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_dev_profile.py +0 -0
  397. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_difficulty_scoring.py +0 -0
  398. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_doc_staleness.py +0 -0
  399. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_docker_assets.py +0 -0
  400. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_docs_coverage.py +0 -0
  401. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_docs_site_quality.py +0 -0
  402. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_doctor.py +0 -0
  403. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_drift.py +0 -0
  404. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_duplicates.py +0 -0
  405. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_effects.py +0 -0
  406. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_effects_propagation.py +0 -0
  407. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_endpoints.py +0 -0
  408. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_entry_points_cmd.py +0 -0
  409. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_eval_retrieve.py +0 -0
  410. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_exclude_patterns.py +0 -0
  411. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_exit_codes.py +0 -0
  412. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_file_roles.py +0 -0
  413. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_fingerprint.py +0 -0
  414. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_fixes.py +0 -0
  415. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_flag_dead.py +0 -0
  416. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_fleet.py +0 -0
  417. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_fn_coupling.py +0 -0
  418. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_forecast.py +0 -0
  419. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_formatters.py +0 -0
  420. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_foxpro.py +0 -0
  421. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_framework_detection.py +0 -0
  422. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_gate_presets.py +0 -0
  423. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_git_utils.py +0 -0
  424. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_guard.py +0 -0
  425. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_health_gate.py +0 -0
  426. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_hooks.py +0 -0
  427. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_hotspots.py +0 -0
  428. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_index.py +0 -0
  429. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_index_bundle.py +0 -0
  430. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_init_cmd.py +0 -0
  431. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_install_check.py +0 -0
  432. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_intent.py +0 -0
  433. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_invariants.py +0 -0
  434. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_json_contracts.py +0 -0
  435. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_json_error_envelope.py +0 -0
  436. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_kotlin_swift_extractors.py +0 -0
  437. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_language_corpus.py +0 -0
  438. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_languages.py +0 -0
  439. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_library_api.py +0 -0
  440. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_math.py +0 -0
  441. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_math_tips.py +0 -0
  442. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_mcp_extras.py +0 -0
  443. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_mcp_setup.py +0 -0
  444. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_mermaid.py +0 -0
  445. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_metrics_cmd.py +0 -0
  446. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_migration_safety.py +0 -0
  447. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_minimap.py +0 -0
  448. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_missing_index.py +0 -0
  449. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_mutate.py +0 -0
  450. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_n1.py +0 -0
  451. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_next_steps.py +0 -0
  452. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_onboard.py +0 -0
  453. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_oracle.py +0 -0
  454. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_orchestrate.py +0 -0
  455. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_orphan_routes.py +0 -0
  456. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_oss_bench_harness.py +0 -0
  457. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_over_fetch.py +0 -0
  458. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_pagerank_truncation.py +0 -0
  459. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_partition.py +0 -0
  460. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_path_coverage.py +0 -0
  461. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_patterns_cmd.py +0 -0
  462. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_performance.py +0 -0
  463. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_personalized_pagerank.py +0 -0
  464. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_plan.py +0 -0
  465. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_plugin_discovery.py +0 -0
  466. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_pr_comment_script.py +0 -0
  467. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_pr_diff.py +0 -0
  468. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_pr_risk_author.py +0 -0
  469. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_progress.py +0 -0
  470. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_progressive_disclosure.py +0 -0
  471. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_properties.py +0 -0
  472. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_python_extractor_v2.py +0 -0
  473. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_refactoring_intelligence.py +0 -0
  474. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_relate.py +0 -0
  475. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_report.py +0 -0
  476. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_reset_clean.py +0 -0
  477. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_resolve.py +0 -0
  478. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_risk.py +0 -0
  479. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ruby.py +0 -0
  480. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rule_profiles.py +0 -0
  481. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rules.py +0 -0
  482. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rules_ast_match.py +0 -0
  483. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rules_community_pack.py +0 -0
  484. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rules_dataflow.py +0 -0
  485. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_rules_symbol_requirements.py +0 -0
  486. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_runtime.py +0 -0
  487. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_runtime_score.py +0 -0
  488. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_salesforce.py +0 -0
  489. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_sarif_flag.py +0 -0
  490. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_sbom.py +0 -0
  491. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_scala.py +0 -0
  492. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_schema_versioning.py +0 -0
  493. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_search_explain.py +0 -0
  494. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_secrets.py +0 -0
  495. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_secrets_v2.py +0 -0
  496. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_semantic_diff.py +0 -0
  497. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_semantic_onnx.py +0 -0
  498. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_semantic_search.py +0 -0
  499. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_simulate.py +0 -0
  500. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_simulate_departure.py +0 -0
  501. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_sketch.py +0 -0
  502. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_smells.py +0 -0
  503. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_smoke.py +0 -0
  504. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_sna_metrics.py +0 -0
  505. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_spectral.py +0 -0
  506. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_split_cmd.py +0 -0
  507. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_sql.py +0 -0
  508. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_suggest_reviewers.py +0 -0
  509. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_supply_chain.py +0 -0
  510. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_syntax_check.py +0 -0
  511. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_taint.py +0 -0
  512. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_taint_analysis.py +0 -0
  513. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_taint_classifier.py +0 -0
  514. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_test_conventions.py +0 -0
  515. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_test_gaps.py +0 -0
  516. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_test_scaffold.py +0 -0
  517. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_testmap.py +0 -0
  518. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_top_flag_consistency.py +0 -0
  519. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_tour_cmd.py +0 -0
  520. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_trends.py +0 -0
  521. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_trends_cohort.py +0 -0
  522. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_triage.py +0 -0
  523. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_uses_cmd.py +0 -0
  524. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_v6_features.py +0 -0
  525. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_v71_features.py +0 -0
  526. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_v7_features.py +0 -0
  527. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_v82_features.py +0 -0
  528. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_verify.py +0 -0
  529. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_verify_imports.py +0 -0
  530. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_vibe_check.py +0 -0
  531. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_visualize.py +0 -0
  532. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_vuln.py +0 -0
  533. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_vulns_cmd.py +0 -0
  534. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_watch.py +0 -0
  535. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_why.py +0 -0
  536. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_workspace.py +0 -0
  537. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_ws_resolve_fixes.py +0 -0
  538. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_xlang.py +0 -0
  539. {roam_code-12.1.0 → roam_code-12.3.0}/tests/test_yaml_hcl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roam-code
3
- Version: 12.1.0
3
+ Version: 12.3.0
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: MIT
@@ -29,7 +29,7 @@ Description-Content-Type: text/markdown
29
29
  License-File: LICENSE
30
30
  Requires-Dist: click>=8.0
31
31
  Requires-Dist: tree-sitter>=0.23
32
- Requires-Dist: tree-sitter-language-pack>=0.6
32
+ Requires-Dist: tree-sitter-language-pack<1.6.3,>=0.6
33
33
  Requires-Dist: networkx>=3.0
34
34
  Provides-Extra: mcp
35
35
  Requires-Dist: fastmcp>=2.0; extra == "mcp"
@@ -37,9 +37,20 @@ Provides-Extra: semantic
37
37
  Requires-Dist: numpy>=1.24; extra == "semantic"
38
38
  Requires-Dist: onnxruntime>=1.16; extra == "semantic"
39
39
  Requires-Dist: tokenizers>=0.15; extra == "semantic"
40
+ Provides-Extra: leiden
41
+ Requires-Dist: igraph>=0.11; extra == "leiden"
42
+ Requires-Dist: leidenalg>=0.10; extra == "leiden"
43
+ Provides-Extra: graph-fast
44
+ Requires-Dist: rustworkx>=0.14; extra == "graph-fast"
45
+ Provides-Extra: sbom
46
+ Requires-Dist: cyclonedx-python-lib>=8.0; extra == "sbom"
47
+ Provides-Extra: learned
48
+ Requires-Dist: lightgbm>=4.0; extra == "learned"
40
49
  Provides-Extra: dev
41
50
  Requires-Dist: pytest>=7.0; extra == "dev"
42
51
  Requires-Dist: pytest-xdist>=3.0; extra == "dev"
52
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
53
+ Requires-Dist: scipy>=1.11; extra == "dev"
43
54
  Requires-Dist: ruff>=0.4; extra == "dev"
44
55
  Requires-Dist: build>=1.0; extra == "dev"
45
56
  Requires-Dist: twine>=5.0; extra == "dev"
@@ -51,7 +62,7 @@ Dynamic: license-file
51
62
 
52
63
  **The architectural intelligence layer for AI coding agents. Structural graph, architecture governance, multi-agent orchestration, vulnerability mapping, runtime analysis -- one CLI, zero API keys.**
53
64
 
54
- *150 commands · 112 MCP tools · 27 languages · 100% local*
65
+ *150 commands · 116 MCP tools · 27 languages · 100% local*
55
66
 
56
67
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
57
68
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -128,7 +139,7 @@ $ roam diff # blast radius of uncommitted changes
128
139
  - **`personalized_pagerank()`** in `graph/pagerank.py`: NetworkX `personalization=` wrapper with empty-seed fallback to global PR; biases ranking toward query-relevant nodes for the retrieve reranker.
129
140
  - **`.roam/config.toml`** (new): zero-dep TOML loader (stdlib `tomllib` → `tomli` → in-tree subset parser). Tunable retrieve weights (`alpha`/`beta`/`gamma`/`delta`/`epsilon`), `tokens_per_line`, `lexical_baseline`, `first_stage_token_cap`, `default_budget`, `default_k`, `default_rerank`.
130
141
  - **DX corrections from dogfood pass**: `roam --detail <cmd>` is the canonical group-level flag; misleading "use --detail" hints in 7 commands rewritten to point users at `roam --detail <cmd>`. `--top N` aliased on `complexity`/`algo`/`rules` (`--top 0` means unlimited on `rules`). `roam fingerprint` no longer refuses graphs ≥5,000 symbols (new soft-warn threshold 20k, hard cap 100k).
131
- - **150 CLI commands, 112 MCP tools** (`fleet`, `ask`, `taint`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`) and `roam_taint_classify` as MCP tools). 33-tool `core` preset is the default for token-budget-conscious clients.
142
+ - **150 CLI commands, 116 MCP tools** (`fleet`, `ask`, `taint`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`) and `roam_taint_classify` as MCP tools). 33-tool `core` preset is the default for token-budget-conscious clients.
132
143
 
133
144
  ## What's New in v11
134
145
 
@@ -159,7 +170,7 @@ $ roam diff # blast radius of uncommitted changes
159
170
  - MCP token overhead for default core context dropped from ~36K to <3K tokens (about 92% reduction).
160
171
 
161
172
  ### Performance and Retrieval
162
- - Symbol search moved to SQLite FTS5/BM25: typical search moved from seconds to milliseconds (about 1000x on benchmarked paths).
173
+ - Symbol search moved to SQLite FTS5/BM25: typical search moved from seconds to tens of milliseconds on the indexed cohort (mileage varies by repo size and query selectivity — see `bench/retrieve/` for the methodology).
163
174
  - Incremental indexing shifted from O(N) full-edge rebuild behavior to O(changed) updates.
164
175
  - DB/runtime optimizations (`mmap_size`, safer large-graph guards, batched writes) reduce first-run and reindex friction on larger repos.
165
176
 
@@ -299,7 +310,7 @@ roam health
299
310
 
300
311
  ## Commands
301
312
 
302
- The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 150 commands are organized into 7 categories.
313
+ **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 145 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **150 commands organised into 7 categories**, but you don't need to know that to start.
303
314
 
304
315
  <details>
305
316
  <summary><strong>Full command reference</strong></summary>
@@ -937,7 +948,7 @@ ROAM_MCP_LITE=0 roam mcp
937
948
  Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`, `roam_complete`, `roam_complexity_report`, `roam_context`, `roam_dead_code`, `roam_deps`, `roam_diagnose`, `roam_diagnose_issue`, `roam_diff`, `roam_expand_toolset`, `roam_explore`, `roam_file_info`, `roam_health`, `roam_impact`, `roam_pr_risk`, `roam_preflight`, `roam_prepare_change`, `roam_review_change`, `roam_search_symbol`, `roam_syntax_check`, `roam_trace`, `roam_understand`, `roam_uses`.
938
949
 
939
950
  <details>
940
- <summary><strong>MCP tool list (all 112)</strong></summary>
951
+ <summary><strong>MCP tool list (all 116)</strong></summary>
941
952
 
942
953
  | Tool | Description |
943
954
  |------|-------------|
@@ -957,6 +968,10 @@ Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`,
957
968
  | `roam_oracle_is_reachable_from_entry` | Boolean oracle: can BFS reach this symbol from any entry-point? |
958
969
  | `roam_oracle_is_clone_of` | Boolean oracle: does this symbol participate in a persisted clone cluster? |
959
970
  | `roam_taint_classify` | LLM-augmented taint classification (IDOR/AUTHZ/SQLI/...) via MCP sampling |
971
+ | `roam_taint` | Static taint analysis — graph-reach BFS with OpenVEX-correct findings |
972
+ | `roam_sbom` | CycloneDX 1.7 / SPDX 2.3 SBOM emit with optional AIBOM extension (EU AI Act) |
973
+ | `roam_cga_emit` | Emit a Code Graph Attestation (in-toto v1) with optional cosign signing |
974
+ | `roam_cga_verify` | Verify a CGA statement — re-derives Merkle + edge digest, checks cosign signature |
960
975
  | `roam_trace` | Dependency path between two symbols |
961
976
  | `roam_impact` | Blast radius of changing a symbol |
962
977
  | `roam_file_info` | File skeleton with all definitions |
@@ -1568,7 +1583,7 @@ roam-code/
1568
1583
  ├── src/roam/
1569
1584
  │ ├── __init__.py # Version (from pyproject.toml)
1570
1585
  │ ├── cli.py # Click CLI (150 commands)
1571
- │ ├── mcp_server.py # MCP server (112 tools, 10 resources, 5 prompts)
1586
+ │ ├── mcp_server.py # MCP server (116 tools, 10 resources, 5 prompts)
1572
1587
  │ ├── db/
1573
1588
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
1574
1589
  │ │ ├── schema.py # Tables, indexes, migrations
@@ -1662,7 +1677,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1662
1677
  ### Shipped
1663
1678
 
1664
1679
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1665
- - [x] Full command and MCP inventory parity in docs: 150 CLI commands and 112 MCP tools.
1680
+ - [x] Full command and MCP inventory parity in docs: 150 CLI commands and 116 MCP tools.
1666
1681
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1667
1682
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1668
1683
  - [x] Agent governance suite: `vibe-check`, `ai-readiness`, `verify`, `ai-ratio`, `duplicates`, advanced `algo` scoring/SARIF.
@@ -4,7 +4,7 @@
4
4
 
5
5
  **The architectural intelligence layer for AI coding agents. Structural graph, architecture governance, multi-agent orchestration, vulnerability mapping, runtime analysis -- one CLI, zero API keys.**
6
6
 
7
- *150 commands · 112 MCP tools · 27 languages · 100% local*
7
+ *150 commands · 116 MCP tools · 27 languages · 100% local*
8
8
 
9
9
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
10
10
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -81,7 +81,7 @@ $ roam diff # blast radius of uncommitted changes
81
81
  - **`personalized_pagerank()`** in `graph/pagerank.py`: NetworkX `personalization=` wrapper with empty-seed fallback to global PR; biases ranking toward query-relevant nodes for the retrieve reranker.
82
82
  - **`.roam/config.toml`** (new): zero-dep TOML loader (stdlib `tomllib` → `tomli` → in-tree subset parser). Tunable retrieve weights (`alpha`/`beta`/`gamma`/`delta`/`epsilon`), `tokens_per_line`, `lexical_baseline`, `first_stage_token_cap`, `default_budget`, `default_k`, `default_rerank`.
83
83
  - **DX corrections from dogfood pass**: `roam --detail <cmd>` is the canonical group-level flag; misleading "use --detail" hints in 7 commands rewritten to point users at `roam --detail <cmd>`. `--top N` aliased on `complexity`/`algo`/`rules` (`--top 0` means unlimited on `rules`). `roam fingerprint` no longer refuses graphs ≥5,000 symbols (new soft-warn threshold 20k, hard cap 100k).
84
- - **150 CLI commands, 112 MCP tools** (`fleet`, `ask`, `taint`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`) and `roam_taint_classify` as MCP tools). 33-tool `core` preset is the default for token-budget-conscious clients.
84
+ - **150 CLI commands, 116 MCP tools** (`fleet`, `ask`, `taint`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`) and `roam_taint_classify` as MCP tools). 33-tool `core` preset is the default for token-budget-conscious clients.
85
85
 
86
86
  ## What's New in v11
87
87
 
@@ -112,7 +112,7 @@ $ roam diff # blast radius of uncommitted changes
112
112
  - MCP token overhead for default core context dropped from ~36K to <3K tokens (about 92% reduction).
113
113
 
114
114
  ### Performance and Retrieval
115
- - Symbol search moved to SQLite FTS5/BM25: typical search moved from seconds to milliseconds (about 1000x on benchmarked paths).
115
+ - Symbol search moved to SQLite FTS5/BM25: typical search moved from seconds to tens of milliseconds on the indexed cohort (mileage varies by repo size and query selectivity — see `bench/retrieve/` for the methodology).
116
116
  - Incremental indexing shifted from O(N) full-edge rebuild behavior to O(changed) updates.
117
117
  - DB/runtime optimizations (`mmap_size`, safer large-graph guards, batched writes) reduce first-run and reindex friction on larger repos.
118
118
 
@@ -252,7 +252,7 @@ roam health
252
252
 
253
253
  ## Commands
254
254
 
255
- The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 150 commands are organized into 7 categories.
255
+ **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 145 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **150 commands organised into 7 categories**, but you don't need to know that to start.
256
256
 
257
257
  <details>
258
258
  <summary><strong>Full command reference</strong></summary>
@@ -890,7 +890,7 @@ ROAM_MCP_LITE=0 roam mcp
890
890
  Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`, `roam_complete`, `roam_complexity_report`, `roam_context`, `roam_dead_code`, `roam_deps`, `roam_diagnose`, `roam_diagnose_issue`, `roam_diff`, `roam_expand_toolset`, `roam_explore`, `roam_file_info`, `roam_health`, `roam_impact`, `roam_pr_risk`, `roam_preflight`, `roam_prepare_change`, `roam_review_change`, `roam_search_symbol`, `roam_syntax_check`, `roam_trace`, `roam_understand`, `roam_uses`.
891
891
 
892
892
  <details>
893
- <summary><strong>MCP tool list (all 112)</strong></summary>
893
+ <summary><strong>MCP tool list (all 116)</strong></summary>
894
894
 
895
895
  | Tool | Description |
896
896
  |------|-------------|
@@ -910,6 +910,10 @@ Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`,
910
910
  | `roam_oracle_is_reachable_from_entry` | Boolean oracle: can BFS reach this symbol from any entry-point? |
911
911
  | `roam_oracle_is_clone_of` | Boolean oracle: does this symbol participate in a persisted clone cluster? |
912
912
  | `roam_taint_classify` | LLM-augmented taint classification (IDOR/AUTHZ/SQLI/...) via MCP sampling |
913
+ | `roam_taint` | Static taint analysis — graph-reach BFS with OpenVEX-correct findings |
914
+ | `roam_sbom` | CycloneDX 1.7 / SPDX 2.3 SBOM emit with optional AIBOM extension (EU AI Act) |
915
+ | `roam_cga_emit` | Emit a Code Graph Attestation (in-toto v1) with optional cosign signing |
916
+ | `roam_cga_verify` | Verify a CGA statement — re-derives Merkle + edge digest, checks cosign signature |
913
917
  | `roam_trace` | Dependency path between two symbols |
914
918
  | `roam_impact` | Blast radius of changing a symbol |
915
919
  | `roam_file_info` | File skeleton with all definitions |
@@ -1521,7 +1525,7 @@ roam-code/
1521
1525
  ├── src/roam/
1522
1526
  │ ├── __init__.py # Version (from pyproject.toml)
1523
1527
  │ ├── cli.py # Click CLI (150 commands)
1524
- │ ├── mcp_server.py # MCP server (112 tools, 10 resources, 5 prompts)
1528
+ │ ├── mcp_server.py # MCP server (116 tools, 10 resources, 5 prompts)
1525
1529
  │ ├── db/
1526
1530
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
1527
1531
  │ │ ├── schema.py # Tables, indexes, migrations
@@ -1615,7 +1619,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1615
1619
  ### Shipped
1616
1620
 
1617
1621
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1618
- - [x] Full command and MCP inventory parity in docs: 150 CLI commands and 112 MCP tools.
1622
+ - [x] Full command and MCP inventory parity in docs: 150 CLI commands and 116 MCP tools.
1619
1623
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1620
1624
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1621
1625
  - [x] Agent governance suite: `vibe-check`, `ai-readiness`, `verify`, `ai-ratio`, `duplicates`, advanced `algo` scoring/SARIF.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "roam-code"
7
- version = "12.1.0"
7
+ version = "12.3.0"
8
8
  description = "Instant codebase comprehension for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -32,7 +32,11 @@ classifiers = [
32
32
  dependencies = [
33
33
  "click>=8.0",
34
34
  "tree-sitter>=0.23",
35
- "tree-sitter-language-pack>=0.6",
35
+ # Pinned upper bound: 1.6.3's cp312 wheel ships a manylinux_2_34
36
+ # tarball that fails to register the ``tree_sitter_language_pack``
37
+ # module post-install (CI run 25217131296). 1.6.2 (cp310-abi3) works
38
+ # cleanly across 3.9–3.13.
39
+ "tree-sitter-language-pack>=0.6,<1.6.3",
36
40
  "networkx>=3.0",
37
41
  ]
38
42
 
@@ -55,9 +59,42 @@ semantic = [
55
59
  "onnxruntime>=1.16",
56
60
  "tokenizers>=0.15",
57
61
  ]
62
+ leiden = [
63
+ # Strictly better community detection than Louvain (no badly-connected
64
+ # communities). Auto-detected at runtime; falls back to seeded Louvain
65
+ # when these aren't installed.
66
+ "igraph>=0.11",
67
+ "leidenalg>=0.10",
68
+ ]
69
+ graph-fast = [
70
+ # rustworkx is a Rust-backed drop-in for many NetworkX algorithms;
71
+ # 3-100× speedup at >250k nodes per the v12.2 architecture review.
72
+ # Auto-detected via ``ROAM_GRAPH_BACKEND=rustworkx``.
73
+ "rustworkx>=0.14",
74
+ ]
75
+ sbom = [
76
+ # CycloneDX 1.7 SBOM emit (with AIBOM extension) for `roam sbom`.
77
+ # Falls back to in-tree minimal emitter when not installed.
78
+ "cyclonedx-python-lib>=8.0",
79
+ ]
80
+ learned = [
81
+ # LightGBM LambdaMART distillation for `roam retrieve --rerank learned`.
82
+ # Optional — current `--rerank fast` blend stays the default.
83
+ "lightgbm>=4.0",
84
+ ]
58
85
  dev = [
59
86
  "pytest>=7.0",
60
87
  "pytest-xdist>=3.0",
88
+ # pytest-asyncio is required by tests/test_taint_classifier.py — those
89
+ # tests use ``@pytest.mark.asyncio`` to verify the MCP-sampling-based
90
+ # taint classifier under a controlled async loop.
91
+ "pytest-asyncio>=0.23",
92
+ # scipy is required by ``nx.pagerank`` on networkx 3.x; without it,
93
+ # the personalized-pagerank tests exercise the degree-based fallback
94
+ # which doesn't honour ``alpha`` and trivially fails the
95
+ # alpha-override / chain-propagation invariants. Production users
96
+ # without scipy still get the (less accurate but correct) fallback.
97
+ "scipy>=1.11",
61
98
  "ruff>=0.4",
62
99
  "build>=1.0",
63
100
  "twine>=5.0",
@@ -69,10 +106,17 @@ where = ["src"]
69
106
  [tool.pytest.ini_options]
70
107
  testpaths = ["tests"]
71
108
  addopts = "-q --tb=short"
109
+ # v12.2: pytest-asyncio strict-mode + auto fixture loop scope. Avoids the
110
+ # 11 PytestUnknownMarkWarning warnings on `@pytest.mark.asyncio` in
111
+ # test_taint_classifier.py when pytest-asyncio is installed (it ships
112
+ # under the `[dev]` extra).
113
+ asyncio_mode = "strict"
114
+ asyncio_default_fixture_loop_scope = "function"
72
115
  markers = [
73
116
  "smoke: fast, high-signal tests for local iteration",
74
117
  "core: broader local suite for pre-push checks",
75
118
  "slow: marks tests as slow (deselect with '-m \"not slow\"')",
119
+ "asyncio: marks async tests requiring pytest-asyncio (skip when missing)",
76
120
  ]
77
121
 
78
122
  [tool.ruff]
@@ -31,6 +31,11 @@ from typing import Any
31
31
  from roam.security.taint_engine import OPENVEX_JUSTIFICATIONS, OPENVEX_STATUSES
32
32
 
33
33
  PREDICATE_TYPE = "https://roam-code.dev/CodeGraph/v1"
34
+ # v12.2: fused CodeGraph + AIBOM predicate. Owns the "structurally bound
35
+ # AI authorship for tamper-evident codebases" lane that SLSA + SPDX +
36
+ # CycloneDX 1.7 + OpenVEX leave gapped. Reference impl candidate for
37
+ # the in-toto attestation registry.
38
+ PREDICATE_TYPE_AIBOM = "https://roam-code.dev/CodeGraph-AIBOM/v1"
34
39
  STATEMENT_TYPE = "https://in-toto.io/Statement/v1"
35
40
  SCHEMA_VERSION = "1"
36
41
 
@@ -218,6 +223,7 @@ def build_cga_statement(
218
223
  project_root: Path,
219
224
  tool_version: str | None = None,
220
225
  taint_findings: list | None = None,
226
+ include_aibom: bool = False,
221
227
  ) -> dict[str, Any]:
222
228
  """Build the full in-toto v1 Statement wrapping the CGA predicate.
223
229
 
@@ -225,9 +231,15 @@ def build_cga_statement(
225
231
  {
226
232
  "_type": "https://in-toto.io/Statement/v1",
227
233
  "predicateType": "https://roam-code.dev/CodeGraph/v1",
234
+ # → CodeGraph-AIBOM/v1 when include_aibom=True
228
235
  "subject": [{"name": "...", "digest": {...}}],
229
236
  "predicate": {...}
230
237
  }
238
+
239
+ With ``include_aibom=True``, the predicate type promotes to
240
+ ``CodeGraph-AIBOM/v1`` and embeds an ``aibom`` block binding
241
+ AI-authored commits to the indexed symbols they touched. Required
242
+ for EU AI Act Art. 50 disclosure (effective 2026-08-02).
231
243
  """
232
244
  sha = _git_commit_sha(project_root) or "unknown"
233
245
  remote = _git_remote_url(project_root)
@@ -236,16 +248,26 @@ def build_cga_statement(
236
248
  "name": subject_name,
237
249
  "digest": {"git_commit_sha1": sha},
238
250
  }
251
+ predicate = build_cga_predicate(
252
+ conn,
253
+ project_root=project_root,
254
+ tool_version=tool_version,
255
+ taint_findings=taint_findings,
256
+ )
257
+ predicate_type = PREDICATE_TYPE
258
+ if include_aibom:
259
+ try:
260
+ from roam.security.aibom_extension import build_aibom_block
261
+
262
+ predicate["aibom"] = build_aibom_block(project_root, conn)
263
+ predicate_type = PREDICATE_TYPE_AIBOM
264
+ except Exception as exc:
265
+ predicate["aibom_error"] = str(exc)
239
266
  return {
240
267
  "_type": STATEMENT_TYPE,
241
- "predicateType": PREDICATE_TYPE,
268
+ "predicateType": predicate_type,
242
269
  "subject": [subject],
243
- "predicate": build_cga_predicate(
244
- conn,
245
- project_root=project_root,
246
- tool_version=tool_version,
247
- taint_findings=taint_findings,
248
- ),
270
+ "predicate": predicate,
249
271
  }
250
272
 
251
273
 
@@ -270,8 +292,11 @@ def verify_cga_statement(
270
292
  errors: list[str] = []
271
293
  if statement.get("_type") != STATEMENT_TYPE:
272
294
  errors.append(f"_type mismatch: got {statement.get('_type')!r}, expected {STATEMENT_TYPE!r}")
273
- if statement.get("predicateType") != PREDICATE_TYPE:
274
- errors.append(f"predicateType mismatch: got {statement.get('predicateType')!r}, expected {PREDICATE_TYPE!r}")
295
+ accepted_types = (PREDICATE_TYPE, PREDICATE_TYPE_AIBOM)
296
+ if statement.get("predicateType") not in accepted_types:
297
+ errors.append(
298
+ f"predicateType mismatch: got {statement.get('predicateType')!r}, expected one of {accepted_types!r}"
299
+ )
275
300
  predicate = statement.get("predicate") or {}
276
301
  if not isinstance(predicate, dict):
277
302
  return False, errors + ["predicate is not a JSON object"]
@@ -110,9 +110,25 @@ def _default_output_path(project_root: Path, statement: dict) -> Path:
110
110
  "browser flow."
111
111
  ),
112
112
  )
113
+ @click.option(
114
+ "--aibom",
115
+ is_flag=True,
116
+ help=(
117
+ "Promote the predicate to ``CodeGraph-AIBOM/v1`` and embed an "
118
+ "AIBOM block binding AI-authored commits to the indexed symbols "
119
+ "they touched. Required for EU AI Act Art. 50 disclosure (effective "
120
+ "2026-08-02) and the GPAI Code of Practice provenance mandate. "
121
+ "Reference impl candidate for the in-toto attestation registry."
122
+ ),
123
+ )
113
124
  @click.pass_context
114
- def cga_emit(ctx, output_path, no_write, include_taint, taint_rules_dir, sign, key_path, keyless):
115
- """Emit a Code Graph Attestation (in-toto v1, optionally cosign-signed)."""
125
+ def cga_emit(ctx, output_path, no_write, include_taint, taint_rules_dir, sign, key_path, keyless, aibom):
126
+ """Emit a Code Graph Attestation (in-toto v1, optionally cosign-signed).
127
+
128
+ With ``--aibom`` the predicate type promotes to
129
+ ``roam-code.dev/CodeGraph-AIBOM/v1`` and the predicate gains an
130
+ ``aibom`` block binding AI-authored commits to indexed symbols.
131
+ """
116
132
  json_mode = ctx.obj.get("json") if ctx.obj else False
117
133
  token_budget = ctx.obj.get("budget", 0) if ctx.obj else 0
118
134
 
@@ -137,6 +153,7 @@ def cga_emit(ctx, output_path, no_write, include_taint, taint_rules_dir, sign, k
137
153
  conn,
138
154
  project_root=project_root,
139
155
  taint_findings=taint_findings,
156
+ include_aibom=aibom,
140
157
  )
141
158
 
142
159
  canonical = serialize_statement(statement)
@@ -198,7 +215,7 @@ def cga_emit(ctx, output_path, no_write, include_taint, taint_rules_dir, sign, k
198
215
  "edge_bundle_digest": pred["edge_bundle_digest"],
199
216
  "symbol_count": pred["symbol_count"],
200
217
  "edge_count": pred["edge_count"],
201
- "predicate_type": PREDICATE_TYPE,
218
+ "predicate_type": statement.get("predicateType", PREDICATE_TYPE),
202
219
  "statement_type": STATEMENT_TYPE,
203
220
  "written_to": written_to,
204
221
  "signed": bool(sign_result and sign_result.get("signed")),
@@ -212,7 +229,7 @@ def cga_emit(ctx, output_path, no_write, include_taint, taint_rules_dir, sign, k
212
229
  return
213
230
 
214
231
  click.echo(f"VERDICT: {verdict}")
215
- click.echo(f"Predicate type: {PREDICATE_TYPE}")
232
+ click.echo(f"Predicate type: {statement.get('predicateType', PREDICATE_TYPE)}")
216
233
  click.echo(f"Statement type: {STATEMENT_TYPE}")
217
234
  click.echo(f"Languages: {', '.join(pred['languages']) or '(none)'}")
218
235
  if written_to:
@@ -31,6 +31,57 @@ from roam.critique.checks import (
31
31
  from roam.db.connection import open_db
32
32
  from roam.output.formatter import json_envelope, to_json
33
33
 
34
+ # Hot-path → bench command. When a diff touches any of these path
35
+ # prefixes, the default critique rules can pass while the change
36
+ # materially alters retrieval/scoring/graph algorithms. The hint
37
+ # names the bench so the user includes it in their verification
38
+ # loop. Order matters: first match wins (most specific first).
39
+ _BENCH_RELEVANCE_RULES = [
40
+ (
41
+ ("src/roam/retrieve/", "src/roam/eval/"),
42
+ "pytest tests/test_retrieve_cross_repo.py + roam eval-retrieve --tasks bench/retrieve/roam_self.jsonl",
43
+ ),
44
+ (
45
+ ("src/roam/graph/pagerank.py", "src/roam/graph/clusters.py"),
46
+ "pytest tests/test_personalized_pagerank.py tests/test_fallback_contracts.py",
47
+ ),
48
+ (("src/roam/graph/",), "pytest tests/ -k graph_ -m 'not slow'"),
49
+ (
50
+ ("src/roam/languages/", "src/roam/index/parser.py"),
51
+ "pytest tests/test_languages.py tests/test_extractor_grammar_drift.py",
52
+ ),
53
+ (("src/roam/security/taint",), "pytest tests/test_taint_analysis.py tests/test_taint_classifier.py"),
54
+ (("src/roam/critique/",), "pytest tests/test_critique.py"),
55
+ (
56
+ ("src/roam/commands/cmd_oracle.py", "src/roam/commands/cmd_health.py"),
57
+ "pytest tests/test_oracle.py tests/test_commands_health.py",
58
+ ),
59
+ ]
60
+
61
+
62
+ def _bench_relevance_hint(regions) -> str:
63
+ """Return a one-line bench/test suggestion when the diff touches a
64
+ structurally-significant path. ``regions`` is the
65
+ ``critique.checks.ChangedRegion`` list from the diff parser; we
66
+ look at each region's file path and pick the first matching rule.
67
+ """
68
+ paths = []
69
+ for r in regions:
70
+ path = getattr(r, "file_path", None) or getattr(r, "file", None) or ""
71
+ if path:
72
+ paths.append(path.replace("\\", "/"))
73
+ if not paths:
74
+ return ""
75
+ seen: set[str] = set()
76
+ for path in paths:
77
+ for prefixes, hint in _BENCH_RELEVANCE_RULES:
78
+ if any(path.startswith(p) or p in path for p in prefixes):
79
+ if hint in seen:
80
+ return hint
81
+ seen.add(hint)
82
+ return hint
83
+ return ""
84
+
34
85
 
35
86
  @click.command()
36
87
  @click.option(
@@ -163,5 +214,17 @@ def critique(ctx, input_path, high_callers, intent_text):
163
214
  click.echo(f" {line}")
164
215
  click.echo()
165
216
 
217
+ # Bench-relevance hint (dogfood notes 2026-05-01): when the diff
218
+ # touches files in the retrieve / graph / catalog hot path, the
219
+ # default rule set ("clones not edited", "blast radius") can
220
+ # legitimately say "no concerns" while the change quietly
221
+ # alters the structural-rerank scoring formula. Surfacing the
222
+ # bench command makes the verifier conversation include the
223
+ # one validation that actually exercises the modified code.
224
+ bench_hint = _bench_relevance_hint(regions)
225
+ if bench_hint:
226
+ click.echo()
227
+ click.echo(f"BENCH HINT: {bench_hint}")
228
+
166
229
  if result["severity_breakdown"].get("high", 0) > 0:
167
230
  ctx.exit(5)
@@ -358,6 +358,19 @@ def _group_dead(dead_items, by):
358
358
  # ---------------------------------------------------------------------------
359
359
 
360
360
 
361
+ _TOOLING_PATH_HINTS = ("/dev/", "/benchmarks/", "/.github/", "\\dev\\", "\\benchmarks\\", "\\.github\\")
362
+
363
+
364
+ def _is_tooling_path(path: str) -> bool:
365
+ """Same hint set as cmd_fan / cmd_smells. Excluded from dead-code
366
+ headline by default (dogfood notes 2026-05-01) — CI scripts are
367
+ expected to have unreferenced helper functions."""
368
+ if not path:
369
+ return False
370
+ p = "/" + path.replace("\\", "/")
371
+ return any(hint.replace("\\", "/") in p for hint in _TOOLING_PATH_HINTS)
372
+
373
+
361
374
  def _analyze_dead(conn):
362
375
  """Run the full dead code analysis.
363
376
 
@@ -366,6 +379,9 @@ def _analyze_dead(conn):
366
379
  rows = conn.execute(UNREFERENCED_EXPORTS).fetchall()
367
380
  # Exclude test files — their symbols are discovered by pytest, not imported
368
381
  rows = [r for r in rows if not _is_test_path(r["file_path"])]
382
+ # Exclude tooling/CI/benchmarks/dev — same default-exclusion that
383
+ # ``cmd_smells`` and ``cmd_fan`` apply.
384
+ rows = [r for r in rows if not _is_tooling_path(r["file_path"])]
369
385
  if not rows:
370
386
  return [], [], set()
371
387
 
@@ -315,6 +315,15 @@ def diagnose(ctx, name, depth):
315
315
 
316
316
  # Text output
317
317
  click.echo(f"VERDICT: {verdict}")
318
+ # Index-staleness hint (dogfood notes 2026-05-01): when index
319
+ # is older than HEAD, commit_count / churn columns are
320
+ # unreliable — surface this so the user knows whether to trust
321
+ # the numbers or re-index.
322
+ from roam.commands.resolve import index_staleness_hint as _stale_hint
323
+
324
+ _stale = _stale_hint()
325
+ if _stale:
326
+ click.echo(f"NOTE: {_stale}")
318
327
  sym_name = sym["qualified_name"] or sym["name"]
319
328
  click.echo(f"Diagnose: {sym_name}")
320
329
  click.echo(f" {loc(target_metrics['file_path'], sym['line_start'])}")
@@ -103,7 +103,13 @@ _NAME_PATTERNS = [
103
103
  ("Scheduled", re.compile(r"cron|schedule|periodic|tick", re.IGNORECASE)),
104
104
  ("Message", re.compile(r"consume|subscriber|on_message|process_message", re.IGNORECASE)),
105
105
  ("CLI", re.compile(r"^cmd_|_command$|_cmd$", re.IGNORECASE)),
106
- ("HTTP", re.compile(r"_view$|_endpoint$|_controller$|_handler$", re.IGNORECASE)),
106
+ # HTTP name patterns: only the strong endpoint/controller suffixes.
107
+ # ``_view$`` and ``_handler$`` matched too broadly — dogfood notes
108
+ # 2026-05-01 caught ``_extract_create_view`` (a SQL parser method)
109
+ # and ``error_handler`` (signal handler) being classified as HTTP
110
+ # routes. The decorator pattern above already catches genuine
111
+ # ``@app.route`` etc. — name fallback can be conservative.
112
+ ("HTTP", re.compile(r"_endpoint$|_controller$", re.IGNORECASE)),
107
113
  ]
108
114
 
109
115
 
@@ -107,12 +107,43 @@ _FRAMEWORK_NAMES = frozenset(
107
107
  )
108
108
 
109
109
 
110
+ _TOOLING_PATH_HINTS = ("/dev/", "/benchmarks/", "/.github/", "\\dev\\", "\\benchmarks\\", "\\.github\\")
111
+
112
+
113
+ def _is_tooling_path(path: str) -> bool:
114
+ """Return True for paths that belong to tooling/CI/benchmarks/dev.
115
+
116
+ Default-excluded from headline metrics so first-time users aren't
117
+ dominated by ``pr-comment.js`` and ``roam-bench.py`` rows.
118
+ Matches the hint set used by ``cmd_smells._file_role_lookup``.
119
+ """
120
+ if not path:
121
+ return False
122
+ p = "/" + path.replace("\\", "/")
123
+ return any(hint.replace("\\", "/") in p for hint in _TOOLING_PATH_HINTS)
124
+
125
+
126
+ def _filter_tooling_rows(rows):
127
+ """Filter out rows whose ``file_path`` is in a tooling location."""
128
+ return [r for r in rows if not _is_tooling_path(r["file_path"] or "")]
129
+
130
+
110
131
  @click.command()
111
132
  @click.argument("mode", default="symbol", type=click.Choice(["symbol", "file"]))
112
133
  @click.option("-n", "count", default=20, help="Number of items to show")
113
134
  @click.option("--no-framework", is_flag=True, help="Filter out framework/boilerplate symbols")
135
+ @click.option(
136
+ "--include-tooling",
137
+ is_flag=True,
138
+ default=False,
139
+ help=(
140
+ "Include CI scripts, dev tooling, build, and generated files. "
141
+ "Excluded by default — high fan-in in dev/.github/benchmarks "
142
+ "is expected and dominates the headline (dogfood notes 2026-05-01)."
143
+ ),
144
+ )
114
145
  @click.pass_context
115
- def fan(ctx, mode, count, no_framework):
146
+ def fan(ctx, mode, count, no_framework, include_tooling):
116
147
  """Show fan-in/fan-out: most connected symbols or files.
117
148
 
118
149
  Unlike ``coupling`` (which measures temporal co-change frequency), this
@@ -124,6 +155,10 @@ def fan(ctx, mode, count, no_framework):
124
155
  ensure_index()
125
156
 
126
157
  with open_db(readonly=True) as conn:
158
+ # Pull more rows than ``count`` when filtering, so the displayed
159
+ # top-N still has ``count`` entries after exclusions. 5x is a
160
+ # comfortable safety factor for typical tooling shares.
161
+ fetch_limit = count * 5 if not include_tooling else count
127
162
  if mode == "symbol":
128
163
  rows = conn.execute(
129
164
  """
@@ -138,9 +173,13 @@ def fan(ctx, mode, count, no_framework):
138
173
  ORDER BY total DESC
139
174
  LIMIT ?
140
175
  """,
141
- (count,),
176
+ (fetch_limit,),
142
177
  ).fetchall()
143
178
 
179
+ if not include_tooling:
180
+ rows = _filter_tooling_rows(rows)
181
+ rows = rows[:count]
182
+
144
183
  if no_framework:
145
184
  rows = [r for r in rows if r["name"] not in _FRAMEWORK_NAMES]
146
185