coderadar-rs 0.9.3__tar.gz → 0.9.4__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 (180) hide show
  1. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/Cargo.lock +3 -3
  2. coderadar_rs-0.9.4/Cargo.toml +10 -0
  3. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/PKG-INFO +19 -10
  4. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/README.md +15 -9
  5. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/Cargo.toml +3 -1
  6. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/cold_start.rs +3 -3
  7. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/persistence.rs +8 -17
  8. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/persistence_tests.rs +23 -3
  9. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/lib.rs +107 -25
  10. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/storage.rs +285 -12
  11. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/__init__.py +1 -1
  12. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/cli.py +10 -1
  13. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/pyproject.toml +5 -1
  14. coderadar_rs-0.9.3/Cargo.toml +0 -8
  15. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/LICENSE +0 -0
  16. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/bash.scm +0 -0
  17. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/c.scm +0 -0
  18. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/clojure.scm +0 -0
  19. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/cmake.scm +0 -0
  20. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/cpp.scm +0 -0
  21. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/csharp.scm +0 -0
  22. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/dart.scm +0 -0
  23. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/dockerfile.scm +0 -0
  24. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/elisp.scm +0 -0
  25. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/elixir.scm +0 -0
  26. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/erlang.scm +0 -0
  27. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/fsharp.scm +0 -0
  28. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/go.scm +0 -0
  29. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/graphql.scm +0 -0
  30. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/groovy.scm +0 -0
  31. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/haskell.scm +0 -0
  32. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/hcl.scm +0 -0
  33. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/java.scm +0 -0
  34. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/javascript.scm +0 -0
  35. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/julia.scm +0 -0
  36. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/kotlin.scm +0 -0
  37. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/lua.scm +0 -0
  38. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/nix.scm +0 -0
  39. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/objc.scm +0 -0
  40. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/ocaml.scm +0 -0
  41. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/perl.scm +0 -0
  42. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/php.scm +0 -0
  43. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/powershell.scm +0 -0
  44. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/protobuf.scm +0 -0
  45. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/python.scm +0 -0
  46. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/r.scm +0 -0
  47. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/ruby.scm +0 -0
  48. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/rust.scm +0 -0
  49. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/scala.scm +0 -0
  50. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/shell.scm +0 -0
  51. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/sql.scm +0 -0
  52. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/swift.scm +0 -0
  53. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/systemverilog.scm +0 -0
  54. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/typescript.scm +0 -0
  55. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/verilog.scm +0 -0
  56. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/queries/zig.scm +0 -0
  57. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/clones/apted.rs +0 -0
  58. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/clones/lsh_index.rs +0 -0
  59. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/clones/minhash.rs +0 -0
  60. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/clones/mod.rs +0 -0
  61. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/clones/tokens.rs +0 -0
  62. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/decorators.rs +0 -0
  63. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/docstring.rs +0 -0
  64. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/mod.rs +0 -0
  65. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/single_pass.rs +0 -0
  66. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/spans.rs +0 -0
  67. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/tagger.rs +0 -0
  68. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/extract/walker.rs +0 -0
  69. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/fs/git.rs +0 -0
  70. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/fs/mod.rs +0 -0
  71. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/fs/watcher.rs +0 -0
  72. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/call_graph.rs +0 -0
  73. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/centrality.rs +0 -0
  74. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/cfg.rs +0 -0
  75. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/config.rs +0 -0
  76. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/deadcode/entry_points.rs +0 -0
  77. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/deadcode/mod.rs +0 -0
  78. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/deadcode/reachability.rs +0 -0
  79. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/embeddings.rs +0 -0
  80. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/import_graph.rs +0 -0
  81. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/indexing.rs +0 -0
  82. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/inheritance.rs +0 -0
  83. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/mod.rs +0 -0
  84. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/module_resolution.rs +0 -0
  85. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/mro.rs +0 -0
  86. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/projection_ops.rs +0 -0
  87. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/resolve_calls.rs +0 -0
  88. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/rta_lite.rs +0 -0
  89. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/call_graph_tests.rs +0 -0
  90. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/embedding_tests.rs +0 -0
  91. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/import_graph_tests.rs +0 -0
  92. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/indexing_tests.rs +0 -0
  93. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/inheritance_tests.rs +0 -0
  94. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/mod.rs +0 -0
  95. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/mro_tests.rs +0 -0
  96. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/projection_tests.rs +0 -0
  97. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/query_compile_tests.rs +0 -0
  98. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/tests/traversal_tests.rs +0 -0
  99. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/graph/traversal.rs +0 -0
  100. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/mutation/edit.rs +0 -0
  101. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/mutation/indent.rs +0 -0
  102. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/mutation/mod.rs +0 -0
  103. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/mutation/write_guard.rs +0 -0
  104. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/query/exec.rs +0 -0
  105. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/query/grammar.pest +0 -0
  106. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/query/grammar.rs +0 -0
  107. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/query/mod.rs +0 -0
  108. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/resolve/cache.rs +0 -0
  109. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/resolve/import_graph.rs +0 -0
  110. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/resolve/mod.rs +0 -0
  111. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/resolve/orchestrator.rs +0 -0
  112. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/resolve/signature.rs +0 -0
  113. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/scaffold/mod.rs +0 -0
  114. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/scaffold/secrets.rs +0 -0
  115. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/scoring/mod.rs +0 -0
  116. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/const_eval.rs +0 -0
  117. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/engine.rs +0 -0
  118. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/metrics.rs +0 -0
  119. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/mod.rs +0 -0
  120. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/profile.rs +0 -0
  121. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rule.rs +0 -0
  122. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/brain_method.rs +0 -0
  123. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/data_class.rs +0 -0
  124. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/dead_branch.rs +0 -0
  125. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/dead_code.rs +0 -0
  126. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/deep_nesting.rs +0 -0
  127. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/excessive_returns.rs +0 -0
  128. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/god_class.rs +0 -0
  129. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/high_cyclomatic_complexity.rs +0 -0
  130. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/intra_dead_statements.rs +0 -0
  131. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/long_method.rs +0 -0
  132. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/long_parameter_list.rs +0 -0
  133. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/mod.rs +0 -0
  134. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/rules/too_many_fields.rs +0 -0
  135. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/smells/types.rs +0 -0
  136. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/types.rs +0 -0
  137. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/core_indexer/src/update/wal.rs +0 -0
  138. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/agent/__init__.py +0 -0
  139. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/agent/graphrag.py +0 -0
  140. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/coldstart.py +0 -0
  141. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/config.py +0 -0
  142. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/embedding/__init__.py +0 -0
  143. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/embedding/dedup.py +0 -0
  144. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/excludes.py +0 -0
  145. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/lsp/__init__.py +0 -0
  146. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/lsp/pool.py +0 -0
  147. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/__init__.py +0 -0
  148. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/lazy.py +0 -0
  149. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/lifecycle.py +0 -0
  150. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/roots.py +0 -0
  151. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/server.py +0 -0
  152. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mcp/startup.py +0 -0
  153. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mutation/__init__.py +0 -0
  154. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/mutation/tool_router.py +0 -0
  155. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/project_state.py +0 -0
  156. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/query/__init__.py +0 -0
  157. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/query/cache.py +0 -0
  158. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/query/executor.py +0 -0
  159. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/query/planner.py +0 -0
  160. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/__init__.py +0 -0
  161. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/actix.py +0 -0
  162. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/aspnet.py +0 -0
  163. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/base.py +0 -0
  164. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/django.py +0 -0
  165. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/exports.py +0 -0
  166. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/express.py +0 -0
  167. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/fastapi.py +0 -0
  168. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/flask.py +0 -0
  169. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/go.py +0 -0
  170. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/laravel.py +0 -0
  171. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/nestjs.py +0 -0
  172. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/rails.py +0 -0
  173. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/reactrouter.py +0 -0
  174. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/resolution.py +0 -0
  175. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/springboot.py +0 -0
  176. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/resolvers/vuerouter.py +0 -0
  177. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/visualizers/__init__.py +0 -0
  178. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/visualizers/call_graph.py +0 -0
  179. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/visualizers/graphviz_viz.py +0 -0
  180. {coderadar_rs-0.9.3 → coderadar_rs-0.9.4}/py_agent/src/coderadar/visualizers/mermaid.py +0 -0
