descry-codegraph 1.0.1__tar.gz → 1.1.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 (221) hide show
  1. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/CHANGELOG.md +50 -0
  2. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/CONTRACT.md +2 -2
  3. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/PKG-INFO +2 -2
  4. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/README.md +1 -1
  5. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/claude-skill/descry/references/cli-reference.md +2 -2
  6. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/claude-skill/descry/references/mcp-tools.md +2 -2
  7. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/docs/TOOLS.md +7 -5
  8. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/pi-extension/descry-cli.py +4 -2
  9. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/pi-extension/descry-tools.ts +4 -0
  10. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/pyproject.toml +1 -1
  11. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/__init__.py +1 -1
  12. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/cli.py +18 -3
  13. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/generate.py +16 -0
  14. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/handlers.py +191 -31
  15. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/mcp_server.py +12 -8
  16. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/resolver.py +101 -16
  17. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/rust_parser.py +65 -1
  18. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/web/server.py +6 -2
  19. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/README.md +20 -0
  20. descry_codegraph-1.1.0/tests/eval/results/search-after.json +510 -0
  21. descry_codegraph-1.1.0/tests/eval/results/search-before.json +510 -0
  22. descry_codegraph-1.1.0/tests/eval/search_eval.py +75 -0
  23. descry_codegraph-1.1.0/tests/eval/search_questions.json +400 -0
  24. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_cli.py +59 -0
  25. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_generate.py +383 -0
  26. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_handlers.py +172 -0
  27. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_interfaces.py +31 -1
  28. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_mcp.py +1 -1
  29. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_resolve_cache.py +46 -0
  30. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_web_server.py +10 -6
  31. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/.github/assets/01-landing.png +0 -0
  32. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/.github/workflows/ci.yml +0 -0
  33. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/.github/workflows/release.yml +0 -0
  34. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/.gitignore +0 -0
  35. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/AGENTS.md +0 -0
  36. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/LICENSE +0 -0
  37. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/SECURITY.md +0 -0
  38. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/THIRD-PARTY-NOTICES.md +0 -0
  39. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/claude-skill/README.md +0 -0
  40. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/claude-skill/descry/SKILL.md +0 -0
  41. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/claude-skill/descry/references/recipes.md +0 -0
  42. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/docs/CERTAINTY.md +0 -0
  43. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/docs/UPGRADING.md +0 -0
  44. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/justfile +0 -0
  45. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/pi-extension/README.md +0 -0
  46. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_answers.py +0 -0
  47. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_comments.py +0 -0
  48. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_env.py +0 -0
  49. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_files.py +0 -0
  50. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_graph.py +0 -0
  51. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_parse_cache.py +0 -0
  52. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_parsing.py +0 -0
  53. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_reads.py +0 -0
  54. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_stdlib.py +0 -0
  55. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/_streams.py +0 -0
  56. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/clang_parser.py +0 -0
  57. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/cross_lang.py +0 -0
  58. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/dart_parser.py +0 -0
  59. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/dotnet_parser.py +0 -0
  60. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/embeddings.py +0 -0
  61. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/git_history.py +0 -0
  62. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/go_parser.py +0 -0
  63. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/java_parser.py +0 -0
  64. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/php_parser.py +0 -0
  65. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/proto_parser.py +0 -0
  66. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/python_parser.py +0 -0
  67. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/query.py +0 -0
  68. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/ruby_parser.py +0 -0
  69. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/__init__.py +0 -0
  70. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapter.py +0 -0
  71. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/__init__.py +0 -0
  72. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/_empty_environment.json +0 -0
  73. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/_java_compat.init.gradle +0 -0
  74. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/clang.py +0 -0
  75. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/dart.py +0 -0
  76. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/dotnet.py +0 -0
  77. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/go.py +0 -0
  78. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/java.py +0 -0
  79. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/php.py +0 -0
  80. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/python.py +0 -0
  81. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/ruby.py +0 -0
  82. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/rust.py +0 -0
  83. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/adapters/typescript.py +0 -0
  84. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/cache.py +0 -0
  85. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/parser.py +0 -0
  86. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/pb2.py +0 -0
  87. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/scip/support.py +0 -0
  88. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/c.json +0 -0
  89. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/cpp.json +0 -0
  90. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/dart.json +0 -0
  91. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/dotnet.json +0 -0
  92. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/go.json +0 -0
  93. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/java.json +0 -0
  94. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/node.json +0 -0
  95. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/php.json +0 -0
  96. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/python.json +0 -0
  97. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/ruby.json +0 -0
  98. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/rust.json +0 -0
  99. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/stdlib/typescript.json +0 -0
  100. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/ts_parser.py +0 -0
  101. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/web/__init__.py +0 -0
  102. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/web/web/index.html +0 -0
  103. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/src/descry/web/web/style.css +0 -0
  104. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/__init__.py +0 -0
  105. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/conftest.py +0 -0
  106. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/__init__.py +0 -0
  107. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/compare.py +0 -0
  108. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/corpus.py +0 -0
  109. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/metrics.py +0 -0
  110. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/registry.py +0 -0
  111. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/results/results-descry.json +0 -0
  112. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/eval/results/results-ripgrep.json +0 -0
  113. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/fixtures/small_graph.json +0 -0
  114. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/Makefile +0 -0
  115. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/expected.json +0 -0
  116. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/io.c +0 -0
  117. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/io.h +0 -0
  118. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/main.c +0 -0
  119. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/c/order.c +0 -0
  120. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/cpp/Makefile +0 -0
  121. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/cpp/expected.json +0 -0
  122. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/cpp/main.cpp +0 -0
  123. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/cpp/models.hpp +0 -0
  124. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/cpp/reader.hpp +0 -0
  125. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/csharp/Gt.csproj +0 -0
  126. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/csharp/Io.cs +0 -0
  127. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/csharp/Models.cs +0 -0
  128. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/csharp/Program.cs +0 -0
  129. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/csharp/expected.json +0 -0
  130. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/dart/bin/main.dart +0 -0
  131. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/dart/expected.json +0 -0
  132. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/dart/lib/io.dart +0 -0
  133. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/dart/lib/models.dart +0 -0
  134. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/dart/pubspec.yaml +0 -0
  135. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/go/expected.json +0 -0
  136. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/go/go.mod +0 -0
  137. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/go/io.go +0 -0
  138. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/go/main.go +0 -0
  139. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/go/models.go +0 -0
  140. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/expected.json +0 -0
  141. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/Base.java +0 -0
  142. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/Io.java +0 -0
  143. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/Main.java +0 -0
  144. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/Order.java +0 -0
  145. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/Reader.java +0 -0
  146. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/java/src/gt/User.java +0 -0
  147. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/javascript/expected.json +0 -0
  148. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/javascript/package.json +0 -0
  149. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/javascript/src/io.js +0 -0
  150. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/javascript/src/main.js +0 -0
  151. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/javascript/src/models.js +0 -0
  152. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/php/composer.json +0 -0
  153. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/php/expected.json +0 -0
  154. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/php/src/Io.php +0 -0
  155. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/php/src/Models.php +0 -0
  156. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/php/src/main.php +0 -0
  157. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/app/__init__.py +0 -0
  158. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/app/io.py +0 -0
  159. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/app/main.py +0 -0
  160. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/app/models.py +0 -0
  161. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/expected.json +0 -0
  162. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/python/pyproject.toml +0 -0
  163. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/ruby/Gemfile +0 -0
  164. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/ruby/expected.json +0 -0
  165. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/ruby/lib/io.rb +0 -0
  166. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/ruby/lib/main.rb +0 -0
  167. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/ruby/lib/models.rb +0 -0
  168. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/rust/Cargo.toml +0 -0
  169. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/rust/expected.json +0 -0
  170. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/rust/src/io.rs +0 -0
  171. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/rust/src/main.rs +0 -0
  172. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/rust/src/models.rs +0 -0
  173. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/typescript/expected.json +0 -0
  174. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/typescript/package.json +0 -0
  175. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/typescript/src/io.ts +0 -0
  176. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/typescript/src/main.ts +0 -0
  177. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/ground_truth/typescript/src/models.ts +0 -0
  178. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_backtracking.py +0 -0
  179. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_clang_parser.py +0 -0
  180. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_config.py +0 -0
  181. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_cross_lang.py +0 -0
  182. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_dart_parser.py +0 -0
  183. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_docs.py +0 -0
  184. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_dotnet_parser.py +0 -0
  185. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_embeddings.py +0 -0
  186. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_git_history.py +0 -0
  187. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_go_parser.py +0 -0
  188. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_ground_truth.py +0 -0
  189. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_hardening.py +0 -0
  190. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_java_parser.py +0 -0
  191. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_non_regular_files.py +0 -0
  192. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_parse_cache.py +0 -0
  193. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_php_parser.py +0 -0
  194. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_query.py +0 -0
  195. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_ruby_parser.py +0 -0
  196. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip.py +0 -0
  197. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_cache.py +0 -0
  198. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_clang.py +0 -0
  199. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_dart.py +0 -0
  200. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_dotnet.py +0 -0
  201. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_go.py +0 -0
  202. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_java.py +0 -0
  203. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_php.py +0 -0
  204. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_scip_ruby.py +0 -0
  205. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_stdlib.py +0 -0
  206. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tests/test_written_through.py +0 -0
  207. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/docs/gen_tools.py +0 -0
  208. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/README.md +0 -0
  209. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/common.py +0 -0
  210. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_c.py +0 -0
  211. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_cpp.py +0 -0
  212. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_dart.py +0 -0
  213. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_dotnet.py +0 -0
  214. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_go.py +0 -0
  215. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_java.py +0 -0
  216. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_node.py +0 -0
  217. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_php.py +0 -0
  218. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_python.py +0 -0
  219. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_ruby.py +0 -0
  220. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_rust.py +0 -0
  221. {descry_codegraph-1.0.1 → descry_codegraph-1.1.0}/tools/stdlib/gen_typescript.py +0 -0
