seam-code 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. seam_code-0.3.0/.env.example +13 -0
  2. seam_code-0.3.0/.gitignore +66 -0
  3. seam_code-0.3.0/AGENTS.md +101 -0
  4. seam_code-0.3.0/APP_FLOW.md +151 -0
  5. seam_code-0.3.0/BACKEND_STRUCTURE.md +253 -0
  6. seam_code-0.3.0/CLAUDE.md +1061 -0
  7. seam_code-0.3.0/CONTEXT.md +36 -0
  8. seam_code-0.3.0/DISCOVERY.md +57 -0
  9. seam_code-0.3.0/IMPLEMENTATION_PLAN.md +211 -0
  10. seam_code-0.3.0/LICENSE +21 -0
  11. seam_code-0.3.0/Makefile +59 -0
  12. seam_code-0.3.0/PKG-INFO +318 -0
  13. seam_code-0.3.0/PRD.md +101 -0
  14. seam_code-0.3.0/README.md +276 -0
  15. seam_code-0.3.0/TECH_STACK.md +105 -0
  16. seam_code-0.3.0/benchmarks/run_benchmark.py +239 -0
  17. seam_code-0.3.0/benchmarks/semantic_recall.py +298 -0
  18. seam_code-0.3.0/docs/ARCHITECTURE.md +1296 -0
  19. seam_code-0.3.0/docs/CONCEPTS.md +352 -0
  20. seam_code-0.3.0/docs/CONFIGURATION.md +196 -0
  21. seam_code-0.3.0/docs/CONTRACT.md +594 -0
  22. seam_code-0.3.0/docs/adr/001-python-over-typescript.md +29 -0
  23. seam_code-0.3.0/docs/adr/002-sqlite-storage.md +32 -0
  24. seam_code-0.3.0/docs/adr/003-heuristic-execution-flows.md +33 -0
  25. seam_code-0.3.0/docs/adr/004-watchdog-file-watcher.md +31 -0
  26. seam_code-0.3.0/docs/adr/005-phase0-language-scope.md +50 -0
  27. seam_code-0.3.0/docs/adr/008-language-expansion.md +108 -0
  28. seam_code-0.3.0/docs/adr/009-swift-support.md +132 -0
  29. seam_code-0.3.0/docs/adr/010-frontend-explorer-architecture.md +77 -0
  30. seam_code-0.3.0/docs/adr/ADR-007-louvain-clustering.md +65 -0
  31. seam_code-0.3.0/docs/api-contracts/mcp-tools.yaml +1261 -0
  32. seam_code-0.3.0/docs/architecture.html +562 -0
  33. seam_code-0.3.0/docs/assets/seam-hero.png +0 -0
  34. seam_code-0.3.0/docs/benchmark.md +128 -0
  35. seam_code-0.3.0/docs/competitive-benchmark.md +104 -0
  36. seam_code-0.3.0/docs/database/schema.sql +225 -0
  37. seam_code-0.3.0/docs/prd/phase1-core.md +187 -0
  38. seam_code-0.3.0/docs/prd/phase10-swift.md +147 -0
  39. seam_code-0.3.0/docs/prd/phase1b-confidence.md +92 -0
  40. seam_code-0.3.0/docs/prd/phase1b-go-rust.md +80 -0
  41. seam_code-0.3.0/docs/prd/phase1b-qa-hardening.md +79 -0
  42. seam_code-0.3.0/docs/prd/phase1b-seam-why.md +81 -0
  43. seam_code-0.3.0/docs/prd/phase2-clustering.md +170 -0
  44. seam_code-0.3.0/docs/prd/phase3-agent-interface.md +117 -0
  45. seam_code-0.3.0/docs/prd/phase4-node-enrichment.md +178 -0
  46. seam_code-0.3.0/docs/prd/phase5-import-resolution.md +254 -0
  47. seam_code-0.3.0/docs/prd/phase6-context-pack.md +193 -0
  48. seam_code-0.3.0/docs/prd/phase7-seam-sync.md +238 -0
  49. seam_code-0.3.0/docs/prd/phase8-lean-output.md +191 -0
  50. seam_code-0.3.0/docs/prd/phase9-language-expansion.md +195 -0
  51. seam_code-0.3.0/lessons.md +108 -0
  52. seam_code-0.3.0/memory/architecture/001-graph-model.md +11 -0
  53. seam_code-0.3.0/memory/decisions/001-language-python.md +9 -0
  54. seam_code-0.3.0/memory/learnings/.gitkeep +0 -0
  55. seam_code-0.3.0/memory/patterns/.gitkeep +0 -0
  56. seam_code-0.3.0/progress.txt +862 -0
  57. seam_code-0.3.0/pyproject.toml +128 -0
  58. seam_code-0.3.0/seam/__init__.py +3 -0
  59. seam_code-0.3.0/seam/_web/assets/index-BL_tqprR.js +216 -0
  60. seam_code-0.3.0/seam/_web/assets/index-GTKUhVyD.css +1 -0
  61. seam_code-0.3.0/seam/_web/index.html +13 -0
  62. seam_code-0.3.0/seam/analysis/__init__.py +14 -0
  63. seam_code-0.3.0/seam/analysis/affected.py +254 -0
  64. seam_code-0.3.0/seam/analysis/builtins.py +966 -0
  65. seam_code-0.3.0/seam/analysis/byte_budget.py +217 -0
  66. seam_code-0.3.0/seam/analysis/changes.py +709 -0
  67. seam_code-0.3.0/seam/analysis/cluster_naming.py +260 -0
  68. seam_code-0.3.0/seam/analysis/clustering.py +216 -0
  69. seam_code-0.3.0/seam/analysis/confidence.py +699 -0
  70. seam_code-0.3.0/seam/analysis/embeddings.py +195 -0
  71. seam_code-0.3.0/seam/analysis/flows.py +708 -0
  72. seam_code-0.3.0/seam/analysis/impact.py +444 -0
  73. seam_code-0.3.0/seam/analysis/imports.py +994 -0
  74. seam_code-0.3.0/seam/analysis/imports_ext.py +780 -0
  75. seam_code-0.3.0/seam/analysis/imports_resolve.py +176 -0
  76. seam_code-0.3.0/seam/analysis/processes.py +453 -0
  77. seam_code-0.3.0/seam/analysis/relevance.py +155 -0
  78. seam_code-0.3.0/seam/analysis/rwr.py +129 -0
  79. seam_code-0.3.0/seam/analysis/staleness.py +328 -0
  80. seam_code-0.3.0/seam/analysis/steer.py +282 -0
  81. seam_code-0.3.0/seam/analysis/synthesis.py +253 -0
  82. seam_code-0.3.0/seam/analysis/synthesis_channels.py +433 -0
  83. seam_code-0.3.0/seam/analysis/testpaths.py +103 -0
  84. seam_code-0.3.0/seam/analysis/traversal.py +470 -0
  85. seam_code-0.3.0/seam/cli/__init__.py +0 -0
  86. seam_code-0.3.0/seam/cli/install.py +232 -0
  87. seam_code-0.3.0/seam/cli/main.py +2602 -0
  88. seam_code-0.3.0/seam/cli/output.py +137 -0
  89. seam_code-0.3.0/seam/cli/read.py +244 -0
  90. seam_code-0.3.0/seam/cli/serve.py +145 -0
  91. seam_code-0.3.0/seam/config.py +551 -0
  92. seam_code-0.3.0/seam/indexer/__init__.py +0 -0
  93. seam_code-0.3.0/seam/indexer/cluster_index.py +425 -0
  94. seam_code-0.3.0/seam/indexer/db.py +496 -0
  95. seam_code-0.3.0/seam/indexer/embedding_index.py +183 -0
  96. seam_code-0.3.0/seam/indexer/field_access.py +536 -0
  97. seam_code-0.3.0/seam/indexer/field_access_c_cpp.py +643 -0
  98. seam_code-0.3.0/seam/indexer/field_access_ext.py +708 -0
  99. seam_code-0.3.0/seam/indexer/field_access_ext2.py +408 -0
  100. seam_code-0.3.0/seam/indexer/field_access_go_rust.py +737 -0
  101. seam_code-0.3.0/seam/indexer/field_access_php_swift.py +888 -0
  102. seam_code-0.3.0/seam/indexer/field_access_ts.py +626 -0
  103. seam_code-0.3.0/seam/indexer/graph.py +321 -0
  104. seam_code-0.3.0/seam/indexer/graph_c.py +562 -0
  105. seam_code-0.3.0/seam/indexer/graph_c_cpp.py +39 -0
  106. seam_code-0.3.0/seam/indexer/graph_common.py +644 -0
  107. seam_code-0.3.0/seam/indexer/graph_cpp.py +615 -0
  108. seam_code-0.3.0/seam/indexer/graph_csharp.py +651 -0
  109. seam_code-0.3.0/seam/indexer/graph_go.py +723 -0
  110. seam_code-0.3.0/seam/indexer/graph_go_rust.py +39 -0
  111. seam_code-0.3.0/seam/indexer/graph_java.py +689 -0
  112. seam_code-0.3.0/seam/indexer/graph_java_csharp.py +38 -0
  113. seam_code-0.3.0/seam/indexer/graph_php.py +914 -0
  114. seam_code-0.3.0/seam/indexer/graph_python.py +628 -0
  115. seam_code-0.3.0/seam/indexer/graph_ruby.py +748 -0
  116. seam_code-0.3.0/seam/indexer/graph_rust.py +653 -0
  117. seam_code-0.3.0/seam/indexer/graph_scope_infer.py +902 -0
  118. seam_code-0.3.0/seam/indexer/graph_scope_infer_ext.py +723 -0
  119. seam_code-0.3.0/seam/indexer/graph_scope_infer_ext2.py +992 -0
  120. seam_code-0.3.0/seam/indexer/graph_swift.py +1014 -0
  121. seam_code-0.3.0/seam/indexer/graph_swift_infer.py +515 -0
  122. seam_code-0.3.0/seam/indexer/graph_typescript.py +663 -0
  123. seam_code-0.3.0/seam/indexer/migrations.py +816 -0
  124. seam_code-0.3.0/seam/indexer/parser.py +204 -0
  125. seam_code-0.3.0/seam/indexer/pipeline.py +197 -0
  126. seam_code-0.3.0/seam/indexer/signatures.py +634 -0
  127. seam_code-0.3.0/seam/indexer/signatures_ext.py +780 -0
  128. seam_code-0.3.0/seam/indexer/sync.py +287 -0
  129. seam_code-0.3.0/seam/indexer/synthesis_index.py +291 -0
  130. seam_code-0.3.0/seam/indexer/tokenize.py +79 -0
  131. seam_code-0.3.0/seam/installer/__init__.py +67 -0
  132. seam_code-0.3.0/seam/installer/claude.py +97 -0
  133. seam_code-0.3.0/seam/installer/codex.py +94 -0
  134. seam_code-0.3.0/seam/installer/core.py +127 -0
  135. seam_code-0.3.0/seam/installer/cursor.py +61 -0
  136. seam_code-0.3.0/seam/installer/guide.py +110 -0
  137. seam_code-0.3.0/seam/installer/jsonfile.py +85 -0
  138. seam_code-0.3.0/seam/installer/markdownfile.py +146 -0
  139. seam_code-0.3.0/seam/installer/tomlfile.py +72 -0
  140. seam_code-0.3.0/seam/query/__init__.py +0 -0
  141. seam_code-0.3.0/seam/query/clusters.py +206 -0
  142. seam_code-0.3.0/seam/query/comments.py +217 -0
  143. seam_code-0.3.0/seam/query/context.py +293 -0
  144. seam_code-0.3.0/seam/query/engine.py +940 -0
  145. seam_code-0.3.0/seam/query/fts.py +328 -0
  146. seam_code-0.3.0/seam/query/names.py +470 -0
  147. seam_code-0.3.0/seam/query/pack.py +433 -0
  148. seam_code-0.3.0/seam/query/semantic.py +339 -0
  149. seam_code-0.3.0/seam/query/structure.py +727 -0
  150. seam_code-0.3.0/seam/server/__init__.py +0 -0
  151. seam_code-0.3.0/seam/server/graph_api.py +437 -0
  152. seam_code-0.3.0/seam/server/handler_common.py +323 -0
  153. seam_code-0.3.0/seam/server/impact_handler.py +615 -0
  154. seam_code-0.3.0/seam/server/mcp.py +556 -0
  155. seam_code-0.3.0/seam/server/tools.py +697 -0
  156. seam_code-0.3.0/seam/server/trace_handler.py +184 -0
  157. seam_code-0.3.0/seam/server/web.py +922 -0
  158. seam_code-0.3.0/seam/watcher/__init__.py +0 -0
  159. seam_code-0.3.0/seam/watcher/__main__.py +56 -0
  160. seam_code-0.3.0/seam/watcher/daemon.py +237 -0
  161. seam_code-0.3.0/tests/__init__.py +0 -0
  162. seam_code-0.3.0/tests/eval/__init__.py +1 -0
  163. seam_code-0.3.0/tests/eval/eval_report.py +165 -0
  164. seam_code-0.3.0/tests/eval/fixtures/dispatcher.py +51 -0
  165. seam_code-0.3.0/tests/eval/fixtures/interfaces.py +57 -0
  166. seam_code-0.3.0/tests/eval/fixtures/pipeline.py +53 -0
  167. seam_code-0.3.0/tests/eval/fixtures/utils.py +37 -0
  168. seam_code-0.3.0/tests/eval/gen_golden.py +247 -0
  169. seam_code-0.3.0/tests/eval/golden.json +189 -0
  170. seam_code-0.3.0/tests/eval/recall_harness.py +176 -0
  171. seam_code-0.3.0/tests/eval/test_metrics.py +288 -0
  172. seam_code-0.3.0/tests/eval/test_recall_regression.py +478 -0
  173. seam_code-0.3.0/tests/fixtures/sample.c +54 -0
  174. seam_code-0.3.0/tests/fixtures/sample.cpp +81 -0
  175. seam_code-0.3.0/tests/fixtures/sample.cs +93 -0
  176. seam_code-0.3.0/tests/fixtures/sample.go +51 -0
  177. seam_code-0.3.0/tests/fixtures/sample.java +90 -0
  178. seam_code-0.3.0/tests/fixtures/sample.php +80 -0
  179. seam_code-0.3.0/tests/fixtures/sample.py +47 -0
  180. seam_code-0.3.0/tests/fixtures/sample.rb +38 -0
  181. seam_code-0.3.0/tests/fixtures/sample.rs +58 -0
  182. seam_code-0.3.0/tests/fixtures/sample.swift +71 -0
  183. seam_code-0.3.0/tests/fixtures/sample.ts +59 -0
  184. seam_code-0.3.0/tests/integration/__init__.py +0 -0
  185. seam_code-0.3.0/tests/integration/test_affected_handler.py +329 -0
  186. seam_code-0.3.0/tests/integration/test_changes.py +552 -0
  187. seam_code-0.3.0/tests/integration/test_cli_e4_surface.py +536 -0
  188. seam_code-0.3.0/tests/integration/test_cli_impact_max_bytes.py +498 -0
  189. seam_code-0.3.0/tests/integration/test_cli_json.py +401 -0
  190. seam_code-0.3.0/tests/integration/test_cli_read.py +95 -0
  191. seam_code-0.3.0/tests/integration/test_cluster_index.py +607 -0
  192. seam_code-0.3.0/tests/integration/test_clusters_handler.py +252 -0
  193. seam_code-0.3.0/tests/integration/test_composition_holds_edges_go_rust_integration.py +266 -0
  194. seam_code-0.3.0/tests/integration/test_composition_holds_edges_integration.py +238 -0
  195. seam_code-0.3.0/tests/integration/test_composition_holds_edges_java_cs_cpp_ruby_php_integration.py +397 -0
  196. seam_code-0.3.0/tests/integration/test_composition_holds_edges_swift_integration.py +189 -0
  197. seam_code-0.3.0/tests/integration/test_embedding_index.py +348 -0
  198. seam_code-0.3.0/tests/integration/test_field_access_integration_c_cpp.py +400 -0
  199. seam_code-0.3.0/tests/integration/test_field_access_integration_go_rust.py +516 -0
  200. seam_code-0.3.0/tests/integration/test_field_access_integration_java_csharp.py +496 -0
  201. seam_code-0.3.0/tests/integration/test_field_access_integration_python_ts.py +723 -0
  202. seam_code-0.3.0/tests/integration/test_field_access_integration_ruby_php_swift.py +627 -0
  203. seam_code-0.3.0/tests/integration/test_flows_cli.py +88 -0
  204. seam_code-0.3.0/tests/integration/test_flows_handler.py +95 -0
  205. seam_code-0.3.0/tests/integration/test_impact_handler.py +279 -0
  206. seam_code-0.3.0/tests/integration/test_impact_relevance.py +248 -0
  207. seam_code-0.3.0/tests/integration/test_impact_summary_parity.py +328 -0
  208. seam_code-0.3.0/tests/integration/test_indexer.py +128 -0
  209. seam_code-0.3.0/tests/integration/test_inheritance_impact.py +84 -0
  210. seam_code-0.3.0/tests/integration/test_init_gitignore.py +69 -0
  211. seam_code-0.3.0/tests/integration/test_install_cli.py +160 -0
  212. seam_code-0.3.0/tests/integration/test_lean_parity.py +322 -0
  213. seam_code-0.3.0/tests/integration/test_mcp_error_contract.py +129 -0
  214. seam_code-0.3.0/tests/integration/test_mcp_tools.py +326 -0
  215. seam_code-0.3.0/tests/integration/test_migration_v12.py +242 -0
  216. seam_code-0.3.0/tests/integration/test_migration_v5.py +526 -0
  217. seam_code-0.3.0/tests/integration/test_migration_v6.py +414 -0
  218. seam_code-0.3.0/tests/integration/test_migration_v7.py +321 -0
  219. seam_code-0.3.0/tests/integration/test_migration_v9.py +150 -0
  220. seam_code-0.3.0/tests/integration/test_no_mcp_profile.py +42 -0
  221. seam_code-0.3.0/tests/integration/test_p4_barrel_reexport.py +313 -0
  222. seam_code-0.3.0/tests/integration/test_pack_homonym.py +236 -0
  223. seam_code-0.3.0/tests/integration/test_pack_parity.py +218 -0
  224. seam_code-0.3.0/tests/integration/test_phase4_read_layer.py +462 -0
  225. seam_code-0.3.0/tests/integration/test_phase5_e2e_homonym.py +417 -0
  226. seam_code-0.3.0/tests/integration/test_phase5_import_promotion.py +483 -0
  227. seam_code-0.3.0/tests/integration/test_phase5_read_layer.py +184 -0
  228. seam_code-0.3.0/tests/integration/test_qa_hardening_wiring.py +263 -0
  229. seam_code-0.3.0/tests/integration/test_seam_why_handler.py +160 -0
  230. seam_code-0.3.0/tests/integration/test_semantic_engine.py +347 -0
  231. seam_code-0.3.0/tests/integration/test_semantic_surfaces.py +525 -0
  232. seam_code-0.3.0/tests/integration/test_serve_cli.py +120 -0
  233. seam_code-0.3.0/tests/integration/test_staleness_banner.py +369 -0
  234. seam_code-0.3.0/tests/integration/test_sync_cli.py +366 -0
  235. seam_code-0.3.0/tests/integration/test_sync_clusters.py +269 -0
  236. seam_code-0.3.0/tests/integration/test_synthesis_channels_integration.py +362 -0
  237. seam_code-0.3.0/tests/integration/test_synthesis_integration.py +237 -0
  238. seam_code-0.3.0/tests/integration/test_tier_a.py +537 -0
  239. seam_code-0.3.0/tests/integration/test_tier_a_slice4.py +428 -0
  240. seam_code-0.3.0/tests/integration/test_tier_b3.py +308 -0
  241. seam_code-0.3.0/tests/integration/test_trace_handler.py +389 -0
  242. seam_code-0.3.0/tests/integration/test_watcher.py +156 -0
  243. seam_code-0.3.0/tests/integration/test_web_api.py +531 -0
  244. seam_code-0.3.0/tests/unit/__init__.py +0 -0
  245. seam_code-0.3.0/tests/unit/test_affected.py +254 -0
  246. seam_code-0.3.0/tests/unit/test_b5_infer_remaining_families.py +957 -0
  247. seam_code-0.3.0/tests/unit/test_b6_instantiates_edges.py +905 -0
  248. seam_code-0.3.0/tests/unit/test_bare_method_resolution.py +168 -0
  249. seam_code-0.3.0/tests/unit/test_builtins.py +266 -0
  250. seam_code-0.3.0/tests/unit/test_byte_budget.py +385 -0
  251. seam_code-0.3.0/tests/unit/test_c_cpp.py +954 -0
  252. seam_code-0.3.0/tests/unit/test_changes_partial.py +195 -0
  253. seam_code-0.3.0/tests/unit/test_cluster_naming.py +242 -0
  254. seam_code-0.3.0/tests/unit/test_clustering.py +260 -0
  255. seam_code-0.3.0/tests/unit/test_clustering_migration.py +306 -0
  256. seam_code-0.3.0/tests/unit/test_composition_holds_edges.py +464 -0
  257. seam_code-0.3.0/tests/unit/test_composition_holds_edges_go_rust.py +488 -0
  258. seam_code-0.3.0/tests/unit/test_composition_holds_edges_java_cs_cpp_ruby_php.py +858 -0
  259. seam_code-0.3.0/tests/unit/test_composition_holds_edges_swift.py +399 -0
  260. seam_code-0.3.0/tests/unit/test_confidence.py +302 -0
  261. seam_code-0.3.0/tests/unit/test_confidence_global.py +150 -0
  262. seam_code-0.3.0/tests/unit/test_confidence_phase5.py +273 -0
  263. seam_code-0.3.0/tests/unit/test_db.py +323 -0
  264. seam_code-0.3.0/tests/unit/test_embeddings.py +350 -0
  265. seam_code-0.3.0/tests/unit/test_entry_score.py +127 -0
  266. seam_code-0.3.0/tests/unit/test_field_access_c_cpp.py +533 -0
  267. seam_code-0.3.0/tests/unit/test_field_access_go_rust.py +791 -0
  268. seam_code-0.3.0/tests/unit/test_field_access_java_csharp.py +712 -0
  269. seam_code-0.3.0/tests/unit/test_field_access_python.py +562 -0
  270. seam_code-0.3.0/tests/unit/test_field_access_ruby_php.py +782 -0
  271. seam_code-0.3.0/tests/unit/test_field_access_swift.py +372 -0
  272. seam_code-0.3.0/tests/unit/test_field_access_typescript.py +500 -0
  273. seam_code-0.3.0/tests/unit/test_flows.py +456 -0
  274. seam_code-0.3.0/tests/unit/test_flows_global_confidence.py +210 -0
  275. seam_code-0.3.0/tests/unit/test_fts.py +511 -0
  276. seam_code-0.3.0/tests/unit/test_fts_tokenize.py +126 -0
  277. seam_code-0.3.0/tests/unit/test_go_rust.py +809 -0
  278. seam_code-0.3.0/tests/unit/test_graph.py +301 -0
  279. seam_code-0.3.0/tests/unit/test_graph_api.py +493 -0
  280. seam_code-0.3.0/tests/unit/test_handler_provenance.py +505 -0
  281. seam_code-0.3.0/tests/unit/test_hardening.py +193 -0
  282. seam_code-0.3.0/tests/unit/test_impact.py +436 -0
  283. seam_code-0.3.0/tests/unit/test_impact_default_production.py +253 -0
  284. seam_code-0.3.0/tests/unit/test_impact_is_test.py +351 -0
  285. seam_code-0.3.0/tests/unit/test_impact_max_bytes.py +582 -0
  286. seam_code-0.3.0/tests/unit/test_impact_omit_null_candidate.py +136 -0
  287. seam_code-0.3.0/tests/unit/test_impact_summary.py +523 -0
  288. seam_code-0.3.0/tests/unit/test_imports.py +493 -0
  289. seam_code-0.3.0/tests/unit/test_inheritance_edges.py +159 -0
  290. seam_code-0.3.0/tests/unit/test_installer.py +349 -0
  291. seam_code-0.3.0/tests/unit/test_java_csharp.py +1035 -0
  292. seam_code-0.3.0/tests/unit/test_lean_output.py +444 -0
  293. seam_code-0.3.0/tests/unit/test_names.py +664 -0
  294. seam_code-0.3.0/tests/unit/test_output.py +201 -0
  295. seam_code-0.3.0/tests/unit/test_p2_cluster_quality.py +407 -0
  296. seam_code-0.3.0/tests/unit/test_pack.py +497 -0
  297. seam_code-0.3.0/tests/unit/test_pack_relevance_rank.py +137 -0
  298. seam_code-0.3.0/tests/unit/test_param_uses_edges.py +151 -0
  299. seam_code-0.3.0/tests/unit/test_parser.py +110 -0
  300. seam_code-0.3.0/tests/unit/test_phase9_type_parity.py +84 -0
  301. seam_code-0.3.0/tests/unit/test_pipeline_walk.py +72 -0
  302. seam_code-0.3.0/tests/unit/test_processes.py +181 -0
  303. seam_code-0.3.0/tests/unit/test_provenance_threading.py +380 -0
  304. seam_code-0.3.0/tests/unit/test_query_clusters.py +383 -0
  305. seam_code-0.3.0/tests/unit/test_query_engine.py +400 -0
  306. seam_code-0.3.0/tests/unit/test_receiver_b1.py +383 -0
  307. seam_code-0.3.0/tests/unit/test_receiver_b2.py +819 -0
  308. seam_code-0.3.0/tests/unit/test_receiver_b3.py +311 -0
  309. seam_code-0.3.0/tests/unit/test_relevance.py +174 -0
  310. seam_code-0.3.0/tests/unit/test_review_fixes.py +611 -0
  311. seam_code-0.3.0/tests/unit/test_review_fixes_phase4.py +864 -0
  312. seam_code-0.3.0/tests/unit/test_review_fixes_phase5.py +403 -0
  313. seam_code-0.3.0/tests/unit/test_richer_edges.py +475 -0
  314. seam_code-0.3.0/tests/unit/test_ruby_php.py +1030 -0
  315. seam_code-0.3.0/tests/unit/test_rwr.py +101 -0
  316. seam_code-0.3.0/tests/unit/test_schema_packaging.py +25 -0
  317. seam_code-0.3.0/tests/unit/test_scope_infer_b4.py +649 -0
  318. seam_code-0.3.0/tests/unit/test_seam_why.py +799 -0
  319. seam_code-0.3.0/tests/unit/test_semantic.py +520 -0
  320. seam_code-0.3.0/tests/unit/test_semantic_hardening.py +669 -0
  321. seam_code-0.3.0/tests/unit/test_semantic_review_fixes.py +707 -0
  322. seam_code-0.3.0/tests/unit/test_signatures.py +573 -0
  323. seam_code-0.3.0/tests/unit/test_smoke.py +43 -0
  324. seam_code-0.3.0/tests/unit/test_staleness.py +405 -0
  325. seam_code-0.3.0/tests/unit/test_steer.py +472 -0
  326. seam_code-0.3.0/tests/unit/test_structure.py +982 -0
  327. seam_code-0.3.0/tests/unit/test_swift.py +853 -0
  328. seam_code-0.3.0/tests/unit/test_symbol_uid.py +215 -0
  329. seam_code-0.3.0/tests/unit/test_sync.py +663 -0
  330. seam_code-0.3.0/tests/unit/test_synthesis_channels.py +615 -0
  331. seam_code-0.3.0/tests/unit/test_synthesis_engine.py +401 -0
  332. seam_code-0.3.0/tests/unit/test_synthesis_index.py +244 -0
  333. seam_code-0.3.0/tests/unit/test_testpaths.py +196 -0
  334. seam_code-0.3.0/tests/unit/test_tokenize.py +80 -0
  335. seam_code-0.3.0/tests/unit/test_tools_split_regression.py +212 -0
  336. seam_code-0.3.0/tests/unit/test_traversal.py +416 -0
  337. seam_code-0.3.0/tests/unit/test_traversal_global_confidence.py +251 -0
  338. seam_code-0.3.0/tests/unit/test_web_packaging.py +43 -0
  339. seam_code-0.3.0/uv.lock +1980 -0