@@ -445,7 +445,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
445
445
 
446
446
  [[package]]
447
447
  name = "core_indexer"
448
- version = "0.9.3"
448
+ version = "0.9.4"
449
449
  dependencies = [
450
450
  "crossbeam-channel",
451
451
  "dashmap",
@@ -1640,9 +1640,9 @@ dependencies = [
1640
1640
 
1641
1641
  [[package]]
1642
1642
  name = "macrame-db"
1643
- version = "0.17.0"
1643
+ version = "0.18.0"
1644
1644
  source = "registry+https://github.com/rust-lang/crates.io-index"
1645
- checksum = "2e2a46b8789555136ad929e72df4ebb5b7cda21e8c6512dc45a1dec54ad2a54d"
1645
+ checksum = "6c07608eae01b1acf1fa71f739e92e9cc4c5ab90c8ebadc82b36eee500fd8a1d"
1646
1646
  dependencies = [
1647
1647
  "bincode",
1648
1648
  "libsql",
@@ -0,0 +1,10 @@
1
+ [workspace]
2
+ members = ["core_indexer"]
3
+ resolver = "2"
4
+
5
+ [workspace.package]
6
+ version = "0.9.4"
7
+ edition = "2021"
8
+ license = "MIT"
9
+ homepage = "https://github.com/opticsWolf/coderadar"
10
+ repository = "https://github.com/opticsWolf/coderadar"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coderadar-rs
3
- Version: 0.9.3
3
+ Version: 0.9.4
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -27,12 +27,15 @@ Provides-Extra: dev
27
27
  Provides-Extra: visualizers
28
28
  License-File: LICENSE
29
29
  Summary: Live semantic graph of your codebase — incremental, queryable, LLM-writable
30
+ Home-Page: https://github.com/opticsWolf/coderadar
30
31
  Author: CodeRadar Team
31
32
  License: MIT
32
33
  Requires-Python: >=3.10
33
34
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
35
+ Project-URL: Homepage, https://github.com/opticsWolf/coderadar
36
+ Project-URL: Repository, https://github.com/opticsWolf/coderadar
34
37
 
35
- # CodeRadar v0.9.2
38
+ # CodeRadar v0.9.4
36
39
 
37
40
  [![CI](https://github.com/opticsWolf/coderadar/actions/workflows/ci.yml/badge.svg)](https://github.com/opticsWolf/coderadar/actions/workflows/ci.yml)
38
41
  [![PyPI](https://img.shields.io/pypi/v/coderadar-rs?label=pypi)](https://pypi.org/project/coderadar-rs/)
@@ -41,6 +44,8 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
41
44
  [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
42
45
  [![Languages](https://img.shields.io/badge/languages-41-brightgreen)]()
43
46
 
47
+ [Homepage](https://github.com/opticsWolf/coderadar) · [Repository](https://github.com/opticsWolf/coderadar)
48
+
44
49
  **Live semantic graph of your codebase — incremental, queryable, LLM-writable.**
45
50
 
46
51
  CodeRadar maintains an incrementally updatable graph of your code's logical structure, enabling LLMs and developer tools to both **query** and **safely rewrite** code through a unified pipeline.
@@ -89,7 +94,7 @@ Rust Core (ProjectedGraph, Tree-sitter 41-lang, Parallel Extraction,
89
94
  | Metric | Value |
90
95
  |--------|-------|
91
96
  | **Languages indexed** | 41 (12 Tier 1, 29 Tier 2, 330+ Tier 3) |
92
- | **Tests** | 1128 (369 Rust + 759 Python) |
97
+ | **Tests** | 1139 passing (372 Rust + 767 Python; 1 Python skipped) |
93
98
  | **MCP Tools** | 22 — 17 `codegraph_*` (explore, search, node, affected, query, search_similar, compute_embeddings, module_children, as_of, traverse, get_smells, dead_code, find_clones, find_scaffolding, reindex, update_file, set_project) + 5 `coderadar_*` (resolve, replace_body, update_signature, rename, create_entity) |
94
99
  | **Query surface** | Pest structural + Macrame agent traversals + vector search |
95
100
  | **Frameworks** | Django, Flask, FastAPI, Go, Actix, Express, Spring Boot, Laravel, ASP.NET, Rails, NestJS, Vue Router, React Router |
@@ -335,13 +340,17 @@ cold-start design in [`docs/v0.8-p1-cold-start-design.md`](docs/v0.8-p1-cold-sta
335
340
  - **Shell-friendly entity IDs (E7).** Stored IDs keep OS-native separators (FK stability);
336
341
  display renders forward slashes with the redundant `./` dropped, and every pasted variant
337
342
  resolves back to the stored key.
338
- - **macrame-db 0.17 (schema v19, auto-rungs v15→v19 on open).** Builders for the now-`#[non_exhaustive]`
339
- `ConceptUpsert`, `Vec<EdgeBelief>` replay folds, distinct `BulkInterrupted`
340
- reporting, and `Database::analyze()` planner statistics after the bulk flush.
341
- Two perf fixes fell out: the ledger-revision stamp reads `MAX(seq_id)` instead
342
- of a full `reconstruct` fold (1.7 s → 0.08 s per analyze on a large log), and
343
- content-hash-gated upserts make no-op analyzes write zero rows (see
344
- [`docs/macrame-0.15-upgrade-notes.md`](docs/macrame-0.15-upgrade-notes.md)).
343
+ - **macrame-db 0.18 (schema v21, auto-rungs v15→v21 on open).** CodeRadar stores
344
+ compact namespaced metadata (`kind`, `file_path`, `content_hash`) in
345
+ `concepts.extra`, indexes the file path for precise stale-row cleanup, and
346
+ gives framework edges stable namespaced kinds such as
347
+ `synthetic:django:handles` instead of flattening their types. This is a
348
+ forward-only database upgrade: a 0.17 binary cannot open v21 or fold a
349
+ concept written by 0.18. Existing 0.17 concept content remains canonical and
350
+ is rewritten with `extra` on the next analyze. Existing no-op-write filtering
351
+ and the `MAX(seq_id)` ledger-revision stamp remain in place; see the
352
+ [integration notes](docs/macrame-0.18-integration.md) for the adopted fields
353
+ and the KV deferral.
345
354
 
346
355
  ## v0.8.1–v0.8.14 Highlights — the dogfood batch
347
356
 
@@ -1,4 +1,4 @@
1
- # CodeRadar v0.9.2
1
+ # CodeRadar v0.9.4
2
2
 
3
3
  [![CI](https://github.com/opticsWolf/coderadar/actions/workflows/ci.yml/badge.svg)](https://github.com/opticsWolf/coderadar/actions/workflows/ci.yml)
4
4
  [![PyPI](https://img.shields.io/pypi/v/coderadar-rs?label=pypi)](https://pypi.org/project/coderadar-rs/)
@@ -7,6 +7,8 @@
7
7
  [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
8
  [![Languages](https://img.shields.io/badge/languages-41-brightgreen)]()
9
9
 
10
+ [Homepage](https://github.com/opticsWolf/coderadar) · [Repository](https://github.com/opticsWolf/coderadar)
11
+
10
12
  **Live semantic graph of your codebase — incremental, queryable, LLM-writable.**
11
13
 
12
14
  CodeRadar maintains an incrementally updatable graph of your code's logical structure, enabling LLMs and developer tools to both **query** and **safely rewrite** code through a unified pipeline.
@@ -55,7 +57,7 @@ Rust Core (ProjectedGraph, Tree-sitter 41-lang, Parallel Extraction,
55
57
  | Metric | Value |
56
58
  |--------|-------|
57
59
  | **Languages indexed** | 41 (12 Tier 1, 29 Tier 2, 330+ Tier 3) |
58
- | **Tests** | 1128 (369 Rust + 759 Python) |
60
+ | **Tests** | 1139 passing (372 Rust + 767 Python; 1 Python skipped) |
59
61
  | **MCP Tools** | 22 — 17 `codegraph_*` (explore, search, node, affected, query, search_similar, compute_embeddings, module_children, as_of, traverse, get_smells, dead_code, find_clones, find_scaffolding, reindex, update_file, set_project) + 5 `coderadar_*` (resolve, replace_body, update_signature, rename, create_entity) |
60
62
  | **Query surface** | Pest structural + Macrame agent traversals + vector search |
61
63
  | **Frameworks** | Django, Flask, FastAPI, Go, Actix, Express, Spring Boot, Laravel, ASP.NET, Rails, NestJS, Vue Router, React Router |
@@ -301,13 +303,17 @@ cold-start design in [`docs/v0.8-p1-cold-start-design.md`](docs/v0.8-p1-cold-sta
301
303
  - **Shell-friendly entity IDs (E7).** Stored IDs keep OS-native separators (FK stability);
302
304
  display renders forward slashes with the redundant `./` dropped, and every pasted variant
303
305
  resolves back to the stored key.
304
- - **macrame-db 0.17 (schema v19, auto-rungs v15→v19 on open).** Builders for the now-`#[non_exhaustive]`
305
- `ConceptUpsert`, `Vec<EdgeBelief>` replay folds, distinct `BulkInterrupted`
306
- reporting, and `Database::analyze()` planner statistics after the bulk flush.
307
- Two perf fixes fell out: the ledger-revision stamp reads `MAX(seq_id)` instead
308
- of a full `reconstruct` fold (1.7 s → 0.08 s per analyze on a large log), and
309
- content-hash-gated upserts make no-op analyzes write zero rows (see
310
- [`docs/macrame-0.15-upgrade-notes.md`](docs/macrame-0.15-upgrade-notes.md)).
306
+ - **macrame-db 0.18 (schema v21, auto-rungs v15→v21 on open).** CodeRadar stores
307
+ compact namespaced metadata (`kind`, `file_path`, `content_hash`) in
308
+ `concepts.extra`, indexes the file path for precise stale-row cleanup, and
309
+ gives framework edges stable namespaced kinds such as
310
+ `synthetic:django:handles` instead of flattening their types. This is a
311
+ forward-only database upgrade: a 0.17 binary cannot open v21 or fold a
312
+ concept written by 0.18. Existing 0.17 concept content remains canonical and
313
+ is rewritten with `extra` on the next analyze. Existing no-op-write filtering
314
+ and the `MAX(seq_id)` ledger-revision stamp remain in place; see the
315
+ [integration notes](docs/macrame-0.18-integration.md) for the adopted fields
316
+ and the KV deferral.
311
317
 
312
318
  ## v0.8.1–v0.8.14 Highlights — the dogfood batch
313
319
 
@@ -3,6 +3,8 @@ name = "core_indexer"
3
3
  version.workspace = true
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
+ homepage.workspace = true
7
+ repository.workspace = true
6
8
 
7
9
  [lib]
8
10
  name = "core_indexer"
@@ -23,7 +25,7 @@ xxhash-rust = { version = "0.8", features = ["xxh3"] }
23
25
  git2 = { version = "0.21" }
24
26
  zstd = "0.13"
25
27
  # slotmap and arc-swap removed in v3.5 — replaced by HashMap<String, Arc<T>> + RwLock
26
- macrame-db = "0.17"
28
+ macrame-db = "0.18"
27
29
  tokio = { version = "1", features = ["rt-multi-thread"] }
28
30
  pest = "2.7"
29
31
  pest_derive = "2.7"
@@ -208,7 +208,7 @@ fn restore_synthetic_edges(
208
208
  state: &MaterializedState,
209
209
  stats: &mut ColdStartStats,
210
210
  ) {
211
- // Defensive (source, target, kind) triple dedup. macrame 0.15 enforces
211
+ // Defensive (source, target, kind) triple dedup. macrame 0.15+ enforces
212
212
  // a single open interval per triple, so duplicates are impossible in
213
213
  // practice; the guard stays cheap in case legacy rows ever appear.
214
214
  let mut seen: HashSet<(String, String, String)> = HashSet::new();
@@ -428,12 +428,12 @@ mod tests {
428
428
  for c in &concepts {
429
429
  map.insert(
430
430
  c.id.clone(),
431
- // macrame 0.17: NodeAttributes is #[non_exhaustive]
431
+ // macrame 0.17+: NodeAttributes is #[non_exhaustive]
432
432
  // (embedding_model defaults None, as before).
433
433
  NodeAttributes::new(c.id.clone(), c.title.clone(), c.content.clone()),
434
434
  );
435
435
  }
436
- // macrame 0.17: MaterializedState is #[non_exhaustive] —
436
+ // macrame 0.17+: MaterializedState is #[non_exhaustive] —
437
437
  // assemble from empty(); fields stay pub and assignable.
438
438
  let mut state = MaterializedState::empty("2026-02-08T00:00:00.000000Z");
439
439
  state.seq_anchor = 42;
@@ -316,19 +316,11 @@ impl CodeGraph {
316
316
  // Persist to Macrame if store attached. Re-registering a synthetic
317
317
  // edge that is already open is skipped (same fact), otherwise the
318
318
  // re-run would abort on the single-open guard and the error would be
319
- // silently dropped below. Two boundary guards, both enforced here so
320
- // no caller can trip them:
321
- //
322
- // * macrame's edge-type validator accepts only `[A-Z0-9]+`, so an
323
- // underscore kind (`DEPENDS_ON`) would fail the whole
324
- // all-or-nothing batch and lose every edge in it. The underscore
325
- // is stripped at this boundary; the in-memory indices are
326
- // kind-agnostic, so nothing else changes.
327
- // * `links` has FKs to `concepts` on both endpoints, so edges whose
328
- // endpoints are not persisted concepts (e.g. `django:route:...`
329
- // route nodes) cannot be asserted; the batch drops the failing
330
- // write rather than failing the registration (best-effort, as
331
- // before).
319
+ // silently dropped below. Macrame 0.18 accepts namespaced kinds, so
320
+ // preserve the caller's semantic edge type rather than flattening it.
321
+ // `links` still has FKs to `concepts` on both endpoints, so edges whose
322
+ // endpoints are not persisted concepts (e.g. `django:route:...` route
323
+ // nodes) cannot be asserted; the batch drops those best-effort.
332
324
  if let Some(store) = self.store.as_ref() {
333
325
  let ts_now = crate::storage::now_iso8601();
334
326
  // Unreadable ledger → assert everything (the pre-existing
@@ -341,13 +333,12 @@ impl CodeGraph {
341
333
  .collect();
342
334
  let batch: Vec<_> = edges
343
335
  .iter()
344
- .map(|(source_id, target_id, kind)| {
345
- let kind = kind.replace('_', "");
346
- (source_id.clone(), target_id.clone(), kind)
347
- })
348
336
  .filter(|(source_id, target_id, kind)| {
349
337
  !open.contains(&edge_key(source_id, target_id, kind))
350
338
  })
339
+ .map(|(source_id, target_id, kind)| {
340
+ (source_id.clone(), target_id.clone(), kind.clone())
341
+ })
351
342
  .map(|(source_id, target_id, kind)| {
352
343
  macrame::graph::EdgeAssertion::new(
353
344
  source_id.as_str(),
@@ -528,10 +528,11 @@ fn synthetic_pairs_not_persisted_as_calls_and_stale_edges_retracted() {
528
528
  .map(|(_, _, k)| k)
529
529
  .collect()
530
530
  };
531
- // Register strips the underscore (macrame kinds are [A-Z0-9]+).
531
+ // Macrame 0.18 preserves the caller's edge-kind spelling, including
532
+ // underscores, instead of collapsing distinct kinds at this boundary.
532
533
  assert_eq!(
533
534
  kinds_for(&run_id, &combine_id),
534
- vec!["DEPENDSON".to_string()]
535
+ vec!["DEPENDS_ON".to_string()]
535
536
  );
536
537
  assert_eq!(kinds_for(&main_id, &run_id), vec!["CALLS".to_string()]);
537
538
 
@@ -556,7 +557,26 @@ fn synthetic_pairs_not_persisted_as_calls_and_stale_edges_retracted() {
556
557
  assert_eq!(retired, 1, "only the legacy synthetic-as-CALLS row closes");
557
558
  assert_eq!(
558
559
  kinds_for(&run_id, &combine_id),
559
- vec!["DEPENDSON".to_string()]
560
+ vec!["DEPENDS_ON".to_string()]
560
561
  );
561
562
  assert_eq!(kinds_for(&main_id, &run_id), vec!["CALLS".to_string()]);
562
563
  }
564
+
565
+ #[test]
566
+ fn namespaced_synthetic_edge_kind_is_persisted_verbatim() {
567
+ let (graph, _dir) = graph_with_temp_store();
568
+ index_source(&graph, "def handler(): pass\n", "views.py");
569
+ let source = "views.py::module";
570
+ let target = "views.py::handler";
571
+ graph
572
+ .register_synthetic_edge(source, target, "synthetic:django:handles")
573
+ .expect("register namespaced kind");
574
+
575
+ let store = graph.store.as_ref().unwrap();
576
+ let open = store
577
+ .open_edge_triples(&crate::storage::now_iso8601())
578
+ .expect("read open edges");
579
+ assert!(open
580
+ .iter()
581
+ .any(|(s, t, kind)| { s == source && t == target && kind == "synthetic:django:handles" }));
582
+ }
@@ -845,7 +845,7 @@ fn analyze(
845
845
  }
846
846
 
847
847
  fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> AnalyzeOutcome {
848
- use crate::types::Language;
848
+ use crate::types::{Language, ParseQuality};
849
849
  use std::fs;
850
850
 
851
851
  let config = active_config();
@@ -901,6 +901,10 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
901
901
  // reported plain success.
902
902
  let mut failures: Vec<String> = Vec::new();
903
903
  let mut panicked_workers: usize = 0;
904
+ // Reconcile absent ledger concepts only after a complete, clean scan. A
905
+ // walk, file-read, extraction, worker, or recovered-parse failure must
906
+ // never make good concepts look stale merely because source was missed.
907
+ let mut reconciliation_safe = root_path.is_dir();
904
908
  let mut all_concepts: Vec<macrame::ConceptUpsert> = Vec::new();
905
909
 
906
910
  if root_path.is_dir() {
@@ -915,7 +919,14 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
915
919
  for entry in project_walk(root, &config.project, extra_excludes) {
916
920
  match entry {
917
921
  Ok(entry) => {
918
- if !entry.file_type().map_or(false, |ft| ft.is_file()) {
922
+ let file_type = match entry.file_type() {
923
+ Some(file_type) => file_type,
924
+ None => {
925
+ reconciliation_safe = false;
926
+ continue;
927
+ }
928
+ };
929
+ if !file_type.is_file() {
919
930
  continue;
920
931
  }
921
932
  let path = entry.path();
@@ -931,26 +942,11 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
931
942
  if CodeGraph::ts_language(&language).is_none() {
932
943
  continue;
933
944
  }
934
- if let Ok(source) = fs::read_to_string(path) {
935
- // F14: mint the canonical id form at write time —
936
- // the walk's spelling embeds the root used (`.`
937
- // vs absolute), so it is normalized here.
938
- let canon = crate::graph::module_resolution::canonical_file_form(
939
- &path.to_string_lossy(),
940
- );
941
- tasks.push(FileTask {
942
- path: canon,
943
- source,
944
- language,
945
- });
946
- }
947
- } else {
948
- // Files without extension (Dockerfile, CMakeLists.txt)
949
- let language = Language::from_filename(&path.to_string_lossy());
950
- if language != Language::OtherTen
951
- && CodeGraph::ts_language(&language).is_some()
952
- {
953
- if let Ok(source) = fs::read_to_string(path) {
945
+ match fs::read_to_string(path) {
946
+ Ok(source) => {
947
+ // F14: mint the canonical id form at write time —
948
+ // the walk's spelling embeds the root used (`.`
949
+ // vs absolute), so it is normalized here.
954
950
  let canon = crate::graph::module_resolution::canonical_file_form(
955
951
  &path.to_string_lossy(),
956
952
  );
@@ -960,10 +956,41 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
960
956
  language,
961
957
  });
962
958
  }
959
+ Err(e) => {
960
+ reconciliation_safe = false;
961
+ failures.push(format!("{}: {e}", path.display()));
962
+ }
963
+ }
964
+ } else {
965
+ // Files without extension (Dockerfile, CMakeLists.txt)
966
+ let language = Language::from_filename(&path.to_string_lossy());
967
+ if language != Language::OtherTen
968
+ && CodeGraph::ts_language(&language).is_some()
969
+ {
970
+ match fs::read_to_string(path) {
971
+ Ok(source) => {
972
+ let canon =
973
+ crate::graph::module_resolution::canonical_file_form(
974
+ &path.to_string_lossy(),
975
+ );
976
+ tasks.push(FileTask {
977
+ path: canon,
978
+ source,
979
+ language,
980
+ });
981
+ }
982
+ Err(e) => {
983
+ reconciliation_safe = false;
984
+ failures.push(format!("{}: {e}", path.display()));
985
+ }
986
+ }
963
987
  }
964
988
  }
965
989
  }
966
- Err(_) => {} // permission errors etc.
990
+ Err(e) => {
991
+ reconciliation_safe = false;
992
+ failures.push(format!("project walk: {e}"));
993
+ }
967
994
  }
968
995
  }
969
996
 
@@ -1052,6 +1079,18 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
1052
1079
  let mut proj = (*graph.snapshot()).clone();
1053
1080
  for chunk_results in all_results {
1054
1081
  for (fragment, concepts) in chunk_results {
1082
+ // Tree-sitter can recover a partial projection from
1083
+ // malformed source without returning an extraction
1084
+ // error. Keep old ledger concepts until every file is
1085
+ // cleanly parsed; absence from a recovered AST is not
1086
+ // reliable evidence of deletion.
1087
+ if fragment
1088
+ .modules
1089
+ .values()
1090
+ .any(|module| module.parse_quality != ParseQuality::Clean)
1091
+ {
1092
+ reconciliation_safe = false;
1093
+ }
1055
1094
  let entity_count = fragment.functions.len()
1056
1095
  + fragment.classes.len()
1057
1096
  + fragment.imports.len()
@@ -1106,6 +1145,8 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
1106
1145
  // building them).
1107
1146
  {
1108
1147
  let mut projection = (*graph.snapshot()).clone();
1148
+ let mut current_concept_ids = HashSet::new();
1149
+ let mut concept_flush_succeeded = true;
1109
1150
  // Dotted-name resolution (resolve_imports, resolve_all_calls) is O(1)
1110
1151
  // per lookup once this suffix index is built; without it the cascade
1111
1152
  // scans every module per import (v0.8 P1: 8.3s of the 46s benchmark).
@@ -1119,7 +1160,11 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
1119
1160
  // Concept JSON v2 flush — post-cascade, pre-edge (FK order).
1120
1161
  if let Some(ref store) = graph.store {
1121
1162
  let v2 = crate::storage::build_v2_concepts_all(&projection);
1122
- let _ = store.upsert_concepts_bulk(&v2);
1163
+ current_concept_ids = v2.iter().map(|concept| concept.id.clone()).collect();
1164
+ if let Err(e) = store.upsert_concepts_bulk(&v2) {
1165
+ concept_flush_succeeded = false;
1166
+ eprintln!("[diag] v2 concept flush failed: {e:?}");
1167
+ }
1123
1168
  }
1124
1169
  // Persist resolved edges to Macrame store
1125
1170
  if let Err(e) = graph.persist_edges(&projection) {
@@ -1164,6 +1209,19 @@ fn analyze_inner(root: &str, create_store: bool, extra_excludes: &[String]) -> A
1164
1209
  Ok(_) => {}
1165
1210
  Err(e) => eprintln!("[diag] non-canonical retraction failed: {e:?}"),
1166
1211
  }
1212
+ // Retire stale canonical rows (notably line-addressed imports)
1213
+ // only when every source was walked/read/extracted and the v2
1214
+ // projection flush succeeded. Otherwise missing data in this
1215
+ // run is not evidence that a ledger concept was deleted.
1216
+ if reconciliation_safe && failures.is_empty() && concept_flush_succeeded {
1217
+ match store.retire_stale_file_concepts(&current_concept_ids) {
1218
+ Ok(n) if n > 0 => eprintln!(
1219
+ "[coderadar] retired {n} stale file concept(s) absent from the fresh index"
1220
+ ),
1221
+ Ok(_) => {}
1222
+ Err(e) => eprintln!("[diag] stale concept retraction failed: {e:?}"),
1223
+ }
1224
+ }
1167
1225
  // R2-2: edge retraction. The persist above is assert-only
1168
1226
  // and the concept retractions only close edges of removed
1169
1227
  // entities, so an edge whose endpoints both survive but
@@ -1337,7 +1395,31 @@ fn remove_file(file_path: &str) -> PyResult<PyObject> {
1337
1395
  // F14: remove by the canonical form or the walk-form entry is
1338
1396
  // never found (forward-slash input vs `\` -joined stored ids).
1339
1397
  let canonical = crate::graph::module_resolution::canonical_file_form(file_path);
1340
- let removed = graph.remove_file(&canonical);
1398
+ let mut removed = graph.remove_file(&canonical);
1399
+ // The in-memory projection may have lost track of concepts written by
1400
+ // an interrupted or older indexer. Use the indexed `extra.file_path`
1401
+ // metadata to retire any such current rows as part of file deletion.
1402
+ if let Some(store) = graph.store.as_ref() {
1403
+ match store.live_concept_ids_for_file(&canonical) {
1404
+ Ok(ledger_ids) => {
1405
+ let known: std::collections::HashSet<&str> =
1406
+ removed.iter().map(String::as_str).collect();
1407
+ let stale: Vec<String> = ledger_ids
1408
+ .into_iter()
1409
+ .filter(|id| !known.contains(id.as_str()))
1410
+ .collect();
1411
+ if !stale.is_empty() {
1412
+ match store.retire_entities(&stale) {
1413
+ Ok(_) => removed.extend(stale),
1414
+ Err(e) => eprintln!(
1415
+ "[diag] failed to retire stale concepts for {canonical}: {e:?}"
1416
+ ),
1417
+ }
1418
+ }
1419
+ }
1420
+ Err(e) => eprintln!("[diag] indexed concept lookup failed for {canonical}: {e:?}"),
1421
+ }
1422
+ }
1341
1423
  let dict = PyDict::new(py);
1342
1424
  dict.set_item("entities_removed", removed.len())?;
1343
1425
  dict.set_item("removed_ids", removed)?;