codingest 0.2.34__tar.gz → 0.2.35__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 (114) hide show
  1. {codingest-0.2.34 → codingest-0.2.35}/Cargo.lock +8 -8
  2. {codingest-0.2.34 → codingest-0.2.35}/Cargo.toml +9 -5
  3. {codingest-0.2.34 → codingest-0.2.35}/PKG-INFO +5 -5
  4. {codingest-0.2.34 → codingest-0.2.35}/README.md +3 -3
  5. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/Cargo.toml +1 -1
  6. codingest-0.2.35/crates/codingest/assets/code_review/skill.md +60 -0
  7. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/other_edges.rs +5 -5
  8. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/methodology.rs +17 -0
  9. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/registry.rs +5 -2
  10. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/typescript.rs +99 -7
  11. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/README.md +22 -0
  12. codingest-0.2.35/crates/codingest/tests/goldens/js_module_exts.sha256 +1 -0
  13. codingest-0.2.35/crates/codingest/tests/goldens/ts_hof_binding.sha256 +1 -0
  14. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/parity.rs +10 -0
  15. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/Cargo.toml +1 -1
  16. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/skills/codingest-code-review/SKILL.md +1 -1
  17. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/skills/codingest-code-review/references/mcp-upgrade.md +1 -1
  18. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-mcp/Cargo.toml +1 -1
  19. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-py/Cargo.toml +3 -3
  20. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-py/src/lib.rs +1 -1
  21. {codingest-0.2.34 → codingest-0.2.35}/pyproject.toml +2 -2
  22. codingest-0.2.34/crates/codingest/assets/code_review/skill.md +0 -70
  23. codingest-0.2.34/crates/codingest/tests/goldens/ts_hof_binding.sha256 +0 -1
  24. {codingest-0.2.34 → codingest-0.2.35}/LICENSE +0 -0
  25. {codingest-0.2.34 → codingest-0.2.35}/codingest/__init__.py +0 -0
  26. {codingest-0.2.34 → codingest-0.2.35}/codingest/__init__.pyi +0 -0
  27. {codingest-0.2.34 → codingest-0.2.35}/codingest/cli.py +0 -0
  28. {codingest-0.2.34 → codingest-0.2.35}/codingest/mcp_server.py +0 -0
  29. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/assets/code_review/recipes.json +0 -0
  30. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/bin/codingest_bench.rs +0 -0
  31. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/bin/codingest_stats.rs +0 -0
  32. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/call_edges.rs +0 -0
  33. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/js_workspace.rs +0 -0
  34. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/load/edge_frames.rs +0 -0
  35. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/load/entity_frames.rs +0 -0
  36. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/load.rs +0 -0
  37. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/mod.rs +0 -0
  38. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/routes/django.rs +0 -0
  39. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/routes/fastapi.rs +0 -0
  40. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/routes/flask.rs +0 -0
  41. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/routes/mod.rs +0 -0
  42. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/semantic_edges.rs +0 -0
  43. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/builder/type_edges.rs +0 -0
  44. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/cross_lang.rs +0 -0
  45. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/docs/mod.rs +0 -0
  46. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/docs/rst.rs +0 -0
  47. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/lib.rs +0 -0
  48. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/manifest/mod.rs +0 -0
  49. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/models.rs +0 -0
  50. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/agc.rs +0 -0
  51. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/cpp.rs +0 -0
  52. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/csharp.rs +0 -0
  53. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/css.rs +0 -0
  54. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/dart.rs +0 -0
  55. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/go.rs +0 -0
  56. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/html.rs +0 -0
  57. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/java.rs +0 -0
  58. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/julia.rs +0 -0
  59. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/mod.rs +0 -0
  60. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/php.rs +0 -0
  61. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/python.rs +0 -0
  62. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/r.rs +0 -0
  63. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/rust_lang.rs +0 -0
  64. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/shared.rs +0 -0
  65. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/parsers/swift.rs +0 -0
  66. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/repo.rs +0 -0
  67. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/src/rev.rs +0 -0
  68. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/agc_apollo.rs +0 -0
  69. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/agc_basic.sha256 +0 -0
  70. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/cpp_extern_c.sha256 +0 -0
  71. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/cpp_include.sha256 +0 -0
  72. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/cross_ts_py.sha256 +0 -0
  73. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/csharp_using_alias.sha256 +0 -0
  74. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/dart_import.sha256 +0 -0
  75. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/dart_part_of.sha256 +0 -0
  76. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/docs_ext_collide.sha256 +0 -0
  77. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/docs_mdx.sha256 +0 -0
  78. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/dup_minified_assets.sha256 +0 -0
  79. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/go_interface.sha256 +0 -0
  80. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/html_js_lang_group.sha256 +0 -0
  81. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/java_javadoc.sha256 +0 -0
  82. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/julia_basic.sha256 +0 -0
  83. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/php_group_use.sha256 +0 -0
  84. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_basic.sha256 +0 -0
  85. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_import.sha256 +0 -0
  86. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_inheritance.sha256 +0 -0
  87. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_nested_defs.sha256 +0 -0
  88. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_routes_dup.sha256 +0 -0
  89. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/py_src_layout.sha256 +0 -0
  90. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/r_basic.sha256 +0 -0
  91. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/rust_import.sha256 +0 -0
  92. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/rust_inline_mod.sha256 +0 -0
  93. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/rust_xfile.sha256 +0 -0
  94. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/swift_basic.sha256 +0 -0
  95. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/ts_callback.sha256 +0 -0
  96. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/ts_closure_scope.sha256 +0 -0
  97. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/ts_monorepo.sha256 +0 -0
  98. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/goldens/web_served_root.sha256 +0 -0
  99. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/grammar_kinds.rs +0 -0
  100. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest/tests/traversal_semantics.rs +0 -0
  101. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/skills/codingest-code-review/references/public-repositories.md +0 -0
  102. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/skills/codingest-code-review/references/queries.md +0 -0
  103. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/code_tree_cli.rs +0 -0
  104. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/lib.rs +0 -0
  105. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/main.rs +0 -0
  106. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/query.rs +0 -0
  107. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/skill.rs +0 -0
  108. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/src/skill_assets.rs +0 -0
  109. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/tests/embed_skills.rs +0 -0
  110. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/tests/exit_codes.rs +0 -0
  111. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-cli/tests/skill_recipes.rs +0 -0
  112. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-mcp/src/lib.rs +0 -0
  113. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-mcp/src/main.rs +0 -0
  114. {codingest-0.2.34 → codingest-0.2.35}/crates/codingest-mcp/tests/response_contract.rs +0 -0