@@ -0,0 +1,13 @@
1
+ # Seam configuration — copy to .env, never commit .env
2
+ # All values shown are defaults. Seam works with zero config.
3
+
4
+ SEAM_LOG_LEVEL=INFO
5
+
6
+ # Override where the index database is stored (default: .seam/seam.db)
7
+ # SEAM_DB_PATH=.seam/seam.db
8
+
9
+ # File watcher debounce delay in milliseconds (default: 500)
10
+ # SEAM_WATCHER_DEBOUNCE_MS=500
11
+
12
+ # Maximum file size to index in bytes (default: 1MB)
13
+ # SEAM_MAX_FILE_BYTES=1048576
@@ -0,0 +1,66 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ .eggs/
11
+ *.whl
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # Testing / coverage
19
+ .pytest_cache/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+ htmlcov/
23
+ .coverage
24
+ coverage.xml
25
+
26
+ # Environment
27
+ .env
28
+
29
+ # Seam index (local per-project, not committed by default)
30
+ .seam/
31
+
32
+ # Built SPA — produced by `make build-web` / `cd web && npm run build`.
33
+ # Shipped inside the wheel via hatch artifacts config; not committed to git.
34
+ seam/_web/
35
+
36
+ # GitNexus index
37
+ .gitnexus/
38
+
39
+ # Competitor index artifacts (benchmark only — never committed)
40
+ .codegraph/
41
+ graphify-out/
42
+
43
+ # macOS
44
+ .DS_Store
45
+ .AppleDouble
46
+ .LSOverride
47
+
48
+ # IDE
49
+ .idea/
50
+ .vscode/
51
+ *.swp
52
+ *.swo
53
+
54
+ # Distribution
55
+ *.tar.gz
56
+ *.zip
57
+
58
+ # uv lockfile (commit uv.lock in production, optional here)
59
+ # uv.lock
60
+
61
+ .bach/
62
+ .claude/
63
+ .koda/
64
+
65
+ # QA artifacts (gstack /qa reports + screenshots) — local, not committed
66
+ .gstack/
@@ -0,0 +1,101 @@
1
+ <!-- gitnexus:start -->
2
+ # GitNexus — Code Intelligence
3
+
4
+ This project is indexed by GitNexus as **seam** (273 symbols, 293 relationships, 0 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
5
+
6
+ > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
7
+
8
+ ## Always Do
9
+
10
+ - **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
11
+ - **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
12
+ - **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
13
+ - When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
14
+ - When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
15
+
16
+ ## When Debugging
17
+
18
+ 1. `gitnexus_query({query: "<error or symptom>"})` — find execution flows related to the issue
19
+ 2. `gitnexus_context({name: "<suspect function>"})` — see all callers, callees, and process participation
20
+ 3. `READ gitnexus://repo/seam/process/{processName}` — trace the full execution flow step by step
21
+ 4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed
22
+
23
+ ## When Refactoring
24
+
25
+ - **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`.
26
+ - **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code.
27
+ - After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed.
28
+
29
+ ## Never Do
30
+
31
+ - NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
32
+ - NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
33
+ - NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
34
+ - NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
35
+
36
+ ## Tools Quick Reference
37
+
38
+ | Tool | When to use | Command |
39
+ |------|-------------|---------|
40
+ | `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` |
41
+ | `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` |
42
+ | `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` |
43
+ | `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` |
44
+ | `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` |
45
+ | `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` |
46
+
47
+ ## Impact Risk Levels
48
+
49
+ | Depth | Meaning | Action |
50
+ |-------|---------|--------|
51
+ | d=1 | WILL BREAK — direct callers/importers | MUST update these |
52
+ | d=2 | LIKELY AFFECTED — indirect deps | Should test |
53
+ | d=3 | MAY NEED TESTING — transitive | Test if critical path |
54
+
55
+ ## Resources
56
+
57
+ | Resource | Use for |
58
+ |----------|---------|
59
+ | `gitnexus://repo/seam/context` | Codebase overview, check index freshness |
60
+ | `gitnexus://repo/seam/clusters` | All functional areas |
61
+ | `gitnexus://repo/seam/processes` | All execution flows |
62
+ | `gitnexus://repo/seam/process/{name}` | Step-by-step execution trace |
63
+
64
+ ## Self-Check Before Finishing
65
+
66
+ Before completing any code modification task, verify:
67
+ 1. `gitnexus_impact` was run for all modified symbols
68
+ 2. No HIGH/CRITICAL risk warnings were ignored
69
+ 3. `gitnexus_detect_changes()` confirms changes match expected scope
70
+ 4. All d=1 (WILL BREAK) dependents were updated
71
+
72
+ ## Keeping the Index Fresh
73
+
74
+ After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it:
75
+
76
+ ```bash
77
+ npx gitnexus analyze
78
+ ```
79
+
80
+ If the index previously included embeddings, preserve them by adding `--embeddings`:
81
+
82
+ ```bash
83
+ npx gitnexus analyze --embeddings
84
+ ```
85
+
86
+ To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.**
87
+
88
+ > Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`.
89
+
90
+ ## CLI
91
+
92
+ | Task | Read this skill file |
93
+ |------|---------------------|
94
+ | Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
95
+ | Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
96
+ | Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
97
+ | Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
98
+ | Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
99
+ | Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
100
+
101
+ <!-- gitnexus:end -->
@@ -0,0 +1,151 @@
1
+ # App Flow — Seam (Phase 0)
2
+
3
+ > Agent interaction flows. Written from the AI agent's perspective.
4
+
5
+ ---
6
+
7
+ ## Flow 1: First-Time Setup (Developer)
8
+
9
+ ```
10
+ Developer opens a new project
11
+
12
+
13
+ $ seam init
14
+
15
+ ├── Walks directory tree
16
+ ├── Detects language per file (Python, TypeScript/JavaScript)
17
+ ├── Parses each file with tree-sitter
18
+ ├── Extracts: symbols (functions, classes, methods), edges (imports, calls)
19
+ ├── Writes to .seam/seam.db (SQLite + FTS5)
20
+ └── Prints summary: "Indexed 847 files, 12,304 symbols in 8.3s"
21
+
22
+
23
+ $ seam start
24
+
25
+ ├── Starts file watcher (background daemon)
26
+ ├── Starts MCP server (stdio transport)
27
+ └── MCP tools ready: seam_query, seam_context, seam_search
28
+ ```
29
+
30
+ **Developer then adds to their Claude Code MCP config:**
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "seam": {
35
+ "command": "seam",
36
+ "args": ["start", "--stdio"],
37
+ "cwd": "/path/to/project"
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Flow 2: Session Start (Agent)
46
+
47
+ ```
48
+ Agent receives task: "Add rate limiting to the API"
49
+
50
+
51
+ Agent uses seam_query("rate limiting middleware")
52
+
53
+ ├── FTS5 search: finds symbols named 'RateLimiter', 'throttle', etc.
54
+ ├── Graph search: finds symbols in same cluster as 'middleware'
55
+ └── Returns: [{symbol, file, line, snippet, callers_count, callees_count}]
56
+
57
+
58
+ Agent narrows to relevant symbol with seam_context("APIMiddleware")
59
+
60
+ ├── Returns: callers (what calls this), callees (what this calls)
61
+ ├── File location + line number
62
+ └── Docstring / comment if present
63
+
64
+
65
+ Agent has full picture before reading a single file
66
+ Ready to implement without exploration tax
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Flow 3: File Change (Auto-Sync)
72
+
73
+ ```
74
+ Developer saves auth/middleware.py
75
+
76
+
77
+ File watcher detects change (FSEvents/inotify)
78
+
79
+
80
+ Debounce 500ms (coalesce rapid saves)
81
+
82
+
83
+ Re-parse changed file with tree-sitter
84
+
85
+ ├── Diff: which symbols added / removed / changed?
86
+ ├── Update seam.db (delete old, insert new)
87
+ └── Update FTS5 index for changed symbols
88
+
89
+
90
+ Index fresh — next seam_query returns updated results
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Flow 4: Finding a Symbol (Agent)
96
+
97
+ ```
98
+ Agent wants to understand how authentication works
99
+
100
+
101
+ seam_search("authenticate login token")
102
+
103
+ └── Returns: top-10 FTS5 matches with snippets
104
+ [{symbol: "authenticate_user", file: "auth/service.py:47", snippet: "..."}]
105
+
106
+
107
+ seam_context("authenticate_user")
108
+
109
+ └── Returns:
110
+ {
111
+ "symbol": "authenticate_user",
112
+ "file": "auth/service.py",
113
+ "line": 47,
114
+ "docstring": "Validates credentials and returns JWT token",
115
+ "callers": ["LoginHandler.post", "TestAuth.test_valid_login"],
116
+ "callees": ["hash_password", "create_token", "UserRepository.find_by_email"]
117
+ }
118
+
119
+
120
+ Agent knows: WHERE it is, WHO calls it, WHAT it calls
121
+ No file reads needed to get this structural picture
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Flow 5: Status Check
127
+
128
+ ```
129
+ $ seam status
130
+
131
+ └── Prints:
132
+ Project: /Users/jordi/projects/bach
133
+ Database: .seam/seam.db (14.2 MB)
134
+ Indexed: 2026-06-01 14:23:01 (3 minutes ago)
135
+ Files: 1,247 | Symbols: 18,432 | Edges: 41,209
136
+ Languages: Python (892 files), TypeScript (355 files)
137
+ Watcher: running (PID 84201)
138
+ Status: FRESH
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Error States
144
+
145
+ | State | User sees | What happens |
146
+ |---|---|---|
147
+ | Unsupported file type | Silently skipped | Added to .seam/ignored.log |
148
+ | Parse error (malformed file) | Warning in seam status | Skipped, rest of index proceeds |
149
+ | seam.db locked (concurrent write) | Retry with backoff | Automatic, transparent |
150
+ | File watcher loses connection | Warning + restart | Auto-restart with exponential backoff |
151
+ | Symbol not found | `{"results": [], "message": "No results for 'X'"}` | Empty results, not an error |
@@ -0,0 +1,253 @@
1
+ # Backend Structure — Seam
2
+
3
+ > This is the authoritative module map. Every new file must fit this structure.
4
+ > Seam has no frontend. All code is in the `seam/` Python package.
5
+
6
+ ---
7
+
8
+ ## Package Layout
9
+
10
+ ```
11
+ seam/ ← Python package root
12
+ ├── __init__.py ← Version + public API surface
13
+ ├── config.py ← All settings (from env via os.getenv)
14
+ │ SEAM_LANGUAGE_MAP: .py→python, .ts/.tsx→typescript,
15
+ │ .js/.mjs/.cjs→javascript, .go→go, .rs→rust
16
+
17
+ ├── cli/ ← CLI entry points (Typer)
18
+ │ ├── __init__.py
19
+ │ └── main.py ← app = typer.Typer(); init, start, status
20
+
21
+ ├── analysis/ ← Read-only graph reasoning + community detection
22
+ │ ├── __init__.py
23
+ │ ├── clustering.py ← LEAF: pure-Python Louvain community detection
24
+ │ │ detect_communities(nodes, edges) → {name: cluster_id}
25
+ │ │ No SQLite, no I/O, no config. Deterministic.
26
+ │ └── cluster_naming.py ← LEAF: cluster label generation
27
+ │ deterministic_label(members) → str (always available)
28
+ │ label_cluster(members, naming_mode, ...) → (label, source)
29
+ │ Opt-in LLM path via stdlib urllib only. Never raises.
30
+
31
+ ├── indexer/ ← Parse → extract → store pipeline
32
+ │ ├── __init__.py
33
+ │ ├── parser.py ← tree-sitter parsing per language
34
+ │ │ parse_python, parse_typescript, parse_javascript,
35
+ │ │ parse_go, parse_rust — all delegate to _parse()
36
+ │ ├── graph_common.py ← LEAF: shared TypedDicts, constants, helpers
37
+ │ │ Symbol, Edge, Comment, Confidence; _text, _node_name,
38
+ │ │ _make_symbol, _match_marker, _block_comment_lines,
39
+ │ │ _find_enclosing_function, _go_recv_type_name,
40
+ │ │ _rust_impl_type_name. Imports stdlib + tree_sitter only.
41
+ │ ├── graph_go_rust.py ← Go + Rust extractors (imports graph_common only)
42
+ │ │ _extract_symbols_go/rust, _extract_edges_go/rust,
43
+ │ │ _extract_comments_go/rust, doc-comment helpers
44
+ │ ├── graph.py ← Python + TypeScript dispatchers; re-exports public types
45
+ │ │ from graph_common; imports Go/Rust extractors from
46
+ │ │ graph_go_rust. Public API: extract_symbols, extract_edges,
47
+ │ │ extract_comments.
48
+ │ ├── pipeline.py ← Shared parse→extract→upsert path (CLI + watcher)
49
+ │ ├── cluster_index.py ← Clustering orchestration (indexer layer bridge)
50
+ │ │ index_clusters(conn, ...) → int (cluster count or -1)
51
+ │ │ Reads DB → detect_communities → label_cluster → writes
52
+ │ │ clusters table + symbols.cluster_id in one transaction.
53
+ │ │ Called by seam init only; watcher never calls this.
54
+ │ └── db.py ← SQLite write operations (schema + upsert)
55
+
56
+ ├── watcher/ ← OS file watcher
57
+ │ ├── __init__.py
58
+ │ └── daemon.py ← watchdog EventHandler; debounced re-index
59
+
60
+ ├── server/ ← MCP server
61
+ │ ├── __init__.py
62
+ │ ├── mcp.py ← MCP server setup (stdio transport)
63
+ │ └── tools.py ← seam_query, seam_context, seam_search implementations
64
+
65
+ └── query/ ← Query engine (read path)
66
+ ├── __init__.py
67
+ ├── engine.py ← FTS5 + graph traversal queries; context() enriched
68
+ │ with cluster_id, cluster_label, cluster_peers (Phase 2)
69
+ └── clusters.py ← Read-only cluster queries (Phase 2)
70
+ list_clusters(conn) → [{id, label, size}]
71
+ cluster_members(conn, id) → [{name, file, line, kind}]
72
+ cluster_peers(conn, symbol) → (id, label, peers) | None
73
+ Guards pre-v4 indexes (returns empty + one-time warning).
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Layer Rules (Import Hierarchy)
79
+
80
+ ```
81
+ cli/ → server/ → analysis/ → query/ → indexer/db
82
+ ↓ ↑
83
+ └─→ indexer/cluster_index → analysis/clustering + analysis/cluster_naming
84
+
85
+ watcher/ → indexer/
86
+ ```
87
+
88
+ Within `indexer/`, the import order is strictly:
89
+ ```
90
+ graph_common (leaf — stdlib + tree_sitter only)
91
+ ↑ ↑
92
+ graph_go_rust graph.py (both import from graph_common; graph.py also imports graph_go_rust)
93
+
94
+ graph.py (dispatchers + re-exports)
95
+
96
+ pipeline.py
97
+
98
+ analysis/clustering (leaf — stdlib only, no seam imports)
99
+ analysis/cluster_naming (leaf — stdlib only, no seam imports)
100
+
101
+ indexer/cluster_index (bridge: imports analysis + db)
102
+ ```
103
+
104
+ | Layer | Can import from | Cannot import from |
105
+ |---|---|---|
106
+ | `cli/` | server, analysis, indexer, watcher, config | — |
107
+ | `server/` | analysis, query, config | cli, watcher |
108
+ | `analysis/` (non-clustering) | indexer.db, query, config | cli, server |
109
+ | `analysis/clustering` | stdlib only | any seam module (leaf) |
110
+ | `analysis/cluster_naming` | stdlib only | any seam module (leaf) |
111
+ | `indexer/cluster_index` | analysis.clustering, analysis.cluster_naming, indexer.db, config | cli, server, query, watcher |
112
+ | `query/` | indexer.db, config | cli, server, analysis, watcher |
113
+ | `indexer/pipeline` | indexer.db, indexer.graph, indexer.parser, config | cli, server, query, analysis, watcher |
114
+ | `indexer/graph` | graph_common, graph_go_rust, config | cli, server, query, analysis, watcher |
115
+ | `indexer/graph_go_rust` | graph_common only | graph.py or any other seam module |
116
+ | `indexer/graph_common` | stdlib, tree_sitter only | any seam module (leaf) |
117
+ | `indexer/parser` | config, tree_sitter grammars | any seam indexer sub-module |
118
+ | `indexer/db` | config | cli, server, query, analysis, watcher |
119
+ | `watcher/` | indexer, config | cli, server, query, analysis |
120
+ | `config` | stdlib only | anything in seam/ |
121
+
122
+ ---
123
+
124
+ ## Module Responsibilities
125
+
126
+ ### `seam/config.py`
127
+ - Reads all config from `os.getenv()` with defaults
128
+ - Exports: `SEAM_DB_PATH`, `SEAM_LOG_LEVEL`, `SEAM_DEBOUNCE_MS`, `SEAM_MAX_FILE_BYTES`,
129
+ `SEAM_CLUSTER_NAMING`, `SEAM_LLM_API_KEY`, `SEAM_LLM_MODEL`, `SEAM_CLUSTER_MIN_SIZE`
130
+ - Never import from other seam modules (avoids circular imports)
131
+
132
+ ### `seam/analysis/clustering.py` (leaf — Phase 2)
133
+ - `detect_communities(nodes, edges) → dict[str, int]` — pure Louvain community detection
134
+ - No SQLite, no file I/O, no config. Input: node names + edge pairs. Output: {name: cluster_id}.
135
+ - Deterministic: nodes processed in sorted order, tie-breaking by community label.
136
+ - Never raises: falls back to singleton clusters on any internal error.
137
+
138
+ ### `seam/analysis/cluster_naming.py` (leaf — Phase 2)
139
+ - `deterministic_label(members) → str` — derive label from dominant dir + highest-degree symbol
140
+ - `label_cluster(members, naming_mode, api_key, model) → (label, naming_source)` — dispatch
141
+ - Opt-in LLM path (`_call_llm_for_label`) uses stdlib urllib only, is isolated, and is
142
+ never called unless `naming_mode="llm"` AND `api_key` is set.
143
+ - Any LLM error falls back to deterministic silently — never raises.
144
+
145
+ ### `seam/indexer/cluster_index.py` (Phase 2)
146
+ - `index_clusters(conn, naming_mode, llm_api_key, llm_model, min_size) → int`
147
+ — orchestrates: read symbols+edges → detect_communities → label_cluster → write DB
148
+ - Returns cluster count (≥0) or -1 on error (never raises).
149
+ - Called by `seam init` ONLY, never by the watcher.
150
+ - Clears old cluster state first (even before early returns) to avoid ghost clusters.
151
+
152
+ ### `seam/indexer/parser.py`
153
+ - One function per language: `parse_python`, `parse_typescript`, `parse_javascript`,
154
+ `parse_go`, `parse_rust` — all delegate to the internal `_parse(path, language)` helper.
155
+ - Returns raw tree-sitter root Node for graph.py to interpret.
156
+ - Handles encoding, binary files, and parse errors gracefully. Never raises.
157
+
158
+ ### `seam/indexer/graph_common.py` (leaf — Phase 1b addition)
159
+ - Shared TypedDicts: `Symbol`, `Edge`, `Comment`; type alias: `Confidence`
160
+ - Shared constants: `SEMANTIC_MARKERS`, `_MARKER_RE`
161
+ - Shared helpers: `_text`, `_node_name`, `_make_symbol`, `_match_marker`,
162
+ `_block_comment_lines`, `_arrow_function_name`, `_find_enclosing_function`
163
+ - Go/Rust receiver helpers: `_go_recv_type_name`, `_rust_impl_type_name`
164
+ (kept here so `_find_enclosing_function` can call them without importing from
165
+ graph_go_rust — this is what maintains the leaf property)
166
+ - MUST remain a leaf: imports stdlib and tree_sitter only.
167
+
168
+ ### `seam/indexer/graph_go_rust.py` (Phase 1b addition)
169
+ - Go extractors: `_extract_symbols_go`, `_extract_edges_go`, `_extract_comments_go`
170
+ - Rust extractors: `_extract_symbols_rust`, `_extract_edges_rust`, `_extract_comments_rust`
171
+ - Doc-comment helpers: `_go_doc_comment`, `_rust_doc_comment`
172
+ - Imports from `graph_common` only — never from `graph.py`.
173
+
174
+ ### `seam/indexer/graph.py`
175
+ - Public API: `extract_symbols(node, language, filepath) → list[Symbol]`
176
+ - Public API: `extract_edges(node, language, filepath, symbols) → list[Edge]`
177
+ - Public API: `extract_comments(node, language, filepath) → list[Comment]`
178
+ - Python + TypeScript/JavaScript extractors live here.
179
+ - Go + Rust extractors are delegated to graph_go_rust.py (imported at top level).
180
+ - Re-exports `Symbol`, `Edge`, `Comment`, `Confidence` from graph_common so callers
181
+ using `from seam.indexer.graph import Symbol` continue to work unchanged.
182
+ - Symbol: `{name, kind, file, start_line, end_line, docstring}`
183
+ - Edge: `{source, target, kind, file, line, confidence}`
184
+
185
+ ### `seam/indexer/db.py`
186
+ - `init_db(db_path) → Connection` — create schema if not exists
187
+ - `upsert_file(conn, filepath, symbols, edges)` — atomic file update
188
+ - `delete_file(conn, filepath)` — remove all data for a file
189
+ - Never holds long-lived connections; pass conn as parameter
190
+
191
+ ### `seam/query/engine.py`
192
+ - `query(conn, concept, limit) → list[QueryResult]` — FTS5 + graph hybrid
193
+ - `context(conn, symbol_name) → ContextResult` — callers + callees + metadata +
194
+ cluster_id, cluster_label, cluster_peers (Phase 2 enrichment via query/clusters.py)
195
+ - `search(conn, text, limit) → list[SearchResult]` — FTS5 full-text
196
+
197
+ ### `seam/query/clusters.py` (Phase 2)
198
+ - `list_clusters(conn) → list[ClusterRow]` — all clusters sorted by id
199
+ - `cluster_members(conn, cluster_id) → list[MemberRow]` — symbols in one cluster
200
+ - `cluster_peers(conn, symbol) → (cluster_id, label, peers) | None` — cluster context
201
+ - Guards pre-v4 indexes (no table/column): returns empty results + one-time warning.
202
+ Mirrors the `_comments_table_exists` guard in `query/comments.py`.
203
+
204
+ ### `seam/server/tools.py`
205
+ - Thin adapter: MCP tool handlers that call query.engine functions
206
+ - Input validation only — no business logic
207
+ - Returns MCP-compatible response format
208
+
209
+ ### `seam/watcher/daemon.py`
210
+ - `SeamWatcher(db_path, root_path)` — watchdog EventHandler subclass
211
+ - `on_modified(event)` — debounced re-index of changed file
212
+ - `start()` / `stop()` — manage Observer lifecycle
213
+
214
+ ---
215
+
216
+ ## File Naming Conventions
217
+
218
+ | Type | Convention | Example |
219
+ |---|---|---|
220
+ | Python files | snake_case | `user_service.py` |
221
+ | Python classes | PascalCase | `SeamWatcher` |
222
+ | Python functions | snake_case | `extract_symbols()` |
223
+ | Python constants | UPPER_SNAKE_CASE | `SEAM_DB_PATH` |
224
+ | Test files | `test_<module>.py` | `test_parser.py` |
225
+ | Test classes | `Test<Feature>` | `TestPythonParser` |
226
+
227
+ ---
228
+
229
+ ## Tests Layout
230
+
231
+ ```
232
+ tests/
233
+ ├── unit/ ← Pure function tests; no I/O
234
+ │ ├── test_parser.py ← parse_python, parse_typescript
235
+ │ ├── test_graph.py ← extract_symbols, extract_edges
236
+ │ └── test_query_engine.py ← query, context, search (in-memory SQLite)
237
+
238
+ ├── integration/ ← Tests that hit real SQLite + file system
239
+ │ ├── test_indexer.py ← Full index pipeline
240
+ │ └── test_watcher.py ← Watcher → re-index cycle
241
+
242
+ └── fixtures/ ← Sample source files for parser tests
243
+ ├── sample.py ← Python with functions, classes, imports
244
+ └── sample.ts ← TypeScript with functions, interfaces
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Max Size Rules
250
+
251
+ - Max 200 lines per function (from global CLAUDE.md)
252
+ - Max 1000 lines per file (from global CLAUDE.md)
253
+ - If a module exceeds 1000 lines, split into `_module_part_a.py` + `_module_part_b.py` and re-export from `module.py`