roam-code 12.31__tar.gz → 12.33__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 (655) hide show
  1. {roam_code-12.31 → roam_code-12.33}/PKG-INFO +1 -1
  2. {roam_code-12.31 → roam_code-12.33}/pyproject.toml +1 -1
  3. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/detectors.py +198 -0
  4. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/tasks.py +69 -0
  5. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_debt.py +8 -1
  6. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_describe.py +0 -1
  7. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_math.py +38 -1
  8. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_n1.py +1 -5
  9. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orphan_routes.py +10 -7
  10. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_comment_render.py +11 -0
  11. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/finding_suppress.py +52 -2
  12. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/resolve.py +7 -5
  13. {roam_code-12.31 → roam_code-12.33}/src/roam/competitor_site_data.py +2 -2
  14. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/clone_detect.py +3 -13
  15. {roam_code-12.31 → roam_code-12.33}/src/roam/index/complexity.py +0 -7
  16. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/foxpro_lang.py +0 -2
  17. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/hcl_lang.py +6 -4
  18. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp-server-card.json +1 -1
  19. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/seeds.py +0 -2
  20. {roam_code-12.31 → roam_code-12.33}/src/roam/search/tfidf.py +0 -1
  21. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/PKG-INFO +1 -1
  22. {roam_code-12.31 → roam_code-12.33}/tests/test_math.py +79 -2
  23. {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_server.py +16 -5
  24. {roam_code-12.31 → roam_code-12.33}/LICENSE +0 -0
  25. {roam_code-12.31 → roam_code-12.33}/README.md +0 -0
  26. {roam_code-12.31 → roam_code-12.33}/setup.cfg +0 -0
  27. {roam_code-12.31 → roam_code-12.33}/src/roam/__init__.py +0 -0
  28. {roam_code-12.31 → roam_code-12.33}/src/roam/__main__.py +0 -0
  29. {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/__init__.py +0 -0
  30. {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/effects.py +0 -0
  31. {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/taint.py +0 -0
  32. {roam_code-12.31 → roam_code-12.33}/src/roam/api.py +0 -0
  33. {roam_code-12.31 → roam_code-12.33}/src/roam/ask/__init__.py +0 -0
  34. {roam_code-12.31 → roam_code-12.33}/src/roam/ask/classifier.py +0 -0
  35. {roam_code-12.31 → roam_code-12.33}/src/roam/ask/recipes.py +0 -0
  36. {roam_code-12.31 → roam_code-12.33}/src/roam/ask/runner.py +0 -0
  37. {roam_code-12.31 → roam_code-12.33}/src/roam/ask/workflow.py +0 -0
  38. {roam_code-12.31 → roam_code-12.33}/src/roam/attest/__init__.py +0 -0
  39. {roam_code-12.31 → roam_code-12.33}/src/roam/attest/cga.py +0 -0
  40. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/__init__.py +0 -0
  41. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/base.py +0 -0
  42. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_config.py +0 -0
  43. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_django.py +0 -0
  44. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_protobuf.py +0 -0
  45. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_rest_api.py +0 -0
  46. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_salesforce.py +0 -0
  47. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_template.py +0 -0
  48. {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/registry.py +0 -0
  49. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/__init__.py +0 -0
  50. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/fixes.py +0 -0
  51. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/python_idioms.py +0 -0
  52. {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/smells.py +0 -0
  53. {roam_code-12.31 → roam_code-12.33}/src/roam/cli.py +0 -0
  54. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/__init__.py +0 -0
  55. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/audit_trail_helpers.py +0 -0
  56. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/changed_files.py +0 -0
  57. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_adrs.py +0 -0
  58. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_adversarial.py +0 -0
  59. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_affected.py +0 -0
  60. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_affected_tests.py +0 -0
  61. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_context.py +0 -0
  62. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_export.py +0 -0
  63. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_plan.py +0 -0
  64. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ai_ratio.py +0 -0
  65. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ai_readiness.py +0 -0
  66. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_alerts.py +0 -0
  67. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_annotate.py +0 -0
  68. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api.py +0 -0
  69. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api_changes.py +0 -0
  70. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api_drift.py +0 -0
  71. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ask.py +0 -0
  72. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_attest.py +0 -0
  73. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit.py +0 -0
  74. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_conformance.py +0 -0
  75. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_export.py +0 -0
  76. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_verify.py +0 -0
  77. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_auth_gaps.py +0 -0
  78. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_bisect.py +0 -0
  79. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_breaking.py +0 -0
  80. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_budget.py +0 -0
  81. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_bus_factor.py +0 -0
  82. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_capsule.py +0 -0
  83. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_cga.py +0 -0
  84. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_changelog.py +0 -0
  85. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_check_rules.py +0 -0
  86. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ci_setup.py +0 -0
  87. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clean.py +0 -0
  88. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clones.py +0 -0
  89. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_closure.py +0 -0
  90. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clusters.py +0 -0
  91. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_codeowners.py +0 -0
  92. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_complexity.py +0 -0
  93. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_config.py +0 -0
  94. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_congestion.py +0 -0
  95. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_context.py +0 -0
  96. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_conventions.py +0 -0
  97. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_coupling.py +0 -0
  98. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_coverage_gaps.py +0 -0
  99. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_critique.py +0 -0
  100. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_cut.py +0 -0
  101. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dark_matter.py +0 -0
  102. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dashboard.py +0 -0
  103. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dead.py +0 -0
  104. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_deps.py +0 -0
  105. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dev_profile.py +0 -0
  106. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_diagnose.py +0 -0
  107. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_diff.py +0 -0
  108. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_disambiguate.py +0 -0
  109. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_doc_staleness.py +0 -0
  110. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_docs_coverage.py +0 -0
  111. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_doctor.py +0 -0
  112. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dogfood.py +0 -0
  113. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_drift.py +0 -0
  114. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_duplicates.py +0 -0
  115. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_effects.py +0 -0
  116. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_endpoints.py +0 -0
  117. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_entry_points.py +0 -0
  118. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_eval_retrieve.py +0 -0
  119. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_exit_codes.py +0 -0
  120. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fan.py +0 -0
  121. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_file.py +0 -0
  122. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fingerprint.py +0 -0
  123. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fitness.py +0 -0
  124. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_flag_dead.py +0 -0
  125. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fleet.py +0 -0
  126. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fn_coupling.py +0 -0
  127. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_forecast.py +0 -0
  128. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_graph_export.py +0 -0
  129. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_graph_stats.py +0 -0
  130. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_grep.py +0 -0
  131. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_guard.py +0 -0
  132. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_health.py +0 -0
  133. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_help_search.py +0 -0
  134. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hooks.py +0 -0
  135. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hotspots.py +0 -0
  136. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hover.py +0 -0
  137. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_impact.py +0 -0
  138. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index.py +0 -0
  139. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index_bundle.py +0 -0
  140. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index_stats.py +0 -0
  141. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ingest_trace.py +0 -0
  142. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_init.py +0 -0
  143. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_intent.py +0 -0
  144. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_invariants.py +0 -0
  145. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_layers.py +0 -0
  146. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_map.py +0 -0
  147. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mcp_setup.py +0 -0
  148. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mcp_status.py +0 -0
  149. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_metrics.py +0 -0
  150. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_metrics_push.py +0 -0
  151. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_migration_safety.py +0 -0
  152. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_minimap.py +0 -0
  153. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_missing_index.py +0 -0
  154. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_module.py +0 -0
  155. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mutate.py +0 -0
  156. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_oracle.py +0 -0
  157. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orchestrate.py +0 -0
  158. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orphan_imports.py +0 -0
  159. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_over_fetch.py +0 -0
  160. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_owner.py +0 -0
  161. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_partition.py +0 -0
  162. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_path_coverage.py +0 -0
  163. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_patterns.py +0 -0
  164. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plan.py +0 -0
  165. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plan_refactor.py +0 -0
  166. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plugins.py +0 -0
  167. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_analyze.py +0 -0
  168. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_diff.py +0 -0
  169. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_prep.py +0 -0
  170. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_risk.py +0 -0
  171. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pre_commit.py +0 -0
  172. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_preflight.py +0 -0
  173. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_py_modern.py +0 -0
  174. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_py_types.py +0 -0
  175. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pytest_fixtures.py +0 -0
  176. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_recipes.py +0 -0
  177. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_recommend.py +0 -0
  178. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_relate.py +0 -0
  179. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_report.py +0 -0
  180. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_reset.py +0 -0
  181. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_retrieve.py +0 -0
  182. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_risk.py +0 -0
  183. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_rules.py +0 -0
  184. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_rules_validate.py +0 -0
  185. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_safe_delete.py +0 -0
  186. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_safe_zones.py +0 -0
  187. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_sbom.py +0 -0
  188. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_schema.py +0 -0
  189. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_search.py +0 -0
  190. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_search_semantic.py +0 -0
  191. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_secrets.py +0 -0
  192. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_semantic_diff.py +0 -0
  193. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_simulate.py +0 -0
  194. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_simulate_departure.py +0 -0
  195. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_sketch.py +0 -0
  196. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_smells.py +0 -0
  197. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_spectral.py +0 -0
  198. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_split.py +0 -0
  199. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_stats.py +0 -0
  200. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
  201. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
  202. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_supply_chain.py +0 -0
  203. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suppress.py +0 -0
  204. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_symbol.py +0 -0
  205. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_syntax_check.py +0 -0
  206. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_taint.py +0 -0
  207. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_telemetry.py +0 -0
  208. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_gaps.py +0 -0
  209. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_impact.py +0 -0
  210. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_pyramid.py +0 -0
  211. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_scaffold.py +0 -0
  212. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_testmap.py +0 -0
  213. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_timeline.py +0 -0
  214. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_tour.py +0 -0
  215. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_trace.py +0 -0
  216. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_trends.py +0 -0
  217. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_triage.py +0 -0
  218. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_understand.py +0 -0
  219. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_uses.py +0 -0
  220. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_verify.py +0 -0
  221. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_verify_imports.py +0 -0
  222. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_version.py +0 -0
  223. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vibe_check.py +0 -0
  224. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_visualize.py +0 -0
  225. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vuln_map.py +0 -0
  226. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vuln_reach.py +0 -0
  227. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vulns.py +0 -0
  228. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_watch.py +0 -0
  229. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_weather.py +0 -0
  230. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_why.py +0 -0
  231. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_why_fail.py +0 -0
  232. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_workflow.py +0 -0
  233. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ws.py +0 -0
  234. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_xlang.py +0 -0
  235. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/codeowners_helpers.py +0 -0
  236. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/context_helpers.py +0 -0
  237. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/gate_presets.py +0 -0
  238. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/git_helpers.py +0 -0
  239. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/graph_helpers.py +0 -0
  240. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/metrics_history.py +0 -0
  241. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/next_steps.py +0 -0
  242. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/__init__.py +0 -0
  243. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/audit_trail.py +0 -0
  244. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/cache.py +0 -0
  245. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/rules.py +0 -0
  246. {roam_code-12.31 → roam_code-12.33}/src/roam/commands/suppression.py +0 -0
  247. {roam_code-12.31 → roam_code-12.33}/src/roam/config.py +0 -0
  248. {roam_code-12.31 → roam_code-12.33}/src/roam/coverage_reports.py +0 -0
  249. {roam_code-12.31 → roam_code-12.33}/src/roam/critique/__init__.py +0 -0
  250. {roam_code-12.31 → roam_code-12.33}/src/roam/critique/aggregator.py +0 -0
  251. {roam_code-12.31 → roam_code-12.33}/src/roam/critique/checks.py +0 -0
  252. {roam_code-12.31 → roam_code-12.33}/src/roam/db/__init__.py +0 -0
  253. {roam_code-12.31 → roam_code-12.33}/src/roam/db/connection.py +0 -0
  254. {roam_code-12.31 → roam_code-12.33}/src/roam/db/queries.py +0 -0
  255. {roam_code-12.31 → roam_code-12.33}/src/roam/db/schema.py +0 -0
  256. {roam_code-12.31 → roam_code-12.33}/src/roam/eval/__init__.py +0 -0
  257. {roam_code-12.31 → roam_code-12.33}/src/roam/eval/harness.py +0 -0
  258. {roam_code-12.31 → roam_code-12.33}/src/roam/exit_codes.py +0 -0
  259. {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/__init__.py +0 -0
  260. {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/adapters.py +0 -0
  261. {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/manifest.py +0 -0
  262. {roam_code-12.31 → roam_code-12.33}/src/roam/git_utils.py +0 -0
  263. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/__init__.py +0 -0
  264. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/anomaly.py +0 -0
  265. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/builder.py +0 -0
  266. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/clusters.py +0 -0
  267. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/cycles.py +0 -0
  268. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/dark_matter.py +0 -0
  269. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/diff.py +0 -0
  270. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/fingerprint.py +0 -0
  271. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/layers.py +0 -0
  272. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/pagerank.py +0 -0
  273. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/partition.py +0 -0
  274. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/pathfinding.py +0 -0
  275. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/propagation.py +0 -0
  276. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/simulate.py +0 -0
  277. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/spectral.py +0 -0
  278. {roam_code-12.31 → roam_code-12.33}/src/roam/graph/stats.py +0 -0
  279. {roam_code-12.31 → roam_code-12.33}/src/roam/index/__init__.py +0 -0
  280. {roam_code-12.31 → roam_code-12.33}/src/roam/index/discovery.py +0 -0
  281. {roam_code-12.31 → roam_code-12.33}/src/roam/index/django_post.py +0 -0
  282. {roam_code-12.31 → roam_code-12.33}/src/roam/index/file_roles.py +0 -0
  283. {roam_code-12.31 → roam_code-12.33}/src/roam/index/git_stats.py +0 -0
  284. {roam_code-12.31 → roam_code-12.33}/src/roam/index/gitignore.py +0 -0
  285. {roam_code-12.31 → roam_code-12.33}/src/roam/index/incremental.py +0 -0
  286. {roam_code-12.31 → roam_code-12.33}/src/roam/index/indexer.py +0 -0
  287. {roam_code-12.31 → roam_code-12.33}/src/roam/index/parser.py +0 -0
  288. {roam_code-12.31 → roam_code-12.33}/src/roam/index/pytest_fixtures.py +0 -0
  289. {roam_code-12.31 → roam_code-12.33}/src/roam/index/registry_dispatch.py +0 -0
  290. {roam_code-12.31 → roam_code-12.33}/src/roam/index/relations.py +0 -0
  291. {roam_code-12.31 → roam_code-12.33}/src/roam/index/symbols.py +0 -0
  292. {roam_code-12.31 → roam_code-12.33}/src/roam/index/test_conventions.py +0 -0
  293. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/__init__.py +0 -0
  294. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/apex_lang.py +0 -0
  295. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/aura_lang.py +0 -0
  296. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/base.py +0 -0
  297. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/c_lang.py +0 -0
  298. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/csharp_lang.py +0 -0
  299. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/extractor_schema.py +0 -0
  300. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/extractors/kotlin.yaml +0 -0
  301. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/generic_lang.py +0 -0
  302. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/go_lang.py +0 -0
  303. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/java_lang.py +0 -0
  304. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/javascript_lang.py +0 -0
  305. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/kotlin_lang.py +0 -0
  306. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/php_lang.py +0 -0
  307. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/python_lang.py +0 -0
  308. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/query_engine.py +0 -0
  309. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/registry.py +0 -0
  310. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/ruby_lang.py +0 -0
  311. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/rust_lang.py +0 -0
  312. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/scala_lang.py +0 -0
  313. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/sfxml_lang.py +0 -0
  314. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/sql_lang.py +0 -0
  315. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/swift_lang.py +0 -0
  316. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/typescript_lang.py +0 -0
  317. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/visualforce_lang.py +0 -0
  318. {roam_code-12.31 → roam_code-12.33}/src/roam/languages/yaml_lang.py +0 -0
  319. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/__init__.py +0 -0
  320. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/completions.py +0 -0
  321. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/concurrency.py +0 -0
  322. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/progress.py +0 -0
  323. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/sampling.py +0 -0
  324. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/session.py +0 -0
  325. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/watcher.py +0 -0
  326. {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_server.py +0 -0
  327. {roam_code-12.31 → roam_code-12.33}/src/roam/observability.py +0 -0
  328. {roam_code-12.31 → roam_code-12.33}/src/roam/output/__init__.py +0 -0
  329. {roam_code-12.31 → roam_code-12.33}/src/roam/output/confidence.py +0 -0
  330. {roam_code-12.31 → roam_code-12.33}/src/roam/output/errors.py +0 -0
  331. {roam_code-12.31 → roam_code-12.33}/src/roam/output/file_role_hints.py +0 -0
  332. {roam_code-12.31 → roam_code-12.33}/src/roam/output/formatter.py +0 -0
  333. {roam_code-12.31 → roam_code-12.33}/src/roam/output/framework_filter.py +0 -0
  334. {roam_code-12.31 → roam_code-12.33}/src/roam/output/mermaid.py +0 -0
  335. {roam_code-12.31 → roam_code-12.33}/src/roam/output/project_shape.py +0 -0
  336. {roam_code-12.31 → roam_code-12.33}/src/roam/output/sarif.py +0 -0
  337. {roam_code-12.31 → roam_code-12.33}/src/roam/output/schema_registry.py +0 -0
  338. {roam_code-12.31 → roam_code-12.33}/src/roam/plugins.py +0 -0
  339. {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/__init__.py +0 -0
  340. {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/codegen.py +0 -0
  341. {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/transforms.py +0 -0
  342. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/__init__.py +0 -0
  343. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/learned_ranker.py +0 -0
  344. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/pipeline.py +0 -0
  345. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/rerank.py +0 -0
  346. {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/semantic.py +0 -0
  347. {roam_code-12.31 → roam_code-12.33}/src/roam/rules/__init__.py +0 -0
  348. {roam_code-12.31 → roam_code-12.33}/src/roam/rules/ast_match.py +0 -0
  349. {roam_code-12.31 → roam_code-12.33}/src/roam/rules/builtin.py +0 -0
  350. {roam_code-12.31 → roam_code-12.33}/src/roam/rules/dataflow.py +0 -0
  351. {roam_code-12.31 → roam_code-12.33}/src/roam/rules/engine.py +0 -0
  352. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/__init__.py +0 -0
  353. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/daemon.py +0 -0
  354. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/graph_backend.py +0 -0
  355. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/hotspots.py +0 -0
  356. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/lock_modes.py +0 -0
  357. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/lockmgr.py +0 -0
  358. {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/trace_ingest.py +0 -0
  359. {roam_code-12.31 → roam_code-12.33}/src/roam/search/__init__.py +0 -0
  360. {roam_code-12.31 → roam_code-12.33}/src/roam/search/framework_packs.py +0 -0
  361. {roam_code-12.31 → roam_code-12.33}/src/roam/search/index_embeddings.py +0 -0
  362. {roam_code-12.31 → roam_code-12.33}/src/roam/search/onnx_embeddings.py +0 -0
  363. {roam_code-12.31 → roam_code-12.33}/src/roam/security/__init__.py +0 -0
  364. {roam_code-12.31 → roam_code-12.33}/src/roam/security/aibom_extension.py +0 -0
  365. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_classifier.py +0 -0
  366. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_engine.py +0 -0
  367. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/api_error_leak.yaml +0 -0
  368. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/java_fileupload_path_traversal.yaml +0 -0
  369. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_insecure_jwt_decode.yaml +0 -0
  370. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_localstorage_secrets.yaml +0 -0
  371. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_prototype_pollution.yaml +0 -0
  372. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_ssrf.yaml +0 -0
  373. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_xss.yaml +0 -0
  374. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_basic.yaml +0 -0
  375. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_deserialization.yaml +0 -0
  376. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_path_traversal.yaml +0 -0
  377. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_socketio_remote_source.yaml +0 -0
  378. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_sqli.yaml +0 -0
  379. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_urllib_open_redirect.yaml +0 -0
  380. {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/vue_v_html.yaml +0 -0
  381. {roam_code-12.31 → roam_code-12.33}/src/roam/security/vuln_reach.py +0 -0
  382. {roam_code-12.31 → roam_code-12.33}/src/roam/security/vuln_store.py +0 -0
  383. {roam_code-12.31 → roam_code-12.33}/src/roam/surface_counts.py +0 -0
  384. {roam_code-12.31 → roam_code-12.33}/src/roam/telemetry.py +0 -0
  385. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/__init__.py +0 -0
  386. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/Jenkinsfile +0 -0
  387. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/__init__.py +0 -0
  388. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/agent-review.yml +0 -0
  389. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/azure-pipelines.yml +0 -0
  390. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/bitbucket-pipelines.yml +0 -0
  391. {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/gitlab-ci.yml +0 -0
  392. {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/__init__.py +0 -0
  393. {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/aggregator.py +0 -0
  394. {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/api_scanner.py +0 -0
  395. {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/config.py +0 -0
  396. {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/db.py +0 -0
  397. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/SOURCES.txt +0 -0
  398. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/dependency_links.txt +0 -0
  399. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/entry_points.txt +0 -0
  400. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/requires.txt +0 -0
  401. {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/top_level.txt +0 -0
  402. {roam_code-12.31 → roam_code-12.33}/tests/test_adrs.py +0 -0
  403. {roam_code-12.31 → roam_code-12.33}/tests/test_adversarial.py +0 -0
  404. {roam_code-12.31 → roam_code-12.33}/tests/test_affected.py +0 -0
  405. {roam_code-12.31 → roam_code-12.33}/tests/test_agent_export.py +0 -0
  406. {roam_code-12.31 → roam_code-12.33}/tests/test_agent_mode.py +0 -0
  407. {roam_code-12.31 → roam_code-12.33}/tests/test_agent_plan_context.py +0 -0
  408. {roam_code-12.31 → roam_code-12.33}/tests/test_ai_ratio.py +0 -0
  409. {roam_code-12.31 → roam_code-12.33}/tests/test_ai_readiness.py +0 -0
  410. {roam_code-12.31 → roam_code-12.33}/tests/test_alerts_cmd.py +0 -0
  411. {roam_code-12.31 → roam_code-12.33}/tests/test_annotations.py +0 -0
  412. {roam_code-12.31 → roam_code-12.33}/tests/test_anomaly.py +0 -0
  413. {roam_code-12.31 → roam_code-12.33}/tests/test_api_changes.py +0 -0
  414. {roam_code-12.31 → roam_code-12.33}/tests/test_api_drift.py +0 -0
  415. {roam_code-12.31 → roam_code-12.33}/tests/test_ask.py +0 -0
  416. {roam_code-12.31 → roam_code-12.33}/tests/test_attest.py +0 -0
  417. {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_aggregate.py +0 -0
  418. {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_conformance.py +0 -0
  419. {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_sequence.py +0 -0
  420. {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_verify.py +0 -0
  421. {roam_code-12.31 → roam_code-12.33}/tests/test_auth_gaps.py +0 -0
  422. {roam_code-12.31 → roam_code-12.33}/tests/test_backend_fixes_round2.py +0 -0
  423. {roam_code-12.31 → roam_code-12.33}/tests/test_backend_fixes_round3.py +0 -0
  424. {roam_code-12.31 → roam_code-12.33}/tests/test_basic.py +0 -0
  425. {roam_code-12.31 → roam_code-12.33}/tests/test_batch_mcp.py +0 -0
  426. {roam_code-12.31 → roam_code-12.33}/tests/test_bisect.py +0 -0
  427. {roam_code-12.31 → roam_code-12.33}/tests/test_bridge_django.py +0 -0
  428. {roam_code-12.31 → roam_code-12.33}/tests/test_bridges.py +0 -0
  429. {roam_code-12.31 → roam_code-12.33}/tests/test_bridges_extended.py +0 -0
  430. {roam_code-12.31 → roam_code-12.33}/tests/test_budget.py +0 -0
  431. {roam_code-12.31 → roam_code-12.33}/tests/test_budget_flag.py +0 -0
  432. {roam_code-12.31 → roam_code-12.33}/tests/test_budget_phase2.py +0 -0
  433. {roam_code-12.31 → roam_code-12.33}/tests/test_bus_factor.py +0 -0
  434. {roam_code-12.31 → roam_code-12.33}/tests/test_capsule.py +0 -0
  435. {roam_code-12.31 → roam_code-12.33}/tests/test_cga.py +0 -0
  436. {roam_code-12.31 → roam_code-12.33}/tests/test_check_rules.py +0 -0
  437. {roam_code-12.31 → roam_code-12.33}/tests/test_ci_gate_eval.py +0 -0
  438. {roam_code-12.31 → roam_code-12.33}/tests/test_ci_sarif_guard.py +0 -0
  439. {roam_code-12.31 → roam_code-12.33}/tests/test_ci_setup.py +0 -0
  440. {roam_code-12.31 → roam_code-12.33}/tests/test_clones.py +0 -0
  441. {roam_code-12.31 → roam_code-12.33}/tests/test_closure.py +0 -0
  442. {roam_code-12.31 → roam_code-12.33}/tests/test_codeowners.py +0 -0
  443. {roam_code-12.31 → roam_code-12.33}/tests/test_commands_architecture.py +0 -0
  444. {roam_code-12.31 → roam_code-12.33}/tests/test_commands_exploration.py +0 -0
  445. {roam_code-12.31 → roam_code-12.33}/tests/test_commands_health.py +0 -0
  446. {roam_code-12.31 → roam_code-12.33}/tests/test_commands_refactoring.py +0 -0
  447. {roam_code-12.31 → roam_code-12.33}/tests/test_commands_workflow.py +0 -0
  448. {roam_code-12.31 → roam_code-12.33}/tests/test_competitor_site_data.py +0 -0
  449. {roam_code-12.31 → roam_code-12.33}/tests/test_comprehensive.py +0 -0
  450. {roam_code-12.31 → roam_code-12.33}/tests/test_config.py +0 -0
  451. {roam_code-12.31 → roam_code-12.33}/tests/test_congestion.py +0 -0
  452. {roam_code-12.31 → roam_code-12.33}/tests/test_context_propagation.py +0 -0
  453. {roam_code-12.31 → roam_code-12.33}/tests/test_conventions_cmd.py +0 -0
  454. {roam_code-12.31 → roam_code-12.33}/tests/test_coverage_gaps_cmd.py +0 -0
  455. {roam_code-12.31 → roam_code-12.33}/tests/test_coverage_ingestion.py +0 -0
  456. {roam_code-12.31 → roam_code-12.33}/tests/test_critique.py +0 -0
  457. {roam_code-12.31 → roam_code-12.33}/tests/test_cut.py +0 -0
  458. {roam_code-12.31 → roam_code-12.33}/tests/test_dark_matter.py +0 -0
  459. {roam_code-12.31 → roam_code-12.33}/tests/test_dark_matter_helpers.py +0 -0
  460. {roam_code-12.31 → roam_code-12.33}/tests/test_dashboard.py +0 -0
  461. {roam_code-12.31 → roam_code-12.33}/tests/test_dataflow_dead.py +0 -0
  462. {roam_code-12.31 → roam_code-12.33}/tests/test_dead_aging.py +0 -0
  463. {roam_code-12.31 → roam_code-12.33}/tests/test_defer_loading.py +0 -0
  464. {roam_code-12.31 → roam_code-12.33}/tests/test_demo_gif_asset.py +0 -0
  465. {roam_code-12.31 → roam_code-12.33}/tests/test_describe.py +0 -0
  466. {roam_code-12.31 → roam_code-12.33}/tests/test_detail_flag_hints.py +0 -0
  467. {roam_code-12.31 → roam_code-12.33}/tests/test_detector_precision.py +0 -0
  468. {roam_code-12.31 → roam_code-12.33}/tests/test_deterministic_output.py +0 -0
  469. {roam_code-12.31 → roam_code-12.33}/tests/test_dev_profile.py +0 -0
  470. {roam_code-12.31 → roam_code-12.33}/tests/test_difficulty_scoring.py +0 -0
  471. {roam_code-12.31 → roam_code-12.33}/tests/test_doc_consistency.py +0 -0
  472. {roam_code-12.31 → roam_code-12.33}/tests/test_doc_staleness.py +0 -0
  473. {roam_code-12.31 → roam_code-12.33}/tests/test_docker_assets.py +0 -0
  474. {roam_code-12.31 → roam_code-12.33}/tests/test_docs_coverage.py +0 -0
  475. {roam_code-12.31 → roam_code-12.33}/tests/test_docs_site_quality.py +0 -0
  476. {roam_code-12.31 → roam_code-12.33}/tests/test_doctor.py +0 -0
  477. {roam_code-12.31 → roam_code-12.33}/tests/test_dogfood.py +0 -0
  478. {roam_code-12.31 → roam_code-12.33}/tests/test_drift.py +0 -0
  479. {roam_code-12.31 → roam_code-12.33}/tests/test_drift_by_team.py +0 -0
  480. {roam_code-12.31 → roam_code-12.33}/tests/test_duplicates.py +0 -0
  481. {roam_code-12.31 → roam_code-12.33}/tests/test_effects.py +0 -0
  482. {roam_code-12.31 → roam_code-12.33}/tests/test_effects_propagation.py +0 -0
  483. {roam_code-12.31 → roam_code-12.33}/tests/test_endpoints.py +0 -0
  484. {roam_code-12.31 → roam_code-12.33}/tests/test_entry_points_cmd.py +0 -0
  485. {roam_code-12.31 → roam_code-12.33}/tests/test_eval_retrieve.py +0 -0
  486. {roam_code-12.31 → roam_code-12.33}/tests/test_except_pass_narrow.py +0 -0
  487. {roam_code-12.31 → roam_code-12.33}/tests/test_exclude_patterns.py +0 -0
  488. {roam_code-12.31 → roam_code-12.33}/tests/test_exit_codes.py +0 -0
  489. {roam_code-12.31 → roam_code-12.33}/tests/test_extractor_grammar_drift.py +0 -0
  490. {roam_code-12.31 → roam_code-12.33}/tests/test_fallback_contracts.py +0 -0
  491. {roam_code-12.31 → roam_code-12.33}/tests/test_file_roles.py +0 -0
  492. {roam_code-12.31 → roam_code-12.33}/tests/test_finding_suppress.py +0 -0
  493. {roam_code-12.31 → roam_code-12.33}/tests/test_fingerprint.py +0 -0
  494. {roam_code-12.31 → roam_code-12.33}/tests/test_fixes.py +0 -0
  495. {roam_code-12.31 → roam_code-12.33}/tests/test_flag_dead.py +0 -0
  496. {roam_code-12.31 → roam_code-12.33}/tests/test_fleet.py +0 -0
  497. {roam_code-12.31 → roam_code-12.33}/tests/test_fn_coupling.py +0 -0
  498. {roam_code-12.31 → roam_code-12.33}/tests/test_forecast.py +0 -0
  499. {roam_code-12.31 → roam_code-12.33}/tests/test_formatters.py +0 -0
  500. {roam_code-12.31 → roam_code-12.33}/tests/test_foxpro.py +0 -0
  501. {roam_code-12.31 → roam_code-12.33}/tests/test_framework_detection.py +0 -0
  502. {roam_code-12.31 → roam_code-12.33}/tests/test_gate_presets.py +0 -0
  503. {roam_code-12.31 → roam_code-12.33}/tests/test_git_helpers.py +0 -0
  504. {roam_code-12.31 → roam_code-12.33}/tests/test_git_utils.py +0 -0
  505. {roam_code-12.31 → roam_code-12.33}/tests/test_guard.py +0 -0
  506. {roam_code-12.31 → roam_code-12.33}/tests/test_health_gate.py +0 -0
  507. {roam_code-12.31 → roam_code-12.33}/tests/test_hooks.py +0 -0
  508. {roam_code-12.31 → roam_code-12.33}/tests/test_hotspots.py +0 -0
  509. {roam_code-12.31 → roam_code-12.33}/tests/test_hover.py +0 -0
  510. {roam_code-12.31 → roam_code-12.33}/tests/test_index.py +0 -0
  511. {roam_code-12.31 → roam_code-12.33}/tests/test_index_bundle.py +0 -0
  512. {roam_code-12.31 → roam_code-12.33}/tests/test_init_cmd.py +0 -0
  513. {roam_code-12.31 → roam_code-12.33}/tests/test_install_check.py +0 -0
  514. {roam_code-12.31 → roam_code-12.33}/tests/test_intent.py +0 -0
  515. {roam_code-12.31 → roam_code-12.33}/tests/test_invariants.py +0 -0
  516. {roam_code-12.31 → roam_code-12.33}/tests/test_json_contracts.py +0 -0
  517. {roam_code-12.31 → roam_code-12.33}/tests/test_json_error_envelope.py +0 -0
  518. {roam_code-12.31 → roam_code-12.33}/tests/test_kotlin_swift_extractors.py +0 -0
  519. {roam_code-12.31 → roam_code-12.33}/tests/test_language_corpus.py +0 -0
  520. {roam_code-12.31 → roam_code-12.33}/tests/test_languages.py +0 -0
  521. {roam_code-12.31 → roam_code-12.33}/tests/test_laravel_fp_fixes.py +0 -0
  522. {roam_code-12.31 → roam_code-12.33}/tests/test_library_api.py +0 -0
  523. {roam_code-12.31 → roam_code-12.33}/tests/test_math_fp_fixes.py +0 -0
  524. {roam_code-12.31 → roam_code-12.33}/tests/test_math_tips.py +0 -0
  525. {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_extras.py +0 -0
  526. {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_setup.py +0 -0
  527. {roam_code-12.31 → roam_code-12.33}/tests/test_mermaid.py +0 -0
  528. {roam_code-12.31 → roam_code-12.33}/tests/test_metrics_cmd.py +0 -0
  529. {roam_code-12.31 → roam_code-12.33}/tests/test_metrics_push.py +0 -0
  530. {roam_code-12.31 → roam_code-12.33}/tests/test_migration_safety.py +0 -0
  531. {roam_code-12.31 → roam_code-12.33}/tests/test_minimap.py +0 -0
  532. {roam_code-12.31 → roam_code-12.33}/tests/test_missing_index.py +0 -0
  533. {roam_code-12.31 → roam_code-12.33}/tests/test_mutate.py +0 -0
  534. {roam_code-12.31 → roam_code-12.33}/tests/test_n1.py +0 -0
  535. {roam_code-12.31 → roam_code-12.33}/tests/test_next_steps.py +0 -0
  536. {roam_code-12.31 → roam_code-12.33}/tests/test_onboard.py +0 -0
  537. {roam_code-12.31 → roam_code-12.33}/tests/test_oracle.py +0 -0
  538. {roam_code-12.31 → roam_code-12.33}/tests/test_orchestrate.py +0 -0
  539. {roam_code-12.31 → roam_code-12.33}/tests/test_orphan_routes.py +0 -0
  540. {roam_code-12.31 → roam_code-12.33}/tests/test_oss_bench_harness.py +0 -0
  541. {roam_code-12.31 → roam_code-12.33}/tests/test_over_fetch.py +0 -0
  542. {roam_code-12.31 → roam_code-12.33}/tests/test_pagerank_truncation.py +0 -0
  543. {roam_code-12.31 → roam_code-12.33}/tests/test_partition.py +0 -0
  544. {roam_code-12.31 → roam_code-12.33}/tests/test_path_coverage.py +0 -0
  545. {roam_code-12.31 → roam_code-12.33}/tests/test_patterns_cmd.py +0 -0
  546. {roam_code-12.31 → roam_code-12.33}/tests/test_performance.py +0 -0
  547. {roam_code-12.31 → roam_code-12.33}/tests/test_personalized_pagerank.py +0 -0
  548. {roam_code-12.31 → roam_code-12.33}/tests/test_plan.py +0 -0
  549. {roam_code-12.31 → roam_code-12.33}/tests/test_plugin_discovery.py +0 -0
  550. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze.py +0 -0
  551. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_cache.py +0 -0
  552. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_edge_cases.py +0 -0
  553. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_helpers.py +0 -0
  554. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_v2_signals.py +0 -0
  555. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_comment_render.py +0 -0
  556. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_comment_script.py +0 -0
  557. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_diff.py +0 -0
  558. {roam_code-12.31 → roam_code-12.33}/tests/test_pr_risk_author.py +0 -0
  559. {roam_code-12.31 → roam_code-12.33}/tests/test_progress.py +0 -0
  560. {roam_code-12.31 → roam_code-12.33}/tests/test_progressive_disclosure.py +0 -0
  561. {roam_code-12.31 → roam_code-12.33}/tests/test_properties.py +0 -0
  562. {roam_code-12.31 → roam_code-12.33}/tests/test_pytest_fixtures.py +0 -0
  563. {roam_code-12.31 → roam_code-12.33}/tests/test_python_extractor_v2.py +0 -0
  564. {roam_code-12.31 → roam_code-12.33}/tests/test_python_idioms_e2e.py +0 -0
  565. {roam_code-12.31 → roam_code-12.33}/tests/test_python_pivot.py +0 -0
  566. {roam_code-12.31 → roam_code-12.33}/tests/test_readme_surface_consistency.py +0 -0
  567. {roam_code-12.31 → roam_code-12.33}/tests/test_realworld_feedback.py +0 -0
  568. {roam_code-12.31 → roam_code-12.33}/tests/test_refactoring_intelligence.py +0 -0
  569. {roam_code-12.31 → roam_code-12.33}/tests/test_registry_dispatch.py +0 -0
  570. {roam_code-12.31 → roam_code-12.33}/tests/test_regression_fp_corpus.py +0 -0
  571. {roam_code-12.31 → roam_code-12.33}/tests/test_relate.py +0 -0
  572. {roam_code-12.31 → roam_code-12.33}/tests/test_report.py +0 -0
  573. {roam_code-12.31 → roam_code-12.33}/tests/test_reset_clean.py +0 -0
  574. {roam_code-12.31 → roam_code-12.33}/tests/test_resolve.py +0 -0
  575. {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve.py +0 -0
  576. {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve_cross_repo.py +0 -0
  577. {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve_seeds.py +0 -0
  578. {roam_code-12.31 → roam_code-12.33}/tests/test_risk.py +0 -0
  579. {roam_code-12.31 → roam_code-12.33}/tests/test_ruby.py +0 -0
  580. {roam_code-12.31 → roam_code-12.33}/tests/test_rule_profiles.py +0 -0
  581. {roam_code-12.31 → roam_code-12.33}/tests/test_rules.py +0 -0
  582. {roam_code-12.31 → roam_code-12.33}/tests/test_rules_ast_match.py +0 -0
  583. {roam_code-12.31 → roam_code-12.33}/tests/test_rules_community_pack.py +0 -0
  584. {roam_code-12.31 → roam_code-12.33}/tests/test_rules_dataflow.py +0 -0
  585. {roam_code-12.31 → roam_code-12.33}/tests/test_rules_symbol_requirements.py +0 -0
  586. {roam_code-12.31 → roam_code-12.33}/tests/test_rules_validate.py +0 -0
  587. {roam_code-12.31 → roam_code-12.33}/tests/test_runtime.py +0 -0
  588. {roam_code-12.31 → roam_code-12.33}/tests/test_runtime_score.py +0 -0
  589. {roam_code-12.31 → roam_code-12.33}/tests/test_salesforce.py +0 -0
  590. {roam_code-12.31 → roam_code-12.33}/tests/test_sarif_flag.py +0 -0
  591. {roam_code-12.31 → roam_code-12.33}/tests/test_sbom.py +0 -0
  592. {roam_code-12.31 → roam_code-12.33}/tests/test_scala.py +0 -0
  593. {roam_code-12.31 → roam_code-12.33}/tests/test_schema_versioning.py +0 -0
  594. {roam_code-12.31 → roam_code-12.33}/tests/test_search_explain.py +0 -0
  595. {roam_code-12.31 → roam_code-12.33}/tests/test_secrets.py +0 -0
  596. {roam_code-12.31 → roam_code-12.33}/tests/test_secrets_v2.py +0 -0
  597. {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_diff.py +0 -0
  598. {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_onnx.py +0 -0
  599. {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_search.py +0 -0
  600. {roam_code-12.31 → roam_code-12.33}/tests/test_simulate.py +0 -0
  601. {roam_code-12.31 → roam_code-12.33}/tests/test_simulate_departure.py +0 -0
  602. {roam_code-12.31 → roam_code-12.33}/tests/test_sketch.py +0 -0
  603. {roam_code-12.31 → roam_code-12.33}/tests/test_smells.py +0 -0
  604. {roam_code-12.31 → roam_code-12.33}/tests/test_smoke.py +0 -0
  605. {roam_code-12.31 → roam_code-12.33}/tests/test_sna_metrics.py +0 -0
  606. {roam_code-12.31 → roam_code-12.33}/tests/test_spectral.py +0 -0
  607. {roam_code-12.31 → roam_code-12.33}/tests/test_split_cmd.py +0 -0
  608. {roam_code-12.31 → roam_code-12.33}/tests/test_sql.py +0 -0
  609. {roam_code-12.31 → roam_code-12.33}/tests/test_suggest_reviewers.py +0 -0
  610. {roam_code-12.31 → roam_code-12.33}/tests/test_supply_chain.py +0 -0
  611. {roam_code-12.31 → roam_code-12.33}/tests/test_surface_counts.py +0 -0
  612. {roam_code-12.31 → roam_code-12.33}/tests/test_syntax_check.py +0 -0
  613. {roam_code-12.31 → roam_code-12.33}/tests/test_taint.py +0 -0
  614. {roam_code-12.31 → roam_code-12.33}/tests/test_taint_analysis.py +0 -0
  615. {roam_code-12.31 → roam_code-12.33}/tests/test_taint_classifier.py +0 -0
  616. {roam_code-12.31 → roam_code-12.33}/tests/test_taint_intraprocedural.py +0 -0
  617. {roam_code-12.31 → roam_code-12.33}/tests/test_test_conventions.py +0 -0
  618. {roam_code-12.31 → roam_code-12.33}/tests/test_test_gaps.py +0 -0
  619. {roam_code-12.31 → roam_code-12.33}/tests/test_test_scaffold.py +0 -0
  620. {roam_code-12.31 → roam_code-12.33}/tests/test_testmap.py +0 -0
  621. {roam_code-12.31 → roam_code-12.33}/tests/test_top_flag_consistency.py +0 -0
  622. {roam_code-12.31 → roam_code-12.33}/tests/test_tour_cmd.py +0 -0
  623. {roam_code-12.31 → roam_code-12.33}/tests/test_trends.py +0 -0
  624. {roam_code-12.31 → roam_code-12.33}/tests/test_trends_cohort.py +0 -0
  625. {roam_code-12.31 → roam_code-12.33}/tests/test_triage.py +0 -0
  626. {roam_code-12.31 → roam_code-12.33}/tests/test_uses_cmd.py +0 -0
  627. {roam_code-12.31 → roam_code-12.33}/tests/test_v1215_passes.py +0 -0
  628. {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes.py +0 -0
  629. {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes_41_50.py +0 -0
  630. {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes_51_60.py +0 -0
  631. {roam_code-12.31 → roam_code-12.33}/tests/test_v1217_passes_61_80.py +0 -0
  632. {roam_code-12.31 → roam_code-12.33}/tests/test_v1218_passes_81_90.py +0 -0
  633. {roam_code-12.31 → roam_code-12.33}/tests/test_v1219_passes_91_100.py +0 -0
  634. {roam_code-12.31 → roam_code-12.33}/tests/test_v1220_passes_101_110.py +0 -0
  635. {roam_code-12.31 → roam_code-12.33}/tests/test_v1221_query_timeout.py +0 -0
  636. {roam_code-12.31 → roam_code-12.33}/tests/test_v1221_untested_commands.py +0 -0
  637. {roam_code-12.31 → roam_code-12.33}/tests/test_v12_2.py +0 -0
  638. {roam_code-12.31 → roam_code-12.33}/tests/test_v2_edge_cases.py +0 -0
  639. {roam_code-12.31 → roam_code-12.33}/tests/test_v2_integration.py +0 -0
  640. {roam_code-12.31 → roam_code-12.33}/tests/test_v6_features.py +0 -0
  641. {roam_code-12.31 → roam_code-12.33}/tests/test_v71_features.py +0 -0
  642. {roam_code-12.31 → roam_code-12.33}/tests/test_v7_features.py +0 -0
  643. {roam_code-12.31 → roam_code-12.33}/tests/test_v82_features.py +0 -0
  644. {roam_code-12.31 → roam_code-12.33}/tests/test_verify.py +0 -0
  645. {roam_code-12.31 → roam_code-12.33}/tests/test_verify_imports.py +0 -0
  646. {roam_code-12.31 → roam_code-12.33}/tests/test_vibe_check.py +0 -0
  647. {roam_code-12.31 → roam_code-12.33}/tests/test_visualize.py +0 -0
  648. {roam_code-12.31 → roam_code-12.33}/tests/test_vuln.py +0 -0
  649. {roam_code-12.31 → roam_code-12.33}/tests/test_vulns_cmd.py +0 -0
  650. {roam_code-12.31 → roam_code-12.33}/tests/test_watch.py +0 -0
  651. {roam_code-12.31 → roam_code-12.33}/tests/test_why.py +0 -0
  652. {roam_code-12.31 → roam_code-12.33}/tests/test_workspace.py +0 -0
  653. {roam_code-12.31 → roam_code-12.33}/tests/test_ws_resolve_fixes.py +0 -0
  654. {roam_code-12.31 → roam_code-12.33}/tests/test_xlang.py +0 -0
  655. {roam_code-12.31 → roam_code-12.33}/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.31
3
+ Version: 12.33
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "roam-code"
7
- version = "12.31"
7
+ version = "12.33"
8
8
  description = "Instant codebase comprehension for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1723,6 +1723,10 @@ def autodetect_framework_profile() -> str | None:
1723
1723
  tanstack = "@tanstack/vue-query" in deps or "@tanstack/query-core" in deps
1724
1724
  if tanstack and (vue_ver.startswith("^3") or vue_ver.startswith("3") or vue_ver.startswith("~3")):
1725
1725
  return "vue3-tanstack"
1726
+ # Z6 (2026-05-06) — Express/Koa/Fastify don't have framework
1727
+ # profiles yet (they're light frameworks; the I/O patterns are
1728
+ # generic Node fs / http). Return None for now but flag in meta
1729
+ # so future versions can add a profile when one becomes useful.
1726
1730
 
1727
1731
  composer = _read_json(_os.path.join(cwd, "composer.json"))
1728
1732
  if composer:
@@ -2766,6 +2770,197 @@ def detect_chained_collection_walks(conn: sqlite3.Connection) -> list[dict]:
2766
2770
  return results
2767
2771
 
2768
2772
 
2773
+ # Z1 (2026-05-06) — React: `useEffect(() => { ... })` without a dependency
2774
+ # array runs on EVERY render. Almost always a bug — the dev forgot the
2775
+ # second argument. The fix is `useEffect(() => { ... }, [deps])` or
2776
+ # `useEffect(() => { ... }, [])` for mount-only.
2777
+ _RE_USEEFFECT_NO_DEPS = re.compile(
2778
+ r"\buseEffect\s*\(\s*(?:async\s+)?(?:\(\s*\)|function\s*\(\s*\))\s*=>\s*\{[^}]*?\}\s*\)",
2779
+ re.DOTALL,
2780
+ )
2781
+ _RE_USEEFFECT_WITH_DEPS = re.compile(
2782
+ r"\buseEffect\s*\(\s*[^,]+,\s*\[",
2783
+ )
2784
+
2785
+
2786
+ def detect_useeffect_missing_deps(conn: sqlite3.Connection) -> list[dict]:
2787
+ """React: `useEffect(() => {...})` without a dependency array."""
2788
+ try:
2789
+ rows = conn.execute(
2790
+ "SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
2791
+ "s.line_start, s.line_end "
2792
+ "FROM symbols s "
2793
+ "JOIN files f ON s.file_id = f.id "
2794
+ "WHERE s.kind IN ('function', 'method') "
2795
+ "AND f.language IN ('javascript', 'typescript', 'tsx', 'jsx')"
2796
+ ).fetchall()
2797
+ except Exception:
2798
+ return []
2799
+ results = []
2800
+ for r in rows:
2801
+ if _is_test_path(r["file_path"]):
2802
+ continue
2803
+ snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
2804
+ if not snippet or "useEffect" not in snippet:
2805
+ continue
2806
+ # Skip if every useEffect call also has a deps array.
2807
+ no_deps = _RE_USEEFFECT_NO_DEPS.search(snippet)
2808
+ if not no_deps:
2809
+ continue
2810
+ # Verify the SAME call doesn't have a deps array (regex catches the
2811
+ # no-deps shape but a more elaborate body could trick it).
2812
+ # Conservative: only fire when there's NO useEffect-with-deps in body.
2813
+ if _RE_USEEFFECT_WITH_DEPS.search(snippet):
2814
+ # Mixed bag — at least one useEffect has deps, can't reliably
2815
+ # tell which one is the problem without a real parser. Skip.
2816
+ continue
2817
+ line_offset = snippet[: no_deps.start()].count("\n")
2818
+ match_line = (r["line_start"] or 1) + line_offset
2819
+ results.append(
2820
+ _finding(
2821
+ "useeffect-missing-deps",
2822
+ "no-deps-array",
2823
+ r,
2824
+ "useEffect without dependency array — runs on every render",
2825
+ "high",
2826
+ match_line=match_line,
2827
+ snippet=snippet,
2828
+ matched_patterns=["useEffect call", "no second-arg dep array"],
2829
+ )
2830
+ )
2831
+ return results
2832
+
2833
+
2834
+ # Z2 (2026-05-06) — `eval()` / `exec()` / `new Function()` / `setTimeout(string)`
2835
+ # in production source. These are arbitrary code execution sinks if the
2836
+ # input is user-derived. Even when "safe" (literal string), they trip
2837
+ # CSP rules and bundler optimisations. Suppress when test path.
2838
+ _RE_EVAL_CALLS = re.compile(
2839
+ r"\b(?:eval|exec|execfile|compile)\s*\("
2840
+ r"|\bnew\s+Function\s*\("
2841
+ r"|\bsetTimeout\s*\(\s*['\"]"
2842
+ r"|\bsetInterval\s*\(\s*['\"]",
2843
+ )
2844
+
2845
+
2846
+ def detect_dangerous_eval(conn: sqlite3.Connection) -> list[dict]:
2847
+ """Detect `eval`, `exec`, `new Function(...)`, `setTimeout(string)` — code-injection sinks."""
2848
+ try:
2849
+ rows = conn.execute(
2850
+ "SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
2851
+ "f.language AS language, s.line_start, s.line_end "
2852
+ "FROM symbols s "
2853
+ "JOIN files f ON s.file_id = f.id "
2854
+ "WHERE s.kind IN ('function', 'method')"
2855
+ ).fetchall()
2856
+ except Exception:
2857
+ return []
2858
+ results = []
2859
+ for r in rows:
2860
+ if _is_test_path(r["file_path"]):
2861
+ continue
2862
+ # Skip non-source roles when we can tell.
2863
+ path = (r["file_path"] or "").replace("\\", "/").lower()
2864
+ if "/migration" in path or "/script" in path or "/cli" in path:
2865
+ # CLI / migration scripts often legitimately use exec/eval.
2866
+ continue
2867
+ snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
2868
+ if not snippet:
2869
+ continue
2870
+ m = _RE_EVAL_CALLS.search(snippet)
2871
+ if not m:
2872
+ continue
2873
+ # Skip ast.literal_eval (safe), regex.compile (different "compile"
2874
+ # — won't actually match because it ends in `.compile(` with a dot
2875
+ # before, so prefix isn't word-boundary — but be defensive).
2876
+ if "literal_eval" in snippet[max(0, m.start() - 20) : m.end()]:
2877
+ continue
2878
+ if ".compile(" in snippet[max(0, m.start() - 5) : m.end() + 1]:
2879
+ continue
2880
+ line_offset = snippet[: m.start()].count("\n")
2881
+ match_line = (r["line_start"] or 1) + line_offset
2882
+ called = m.group(0).rstrip("(")
2883
+ results.append(
2884
+ _finding(
2885
+ "dangerous-eval",
2886
+ "eval-or-exec",
2887
+ r,
2888
+ f"Dangerous dynamic execution sink ({called}) — code-injection risk if input is user-derived",
2889
+ "high",
2890
+ match_line=match_line,
2891
+ snippet=snippet,
2892
+ matched_patterns=[f"call: {called}", "not in test/migration/script path"],
2893
+ )
2894
+ )
2895
+ return results
2896
+
2897
+
2898
+ # Z5 (2026-05-06) — JS/TS DOM listener leak: `addEventListener` without
2899
+ # a paired `removeEventListener` keeps references alive after the
2900
+ # component unmounts. Detect ONLY when the function looks like a
2901
+ # component lifecycle (useEffect / componentDidMount / connectedCallback /
2902
+ # constructor) and addEventListener appears without remove.
2903
+ _RE_ADD_LISTENER = re.compile(r"\baddEventListener\s*\(")
2904
+ _RE_REMOVE_LISTENER = re.compile(r"\bremoveEventListener\s*\(")
2905
+ _RE_LIFECYCLE = re.compile(
2906
+ r"\b(?:useEffect|componentDidMount|componentWillMount|connectedCallback|constructor)\b",
2907
+ )
2908
+
2909
+
2910
+ def detect_unremoved_event_listener(conn: sqlite3.Connection) -> list[dict]:
2911
+ """JS/TS: `addEventListener` in a lifecycle without paired `removeEventListener`."""
2912
+ try:
2913
+ rows = conn.execute(
2914
+ "SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
2915
+ "s.line_start, s.line_end "
2916
+ "FROM symbols s "
2917
+ "JOIN files f ON s.file_id = f.id "
2918
+ "WHERE s.kind IN ('function', 'method') "
2919
+ "AND f.language IN ('javascript', 'typescript', 'tsx', 'jsx')"
2920
+ ).fetchall()
2921
+ except Exception:
2922
+ return []
2923
+ results = []
2924
+ for r in rows:
2925
+ if _is_test_path(r["file_path"]):
2926
+ continue
2927
+ snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
2928
+ if not snippet:
2929
+ continue
2930
+ if not _RE_ADD_LISTENER.search(snippet):
2931
+ continue
2932
+ # Only fire for lifecycle-ish bodies — outside of components,
2933
+ # listeners are often global and intentionally never removed.
2934
+ if not _RE_LIFECYCLE.search(snippet):
2935
+ continue
2936
+ # Already paired: presence of removeEventListener anywhere in body.
2937
+ if _RE_REMOVE_LISTENER.search(snippet):
2938
+ continue
2939
+ # `useEffect` should also return a cleanup function. Check for one.
2940
+ if "useEffect" in snippet and re.search(r"return\s+(?:\(\s*\)|function)", snippet):
2941
+ continue
2942
+ m = _RE_ADD_LISTENER.search(snippet)
2943
+ line_offset = snippet[: m.start()].count("\n")
2944
+ match_line = (r["line_start"] or 1) + line_offset
2945
+ results.append(
2946
+ _finding(
2947
+ "unremoved-event-listener",
2948
+ "no-cleanup",
2949
+ r,
2950
+ "addEventListener in component lifecycle without removeEventListener — memory leak",
2951
+ "high",
2952
+ match_line=match_line,
2953
+ snippet=snippet,
2954
+ matched_patterns=[
2955
+ "addEventListener call",
2956
+ "lifecycle context (useEffect / componentDidMount / etc.)",
2957
+ "no paired removeEventListener",
2958
+ ],
2959
+ )
2960
+ )
2961
+ return results
2962
+
2963
+
2769
2964
  def detect_loop_lookup(conn: sqlite3.Connection) -> list[dict]:
2770
2965
  """.index(), .indexOf(), .contains(), .includes() called inside a loop.
2771
2966
 
@@ -3736,6 +3931,9 @@ _MATH_DETECTORS = [
3736
3931
  ("spread-accumulator", "spread-rebind", detect_spread_accumulator),
3737
3932
  ("defer-in-loop", "loop-defer", detect_defer_in_loop),
3738
3933
  ("chained-collection-walk", "two-pass-walk", detect_chained_collection_walks),
3934
+ ("useeffect-missing-deps", "no-deps-array", detect_useeffect_missing_deps),
3935
+ ("dangerous-eval", "eval-or-exec", detect_dangerous_eval),
3936
+ ("unremoved-event-listener", "no-cleanup", detect_unremoved_event_listener),
3739
3937
  ("list-prepend", "insert-front", detect_list_prepend),
3740
3938
  ("sort-to-select", "full-sort", detect_sort_to_select),
3741
3939
  ("loop-lookup", "method-scan", detect_loop_lookup),
@@ -400,6 +400,75 @@ CATALOG: dict[str, dict] = {
400
400
  },
401
401
  ],
402
402
  },
403
+ "unremoved-event-listener": {
404
+ "name": "addEventListener without paired removeEventListener (memory leak)",
405
+ "category": "concurrency",
406
+ "kind": "idiom",
407
+ "ways": [
408
+ {
409
+ "id": "with-cleanup",
410
+ "name": "useEffect cleanup / removeEventListener",
411
+ "time": "n/a",
412
+ "space": "n/a",
413
+ "rank": 1,
414
+ "tip": "Return a cleanup function from useEffect: `useEffect(() => { window.addEventListener('x', h); return () => window.removeEventListener('x', h); }, [])`. For class components, pair in componentWillUnmount.",
415
+ },
416
+ {
417
+ "id": "no-cleanup",
418
+ "name": "addEventListener with no cleanup",
419
+ "time": "n/a",
420
+ "space": "n/a",
421
+ "rank": 10,
422
+ "tip": "",
423
+ },
424
+ ],
425
+ },
426
+ "dangerous-eval": {
427
+ "name": "Dynamic execution sink (eval / exec / new Function)",
428
+ "category": "error-handling",
429
+ "kind": "idiom",
430
+ "ways": [
431
+ {
432
+ "id": "narrow-or-remove",
433
+ "name": "Use a parser / template / safer dispatch",
434
+ "time": "n/a",
435
+ "space": "n/a",
436
+ "rank": 1,
437
+ "tip": "Prefer ast.literal_eval, JSON.parse, a real template engine, or a switch/dispatch dict over arbitrary-string execution. Tightens CSP; eliminates injection surface.",
438
+ },
439
+ {
440
+ "id": "eval-or-exec",
441
+ "name": "eval / exec / new Function with dynamic input",
442
+ "time": "n/a",
443
+ "space": "n/a",
444
+ "rank": 10,
445
+ "tip": "",
446
+ },
447
+ ],
448
+ },
449
+ "useeffect-missing-deps": {
450
+ "name": "React useEffect without dependency array",
451
+ "category": "concurrency",
452
+ "kind": "idiom",
453
+ "ways": [
454
+ {
455
+ "id": "with-deps",
456
+ "name": "useEffect with explicit dep array",
457
+ "time": "n/a",
458
+ "space": "n/a",
459
+ "rank": 1,
460
+ "tip": "Add the dependency array as the second argument: `useEffect(() => {...}, [deps])`. Use `[]` for mount-only effects.",
461
+ },
462
+ {
463
+ "id": "no-deps-array",
464
+ "name": "useEffect without deps (runs every render)",
465
+ "time": "n/a",
466
+ "space": "n/a",
467
+ "rank": 10,
468
+ "tip": "",
469
+ },
470
+ ],
471
+ },
403
472
  "chained-collection-walk": {
404
473
  "name": "Chained collection walk (filter+find / map+find / filter+length)",
405
474
  "category": "collections",
@@ -562,10 +562,17 @@ def debt(ctx, limit, by_kind, threshold, roi):
562
562
  _debt_label = (
563
563
  "low debt" if stats["mean_debt"] < 0.1 else "moderate debt" if stats["mean_debt"] < 0.3 else "high debt"
564
564
  )
565
+ # Z14 (2026-05-06) — append top-1 hotspot to the verdict so the
566
+ # one-line summary tells you WHERE to look first, not just IF
567
+ # there's debt.
568
+ top_hint = ""
569
+ if all_items:
570
+ top1 = all_items[0]
571
+ top_hint = f" — top hotspot: {top1['path']} (score={top1['debt_score']})"
565
572
  _debt_verdict = (
566
573
  f"{_debt_label}: {_n_cycles} cycle files, "
567
574
  f"{_n_gods} god components, {_n_hotspots} hotspots "
568
- f"across {stats['total_files']} files"
575
+ f"across {stats['total_files']} files{top_hint}"
569
576
  )
570
577
 
571
578
  roi_summary, roi_by_path = ({}, {})
@@ -353,7 +353,6 @@ _DOMAIN_STOP_WORDS = frozenset(
353
353
  "context",
354
354
  "hook",
355
355
  # DOM events / UI interactions
356
- "click",
357
356
  "focus",
358
357
  "blur",
359
358
  "hover",
@@ -147,6 +147,23 @@ def math_cmd(
147
147
  click.echo(name)
148
148
  return
149
149
 
150
+ # Z7 (2026-05-06) — validate --task against the catalog; on typo, show
151
+ # the closest matches by edit distance instead of running 49 detectors
152
+ # silently to find zero results.
153
+ if task_filter:
154
+ from roam.catalog.tasks import CATALOG
155
+
156
+ if task_filter not in CATALOG:
157
+ import difflib
158
+
159
+ close = difflib.get_close_matches(task_filter, list(CATALOG.keys()), n=3, cutoff=0.4)
160
+ hint = f" Did you mean: {', '.join(close)}?" if close else ""
161
+ click.echo(
162
+ f"NOTE: --task '{task_filter}' is not a known task id."
163
+ f" Run `roam math --json` then look at distinct `task_id` values." + hint,
164
+ err=True,
165
+ )
166
+
150
167
  ensure_index()
151
168
 
152
169
  from roam.catalog.detectors import autodetect_framework_profile, run_detectors
@@ -289,7 +306,18 @@ def math_cmd(
289
306
  if top_n >= max(3, total // 2):
290
307
  category_hint = f"; mostly: {top_cat}"
291
308
  if total == 0:
292
- verdict = "No algorithmic issues detected"
309
+ # Z3 (2026-05-06) informative zero-state. When 0 findings,
310
+ # tell the user (a) which profile filter was active, (b) how
311
+ # many detectors ran, (c) what to try next.
312
+ profile_note = ""
313
+ if profile != "balanced":
314
+ profile_note = f" (profile={profile} may be too strict; try --profile balanced)"
315
+ verdict = (
316
+ f"No algorithmic issues detected{profile_note} — "
317
+ f"{detector_meta.get('detectors_executed', 0)} detector(s) ran cleanly. "
318
+ f"Try `roam math --profile aggressive` for more candidates "
319
+ f"or `roam debt --top 10` for refactoring ROI hotspots."
320
+ )
293
321
  elif suppressed_count > 0:
294
322
  verdict = (
295
323
  f"{unsuppressed_total} unsuppressed candidate{'s' if unsuppressed_total != 1 else ''} "
@@ -341,6 +369,15 @@ def math_cmd(
341
369
  [float(f.get("impact_score", 0.0) or 0.0) for f in findings],
342
370
  default=0.0,
343
371
  ),
372
+ # Z13 (2026-05-06) — top_tasks_by_count helps CI
373
+ # dashboards / agents prioritise without iterating
374
+ # every finding. Format: [{task_id, count}, ...].
375
+ "top_tasks_by_count": [
376
+ {"task_id": tid, "count": n}
377
+ for tid, n in __import__("collections")
378
+ .Counter(f.get("task_id", "?") for f in findings)
379
+ .most_common(3)
380
+ ],
344
381
  },
345
382
  findings=findings,
346
383
  )
@@ -39,13 +39,11 @@ from roam.output.formatter import json_envelope, loc, to_json
39
39
 
40
40
  # Patterns that identify ORM model classes by parent class or trait
41
41
  _MODEL_PARENTS = {
42
- # Laravel / Eloquent
42
+ # Laravel / Eloquent / Django (both use bare "Model" — single membership)
43
43
  "Model",
44
44
  "Eloquent",
45
45
  "Authenticatable",
46
- # Django
47
46
  "models.Model",
48
- "Model",
49
47
  # Rails / ActiveRecord
50
48
  "ApplicationRecord",
51
49
  "ActiveRecord::Base",
@@ -129,7 +127,6 @@ _RELATIONSHIP_CALLS = {
129
127
  "load",
130
128
  "fetch",
131
129
  "findOrFail",
132
- "find",
133
130
  }
134
131
 
135
132
  # I/O operations that indicate a DB query or network call
@@ -154,7 +151,6 @@ _IO_INDICATORS = {
154
151
  # HTTP
155
152
  "fetch",
156
153
  "request",
157
- "get",
158
154
  "post",
159
155
  "put",
160
156
  # File
@@ -468,17 +468,20 @@ def _analyse_orphan_routes(project_root: Path, conn, limit: int) -> dict:
468
468
  # Deduplicate
469
469
  all_matching = list(set(all_matching))
470
470
 
471
- # Remove the route files themselves and the controller file from matches
471
+ # Remove the route files themselves and the controller file from matches.
472
+ # `_ctrl` and `_route_files` are bound as defaults so the closure
473
+ # captures THIS iteration's values (per-loop B023 fix).
472
474
  controller_name = route.get("controller") or ""
473
475
 
474
- def _is_self_reference(file_path: str) -> bool:
476
+ def _is_self_reference(
477
+ file_path: str,
478
+ _ctrl: str = controller_name,
479
+ _route_files: set = route_file_prefixes,
480
+ ) -> bool:
475
481
  norm = file_path.replace("\\", "/")
476
- # Exclude the route definition files
477
- if norm in route_file_prefixes:
482
+ if norm in _route_files:
478
483
  return True
479
- # Exclude the controller file itself
480
- if controller_name and controller_name.lower() in norm.lower():
481
- # Check it actually looks like a controller path
484
+ if _ctrl and _ctrl.lower() in norm.lower():
482
485
  if "controller" in norm.lower() or "http" in norm.lower():
483
486
  return True
484
487
  return False
@@ -287,6 +287,13 @@ def _section_rule_violations(rule_violations: list[dict]) -> list[str]:
287
287
  out = ["### Architecture rule violations", ""]
288
288
  block_v = [v for v in rule_violations if v.get("severity") == "BLOCK"]
289
289
  warn_v = [v for v in rule_violations if v.get("severity") in ("WARN", "WARNING")]
290
+ # Z4 (2026-05-06) — when total violations is huge, wrap the per-item
291
+ # detail in a collapsible <details> block so the comment doesn't
292
+ # dominate the PR thread on noisy diffs.
293
+ use_details = len(rule_violations) >= 12
294
+ if use_details:
295
+ out.append(f"<details><summary>{len(rule_violations)} violation(s) — expand for detail</summary>")
296
+ out.append("")
290
297
  for v in block_v[:5]:
291
298
  out.append(f"- **BLOCK** `{v['rule_id']}`: `{v['file']}` -> `{v['matched_import']}`")
292
299
  if v.get("description"):
@@ -309,6 +316,10 @@ def _section_rule_violations(rule_violations: list[dict]) -> list[str]:
309
316
  chunks = [f"`{rid}` x{n} ({sev})" for (sev, rid), n in counts.most_common(5)]
310
317
  more_total = extra_block + extra_warn
311
318
  out.append(f"- _...{more_total} more violation(s): " + ", ".join(chunks) + "._")
319
+ # Z4 — close the collapsible block when we opened one.
320
+ if use_details:
321
+ out.append("")
322
+ out.append("</details>")
312
323
  out.append("")
313
324
  return out
314
325
 
@@ -91,6 +91,52 @@ def _inline_match(line_text: str, command: str, task_id: str) -> bool:
91
91
  return False
92
92
 
93
93
 
94
+ def _parse_simple_ignore_findings_yaml(text: str) -> dict:
95
+ """Minimal YAML parser for .roamignore-findings — no PyYAML required.
96
+
97
+ Handles the documented shape only:
98
+
99
+ rules:
100
+ - task_id: io-in-loop
101
+ path_glob: "src/composables/**/*.ts"
102
+ reason: "..."
103
+ - task_id: branching-recursion
104
+ path_glob: "src/utils/object-diff.ts"
105
+
106
+ Anything more complex (anchors, multi-line strings, nested lists)
107
+ needs real PyYAML. Returns ``{}`` on shapes we can't recognise so
108
+ callers fall through to a clean empty-rules state.
109
+ """
110
+ rules: list[dict] = []
111
+ current: dict | None = None
112
+ in_rules_block = False
113
+ for raw in text.splitlines():
114
+ line = raw.rstrip()
115
+ stripped = line.strip()
116
+ if not stripped or stripped.startswith("#"):
117
+ continue
118
+ if stripped == "rules:" or stripped.startswith("rules:"):
119
+ in_rules_block = True
120
+ continue
121
+ if not in_rules_block:
122
+ continue
123
+ if stripped.startswith("- "):
124
+ if current:
125
+ rules.append(current)
126
+ current = {}
127
+ stripped = stripped[2:].strip()
128
+ # First key on the same line as `-` is the common shape.
129
+ if ":" in stripped:
130
+ k, _, v = stripped.partition(":")
131
+ current[k.strip()] = v.strip().strip('"').strip("'")
132
+ elif current is not None and ":" in stripped:
133
+ k, _, v = stripped.partition(":")
134
+ current[k.strip()] = v.strip().strip('"').strip("'")
135
+ if current:
136
+ rules.append(current)
137
+ return {"rules": rules} if rules else {}
138
+
139
+
94
140
  def _load_ignore_findings_file(path: Path) -> list[dict]:
95
141
  """Load `.roamignore-findings` from ``path``. Returns ``[]`` on any error.
96
142
 
@@ -116,11 +162,15 @@ def _load_ignore_findings_file(path: Path) -> list[dict]:
116
162
 
117
163
  data = yaml.safe_load(text) or {}
118
164
  except ImportError:
119
- # No PyYAML: assume strict JSON
165
+ # No PyYAML: try strict JSON first, then a minimal-YAML fallback so
166
+ # the .roamignore-findings format works on Python 3.9 / installs
167
+ # without PyYAML (PyYAML is not a project dependency).
120
168
  try:
121
169
  data = _json.loads(text)
122
170
  except _json.JSONDecodeError:
123
- return []
171
+ data = _parse_simple_ignore_findings_yaml(text)
172
+ if not data:
173
+ return []
124
174
  except Exception: # noqa: BLE001 — malformed YAML never crashes the analyser
125
175
  return []
126
176
  rules = data.get("rules") if isinstance(data, dict) else []
@@ -414,12 +414,14 @@ def find_symbol_with_alternatives(conn: sqlite3.Connection, name: str) -> tuple[
414
414
 
415
415
  signals = _ambiguity_signals(conn, rows)
416
416
 
417
- def _score(r):
417
+ # Bind `signals` as default so the closure captures THIS iteration's
418
+ # value (avoids the late-binding-loop closure pitfall flagged by B023).
419
+ def _score(r, _sig=signals):
418
420
  return (
419
- signals["ref"].get(r["id"], 0),
420
- signals["pr"].get(r["id"], 0),
421
- signals["cc"].get(r["id"], 0),
422
- signals["churn"].get(r["file_id"], 0) if "file_id" in r.keys() else 0,
421
+ _sig["ref"].get(r["id"], 0),
422
+ _sig["pr"].get(r["id"], 0),
423
+ _sig["cc"].get(r["id"], 0),
424
+ _sig["churn"].get(r["file_id"], 0) if "file_id" in r.keys() else 0,
423
425
  _path_rank(r["file_path"]),
424
426
  -r["id"],
425
427
  )
@@ -1362,8 +1362,8 @@ MAP_METADATA: dict[str, dict[str, object]] = {
1362
1362
  "relationship": "self",
1363
1363
  "peer": True,
1364
1364
  "graph": "PageRank + Tarjan + Louvain + layers",
1365
- "note": "Graph algorithms (PageRank, SCC, Louvain, Fiedler) on tree-sitter ASTs fused with git history in SQLite. 136 MCP tools, 187 CLI commands. 19 Python idiom detectors (v12.7+). 51 algo detectors (12.31).",
1366
- "version_evaluated": "12.31",
1365
+ "note": "Graph algorithms (PageRank, SCC, Louvain, Fiedler) on tree-sitter ASTs fused with git history in SQLite. 136 MCP tools, 187 CLI commands. 19 Python idiom detectors (v12.7+). 54 algo detectors (12.33).",
1366
+ "version_evaluated": "12.33",
1367
1367
  "repo_url": "https://github.com/Cranot/roam-code",
1368
1368
  },
1369
1369
  "CKB/CodeMCP": {
@@ -158,29 +158,19 @@ def _jaccard_bags(a: Counter, b: Counter) -> float:
158
158
 
159
159
  _FUNCTION_NODE_TYPES = frozenset(
160
160
  {
161
- # Python
161
+ # Python / C / C++ all share `function_definition`
162
162
  "function_definition",
163
- # JS/TS
163
+ # JS/TS / Swift share `function_declaration`
164
164
  "function_declaration",
165
165
  "method_definition",
166
166
  "arrow_function",
167
- # Java/C#/Kotlin/Scala
167
+ # Java/C#/Kotlin/Scala / Go / PHP all share `method_declaration`
168
168
  "method_declaration",
169
169
  "constructor_declaration",
170
- # Go
171
- "function_declaration",
172
- "method_declaration",
173
170
  # Rust
174
171
  "function_item",
175
- # C/C++
176
- "function_definition",
177
172
  # Ruby
178
173
  "method",
179
- # PHP
180
- "function_definition",
181
- "method_declaration",
182
- # Swift
183
- "function_declaration",
184
174
  }
185
175
  )
186
176
 
@@ -28,20 +28,13 @@ _CONTROL_FLOW = {
28
28
  "with_statement",
29
29
  "match_statement",
30
30
  # JS/TS
31
- "if_statement",
32
- "for_statement",
33
31
  "for_in_statement",
34
- "while_statement",
35
32
  "do_statement",
36
33
  "switch_statement",
37
- "try_statement",
38
34
  "catch_clause",
39
35
  # Java/C#/Go/Rust
40
- "for_statement",
41
36
  "enhanced_for_statement",
42
37
  "foreach_statement",
43
- "while_statement",
44
- "do_statement",
45
38
  "if_expression",
46
39
  "match_expression",
47
40
  # General
@@ -329,8 +329,6 @@ _VFP_BUILTINS = frozenset(
329
329
  "TRIM",
330
330
  "UPPER",
331
331
  # ── Date / Time ──
332
- "CDOW",
333
- "CMONTH",
334
332
  "CTOD",
335
333
  "CTOT",
336
334
  "DATE",