@@ -306,7 +306,7 @@ dependencies = [
306
306
 
307
307
  [[package]]
308
308
  name = "codingest"
309
- version = "0.2.34"
309
+ version = "0.2.35"
310
310
  dependencies = [
311
311
  "aho-corasick",
312
312
  "base64",
@@ -342,7 +342,7 @@ dependencies = [
342
342
 
343
343
  [[package]]
344
344
  name = "codingest-cli"
345
- version = "0.2.34"
345
+ version = "0.2.35"
346
346
  dependencies = [
347
347
  "anyhow",
348
348
  "clap",
@@ -354,7 +354,7 @@ dependencies = [
354
354
 
355
355
  [[package]]
356
356
  name = "codingest-mcp"
357
- version = "0.2.34"
357
+ version = "0.2.35"
358
358
  dependencies = [
359
359
  "anyhow",
360
360
  "codingest",
@@ -365,7 +365,7 @@ dependencies = [
365
365
 
366
366
  [[package]]
367
367
  name = "codingest-py"
368
- version = "0.2.34"
368
+ version = "0.2.35"
369
369
  dependencies = [
370
370
  "codingest",
371
371
  "codingest-cli",
@@ -1421,9 +1421,9 @@ dependencies = [
1421
1421
 
1422
1422
  [[package]]
1423
1423
  name = "kglite"
1424
- version = "0.21.4"
1424
+ version = "0.21.5"
1425
1425
  source = "registry+https://github.com/rust-lang/crates.io-index"
1426
- checksum = "ea25c6ce4f981f578525b076e8c6fae3b0a3c4b79dcdf50967312a5ae52f3ebd"
1426
+ checksum = "68f04fd73825dfbf10f9da22f85a2bdb084fd642b36a9b99400719f1df33c7ed"
1427
1427
  dependencies = [
1428
1428
  "bzip2",
1429
1429
  "chrono",
@@ -1461,9 +1461,9 @@ dependencies = [
1461
1461
 
1462
1462
  [[package]]
1463
1463
  name = "kglite-mcp-server"
1464
- version = "0.21.4"
1464
+ version = "0.21.5"
1465
1465
  source = "registry+https://github.com/rust-lang/crates.io-index"
1466
- checksum = "059267ba7a8bc228da3cef35351ce6b01bbc866447688f3940e5e5346c4c898b"
1466
+ checksum = "867346f8685bc1c76c698049a347583ebdef43907b22335d5b62d0aea7f29b6f"
1467
1467
  dependencies = [
1468
1468
  "anyhow",
1469
1469
  "base64",
@@ -3,7 +3,7 @@ members = ["crates/codingest", "crates/codingest-cli", "crates/codingest-mcp", "
3
3
  resolver = "2"
4
4
 
5
5
  [workspace.package]
6
- version = "0.2.34"
6
+ version = "0.2.35"
7
7
  edition = "2021"
8
8
  rust-version = "1.88"
9
9
  license = "MIT"
@@ -12,8 +12,12 @@ repository = "https://github.com/kkollsga/codingest"
12
12
  [workspace.dependencies]
13
13
  base64 = "0.23.1"
14
14
  sha2 = "0.11"
15
- # kglite engine + MCP server — imported as crates.io libraries. The 0.21.4
16
- # floor is a patch step within 0.21 (0.21.2 -> 0.21.4: MCP clients that never
15
+ # kglite engine + MCP server — imported as crates.io libraries. The 0.21.5
16
+ # floor is a patch step within 0.21 (0.21.4 -> 0.21.5): a query-path speedup
17
+ # only — a fused columnar kernel for single-label filtered `count`/`sum`/`avg`/
18
+ # `min`/`max` and negative-literal pushdown, results identical. It changes no
19
+ # `kglite::api` codingest calls and nothing the builder writes. The 0.21.4
20
+ # floor was a patch step within 0.21 (0.21.2 -> 0.21.4: MCP clients that never
17
21
  # send `initialize`, Python 3.12+ wheel, `with_identity` `--help` fix and the
18
22
  # embedder `serverInfo.name`); it changes no `kglite::api` codingest calls. The 0.21.1
19
23
  # floor is an engine minor (0.20.0 -> 0.21.1, taking 0.21.0 with it): graphs of
@@ -660,8 +664,8 @@ sha2 = "0.11"
660
664
  # and no disk storage. Neither 0.15.7 nor 0.15.8 changes the `kglite::api` we
661
665
  # call, graph output, property encoding, or `.kgl` serialization.
662
666
  # Keep both libraries aligned so the graph and server share one engine release.
663
- kglite = { version = "0.21.4", default-features = false }
664
- kglite-mcp-server = { version = "0.21.4", default-features = false }
667
+ kglite = { version = "0.21.5", default-features = false }
668
+ kglite-mcp-server = { version = "0.21.5", default-features = false }
665
669
 
666
670
  # Dependency debuginfo capped at line tables (kglite coordination, 2026-08-31,
667
671
  # after unbounded debug trees filled the build-cache disk to zero): a
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codingest
3
- Version: 0.2.34
3
+ Version: 0.2.35
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Programming Language :: Python :: 3
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.15
11
11
  Classifier: Programming Language :: Rust
12
12
  Classifier: Topic :: Software Development
13
13
  Classifier: Topic :: Software Development :: Libraries
14
- Requires-Dist: kglite>=0.21.4,<0.22
14
+ Requires-Dist: kglite>=0.21.5,<0.22
15
15
  License-File: LICENSE
16
16
  Summary: Build fast, queryable code graphs for AI agents, MCP code review, and local or GitHub repository analysis.
17
17
  Keywords: ai-agents,mcp,code-review,knowledge-graph,code-analysis,github,tree-sitter,cypher
@@ -193,7 +193,7 @@ codingest skill install # code-review Agent Skill
193
193
  ```
194
194
 
195
195
  The wheel bundles every grammar plus the `codingest` and `codingest-mcp`
196
- commands. KGLite ≥0.21.4 is installed automatically as the query/storage
196
+ commands. KGLite ≥0.21.5 is installed automatically as the query/storage
197
197
  engine; its MCP server and the transitive `mcp-methods` framework power the
198
198
  builder-aware Codingest server. Nothing else needs to be installed.
199
199
 
@@ -206,7 +206,7 @@ Python prerequisites.
206
206
  ```toml
207
207
  [dependencies]
208
208
  codingest = "0.2"
209
- kglite = "0.21.4"
209
+ kglite = "0.21.5"
210
210
  ```
211
211
 
212
212
  ```rust
@@ -278,7 +278,7 @@ diagnostic.
278
278
  ## Dependency policy
279
279
 
280
280
  `kglite` and `kglite-mcp-server` use matching crates.io requirements with a
281
- 0.21.4 minimum and a shared lockfile. This keeps the builder, persistence
281
+ 0.21.5 minimum and a shared lockfile. This keeps the builder, persistence
282
282
  handoff, and embedded MCP server on one compatible engine patch line.
283
283
 
284
284
  ## Parity with the (now-removed) in-tree component
@@ -167,7 +167,7 @@ codingest skill install # code-review Agent Skill
167
167
  ```
168
168
 
169
169
  The wheel bundles every grammar plus the `codingest` and `codingest-mcp`
170
- commands. KGLite ≥0.21.4 is installed automatically as the query/storage
170
+ commands. KGLite ≥0.21.5 is installed automatically as the query/storage
171
171
  engine; its MCP server and the transitive `mcp-methods` framework power the
172
172
  builder-aware Codingest server. Nothing else needs to be installed.
173
173
 
@@ -180,7 +180,7 @@ Python prerequisites.
180
180
  ```toml
181
181
  [dependencies]
182
182
  codingest = "0.2"
183
- kglite = "0.21.4"
183
+ kglite = "0.21.5"
184
184
  ```
185
185
 
186
186
  ```rust
@@ -252,7 +252,7 @@ diagnostic.
252
252
  ## Dependency policy
253
253
 
254
254
  `kglite` and `kglite-mcp-server` use matching crates.io requirements with a
255
- 0.21.4 minimum and a shared lockfile. This keeps the builder, persistence
255
+ 0.21.5 minimum and a shared lockfile. This keeps the builder, persistence
256
256
  handoff, and embedded MCP server on one compatible engine patch line.
257
257
 
258
258
  ## Parity with the (now-removed) in-tree component
@@ -10,7 +10,7 @@ keywords = ["knowledge-graph", "code-analysis", "tree-sitter", "cypher", "kglite
10
10
  categories = ["development-tools", "parser-implementations"]
11
11
 
12
12
  # Requires the kglite 0.15 engine API (`kglite::api::code_entities`); the
13
- # workspace pins the current engine floor (0.21.4).
13
+ # workspace pins the current engine floor (0.21.5).
14
14
 
15
15
  [lib]
16
16
  name = "codingest"
@@ -0,0 +1,60 @@
1
+ # Reviewing a codingest code graph
2
+
3
+ codingest built every graph this server serves, so the shapes are fixed:
4
+ `Function`, `Struct`, `Class`, `Trait`, `Interface`, `Protocol`, `Enum`,
5
+ `Module`, `File`, `Doc` nodes keyed by `qualified_name`; `CALLS`,
6
+ `USES_TYPE`, `IMPLEMENTS`, `EXTENDS`, `HAS_METHOD`, `IMPORTS`, `DEFINES`,
7
+ `HAS_FILE` edges. Functions carry `file_path`, `line_number`, `is_test`.
8
+ Use the graph only as far as the question requires.
9
+
10
+ ## Sequence
11
+
12
+ Recipe `code_review/<name>` runs as `run_recipe_query("code_review", "<name>", {…})`.
13
+
14
+ 1. **Resolve targets first** with `code_review/target_coverage`
15
+ (`{"requested": [...]}`). A null `target` means the name is not in this
16
+ graph (typo, macro-generated, other revision); `callers` of zero for an
17
+ existing target is a real absence. Never read an empty result as an absence
18
+ until the target has resolved.
19
+ 2. **Count before paging.** `code_review/caller_coverage` splits one target's
20
+ callers into production and test counts. One target per call: a shared page
21
+ can fill with one target and hide another.
22
+ 3. **Page callers by kind.** `code_review/callers_page` with `is_test: false`
23
+ gives the production callers, `is_test: true` the tests that would notice,
24
+ 25 at a time with file and line. Each row carries the `CALLS` edge's
25
+ evidence: `resolution`, `candidates` (>1 = the call site fanned out),
26
+ `import_backed` (false is unconfirmed, not refuted) and `call_lines`.
27
+ 4. **Walk the other way** with `code_review/direct_callees`, same evidence
28
+ columns. An unresolved source call has no `CALLS` edge at all, so read the
29
+ source before concluding a call is absent.
30
+ 5. **Witness reachability, do not explore it.** `code_review/bounded_call_path`
31
+ returns up to ten paths of at most four hops between two resolved functions.
32
+ 6. **Type and trait impact.** `code_review/type_consumers` lists functions
33
+ taking a struct as an explicit parameter; `code_review/trait_implementations`
34
+ lists structs with an `IMPLEMENTS` edge to a trait. Macro-generated or
35
+ heuristic structure may be missing — a reason to read source.
36
+ 7. **Read the selected source** with `read_code_source` (qualified name) or
37
+ `read_source` (path), bounded by `start_line` / `end_line`.
38
+ 8. **Use `cypher_query` only for a question no recipe shapes** — imports,
39
+ module structure, docs links, `CALL rev_diff({from, to})` on a multi-rev
40
+ graph — and check the shape with `graph_overview` first.
41
+
42
+ For a diff-scoped review, start from the functions whose `file_path` the diff
43
+ touched, resolve them, then run steps 2 to 4 on each.
44
+
45
+ ## Reading results
46
+
47
+ A page is complete only up to its literal size (25 rows, 10 paths); a full page
48
+ proves nothing about other targets. Expansion cannot recover rows a `LIMIT`
49
+ excluded — narrow the target instead. A warning about an unknown property or
50
+ reversed relationship means the query shape is wrong, not that the result is
51
+ empty.
52
+
53
+ ## Findings and honesty
54
+
55
+ A finding names a concrete failure — the input or state and the wrong outcome
56
+ — verified against exact source lines at the reviewed revision. "No findings"
57
+ is a valid review; design preferences are not findings, and an edge showing
58
+ coupling is a fact, not a defect. Never invent labels, properties, edge types
59
+ or recipe names; a missing edge is absence of evidence, not proof of absence;
60
+ never build or execute a repository's code merely to review it.
@@ -228,11 +228,11 @@ fn path_import_candidates(file: &FileInfo, raw: &str) -> Vec<String> {
228
228
  }
229
229
 
230
230
  /// Module-path suffixes a TS/JS specifier may carry. Stripped before matching,
231
- /// mirroring `JstsParser::file_to_module_path`. `.js`/`.mjs`/`.cjs` are in the
232
- /// list because TS's NodeNext resolution has source files import each other by
233
- /// their *emitted* name (`import "./util.js"` resolving to `util.ts`).
234
- const MODULE_PATH_EXTENSIONS: &[&str] =
235
- &[".tsx", ".ts", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".js"];
231
+ /// with the same list `JstsParser::file_to_module_path` strips. The JS
232
+ /// suffixes matter for TS too: NodeNext resolution has source files import
233
+ /// each other by their *emitted* name (`import "./util.js"` resolving to
234
+ /// `util.ts`).
235
+ const MODULE_PATH_EXTENSIONS: &[&str] = crate::parsers::typescript::JSTS_MODULE_SUFFIXES;
236
236
 
237
237
  /// Candidate module paths for one TS/JS import specifier, in fixed priority
238
238
  /// order — first match wins, and the order IS the documented tie-break.
@@ -228,6 +228,23 @@ mod tests {
228
228
  assert_eq!(record.references_tools, REFERENCES_TOOLS);
229
229
  }
230
230
 
231
+ /// mcp-methods warns on every server boot and `--selftest` when a skill
232
+ /// exceeds its soft limit (`SOFT_SIZE_LIMIT_BYTES`, 4 KiB in 0.6.2), and it
233
+ /// measures the skill as served: the frontmatter kglite renders from the
234
+ /// record fields plus the body. A body sized against the limit alone
235
+ /// (4,093 bytes) rendered to 4,709 and warned on every boot.
236
+ #[test]
237
+ fn rendered_skill_fits_the_mcp_soft_size_limit() {
238
+ const MCP_SOFT_SIZE_LIMIT_BYTES: usize = 4 * 1024;
239
+ let rendered = skills::render_markdown(&skill_record());
240
+ assert!(
241
+ rendered.len() <= MCP_SOFT_SIZE_LIMIT_BYTES,
242
+ "rendered skill is {} bytes (body {}), soft limit is {MCP_SOFT_SIZE_LIMIT_BYTES}",
243
+ rendered.len(),
244
+ SKILL_BODY.len()
245
+ );
246
+ }
247
+
231
248
  #[test]
232
249
  fn skill_body_names_every_recipe_and_the_description_loads_it_before_cypher() {
233
250
  for record in recipe_records() {
@@ -192,7 +192,7 @@ language_registry! {
192
192
  make_parser: python_parser,
193
193
  },
194
194
  "typescript" => {
195
- extensions: ["ts", "tsx"],
195
+ extensions: ["ts", "tsx", "mts", "cts"],
196
196
  module_sep: "/",
197
197
  edge_sep: "/",
198
198
  group: LangGroup::GoTsJs,
@@ -200,7 +200,7 @@ language_registry! {
200
200
  make_parser: typescript_parser,
201
201
  },
202
202
  "javascript" => {
203
- extensions: ["js", "jsx", "mjs"],
203
+ extensions: ["js", "jsx", "mjs", "cjs"],
204
204
  module_sep: "/",
205
205
  edge_sep: "/",
206
206
  group: LangGroup::GoTsJs,
@@ -411,9 +411,12 @@ mod tests {
411
411
  ("pyi", "python"),
412
412
  ("ts", "typescript"),
413
413
  ("tsx", "typescript"),
414
+ ("mts", "typescript"),
415
+ ("cts", "typescript"),
414
416
  ("js", "javascript"),
415
417
  ("jsx", "javascript"),
416
418
  ("mjs", "javascript"),
419
+ ("cjs", "javascript"),
417
420
  ("go", "go"),
418
421
  ("java", "java"),
419
422
  ("cs", "csharp"),
@@ -142,18 +142,26 @@ thread_local! {
142
142
  };
143
143
  }
144
144
 
145
+ /// File-name suffixes stripped to form a TS/JS module path, shared by
146
+ /// `file_to_module_path` and the import resolver in `builder::other_edges` so
147
+ /// the two agree on module identity. Every extension the `typescript` and
148
+ /// `javascript` registry entries claim must be here, or its files get a
149
+ /// module path that still carries the extension and no import can reach them.
150
+ pub(crate) const JSTS_MODULE_SUFFIXES: &[&str] =
151
+ &[".tsx", ".ts", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".js"];
152
+
145
153
  impl JstsParser {
146
154
  pub fn typescript() -> Self {
147
155
  JstsParser {
148
156
  lang_name: "typescript",
149
- extensions: &["ts", "tsx"],
157
+ extensions: &["ts", "tsx", "mts", "cts"],
150
158
  }
151
159
  }
152
160
 
153
161
  pub fn javascript() -> Self {
154
162
  JstsParser {
155
163
  lang_name: "javascript",
156
- extensions: &["js", "jsx", "mjs"],
164
+ extensions: &["js", "jsx", "mjs", "cjs"],
157
165
  }
158
166
  }
159
167
 
@@ -1095,7 +1103,7 @@ impl JstsParser {
1095
1103
  .filter_map(|c| c.as_os_str().to_str().map(str::to_string))
1096
1104
  .collect();
1097
1105
  if let Some(last) = parts.last_mut() {
1098
- for ext in [".tsx", ".ts", ".jsx", ".mjs", ".js"] {
1106
+ for ext in JSTS_MODULE_SUFFIXES {
1099
1107
  if let Some(stem) = last.strip_suffix(ext) {
1100
1108
  *last = stem.to_string();
1101
1109
  break;
@@ -1248,7 +1256,19 @@ impl JstsParser {
1248
1256
  None => module_path.to_string(),
1249
1257
  };
1250
1258
  let qualified_name = format!("{}.{}", prefix, name);
1251
- let block = Self::get_block(node);
1259
+ // A concise arrow (`x => expr`) has no `{ … }` block; its expression IS
1260
+ // the body. Without this fallback such a function had null metrics and
1261
+ // dropped every call it made (`const run = c => execSync(c)` had no
1262
+ // CALLS edge at all).
1263
+ let body = Self::get_block(node).or_else(|| {
1264
+ (node.kind() == "arrow_function")
1265
+ .then(|| node.child_by_field_name("body"))
1266
+ .flatten()
1267
+ });
1268
+ // A concise body that is itself a nested scope (`a => b => f()`) stays
1269
+ // behind the boundary a `{ return b => f(); }` block puts it behind:
1270
+ // measured as empty, its calls not folded into this function.
1271
+ let block = body.filter(|b| !NESTED_SCOPES.contains(&b.kind()));
1252
1272
 
1253
1273
  let mut metadata = crate::models::MetadataMap::new();
1254
1274
  let mut cursor = node.walk();
@@ -1269,12 +1289,13 @@ impl JstsParser {
1269
1289
  .filter(|p| p.kind != ParameterKind::Receiver)
1270
1290
  .count() as u32,
1271
1291
  );
1272
- let (branch_count, max_nesting) = match block {
1273
- Some(b) => {
1292
+ let (branch_count, max_nesting) = match (block, body) {
1293
+ (Some(b), _) => {
1274
1294
  let (c, n) = compute_complexity(b, BRANCH_KINDS_TS, NESTED_SCOPES);
1275
1295
  (Some(c), Some(n))
1276
1296
  }
1277
- None => (None, None),
1297
+ (None, Some(_)) => (Some(0), Some(0)),
1298
+ (None, None) => (None, None),
1278
1299
  };
1279
1300
  let is_recursive = Some(calls.iter().any(|(n, _)| n == &name));
1280
1301
  let docstring = Self::get_docstring(node, source);
@@ -1865,6 +1886,12 @@ impl LanguageParser for JstsParser {
1865
1886
  ".spec.jsx",
1866
1887
  ".test.mjs",
1867
1888
  ".spec.mjs",
1889
+ ".test.cjs",
1890
+ ".spec.cjs",
1891
+ ".test.mts",
1892
+ ".spec.mts",
1893
+ ".test.cts",
1894
+ ".spec.cts",
1868
1895
  ];
1869
1896
  let is_test = crate::parsers::shared::is_test_path(&rel_path, &filename, &test_suffixes);
1870
1897
 
@@ -2759,3 +2786,68 @@ export function outer(items: string[]) {
2759
2786
  assert_eq!(calls_of(src, "a.outer"), vec!["items.forEach", "transform"]);
2760
2787
  }
2761
2788
  }
2789
+
2790
+ #[cfg(test)]
2791
+ mod concise_arrow_tests {
2792
+ use super::*;
2793
+ use crate::parsers::LanguageParser;
2794
+
2795
+ /// `(branch_count, max_nesting, call names)` for the Function named `name`.
2796
+ fn measured(src: &str, name: &str) -> (Option<u32>, Option<u32>, Vec<String>) {
2797
+ let dir = tempfile::tempdir().expect("tempdir");
2798
+ let path = dir.path().join("a.ts");
2799
+ std::fs::write(&path, src).expect("write fixture");
2800
+ let result = JstsParser::typescript().parse_file(&path, dir.path());
2801
+ let f = result
2802
+ .functions
2803
+ .iter()
2804
+ .find(|f| f.name == name)
2805
+ .unwrap_or_else(|| panic!("no Function named {name}"));
2806
+ let calls = f.calls.iter().map(|(c, _)| c.clone()).collect();
2807
+ (f.branch_count, f.max_nesting, calls)
2808
+ }
2809
+
2810
+ /// The regression: an arrow whose body is an expression rather than a
2811
+ /// `{ … }` block had null metrics and no calls at all.
2812
+ #[test]
2813
+ fn concise_arrow_is_measured_and_keeps_its_calls() {
2814
+ let src = "const run = (cmd: string) => execSync(cmd, { stdio: \"inherit\" });\n";
2815
+ assert_eq!(
2816
+ measured(src, "run"),
2817
+ (Some(0), Some(0), vec!["execSync".to_string()])
2818
+ );
2819
+ let src = "const pick = (x: number) => x > 0 ? up(x) : down(x);\n";
2820
+ assert_eq!(
2821
+ measured(src, "pick"),
2822
+ (Some(1), Some(1), vec!["up".to_string(), "down".to_string()])
2823
+ );
2824
+ }
2825
+
2826
+ /// A concise body that is itself an arrow reads the same as its
2827
+ /// block-bodied twin: the inner scope stays behind the nested-scope
2828
+ /// boundary in both spellings.
2829
+ #[test]
2830
+ fn curried_concise_arrow_matches_its_block_twin() {
2831
+ let concise = "const f = (a: number) => (b: number) => g(a ? b : 0);\n";
2832
+ let block = "const f = (a: number) => { return (b: number) => g(a ? b : 0); };\n";
2833
+ assert_eq!(measured(concise, "f"), (Some(0), Some(0), Vec::new()));
2834
+ assert_eq!(measured(concise, "f"), measured(block, "f"));
2835
+ }
2836
+
2837
+ /// Every extension the registry routes to this parser must be stripped
2838
+ /// to form a module path; one left out makes its files unreachable by
2839
+ /// any import.
2840
+ #[test]
2841
+ fn module_suffixes_cover_every_registered_extension() {
2842
+ for language in ["typescript", "javascript"] {
2843
+ let spec = crate::parsers::registry::spec(language).expect("registered");
2844
+ for ext in spec.extensions {
2845
+ let suffix = format!(".{ext}");
2846
+ assert!(
2847
+ JSTS_MODULE_SUFFIXES.contains(&suffix.as_str()),
2848
+ "{language} extension {suffix} is parsed but not stripped from module paths"
2849
+ );
2850
+ }
2851
+ }
2852
+ }
2853
+ }
@@ -389,6 +389,28 @@ what shows the change is pure identity and not behaviour. Verified the strict
389
389
  way: `capture_goldens` rewrote every file, and afterwards `git status` reported
390
390
  exactly those two digests as modified.
391
391
 
392
+ The additive `js_module_exts` digest was captured on 2026-11-01 with the
393
+ corpus itself. The parser registry listed `js`/`jsx`/`mjs` and `ts`/`tsx` only,
394
+ so every `.cjs`, `.mts` and `.cts` file was skipped without a diagnostic — and
395
+ no corpus contained one, so the gap had no golden to move. The corpus pins all
396
+ three extensions and a `.d.mts` declaration file, the `.test.cts` test flag,
397
+ and import resolution onto a `.mts` module both by its emitted name
398
+ (`./util.mjs`, NodeNext) and by its own (`./util.mts`). Verified additive the
399
+ strict way: `capture_goldens` rewrote every file, and afterwards `git status`
400
+ reported only `js_module_exts.sha256` as new. Every pre-existing corpus is a
401
+ control and does not move.
402
+
403
+ **`ts_hof_binding` regenerated 2026-11-01 (concise-arrow bodies).** A
404
+ TS/JS arrow whose body is an expression rather than a `{ … }` block was never
405
+ measured and never walked for calls: `branch_count`/`max_nesting` were null and
406
+ `const run = c => execSync(c)` had no CALLS edge. The parser now treats the
407
+ expression as the body. The digest movement is the record: `ts_hof_binding` is
408
+ the only corpus with a concise-bodied Function node, and its one such node
409
+ (`createMemo(() => 1 + 2)`'s binding, no calls) gained `branch_count=0` and
410
+ `max_nesting=0` — two added properties, nothing else. Verified by dumping every
411
+ corpus with and without the fix (`dump_canonical`); only that file differed.
412
+ The calls half is pinned by `concise_arrow_tests` in the parser.
413
+
392
414
  ## The 2026-08-10 bulk regeneration (13 of 14 digests)
393
415
 
394
416
  **This is the first bulk regeneration since the extraction**, and the only one
@@ -0,0 +1 @@
1
+ ecba2b7d126857eab60248df7d88753f68fcf00e5774ba1308b4c27260411a8e
@@ -0,0 +1 @@
1
+ 804888ec5bbf3e6b76f5d17a4f31f8bf62b4fd3bd422507ede01f45adc327863
@@ -351,6 +351,16 @@ const CORPORA: &[&str] = &[
351
351
  // root is still tried first. Its golden is captured additively (see
352
352
  // `tests/goldens/README.md`).
353
353
  "web_served_root",
354
+ // Added 2026-11-01. No other corpus contains a `.cjs`, `.mts` or `.cts`
355
+ // file — the parser registry did not list those extensions at all, so the
356
+ // builder skipped them without a word (an Electron app's whole
357
+ // `electron/*.cjs` main process was absent from its graph). It pins all
358
+ // three extensions plus a `.d.mts` declaration file, the `.test.cts` test
359
+ // flag, and import resolution onto a `.mts` module both by its emitted
360
+ // name (`./util.mjs`, NodeNext) and by its own (`./util.mts`). Its golden
361
+ // is captured additively (see
362
+ // `tests/goldens/README.md`).
363
+ "js_module_exts",
354
364
  ];
355
365
 
356
366
  /// Independent builds of each corpus per `golden_parity` run.
@@ -14,7 +14,7 @@ name = "codingest"
14
14
  path = "src/main.rs"
15
15
 
16
16
  [dependencies]
17
- codingest = { version = "0.2.34", path = "../codingest" }
17
+ codingest = { version = "0.2.35", path = "../codingest" }
18
18
  kglite = { workspace = true }
19
19
  anyhow = "1.0.104"
20
20
  clap = { version = "4.6.7", features = ["derive"] }
@@ -14,7 +14,7 @@ git diff, source reading, and literal-text search; it does not replace them.
14
14
  > codingest` also provides the builder-aware `codingest-mcp` server and a
15
15
  > compatible graph engine. Rust-only environments can alternatively use Cargo.
16
16
  > Examples that invoke the external `kglite` CLI require a compatible
17
- > `kglite>=0.21.4,<0.22`; verify `kglite --version` before using its
17
+ > `kglite>=0.21.5,<0.22`; verify `kglite --version` before using its
18
18
  > agent-response features.
19
19
 
20
20
  Inspect the diff and repository guidance first. Identify changed symbols and
@@ -54,7 +54,7 @@ preconditions are still current.
54
54
  ## External CLI agent output is optional
55
55
 
56
56
  The examples below require an external `kglite` CLI satisfying
57
- `>=0.21.4,<0.22`:
57
+ `>=0.21.5,<0.22`:
58
58
 
59
59
  ```console
60
60
  kglite --version
@@ -14,7 +14,7 @@ name = "codingest-mcp"
14
14
  path = "src/main.rs"
15
15
 
16
16
  [dependencies]
17
- codingest = { version = "0.2.34", path = "../codingest" }
17
+ codingest = { version = "0.2.35", path = "../codingest" }
18
18
  kglite-mcp-server = { workspace = true }
19
19
  anyhow = "1.0.104"
20
20
 
@@ -42,7 +42,7 @@ doctest = false
42
42
  pyo3 = { version = "0.30" }
43
43
  # The engine-free builder (parsers, call/type/route edges, rev merge, repo
44
44
  # clone, manifest reader). Docs pass gated by this crate's `docs` feature.
45
- codingest = { version = "0.2.34", path = "../codingest", default-features = false }
45
+ codingest = { version = "0.2.35", path = "../codingest", default-features = false }
46
46
  # `.kgl` persistence (`kglite::api::io::save_graph`) for the serialize half of
47
47
  # the build-then-load handoff, plus the `DirGraph` type the builder returns.
48
48
  kglite = { workspace = true }
@@ -53,9 +53,9 @@ tempfile = "3.27.0"
53
53
  # through `_run_cli`, so `pip install codingest` also installs the `codingest`
54
54
  # command without a second wheel or a duplicated builder build. Mirrors
55
55
  # kglite-py's `kglite-cli` bundling.
56
- codingest-cli = { version = "0.2.34", path = "../codingest-cli" }
56
+ codingest-cli = { version = "0.2.35", path = "../codingest-cli" }
57
57
  # Source-building MCP composition. The graph server and generic MCP lifecycle
58
58
  # remain owned by its existing kglite-mcp-server -> mcp-methods Rust dependency
59
59
  # chain; linking this thin library into the extension gives pip users the same
60
60
  # builder-aware server as the standalone `codingest-mcp` binary.
61
- codingest-mcp = { version = "0.2.34", path = "../codingest-mcp" }
61
+ codingest-mcp = { version = "0.2.35", path = "../codingest-mcp" }
@@ -86,7 +86,7 @@ fn load_via_kglite(py: Python<'_>, path: &Path) -> PyResult<Py<PyAny>> {
86
86
  PyRuntimeError::new_err(format!(
87
87
  "codingest.build() returns a kglite.KnowledgeGraph, but importing \
88
88
  `kglite` failed ({e}). Install it: `pip install \
89
- 'kglite>=0.21.4,<0.22'`."
89
+ 'kglite>=0.21.5,<0.22'`."
90
90
  ))
91
91
  })?;
92
92
  let graph = kglite.call_method1("load", (path.to_string_lossy().as_ref(),))?;
@@ -41,9 +41,9 @@ dynamic = ["version"]
41
41
  # minor releases (e.g. the v3->v4 break, which refuses old files outright), so
42
42
  # pip must never be free to pair our writer with a reader from a different
43
43
  # minor. This range therefore mirrors the Cargo semver range for the pin above
44
- # (`version = "0.21.4"` == `>=0.21.4,<0.22.0`) exactly — bump both together.
44
+ # (`version = "0.21.5"` == `>=0.21.5,<0.22.0`) exactly — bump both together.
45
45
  dependencies = [
46
- "kglite>=0.21.4,<0.22",
46
+ "kglite>=0.21.5,<0.22",
47
47
  ]
48
48
 
49
49
  [project.urls]
@@ -1,70 +0,0 @@
1
- # Reviewing a codingest code graph
2
-
3
- codingest built every graph this server serves, so the shapes are fixed:
4
- `Function`, `Struct`, `Class`, `Trait`, `Interface`, `Protocol`, `Enum`,
5
- `Module`, `File`, `Doc` nodes keyed by `qualified_name`; `CALLS`,
6
- `USES_TYPE`, `IMPLEMENTS`, `EXTENDS`, `HAS_METHOD`, `IMPORTS`, `DEFINES`,
7
- `HAS_FILE` edges. Functions carry `file_path`, `line_number`, `is_test`.
8
- The graph is structural evidence beside the diff and the source; use it
9
- only as far as the question requires.
10
-
11
- ## Sequence
12
-
13
- 1. **Resolve targets first** with `run_recipe_query("code_review",
14
- "target_coverage", {"requested": [...]})`. A null `target` means the name is
15
- not in this graph (typo, macro-generated, other revision); `callers` of zero
16
- for an existing target is a real absence. Never read an empty result as an
17
- absence until the target has resolved.
18
- 2. **Count before paging.** `caller_coverage` splits one target's callers into
19
- production and test counts. One target per call: a shared page can fill
20
- with one target and hide another.
21
- 3. **Page callers by kind.** `callers_page` with `is_test: false` gives the
22
- production callers, `is_test: true` the tests that would notice, 25 at a
23
- time with file and line. Each row carries the `CALLS` edge's evidence:
24
- `resolution`, `candidates` (>1 = the call site fanned out), `import_backed`
25
- (false is unconfirmed, not refuted) and `call_lines`.
26
- 4. **Walk the other way** with `direct_callees`, same evidence columns. An
27
- unresolved source call has no `CALLS` edge at all, so read the source before
28
- concluding a call is absent.
29
- 5. **Witness reachability, do not explore it.** `bounded_call_path` returns up
30
- to ten paths of at most four hops between two resolved functions.
31
- 6. **Type and trait impact.** `type_consumers` lists functions taking a struct
32
- as an explicit parameter; `trait_implementations` lists structs with an
33
- `IMPLEMENTS` edge to a trait. Macro-generated or heuristic structure may be
34
- missing, so a missing edge is a reason to read source.
35
- 7. **Read the selected source** with `read_code_source` (qualified name) or
36
- `read_source` (path), bounded by `start_line` / `end_line`.
37
- 8. **Use `cypher_query` only for a question no recipe shapes** — imports,
38
- module structure, docs links, `CALL rev_diff({from, to})` on a multi-rev
39
- graph — and check the shape with `graph_overview` first.
40
-
41
- ## Recipes served for this graph
42
-
43
- - `code_review/target_coverage` — existence plus caller count, for a list of names.
44
- - `code_review/caller_coverage` — production versus test caller counts for one target.
45
- - `code_review/callers_page` — direct callers of one kind, 25 at a time, with edge evidence.
46
- - `code_review/direct_callees` — what one function calls, 25 at a time, with edge evidence.
47
- - `code_review/bounded_call_path` — up to ten paths of at most four hops between two functions.
48
- - `code_review/type_consumers` — functions taking a struct as an explicit parameter.
49
- - `code_review/trait_implementations` — structs implementing a trait.
50
-
51
- For a diff-scoped review, start from the functions whose `file_path` the
52
- diff touched, resolve them, then run steps 2 to 4 on each.
53
-
54
- ## Reading results
55
-
56
- A page is complete only up to its literal size (25 rows, 10 paths); a full
57
- page proves nothing about other targets or edges the builder never emitted.
58
- Follow a retained result's advertised expansion; expansion cannot recover
59
- rows a `LIMIT` excluded — narrow the target instead. A warning about an
60
- unknown property or reversed relationship means the query shape is wrong, not
61
- that the result is empty.
62
-
63
- ## Findings and honesty
64
-
65
- A finding names a concrete failure — the input or state and the wrong outcome
66
- — verified against exact source lines at the reviewed revision. "No findings"
67
- is a valid review; design preferences are not findings, and an edge showing
68
- coupling is a fact, not a defect. Never invent labels, properties, edge types
69
- or recipe names; a missing edge is absence of evidence, not proof of absence;
70
- never build or execute a repository's code merely to review it.
@@ -1 +0,0 @@
1
- 68ea85e83b5135a8030d282475490e453fb4afd2f98779e05e5cd5992f3e5585
File without changes
File without changes