@@ -4,6 +4,56 @@ All notable changes to Descry will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [semver](https://semver.org/) from 1.0.0.
6
6
 
7
+ ## [1.1.0] — 2026-11-03
8
+
9
+ ### Added
10
+
11
+ - `callers` and `callees` take `exclude_tests` (CLI `--exclude-tests`, MCP
12
+ `exclude_tests`, web `?exclude_tests=true`), as `search` does.
13
+ - `status` answers `changed_since_index`: how many files the graph tracks
14
+ are newer than it or gone; every text answer's header says so
15
+ (`| 2 file(s) changed since index`).
16
+ - `descry index` logs its progress every 15 seconds while it parses and
17
+ while it resolves calls.
18
+
19
+ ### Changed
20
+
21
+ - Rust: `<X as Trait>::f(x)` calls `X`'s impl of `Trait::f`, the trait's
22
+ default body where the impl has none, and `<dyn Trait>::f(x)` is
23
+ `Trait::f(x)`; the callee was read from the trait's type arguments
24
+ (`Trait>::f`).
25
+ - Rust: a call on an element of a `vec![..]` a `let` binds reads what its
26
+ elements hold (`d[0].go()`).
27
+ - Search: the keyword side leaves out the words a question or prompt is
28
+ written with ("where", "which", "the", "function"), so a whole prompt
29
+ searches what it asks about; a search of such words alone is unchanged.
30
+ - Rust: glob re-exports that lead back round a cycle are walked once per
31
+ file: the walk that entered the cycle gives every module of it its answer.
32
+ - Search: while an embedding model load is under way (the MCP server's at
33
+ its start, or the one an index run begins), a search answers keyword-only
34
+ instead of waiting; a search that finds no load under way, as each CLI
35
+ command's, begins one and waits as before.
36
+
37
+ ## [1.0.2] — 2026-10-31
38
+
39
+ ### Fixed
40
+
41
+ - Rust glob re-exports (`pub use m::*`) that reach a module by several
42
+ routes, or lead back round a cycle, no longer make indexing exponential:
43
+ each name a glob brings, and each type alias, is looked up once per
44
+ file.
45
+ - Rust: `<Self>::f(x)` is read as `Self::f(x)`; it, and a crate-root path
46
+ `::f(x)` with an argument of a project type, stopped the index.
47
+ - Rust: indexing a nested `vec![vec![..]; n]` twice stopped the index.
48
+ - Rust: a `static` or `const` in a `quote!` template, its type written
49
+ with `#` interpolations, stopped the index.
50
+ - MCP: arguments a tool cannot read are refused naming what is wrong with
51
+ each (`terms: Field required`), not the field alone.
52
+ - CLI: without a terminal on stderr, loading the embedding model prints no
53
+ progress bars or Hugging Face Hub notices; `HF_HUB_DISABLE_PROGRESS_BARS`,
54
+ `HF_HUB_VERBOSITY` and `TRANSFORMERS_VERBOSITY` set by the user are kept.
55
+ - README: `[timeouts] index_minutes = 0` is no time limit.
56
+
7
57
  ## [1.0.1] — 2026-10-30
8
58
 
9
59
  ### Fixed
@@ -59,7 +59,7 @@ as its type (`limit=ten`) is `invalid` there too.
59
59
 
60
60
  | tool | parameters | answer |
61
61
  |---|---|---|
62
- | `callers`, `callees` | `symbol`, `limit`=20 | `symbol`, `total`, counts, `more` (counts), `callers` / `callees` (references) |
62
+ | `callers`, `callees` | `symbol`, `limit`=20, `exclude_tests`=false | `symbol`, `total`, counts, `more` (counts), `callers` / `callees` (references) |
63
63
  | `context` | `symbol`, `brief`, `full`, `expand_callees`, `deduplicate`, `depth`=1, `max_tokens`=2000, `callee_budget`=2000, `head_lines`, `max_output_tokens` | `symbol` (definition), `brief`; brief: `callers`, `callees` (counts); else `depth`, `callers`, `callees` (references), `callers_more`, `callees_more` (counts), `examples` (`file`, `line`, `candidates`), `members` (`id`, `name`, `line`, `tokens`), `tests`, `configs` (`id`, `line`, `type`), `omitted`, `truncated`; with `deduplicate`, a symbol shown before answers `symbol` and `repeated` only |
64
64
  | `flow` | `start`, `direction`=forward, `depth`=3, `target`, `inline_threshold`=100 | `start`, `direction`, `asked`, `depth`, `target`, `root` (tree: `id`, `name`, `type`, `tokens`, `file`, `line`, `kind`, `candidates`, `children`, `more`, `more_possible`, `seen`), `path_to_target`?, `cut`? |
65
65
  | `path` | `start`, `end`, `max_depth`=10, `direction`=forward | `status` (`found`, `not_found`, `timeout`), `start`, `end`, `direction`, `max_depth`, `hops` (`caller`, `callee` references, `file`, `line`) |
@@ -73,7 +73,7 @@ as its type (`limit=ten`) is `invalid` there too.
73
73
  | `churn` | `time_range`, `path_filter`, `limit`=20, `mode`=symbols, `exclude_generated`=true | `mode`, `time_range`, `path_filter`, `truncation_note`?, and `symbols`, `files`, `pairs` (with `file_level`?) or `message` |
74
74
  | `changes` | `commit_range`, `time_range`, `path_filter`, `show_callers`=true, `limit`=50 | `range`, `commits`, `files_count`, `symbols_count`, and `symbols` (with `callers`) or `changed_files`; or `message` |
75
75
  | `evolution` | `symbol`, `time_range`, `limit`=10, `show_diff`, `crate` | `node_id`, `mode` (`lines`, `file`), `truncation_note`?, `authors`, `commits` (`hash`, `date`, and in `lines` mode `added`, `removed`); or `message` |
76
- | `status` | — | `exists`, `age_str`, `age_hours`, `nodes`, `edges`, `languages`, `stale`, `error`, `scip` (`state`, `indexers`, `cached`), `embeddings` (`state`, `nodes`, `model`) |
76
+ | `status` | — | `exists`, `age_str`, `age_hours`, `nodes`, `edges`, `languages`, `stale`, `changed_since_index`, `error`, `scip` (`state`, `indexers`, `cached`), `embeddings` (`state`, `nodes`, `model`) |
77
77
  | `health` | — | `status`, `version`, `project_root`, `cache_dir`, `warm`, `max_depth` (the deepest a `flow` or `context` goes), `features`, `graph` |
78
78
  | `ensure` | `max_age_hours` | `action` (`ready`, `refreshed`, `generated`), `summary`, `graph` (status) |
79
79
  | `index` | `path`=. (not on the web, which always indexes the project root) | the graph's status after the run |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: descry-codegraph
3
- Version: 1.0.1
3
+ Version: 1.1.0
4
4
  Summary: Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis
5
5
  Project-URL: Homepage, https://github.com/06chaynes/descry
6
6
  Project-URL: Repository, https://github.com/06chaynes/descry
@@ -308,7 +308,7 @@ timeout = 30
308
308
  scip_minutes = 30 # per indexer; 0 = unlimited
309
309
  embedding_seconds = 60 # MCP and web answer `loading` past it; the CLI waits
310
310
  query_ms = 4000 # 0 = no time limit
311
- index_minutes = 30 # Timeout for `descry index` subprocess
311
+ index_minutes = 30 # Timeout for `descry index` subprocess; 0 = unlimited
312
312
 
313
313
  [query]
314
314
  max_depth = 3
@@ -247,7 +247,7 @@ timeout = 30
247
247
  scip_minutes = 30 # per indexer; 0 = unlimited
248
248
  embedding_seconds = 60 # MCP and web answer `loading` past it; the CLI waits
249
249
  query_ms = 4000 # 0 = no time limit
250
- index_minutes = 30 # Timeout for `descry index` subprocess
250
+ index_minutes = 30 # Timeout for `descry index` subprocess; 0 = unlimited
251
251
 
252
252
  [query]
253
253
  max_depth = 3
@@ -43,8 +43,8 @@ descry quick <symbol>
43
43
  ## Call graph
44
44
 
45
45
  ```bash
46
- descry callers <symbol> [--limit N] # default 20
47
- descry callees <symbol> [--limit N] # default 20
46
+ descry callers <symbol> [--limit N] [--exclude-tests] # default 20
47
+ descry callees <symbol> [--limit N] [--exclude-tests] # default 20
48
48
 
49
49
  descry flow <start>
50
50
  [--direction forward|backward] # default forward
@@ -35,8 +35,8 @@ This is descry's prompt-injection defense — preserve it when quoting.
35
35
  - `descry_quick(symbol, full=False, brief=False)` — search + context in one.
36
36
 
37
37
  ### Call graph
38
- - `descry_callers(symbol, limit=20)`
39
- - `descry_callees(symbol, limit=20)`
38
+ - `descry_callers(symbol, limit=20, exclude_tests=False)`
39
+ - `descry_callees(symbol, limit=20, exclude_tests=False)`
40
40
  - `descry_flow(start, direction="forward", depth=3, target=None, inline_threshold=100)`
41
41
  - `descry_path(start, end, max_depth=10, direction="forward")`
42
42
 
@@ -46,22 +46,23 @@ Check if the codebase graph exists and its freshness. Returns existence, age, an
46
46
 
47
47
  No parameters.
48
48
 
49
- Answer: `exists`, `age_str`, `age_hours`, `nodes`, `edges`, `languages`, `stale`, `error`, `scip` (`state`, `indexers`, `cached`), `embeddings` (`state`, `nodes`, `model`)
49
+ Answer: `exists`, `age_str`, `age_hours`, `nodes`, `edges`, `languages`, `stale`, `changed_since_index`, `error`, `scip` (`state`, `indexers`, `cached`), `embeddings` (`state`, `nodes`, `model`)
50
50
 
51
51
  MCP `descry_status`; web `GET /api/status`; CLI `usage: descry status [--json]`
52
52
 
53
53
  ## callers
54
54
 
55
- Find all functions/methods that call a given symbol. More reliable than grep for call relationships - distinguishes actual calls from definitions and comments. Use for impact analysis before refactoring or to understand usage patterns.
55
+ Find all functions/methods that call a given symbol. More reliable than grep for call relationships - distinguishes actual calls from definitions and comments. Use for impact analysis before refactoring or to understand usage patterns. Set exclude_tests=true to leave out test callers.
56
56
 
57
57
  | parameter | type | default |
58
58
  |---|---|---|
59
59
  | `symbol` | string | required |
60
60
  | `limit` | integer | 20 |
61
+ | `exclude_tests` | boolean | false |
61
62
 
62
63
  Answer: `symbol`, `total`, counts, `more` (counts), `callers` / `callees` (references)
63
64
 
64
- MCP `descry_callers`; web `GET /api/callers`; CLI `usage: descry callers [--json] [--limit LIMIT] symbol`
65
+ MCP `descry_callers`; web `GET /api/callers`; CLI `usage: descry callers [--json] [--limit LIMIT] [--exclude-tests] symbol`
65
66
 
66
67
  `descry callers load --json`:
67
68
 
@@ -91,16 +92,17 @@ MCP `descry_callers`; web `GET /api/callers`; CLI `usage: descry callers [--json
91
92
 
92
93
  ## callees
93
94
 
94
- Find what functions/methods a given symbol calls. Use for dependency analysis and understanding what a function relies on.
95
+ Find what functions/methods a given symbol calls. Use for dependency analysis and understanding what a function relies on. Set exclude_tests=true to leave out test callees.
95
96
 
96
97
  | parameter | type | default |
97
98
  |---|---|---|
98
99
  | `symbol` | string | required |
99
100
  | `limit` | integer | 20 |
101
+ | `exclude_tests` | boolean | false |
100
102
 
101
103
  Answer: `symbol`, `total`, counts, `more` (counts), `callers` / `callees` (references)
102
104
 
103
- MCP `descry_callees`; web `GET /api/callees`; CLI `usage: descry callees [--json] [--limit LIMIT] symbol`
105
+ MCP `descry_callees`; web `GET /api/callees`; CLI `usage: descry callees [--json] [--limit LIMIT] [--exclude-tests] symbol`
104
106
 
105
107
  `descry callees main --json`:
106
108
 
@@ -38,11 +38,13 @@ def main():
38
38
  p = subparsers.add_parser("callers")
39
39
  p.add_argument("--symbol", required=True)
40
40
  p.add_argument("--limit", type=int, default=20)
41
+ p.add_argument("--exclude-tests", action="store_true")
41
42
 
42
43
  # callees
43
44
  p = subparsers.add_parser("callees")
44
45
  p.add_argument("--symbol", required=True)
45
46
  p.add_argument("--limit", type=int, default=20)
47
+ p.add_argument("--exclude-tests", action="store_true")
46
48
 
47
49
  # context
48
50
  p = subparsers.add_parser("context")
@@ -157,9 +159,9 @@ async def dispatch(args):
157
159
  elif cmd == "status":
158
160
  return await service.status()
159
161
  elif cmd == "callers":
160
- return await service.callers(args.symbol, args.limit)
162
+ return await service.callers(args.symbol, args.limit, args.exclude_tests)
161
163
  elif cmd == "callees":
162
- return await service.callees(args.symbol, args.limit)
164
+ return await service.callees(args.symbol, args.limit, args.exclude_tests)
163
165
  elif cmd == "context":
164
166
  return await service.context(
165
167
  args.symbol,
@@ -124,10 +124,12 @@ export default function (pi: ExtensionAPI) {
124
124
  parameters: Type.Object({
125
125
  symbol: Type.String({ description: "A node ID, or a symbol name" }),
126
126
  limit: Type.Optional(Type.Number({ description: "Max results", default: 20 })),
127
+ exclude_tests: Type.Optional(Type.Boolean({ description: "Exclude test files", default: false })),
127
128
  }),
128
129
  async execute(_toolCallId, params, signal) {
129
130
  const args = ["--symbol", params.symbol];
130
131
  if (params.limit !== undefined) args.push("--limit", String(params.limit));
132
+ if (params.exclude_tests) args.push("--exclude-tests");
131
133
  const result = await runDescry("callers", args, signal);
132
134
  return { content: [{ type: "text", text: result }] };
133
135
  },
@@ -142,10 +144,12 @@ export default function (pi: ExtensionAPI) {
142
144
  parameters: Type.Object({
143
145
  symbol: Type.String({ description: "A node ID, or a symbol name" }),
144
146
  limit: Type.Optional(Type.Number({ description: "Max results", default: 20 })),
147
+ exclude_tests: Type.Optional(Type.Boolean({ description: "Exclude test files", default: false })),
145
148
  }),
146
149
  async execute(_toolCallId, params, signal) {
147
150
  const args = ["--symbol", params.symbol];
148
151
  if (params.limit !== undefined) args.push("--limit", String(params.limit));
152
+ if (params.exclude_tests) args.push("--exclude-tests");
149
153
  const result = await runDescry("callees", args, signal);
150
154
  return { content: [{ type: "text", text: result }] };
151
155
  },
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "descry-codegraph"
3
- version = "1.0.1"
3
+ version = "1.1.0"
4
4
  description = "Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis"
5
5
  requires-python = ">=3.11"
6
6
  authors = [{name = "Christian Haynes"}]
@@ -1,4 +1,4 @@
1
1
  """Descry — Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis."""
2
2
 
3
- __version__ = "1.0.1"
3
+ __version__ = "1.1.0"
4
4
  __all__ = ["__version__"]
@@ -11,6 +11,7 @@ Usage:
11
11
  import argparse
12
12
  import asyncio
13
13
  import json
14
+ import os
14
15
  import sys
15
16
 
16
17
  from descry._answers import fail
@@ -66,14 +67,14 @@ def cmd_ensure(args):
66
67
  def cmd_index(args):
67
68
  svc = _make_service()
68
69
  path = args.path if args.path else "."
69
- _print_answer(args, svc.index_answer(path), svc.index_text)
70
+ _print_answer(args, svc.index_answer(path, echo=True), svc.index_text)
70
71
 
71
72
 
72
73
  def cmd_callers(args):
73
74
  svc = _make_service()
74
75
  _print_answer(
75
76
  args,
76
- svc.callers_answer(args.symbol, args.limit),
77
+ svc.callers_answer(args.symbol, args.limit, args.exclude_tests),
77
78
  lambda a: svc.listing_text(a, "callers", args.limit),
78
79
  )
79
80
 
@@ -82,7 +83,7 @@ def cmd_callees(args):
82
83
  svc = _make_service()
83
84
  _print_answer(
84
85
  args,
85
- svc.callees_answer(args.symbol, args.limit),
86
+ svc.callees_answer(args.symbol, args.limit, args.exclude_tests),
86
87
  lambda a: svc.listing_text(a, "callees", args.limit),
87
88
  )
88
89
 
@@ -288,6 +289,9 @@ def build_parser():
288
289
  )
289
290
  sub.add_argument("symbol", help="A node ID, or a name")
290
291
  sub.add_argument("--limit", type=int, default=20, help="Max results (default: 20)")
292
+ sub.add_argument(
293
+ "--exclude-tests", action="store_true", help="Exclude test symbols"
294
+ )
291
295
  sub.set_defaults(func=cmd_callers)
292
296
 
293
297
  sub = subparsers.add_parser(
@@ -295,6 +299,9 @@ def build_parser():
295
299
  )
296
300
  sub.add_argument("symbol", help="A node ID, or a name")
297
301
  sub.add_argument("--limit", type=int, default=20, help="Max results (default: 20)")
302
+ sub.add_argument(
303
+ "--exclude-tests", action="store_true", help="Exclude test symbols"
304
+ )
298
305
  sub.set_defaults(func=cmd_callees)
299
306
 
300
307
  sub = subparsers.add_parser(
@@ -516,6 +523,14 @@ def build_parser():
516
523
 
517
524
  def main():
518
525
  write_utf8()
526
+ if not sys.stderr.isatty():
527
+ # Scripted use: no model-loading progress bars or Hub notices.
528
+ for name, value in (
529
+ ("HF_HUB_DISABLE_PROGRESS_BARS", "1"),
530
+ ("HF_HUB_VERBOSITY", "error"),
531
+ ("TRANSFORMERS_VERBOSITY", "error"),
532
+ ):
533
+ os.environ.setdefault(name, value)
519
534
  parser = build_parser()
520
535
  args = parser.parse_args()
521
536
 
@@ -11,6 +11,7 @@ import re
11
11
  import signal
12
12
  import stat
13
13
  import threading
14
+ import time
14
15
  import tomllib
15
16
  from collections import Counter
16
17
  from pathlib import Path
@@ -704,6 +705,7 @@ class CodeGraphBuilder:
704
705
  logger.warning("Skipping %s — escapes project root via symlink", real)
705
706
  return False
706
707
 
708
+ parsed_count, heartbeat = 0, time.monotonic()
707
709
  for root, dirs, files in os.walk(self.root_dir, followlinks=False):
708
710
  dirs.sort()
709
711
  # A directory's manifests first: they tell how its files parse.
@@ -809,6 +811,10 @@ class CodeGraphBuilder:
809
811
  rel_path, content, module
810
812
  )
811
813
  self._merge(shell)
814
+ parsed_count += 1
815
+ if time.monotonic() - heartbeat > 15:
816
+ logger.info("Parsing: %d files so far", parsed_count)
817
+ heartbeat = time.monotonic()
812
818
  if self.parse_cache:
813
819
  self.parse_cache.prune(whole=self.root_dir == self.rel_base)
814
820
 
@@ -990,6 +996,7 @@ class CodeGraphBuilder:
990
996
  edges_to_remove = set()
991
997
  file_stats, file_reads = {}, {}
992
998
  resolving = None # the file whose calls are being resolved
999
+ resolved_count, heartbeat = 0, time.monotonic()
993
1000
  for idx, edge in enumerate(self.edges):
994
1001
  target = edge["target"]
995
1002
  if (file_id := edge["source"].split("::")[0]) != resolving:
@@ -998,6 +1005,15 @@ class CodeGraphBuilder:
998
1005
  stats = file_stats[file_id] = dict.fromkeys(_STATS, 0)
999
1006
  if reads:
1000
1007
  file_reads[file_id] = reads.start()
1008
+ resolved_count += 1
1009
+ if time.monotonic() - heartbeat > 15:
1010
+ logger.info(
1011
+ "Resolving calls: %d files, %d/%d edges",
1012
+ resolved_count,
1013
+ idx,
1014
+ len(self.edges),
1015
+ )
1016
+ heartbeat = time.monotonic()
1001
1017
  if file_id in kept:
1002
1018
  continue
1003
1019
  if target.startswith("REF:"):