roam-code 12.6.0__tar.gz → 12.7.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 (543) hide show
  1. {roam_code-12.6.0/src/roam_code.egg-info → roam_code-12.7.0}/PKG-INFO +1 -1
  2. {roam_code-12.6.0 → roam_code-12.7.0}/pyproject.toml +1 -1
  3. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/python_idioms.py +374 -0
  4. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_context.py +35 -0
  5. {roam_code-12.6.0 → roam_code-12.7.0/src/roam_code.egg-info}/PKG-INFO +1 -1
  6. {roam_code-12.6.0 → roam_code-12.7.0}/LICENSE +0 -0
  7. {roam_code-12.6.0 → roam_code-12.7.0}/README.md +0 -0
  8. {roam_code-12.6.0 → roam_code-12.7.0}/setup.cfg +0 -0
  9. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/__init__.py +0 -0
  10. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/__main__.py +0 -0
  11. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/analysis/__init__.py +0 -0
  12. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/analysis/effects.py +0 -0
  13. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/analysis/taint.py +0 -0
  14. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/api.py +0 -0
  15. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/ask/__init__.py +0 -0
  16. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/ask/classifier.py +0 -0
  17. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/ask/recipes.py +0 -0
  18. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/ask/runner.py +0 -0
  19. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/attest/__init__.py +0 -0
  20. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/attest/cga.py +0 -0
  21. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/__init__.py +0 -0
  22. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/base.py +0 -0
  23. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_config.py +0 -0
  24. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_django.py +0 -0
  25. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_protobuf.py +0 -0
  26. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_rest_api.py +0 -0
  27. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_salesforce.py +0 -0
  28. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/bridge_template.py +0 -0
  29. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/bridges/registry.py +0 -0
  30. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/__init__.py +0 -0
  31. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/detectors.py +0 -0
  32. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/fixes.py +0 -0
  33. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/smells.py +0 -0
  34. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/catalog/tasks.py +0 -0
  35. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/cli.py +0 -0
  36. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/__init__.py +0 -0
  37. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/changed_files.py +0 -0
  38. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_adrs.py +0 -0
  39. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_adversarial.py +0 -0
  40. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_affected.py +0 -0
  41. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_affected_tests.py +0 -0
  42. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_agent_context.py +0 -0
  43. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_agent_export.py +0 -0
  44. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_agent_plan.py +0 -0
  45. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ai_ratio.py +0 -0
  46. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ai_readiness.py +0 -0
  47. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_alerts.py +0 -0
  48. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_annotate.py +0 -0
  49. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_api_changes.py +0 -0
  50. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_api_drift.py +0 -0
  51. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ask.py +0 -0
  52. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_attest.py +0 -0
  53. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_auth_gaps.py +0 -0
  54. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_bisect.py +0 -0
  55. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_breaking.py +0 -0
  56. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_budget.py +0 -0
  57. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_bus_factor.py +0 -0
  58. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_capsule.py +0 -0
  59. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_cga.py +0 -0
  60. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_check_rules.py +0 -0
  61. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ci_setup.py +0 -0
  62. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_clean.py +0 -0
  63. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_clones.py +0 -0
  64. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_closure.py +0 -0
  65. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_clusters.py +0 -0
  66. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_codeowners.py +0 -0
  67. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_complexity.py +0 -0
  68. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_config.py +0 -0
  69. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_congestion.py +0 -0
  70. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_conventions.py +0 -0
  71. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_coupling.py +0 -0
  72. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_coverage_gaps.py +0 -0
  73. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_critique.py +0 -0
  74. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_cut.py +0 -0
  75. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_dark_matter.py +0 -0
  76. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_dashboard.py +0 -0
  77. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_dead.py +0 -0
  78. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_debt.py +0 -0
  79. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_deps.py +0 -0
  80. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_describe.py +0 -0
  81. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_dev_profile.py +0 -0
  82. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_diagnose.py +0 -0
  83. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_diff.py +0 -0
  84. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_doc_staleness.py +0 -0
  85. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_docs_coverage.py +0 -0
  86. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_doctor.py +0 -0
  87. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_drift.py +0 -0
  88. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_duplicates.py +0 -0
  89. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_effects.py +0 -0
  90. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_endpoints.py +0 -0
  91. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_entry_points.py +0 -0
  92. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_eval_retrieve.py +0 -0
  93. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_fan.py +0 -0
  94. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_file.py +0 -0
  95. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_fingerprint.py +0 -0
  96. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_fitness.py +0 -0
  97. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_flag_dead.py +0 -0
  98. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_fleet.py +0 -0
  99. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_fn_coupling.py +0 -0
  100. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_forecast.py +0 -0
  101. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_grep.py +0 -0
  102. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_guard.py +0 -0
  103. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_health.py +0 -0
  104. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_hooks.py +0 -0
  105. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_hotspots.py +0 -0
  106. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_impact.py +0 -0
  107. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_index.py +0 -0
  108. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_index_bundle.py +0 -0
  109. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ingest_trace.py +0 -0
  110. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_init.py +0 -0
  111. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_intent.py +0 -0
  112. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_invariants.py +0 -0
  113. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_layers.py +0 -0
  114. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_map.py +0 -0
  115. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_math.py +0 -0
  116. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_mcp_setup.py +0 -0
  117. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_metrics.py +0 -0
  118. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_migration_safety.py +0 -0
  119. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_minimap.py +0 -0
  120. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_missing_index.py +0 -0
  121. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_module.py +0 -0
  122. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_mutate.py +0 -0
  123. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_n1.py +0 -0
  124. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_oracle.py +0 -0
  125. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_orchestrate.py +0 -0
  126. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_orphan_routes.py +0 -0
  127. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_over_fetch.py +0 -0
  128. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_owner.py +0 -0
  129. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_partition.py +0 -0
  130. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_path_coverage.py +0 -0
  131. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_patterns.py +0 -0
  132. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_plan.py +0 -0
  133. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_plan_refactor.py +0 -0
  134. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_pr_diff.py +0 -0
  135. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_pr_risk.py +0 -0
  136. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_preflight.py +0 -0
  137. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_py_modern.py +0 -0
  138. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_py_types.py +0 -0
  139. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_relate.py +0 -0
  140. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_report.py +0 -0
  141. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_reset.py +0 -0
  142. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_retrieve.py +0 -0
  143. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_risk.py +0 -0
  144. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_rules.py +0 -0
  145. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_safe_delete.py +0 -0
  146. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_safe_zones.py +0 -0
  147. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_sbom.py +0 -0
  148. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_schema.py +0 -0
  149. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_search.py +0 -0
  150. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_search_semantic.py +0 -0
  151. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_secrets.py +0 -0
  152. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_semantic_diff.py +0 -0
  153. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_simulate.py +0 -0
  154. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_simulate_departure.py +0 -0
  155. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_sketch.py +0 -0
  156. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_smells.py +0 -0
  157. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_spectral.py +0 -0
  158. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_split.py +0 -0
  159. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
  160. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
  161. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_supply_chain.py +0 -0
  162. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_symbol.py +0 -0
  163. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_syntax_check.py +0 -0
  164. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_taint.py +0 -0
  165. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_test_gaps.py +0 -0
  166. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_test_scaffold.py +0 -0
  167. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_testmap.py +0 -0
  168. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_tour.py +0 -0
  169. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_trace.py +0 -0
  170. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_trends.py +0 -0
  171. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_triage.py +0 -0
  172. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_understand.py +0 -0
  173. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_uses.py +0 -0
  174. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_verify.py +0 -0
  175. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_verify_imports.py +0 -0
  176. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_vibe_check.py +0 -0
  177. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_visualize.py +0 -0
  178. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_vuln_map.py +0 -0
  179. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_vuln_reach.py +0 -0
  180. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_vulns.py +0 -0
  181. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_watch.py +0 -0
  182. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_weather.py +0 -0
  183. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_why.py +0 -0
  184. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_ws.py +0 -0
  185. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/cmd_xlang.py +0 -0
  186. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/codeowners_helpers.py +0 -0
  187. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/context_helpers.py +0 -0
  188. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/gate_presets.py +0 -0
  189. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/graph_helpers.py +0 -0
  190. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/metrics_history.py +0 -0
  191. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/next_steps.py +0 -0
  192. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/resolve.py +0 -0
  193. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/commands/suppression.py +0 -0
  194. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/competitor_site_data.py +0 -0
  195. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/config.py +0 -0
  196. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/coverage_reports.py +0 -0
  197. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/critique/__init__.py +0 -0
  198. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/critique/aggregator.py +0 -0
  199. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/critique/checks.py +0 -0
  200. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/db/__init__.py +0 -0
  201. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/db/connection.py +0 -0
  202. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/db/queries.py +0 -0
  203. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/db/schema.py +0 -0
  204. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/eval/__init__.py +0 -0
  205. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/eval/harness.py +0 -0
  206. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/exit_codes.py +0 -0
  207. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/fleet/__init__.py +0 -0
  208. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/fleet/adapters.py +0 -0
  209. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/fleet/manifest.py +0 -0
  210. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/git_utils.py +0 -0
  211. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/__init__.py +0 -0
  212. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/anomaly.py +0 -0
  213. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/builder.py +0 -0
  214. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/clone_detect.py +0 -0
  215. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/clusters.py +0 -0
  216. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/cycles.py +0 -0
  217. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/dark_matter.py +0 -0
  218. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/diff.py +0 -0
  219. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/fingerprint.py +0 -0
  220. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/layers.py +0 -0
  221. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/pagerank.py +0 -0
  222. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/partition.py +0 -0
  223. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/pathfinding.py +0 -0
  224. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/propagation.py +0 -0
  225. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/simulate.py +0 -0
  226. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/spectral.py +0 -0
  227. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/graph/stats.py +0 -0
  228. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/__init__.py +0 -0
  229. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/complexity.py +0 -0
  230. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/discovery.py +0 -0
  231. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/django_post.py +0 -0
  232. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/file_roles.py +0 -0
  233. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/git_stats.py +0 -0
  234. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/gitignore.py +0 -0
  235. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/incremental.py +0 -0
  236. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/indexer.py +0 -0
  237. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/parser.py +0 -0
  238. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/relations.py +0 -0
  239. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/symbols.py +0 -0
  240. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/index/test_conventions.py +0 -0
  241. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/__init__.py +0 -0
  242. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/apex_lang.py +0 -0
  243. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/aura_lang.py +0 -0
  244. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/base.py +0 -0
  245. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/c_lang.py +0 -0
  246. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/csharp_lang.py +0 -0
  247. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/extractor_schema.py +0 -0
  248. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/foxpro_lang.py +0 -0
  249. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/generic_lang.py +0 -0
  250. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/go_lang.py +0 -0
  251. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/hcl_lang.py +0 -0
  252. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/java_lang.py +0 -0
  253. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/javascript_lang.py +0 -0
  254. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/kotlin_lang.py +0 -0
  255. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/php_lang.py +0 -0
  256. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/python_lang.py +0 -0
  257. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/query_engine.py +0 -0
  258. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/registry.py +0 -0
  259. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/ruby_lang.py +0 -0
  260. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/rust_lang.py +0 -0
  261. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/scala_lang.py +0 -0
  262. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/sfxml_lang.py +0 -0
  263. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/sql_lang.py +0 -0
  264. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/swift_lang.py +0 -0
  265. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/typescript_lang.py +0 -0
  266. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/visualforce_lang.py +0 -0
  267. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/languages/yaml_lang.py +0 -0
  268. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/__init__.py +0 -0
  269. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/completions.py +0 -0
  270. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/progress.py +0 -0
  271. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/sampling.py +0 -0
  272. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/session.py +0 -0
  273. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_extras/watcher.py +0 -0
  274. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/mcp_server.py +0 -0
  275. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/__init__.py +0 -0
  276. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/file_role_hints.py +0 -0
  277. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/formatter.py +0 -0
  278. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/mermaid.py +0 -0
  279. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/sarif.py +0 -0
  280. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/output/schema_registry.py +0 -0
  281. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/plugins.py +0 -0
  282. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/refactor/__init__.py +0 -0
  283. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/refactor/codegen.py +0 -0
  284. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/refactor/transforms.py +0 -0
  285. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/__init__.py +0 -0
  286. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/learned_ranker.py +0 -0
  287. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/pipeline.py +0 -0
  288. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/rerank.py +0 -0
  289. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/seeds.py +0 -0
  290. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/retrieve/semantic.py +0 -0
  291. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/rules/__init__.py +0 -0
  292. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/rules/ast_match.py +0 -0
  293. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/rules/builtin.py +0 -0
  294. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/rules/dataflow.py +0 -0
  295. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/rules/engine.py +0 -0
  296. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/__init__.py +0 -0
  297. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/daemon.py +0 -0
  298. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/graph_backend.py +0 -0
  299. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/hotspots.py +0 -0
  300. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/lock_modes.py +0 -0
  301. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/lockmgr.py +0 -0
  302. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/runtime/trace_ingest.py +0 -0
  303. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/search/__init__.py +0 -0
  304. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/search/framework_packs.py +0 -0
  305. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/search/index_embeddings.py +0 -0
  306. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/search/onnx_embeddings.py +0 -0
  307. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/search/tfidf.py +0 -0
  308. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/__init__.py +0 -0
  309. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/aibom_extension.py +0 -0
  310. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/taint_classifier.py +0 -0
  311. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/taint_engine.py +0 -0
  312. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/vuln_reach.py +0 -0
  313. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/security/vuln_store.py +0 -0
  314. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/surface_counts.py +0 -0
  315. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/templates/__init__.py +0 -0
  316. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/templates/ci/__init__.py +0 -0
  317. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/workspace/__init__.py +0 -0
  318. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/workspace/aggregator.py +0 -0
  319. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/workspace/api_scanner.py +0 -0
  320. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/workspace/config.py +0 -0
  321. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam/workspace/db.py +0 -0
  322. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam_code.egg-info/SOURCES.txt +0 -0
  323. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam_code.egg-info/dependency_links.txt +0 -0
  324. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam_code.egg-info/entry_points.txt +0 -0
  325. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam_code.egg-info/requires.txt +0 -0
  326. {roam_code-12.6.0 → roam_code-12.7.0}/src/roam_code.egg-info/top_level.txt +0 -0
  327. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_adrs.py +0 -0
  328. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_adversarial.py +0 -0
  329. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_affected.py +0 -0
  330. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_agent_export.py +0 -0
  331. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_agent_mode.py +0 -0
  332. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_agent_plan_context.py +0 -0
  333. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ai_ratio.py +0 -0
  334. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ai_readiness.py +0 -0
  335. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_alerts_cmd.py +0 -0
  336. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_annotations.py +0 -0
  337. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_anomaly.py +0 -0
  338. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_api_changes.py +0 -0
  339. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_api_drift.py +0 -0
  340. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ask.py +0 -0
  341. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_attest.py +0 -0
  342. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_auth_gaps.py +0 -0
  343. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_backend_fixes_round2.py +0 -0
  344. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_backend_fixes_round3.py +0 -0
  345. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_basic.py +0 -0
  346. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_batch_mcp.py +0 -0
  347. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_bisect.py +0 -0
  348. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_bridge_django.py +0 -0
  349. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_bridges.py +0 -0
  350. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_bridges_extended.py +0 -0
  351. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_budget.py +0 -0
  352. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_budget_flag.py +0 -0
  353. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_budget_phase2.py +0 -0
  354. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_bus_factor.py +0 -0
  355. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_capsule.py +0 -0
  356. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_cga.py +0 -0
  357. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_check_rules.py +0 -0
  358. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ci_gate_eval.py +0 -0
  359. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ci_sarif_guard.py +0 -0
  360. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ci_setup.py +0 -0
  361. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_clones.py +0 -0
  362. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_closure.py +0 -0
  363. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_codeowners.py +0 -0
  364. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_commands_architecture.py +0 -0
  365. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_commands_exploration.py +0 -0
  366. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_commands_health.py +0 -0
  367. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_commands_refactoring.py +0 -0
  368. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_commands_workflow.py +0 -0
  369. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_competitor_site_data.py +0 -0
  370. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_comprehensive.py +0 -0
  371. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_config.py +0 -0
  372. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_congestion.py +0 -0
  373. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_context_propagation.py +0 -0
  374. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_conventions_cmd.py +0 -0
  375. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_coverage_gaps_cmd.py +0 -0
  376. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_coverage_ingestion.py +0 -0
  377. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_critique.py +0 -0
  378. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_cut.py +0 -0
  379. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dark_matter.py +0 -0
  380. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dark_matter_helpers.py +0 -0
  381. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dashboard.py +0 -0
  382. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dataflow_dead.py +0 -0
  383. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dead_aging.py +0 -0
  384. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_defer_loading.py +0 -0
  385. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_demo_gif_asset.py +0 -0
  386. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_describe.py +0 -0
  387. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_detail_flag_hints.py +0 -0
  388. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_deterministic_output.py +0 -0
  389. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_dev_profile.py +0 -0
  390. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_difficulty_scoring.py +0 -0
  391. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_doc_staleness.py +0 -0
  392. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_docker_assets.py +0 -0
  393. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_docs_coverage.py +0 -0
  394. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_docs_site_quality.py +0 -0
  395. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_doctor.py +0 -0
  396. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_drift.py +0 -0
  397. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_duplicates.py +0 -0
  398. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_effects.py +0 -0
  399. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_effects_propagation.py +0 -0
  400. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_endpoints.py +0 -0
  401. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_entry_points_cmd.py +0 -0
  402. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_eval_retrieve.py +0 -0
  403. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_exclude_patterns.py +0 -0
  404. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_exit_codes.py +0 -0
  405. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_extractor_grammar_drift.py +0 -0
  406. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_fallback_contracts.py +0 -0
  407. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_file_roles.py +0 -0
  408. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_fingerprint.py +0 -0
  409. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_fixes.py +0 -0
  410. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_flag_dead.py +0 -0
  411. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_fleet.py +0 -0
  412. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_fn_coupling.py +0 -0
  413. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_forecast.py +0 -0
  414. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_formatters.py +0 -0
  415. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_foxpro.py +0 -0
  416. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_framework_detection.py +0 -0
  417. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_gate_presets.py +0 -0
  418. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_git_utils.py +0 -0
  419. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_guard.py +0 -0
  420. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_health_gate.py +0 -0
  421. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_hooks.py +0 -0
  422. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_hotspots.py +0 -0
  423. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_index.py +0 -0
  424. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_index_bundle.py +0 -0
  425. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_init_cmd.py +0 -0
  426. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_install_check.py +0 -0
  427. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_intent.py +0 -0
  428. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_invariants.py +0 -0
  429. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_json_contracts.py +0 -0
  430. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_json_error_envelope.py +0 -0
  431. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_kotlin_swift_extractors.py +0 -0
  432. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_language_corpus.py +0 -0
  433. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_languages.py +0 -0
  434. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_library_api.py +0 -0
  435. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_math.py +0 -0
  436. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_math_tips.py +0 -0
  437. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_mcp_extras.py +0 -0
  438. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_mcp_server.py +0 -0
  439. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_mcp_setup.py +0 -0
  440. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_mermaid.py +0 -0
  441. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_metrics_cmd.py +0 -0
  442. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_migration_safety.py +0 -0
  443. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_minimap.py +0 -0
  444. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_missing_index.py +0 -0
  445. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_mutate.py +0 -0
  446. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_n1.py +0 -0
  447. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_next_steps.py +0 -0
  448. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_onboard.py +0 -0
  449. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_oracle.py +0 -0
  450. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_orchestrate.py +0 -0
  451. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_orphan_routes.py +0 -0
  452. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_oss_bench_harness.py +0 -0
  453. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_over_fetch.py +0 -0
  454. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_pagerank_truncation.py +0 -0
  455. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_partition.py +0 -0
  456. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_path_coverage.py +0 -0
  457. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_patterns_cmd.py +0 -0
  458. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_performance.py +0 -0
  459. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_personalized_pagerank.py +0 -0
  460. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_plan.py +0 -0
  461. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_plugin_discovery.py +0 -0
  462. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_pr_comment_script.py +0 -0
  463. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_pr_diff.py +0 -0
  464. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_pr_risk_author.py +0 -0
  465. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_progress.py +0 -0
  466. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_progressive_disclosure.py +0 -0
  467. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_properties.py +0 -0
  468. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_python_extractor_v2.py +0 -0
  469. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_python_idioms_e2e.py +0 -0
  470. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_python_pivot.py +0 -0
  471. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_readme_surface_consistency.py +0 -0
  472. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_refactoring_intelligence.py +0 -0
  473. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_relate.py +0 -0
  474. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_report.py +0 -0
  475. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_reset_clean.py +0 -0
  476. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_resolve.py +0 -0
  477. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_retrieve.py +0 -0
  478. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_retrieve_cross_repo.py +0 -0
  479. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_retrieve_seeds.py +0 -0
  480. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_risk.py +0 -0
  481. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ruby.py +0 -0
  482. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rule_profiles.py +0 -0
  483. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rules.py +0 -0
  484. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rules_ast_match.py +0 -0
  485. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rules_community_pack.py +0 -0
  486. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rules_dataflow.py +0 -0
  487. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_rules_symbol_requirements.py +0 -0
  488. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_runtime.py +0 -0
  489. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_runtime_score.py +0 -0
  490. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_salesforce.py +0 -0
  491. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_sarif_flag.py +0 -0
  492. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_sbom.py +0 -0
  493. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_scala.py +0 -0
  494. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_schema_versioning.py +0 -0
  495. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_search_explain.py +0 -0
  496. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_secrets.py +0 -0
  497. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_secrets_v2.py +0 -0
  498. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_semantic_diff.py +0 -0
  499. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_semantic_onnx.py +0 -0
  500. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_semantic_search.py +0 -0
  501. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_simulate.py +0 -0
  502. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_simulate_departure.py +0 -0
  503. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_sketch.py +0 -0
  504. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_smells.py +0 -0
  505. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_smoke.py +0 -0
  506. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_sna_metrics.py +0 -0
  507. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_spectral.py +0 -0
  508. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_split_cmd.py +0 -0
  509. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_sql.py +0 -0
  510. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_suggest_reviewers.py +0 -0
  511. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_supply_chain.py +0 -0
  512. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_surface_counts.py +0 -0
  513. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_syntax_check.py +0 -0
  514. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_taint.py +0 -0
  515. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_taint_analysis.py +0 -0
  516. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_taint_classifier.py +0 -0
  517. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_test_conventions.py +0 -0
  518. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_test_gaps.py +0 -0
  519. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_test_scaffold.py +0 -0
  520. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_testmap.py +0 -0
  521. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_top_flag_consistency.py +0 -0
  522. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_tour_cmd.py +0 -0
  523. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_trends.py +0 -0
  524. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_trends_cohort.py +0 -0
  525. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_triage.py +0 -0
  526. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_uses_cmd.py +0 -0
  527. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_v12_2.py +0 -0
  528. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_v6_features.py +0 -0
  529. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_v71_features.py +0 -0
  530. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_v7_features.py +0 -0
  531. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_v82_features.py +0 -0
  532. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_verify.py +0 -0
  533. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_verify_imports.py +0 -0
  534. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_vibe_check.py +0 -0
  535. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_visualize.py +0 -0
  536. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_vuln.py +0 -0
  537. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_vulns_cmd.py +0 -0
  538. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_watch.py +0 -0
  539. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_why.py +0 -0
  540. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_workspace.py +0 -0
  541. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_ws_resolve_fixes.py +0 -0
  542. {roam_code-12.6.0 → roam_code-12.7.0}/tests/test_xlang.py +0 -0
  543. {roam_code-12.6.0 → roam_code-12.7.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.6.0
3
+ Version: 12.7.0
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "roam-code"
7
- version = "12.6.0"
7
+ version = "12.7.0"
8
8
  description = "Instant codebase comprehension for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -140,6 +140,50 @@ _MAGIC_NUMBER_RE = re.compile(
140
140
  # function name appears in its own body. Done in detector loop, not
141
141
  # regex.
142
142
 
143
+ # Django ORM N+1: ``.filter(...)`` then ``for x in qs:`` then access
144
+ # of related field (e.g. ``x.author.name``). The simplified detector
145
+ # below catches the canonical pattern: ``.all()`` immediately
146
+ # followed by ``for x in qs`` in the same function body.
147
+ _DJANGO_ALL_THEN_FOR = re.compile(
148
+ r"\.\s*all\s*\(\s*\)[^\n]*\n[^\n]*for\s+\w+\s+in\s+\w+\s*:",
149
+ )
150
+ # Calling ``.objects.filter(...)`` inside a loop — N+1.
151
+ _DJANGO_FILTER_IN_LOOP = re.compile(
152
+ r"^\s+.*\.objects\.\s*(?:filter|get)\s*\(",
153
+ re.MULTILINE,
154
+ )
155
+
156
+ # SQLAlchemy: ``.all()`` then iterate accessing a relationship attribute.
157
+ # Simplified pattern: ``.all()`` in any function with ``relationship``
158
+ # imported. Caller needs to verify it's worth flagging.
159
+ _SQLALCHEMY_RELATIONSHIP = re.compile(r"=\s*relationship\s*\(")
160
+ _SQLALCHEMY_ALL_THEN_DOT = re.compile(
161
+ r"\.\s*all\s*\(\s*\)[^\n]*\n[^\n]*\bfor\b[^\n]*\n[^\n]*\.\w+",
162
+ )
163
+
164
+ # FastAPI Depends() — dependency injection chain.
165
+ _FASTAPI_DEPENDS_RE = re.compile(r"\bDepends\s*\(\s*(\w+)\s*\)")
166
+
167
+ # Late-binding closure: ``lambda x: i*x`` inside a loop where ``i``
168
+ # changes per iteration. Pattern: ``for i in ...:\n ... lambda``
169
+ # in same body. Caller verifies same-loop scope.
170
+ _LAMBDA_IN_LOOP_RE = re.compile(
171
+ r"^\s+for\s+(\w+)\s+in\s[^\n]+:\s*\n[\s\S]{0,200}?lambda\b",
172
+ re.MULTILINE,
173
+ )
174
+
175
+ # ``except SomeError: pass`` — silently swallowing exceptions.
176
+ _EXCEPT_PASS_RE = re.compile(r"^\s*except\b[^:]*:\s*\n\s*pass\s*\n", re.MULTILINE)
177
+
178
+ # ``except Exception:`` (broad) — catches too much. Less severe than
179
+ # bare ``except:`` but still flagged.
180
+ _BROAD_EXCEPT_RE = re.compile(r"^\s*except\s+(?:Exception|BaseException)\s*(?:as\s+\w+\s*)?:", re.MULTILINE)
181
+
182
+ # ``async for`` missing on async iterators (StreamReader, async generators)
183
+ # — heuristic: ``for X in <name>`` where the iterator type hint suggests
184
+ # async (AsyncIterator, AsyncGenerator, AsyncIterable).
185
+ _ASYNC_ITER_HINT = re.compile(r"AsyncIterator|AsyncGenerator|AsyncIterable")
186
+
143
187
 
144
188
  def _project_root_for_conn(conn: sqlite3.Connection) -> str:
145
189
  """Resolve the project root for ``conn`` by inspecting its
@@ -772,6 +816,329 @@ def detect_async_not_awaited(conn: sqlite3.Connection) -> list[dict]:
772
816
  return findings
773
817
 
774
818
 
819
+ def detect_lambda_in_loop(conn: sqlite3.Connection) -> list[dict]:
820
+ """Find ``lambda`` in a ``for``-loop body — classic late-binding bug.
821
+
822
+ The lambda captures the loop variable by reference, so all
823
+ lambdas end up bound to the LAST value of the variable. Fix:
824
+ add ``i=i`` default argument or use functools.partial.
825
+ """
826
+ findings: list[dict] = []
827
+ for file_id, path in _python_files(conn):
828
+ text = _file_text(conn, file_id)
829
+ if text:
830
+ text = _strip_strings_and_comments(text)
831
+ if not text:
832
+ continue
833
+ sym_index = _line_to_symbol(conn, file_id)
834
+ for match in _LAMBDA_IN_LOOP_RE.finditer(text):
835
+ line_no = text.count("\n", 0, match.start()) + 1
836
+ sym = _enclosing_symbol(line_no, sym_index)
837
+ if sym is None:
838
+ continue
839
+ var = match.group(1)
840
+ findings.append(
841
+ _idiom_finding(
842
+ task_id="py-lambda-in-loop",
843
+ detected_way="late-binding-closure",
844
+ symbol_id=sym[0],
845
+ symbol_name=sym[1],
846
+ file_path=path,
847
+ line_no=line_no,
848
+ reason=(
849
+ f"``lambda`` inside ``for {var} in …`` loop — late binding: "
850
+ f"all lambdas bind to the LAST value of {var}"
851
+ ),
852
+ confidence="medium",
853
+ fix=f"lambda x, {var}={var}: ... # capture by default arg",
854
+ )
855
+ )
856
+ return findings
857
+
858
+
859
+ def detect_except_pass(conn: sqlite3.Connection) -> list[dict]:
860
+ """Find ``except X: pass`` — silently swallowing exceptions."""
861
+ findings: list[dict] = []
862
+ for file_id, path in _python_files(conn):
863
+ text = _file_text(conn, file_id)
864
+ if text:
865
+ text = _strip_strings_and_comments(text)
866
+ if not text:
867
+ continue
868
+ sym_index = _line_to_symbol(conn, file_id)
869
+ for match in _EXCEPT_PASS_RE.finditer(text):
870
+ line_no = text.count("\n", 0, match.start()) + 1
871
+ sym = _enclosing_symbol(line_no, sym_index)
872
+ if sym is None:
873
+ continue
874
+ findings.append(
875
+ _idiom_finding(
876
+ task_id="py-except-pass",
877
+ detected_way="silent-swallow",
878
+ symbol_id=sym[0],
879
+ symbol_name=sym[1],
880
+ file_path=path,
881
+ line_no=line_no,
882
+ reason="``except X: pass`` silently swallows the exception — log it or re-raise",
883
+ confidence="high",
884
+ fix="except X as exc:\n logger.warning('...', exc_info=exc)\n raise",
885
+ )
886
+ )
887
+ return findings
888
+
889
+
890
+ def detect_broad_except(conn: sqlite3.Connection) -> list[dict]:
891
+ """Find ``except Exception:`` / ``except BaseException:``."""
892
+ findings: list[dict] = []
893
+ for file_id, path in _python_files(conn):
894
+ text = _file_text(conn, file_id)
895
+ if text:
896
+ text = _strip_strings_and_comments(text)
897
+ if not text:
898
+ continue
899
+ sym_index = _line_to_symbol(conn, file_id)
900
+ for match in _BROAD_EXCEPT_RE.finditer(text):
901
+ line_no = text.count("\n", 0, match.start()) + 1
902
+ sym = _enclosing_symbol(line_no, sym_index)
903
+ if sym is None:
904
+ continue
905
+ findings.append(
906
+ _idiom_finding(
907
+ task_id="py-broad-except",
908
+ detected_way="catch-too-much",
909
+ symbol_id=sym[0],
910
+ symbol_name=sym[1],
911
+ file_path=path,
912
+ line_no=line_no,
913
+ reason="``except Exception:`` catches more than intended — narrow to specific class(es)",
914
+ confidence="low",
915
+ fix="except (ValueError, KeyError): # or whatever the actual cases are",
916
+ )
917
+ )
918
+ return findings
919
+
920
+
921
+ def detect_django_n1(conn: sqlite3.Connection) -> list[dict]:
922
+ """Find Django ORM N+1 patterns:
923
+
924
+ * ``.objects.filter(...)`` / ``.get(...)`` *inside* a loop body.
925
+ * ``.all()`` immediately followed by ``for x in qs:`` (suggests
926
+ ``.select_related()`` / ``.prefetch_related()``).
927
+ """
928
+ findings: list[dict] = []
929
+ for file_id, path in _python_files(conn):
930
+ text = _file_text(conn, file_id)
931
+ if text:
932
+ text = _strip_strings_and_comments(text)
933
+ if not text:
934
+ continue
935
+ # Quick reject: skip files with no Django ORM hints
936
+ if ".objects." not in text and ".all()" not in text:
937
+ continue
938
+ sym_index = _line_to_symbol(conn, file_id)
939
+ for match in _DJANGO_ALL_THEN_FOR.finditer(text):
940
+ line_no = text.count("\n", 0, match.start()) + 1
941
+ sym = _enclosing_symbol(line_no, sym_index)
942
+ if sym is None:
943
+ continue
944
+ findings.append(
945
+ _idiom_finding(
946
+ task_id="py-django-n1",
947
+ detected_way="all-then-for",
948
+ symbol_id=sym[0],
949
+ symbol_name=sym[1],
950
+ file_path=path,
951
+ line_no=line_no,
952
+ reason="``.all()`` then iterate — likely N+1; use ``.select_related()`` / ``.prefetch_related()``",
953
+ confidence="medium",
954
+ fix=".all().select_related('fk_field')",
955
+ )
956
+ )
957
+ # filter/get inside loop: detect by walking lines, tracking
958
+ # indent depth from preceding ``for``/``while``.
959
+ lines = text.splitlines()
960
+ for i, line in enumerate(lines, 1):
961
+ if not _DJANGO_FILTER_IN_LOOP.search("\n" + line):
962
+ continue
963
+ # Look back up to 20 lines for ``for X in`` at lesser indent
964
+ current_indent = len(line) - len(line.lstrip())
965
+ in_loop = False
966
+ for back in range(max(0, i - 20), i - 1):
967
+ prev = lines[back]
968
+ prev_indent = len(prev) - len(prev.lstrip())
969
+ if prev_indent < current_indent and (
970
+ prev.lstrip().startswith("for ") or prev.lstrip().startswith("while ")
971
+ ):
972
+ in_loop = True
973
+ break
974
+ if not in_loop:
975
+ continue
976
+ sym = _enclosing_symbol(i, sym_index)
977
+ if sym is None:
978
+ continue
979
+ findings.append(
980
+ _idiom_finding(
981
+ task_id="py-django-n1",
982
+ detected_way="query-in-loop",
983
+ symbol_id=sym[0],
984
+ symbol_name=sym[1],
985
+ file_path=path,
986
+ line_no=i,
987
+ reason="Django ORM query inside loop — N+1; lift the query out or use ``.in_bulk()``",
988
+ confidence="high",
989
+ fix="ids = [x.id for x in items]; lookup = Model.objects.in_bulk(ids)",
990
+ )
991
+ )
992
+ return findings
993
+
994
+
995
+ def detect_sqlalchemy_lazy(conn: sqlite3.Connection) -> list[dict]:
996
+ """Find SQLAlchemy ``.all()`` then iterate-with-attribute patterns.
997
+
998
+ Heuristic: the file has ``relationship(`` (so it defines models)
999
+ AND the ``.all()`` call is immediately followed by a ``for``-loop
1000
+ that accesses an attribute on each item. The accessed attribute
1001
+ is likely a relationship that triggers a lazy SELECT per row.
1002
+ """
1003
+ findings: list[dict] = []
1004
+ for file_id, path in _python_files(conn):
1005
+ text = _file_text(conn, file_id)
1006
+ if text:
1007
+ text = _strip_strings_and_comments(text)
1008
+ if not text:
1009
+ continue
1010
+ # Quick reject: must have at least one relationship() declaration
1011
+ if not _SQLALCHEMY_RELATIONSHIP.search(text):
1012
+ continue
1013
+ sym_index = _line_to_symbol(conn, file_id)
1014
+ for match in _SQLALCHEMY_ALL_THEN_DOT.finditer(text):
1015
+ line_no = text.count("\n", 0, match.start()) + 1
1016
+ sym = _enclosing_symbol(line_no, sym_index)
1017
+ if sym is None:
1018
+ continue
1019
+ findings.append(
1020
+ _idiom_finding(
1021
+ task_id="py-sqlalchemy-lazy",
1022
+ detected_way="lazy-load-in-loop",
1023
+ symbol_id=sym[0],
1024
+ symbol_name=sym[1],
1025
+ file_path=path,
1026
+ line_no=line_no,
1027
+ reason=".all() then for-loop accessing attr — likely lazy-load N+1",
1028
+ confidence="medium",
1029
+ fix=".options(selectinload(Model.relationship)).all()",
1030
+ )
1031
+ )
1032
+ return findings
1033
+
1034
+
1035
+ def detect_fastapi_depends(conn: sqlite3.Connection) -> list[dict]:
1036
+ """Inventory FastAPI ``Depends(X)`` provider chain.
1037
+
1038
+ Not strictly an anti-pattern; surfaces as info-level findings so
1039
+ agents can discover the dependency graph for FastAPI apps.
1040
+ """
1041
+ findings: list[dict] = []
1042
+ for file_id, path in _python_files(conn):
1043
+ text = _file_text(conn, file_id)
1044
+ if text:
1045
+ text = _strip_strings_and_comments(text)
1046
+ if not text:
1047
+ continue
1048
+ if "Depends(" not in text:
1049
+ continue
1050
+ sym_index = _line_to_symbol(conn, file_id)
1051
+ seen: set[tuple[int, str]] = set()
1052
+ for match in _FASTAPI_DEPENDS_RE.finditer(text):
1053
+ provider = match.group(1)
1054
+ line_no = text.count("\n", 0, match.start()) + 1
1055
+ sym = _enclosing_symbol(line_no, sym_index)
1056
+ if sym is None:
1057
+ continue
1058
+ key = (sym[0], provider)
1059
+ if key in seen:
1060
+ continue
1061
+ seen.add(key)
1062
+ findings.append(
1063
+ _idiom_finding(
1064
+ task_id="py-fastapi-depends",
1065
+ detected_way="dependency-provider",
1066
+ symbol_id=sym[0],
1067
+ symbol_name=sym[1],
1068
+ file_path=path,
1069
+ line_no=line_no,
1070
+ reason=f"FastAPI dependency: depends on ``{provider}``",
1071
+ confidence="high",
1072
+ fix="",
1073
+ )
1074
+ )
1075
+ return findings
1076
+
1077
+
1078
+ def detect_sync_calls_async_via_graph(conn: sqlite3.Connection) -> list[dict]:
1079
+ """Use the call graph to find sync functions calling async ones.
1080
+
1081
+ Complement to ``detect_async_not_awaited`` (regex-based on names).
1082
+ This walks ``edges.kind='call'`` and reports edges where source
1083
+ is sync and target is async. Strong-evidence finding because it's
1084
+ backed by the indexed graph not text matching.
1085
+
1086
+ Skips when the source itself is a known wrapper (test runner,
1087
+ ``asyncio.run``-style entry point) by name.
1088
+ """
1089
+ findings: list[dict] = []
1090
+ # Names that are legitimate sync→async entry points and should be
1091
+ # excluded from the scan.
1092
+ skip_source_names = {"main", "cli", "run", "entrypoint", "_main", "__main__"}
1093
+ try:
1094
+ rows = conn.execute(
1095
+ """
1096
+ SELECT e.source_id, src.name AS src_name, src.is_async AS src_async,
1097
+ e.target_id, tgt.name AS tgt_name,
1098
+ src_f.path AS src_file, src.line_start AS src_line
1099
+ FROM edges e
1100
+ JOIN symbols src ON src.id = e.source_id
1101
+ JOIN symbols tgt ON tgt.id = e.target_id
1102
+ JOIN files src_f ON src_f.id = src.file_id
1103
+ WHERE e.kind = 'call'
1104
+ AND src.kind IN ('function', 'method')
1105
+ AND tgt.kind IN ('function', 'method')
1106
+ AND tgt.is_async = 1
1107
+ AND src.is_async = 0
1108
+ AND COALESCE(src_f.file_role, '') != 'test'
1109
+ """
1110
+ ).fetchall()
1111
+ except Exception:
1112
+ return findings
1113
+ seen: set[tuple[int, int]] = set()
1114
+ for r in rows:
1115
+ sid = int(r["source_id"])
1116
+ tid = int(r["target_id"])
1117
+ key = (sid, tid)
1118
+ if key in seen:
1119
+ continue
1120
+ seen.add(key)
1121
+ if r["src_name"] in skip_source_names:
1122
+ continue
1123
+ findings.append(
1124
+ _idiom_finding(
1125
+ task_id="py-sync-calls-async",
1126
+ detected_way="missing-await-graph",
1127
+ symbol_id=sid,
1128
+ symbol_name=r["src_name"],
1129
+ file_path=r["src_file"],
1130
+ line_no=int(r["src_line"] or 0),
1131
+ reason=(
1132
+ f"sync ``{r['src_name']}`` calls async ``{r['tgt_name']}`` — "
1133
+ f"either ``await`` it (mark caller async) or use ``asyncio.run``"
1134
+ ),
1135
+ confidence="medium",
1136
+ fix=f"async def {r['src_name']}(...): await {r['tgt_name']}(...)",
1137
+ )
1138
+ )
1139
+ return findings
1140
+
1141
+
775
1142
  def detect_lock_without_with(conn: sqlite3.Connection) -> list[dict]:
776
1143
  """Find ``lock.acquire()`` without ``with``-block — lock leak.
777
1144
 
@@ -967,4 +1334,11 @@ PYTHON_IDIOM_DETECTORS = [
967
1334
  ("py-async-with-missing", "async-resource-leak", detect_async_with_missing),
968
1335
  ("py-type-eq", "type-not-isinstance", detect_type_eq),
969
1336
  ("py-lock-without-with", "lock-leak", detect_lock_without_with),
1337
+ ("py-sync-calls-async", "missing-await-graph", detect_sync_calls_async_via_graph),
1338
+ ("py-django-n1", "django-orm", detect_django_n1),
1339
+ ("py-sqlalchemy-lazy", "sqla-lazy", detect_sqlalchemy_lazy),
1340
+ ("py-fastapi-depends", "fastapi-di", detect_fastapi_depends),
1341
+ ("py-lambda-in-loop", "late-binding-closure", detect_lambda_in_loop),
1342
+ ("py-except-pass", "silent-swallow", detect_except_pass),
1343
+ ("py-broad-except", "catch-too-much", detect_broad_except),
970
1344
  ]
@@ -653,6 +653,41 @@ def _render_single_text(data):
653
653
  click.echo(f" (+{len(siblings) - 10} more)")
654
654
  click.echo()
655
655
 
656
+ # Python pivot v12.7: model-class fields. When the symbol is a
657
+ # Pydantic / dataclass / attrs / TypedDict / NamedTuple class,
658
+ # surface its fields directly (not just as siblings) so an agent
659
+ # working with the class immediately sees its shape.
660
+ if sym_kind == "class":
661
+ try:
662
+ from roam.catalog.python_idioms import is_model_class
663
+
664
+ sig_for_model = sym["signature"] if "signature" in _row_keys else ""
665
+ is_model, _label = is_model_class(sig_for_model, decorators_str)
666
+ except Exception:
667
+ is_model = False
668
+ if is_model:
669
+ from roam.db.connection import open_db as _open_db
670
+
671
+ try:
672
+ with _open_db(readonly=True) as _conn:
673
+ field_rows = _conn.execute(
674
+ "SELECT name, default_value FROM symbols "
675
+ "WHERE parent_id = ? AND kind = 'property' ORDER BY line_start",
676
+ (sym["id"],),
677
+ ).fetchall()
678
+ except Exception:
679
+ field_rows = []
680
+ if field_rows:
681
+ click.echo(f"Fields ({len(field_rows)}):")
682
+ for fr in field_rows[:20]:
683
+ fname = fr["name"] if "name" in fr.keys() else fr[0]
684
+ fdef = (fr["default_value"] if "default_value" in fr.keys() else fr[1]) or ""
685
+ badge = f" = {fdef}" if fdef and fdef not in ("None",) else ""
686
+ click.echo(f" {fname}{badge}")
687
+ if len(field_rows) > 20:
688
+ click.echo(f" (+{len(field_rows) - 20} more)")
689
+ click.echo()
690
+
656
691
  # Always render all extras
657
692
  _render_complexity_text(data.get("complexity"))
658
693
  _render_graph_centrality_text(data.get("graph_centrality"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roam-code
3
- Version: 12.6.0
3
+ Version: 12.7.0
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes
File without changes