fix(cargo): discover Cargo.toml in a subdirectory when none sits at the scan root - #3740
ayushcodes10 wants to merge 3 commits into
Conversation
introspect_cargo only ever looked at root divided by Cargo dot toml, with no search, so any repository whose crate lives in a subdirectory got no crate nodes or dependency edges at all, even though the AST pass had already parsed every rs file there. The common case is a Tauri app, whose default scaffold keeps its manifest under its own frontend adjacent crate folder rather than the project root. Add a bounded depth search that only runs when the root manifest is missing, reusing the same noise directory pruning the AST scanner already applies so a vendored or example manifest nested inside a dependency folder never wins over the project's own. A workspace manifest found this way now resolves its own members relative to its own directory rather than the outer scan root, since those two can now differ. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
Cover a Tauri style layout where the manifest lives one level down and must still be found, a discovered workspace manifest whose own members resolve relative to its own directory rather than the outer scan root, a decoy manifest inside a dependency install folder that must never be searched into, and a manifest nested past the discovery depth cap that is correctly left unfound. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Graphify review — findings
Makes introspect_cargo fall back to a bounded search for Cargo.toml when none sits at the scan root, so Tauri-style layouts (crate in src-tauri/) and other repos where the manifest lives one or two levels down produce crate nodes and dependency edges instead of nothing. The _discover_root_manifest walk stops at depth 2, prunes the same noise directories (node_modules, venvs, caches) the AST scanner skips, and breaks ties by sorted path order; anything deeper stays unfound and raises FileNotFoundError. Workspace members of a discovered manifest now resolve relative to the manifest's own directory rather than the scan root, while emitted source_file paths stay relative to the root.
Worth a look
- Manifest discovery can choose a deeper crate over a shallower one —
graphify/cargo_introspect.py:56· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 423 functions depend on the 244 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 125 callees - new:
introspect_cargo()— 15 callers, 4 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 423 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 249 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
290 of 290 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— impact, changed-test, full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_external_call_guards.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safety- … and 240 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
· 3 more finding(s) on lines outside this diff (see the check run).
|
Shipped in v0.9.66 (on PyPI). Cherry-picked with authorship preserved so it shows under your GitHub contributions. Thanks @ayushcodes10! |
Fixes #3678. Natural follow-up to #3677 (already fixed separately, PR #3739) — this is the "discovery gap... filed separately" the earlier issue references.
introspect_cargoonly ever looked at<scan-root>/Cargo.toml, with no search. Any repository whose Rust crate lives in a subdirectory — most commonly a Tauri app, whose default scaffold putsCargo.tomlinsrc-tauri/— got no crate nodes or crate-to-crate dependency edges at all, even though the AST pass had already parsed every.rsfile there.Adds a bounded-depth (1-2 levels) search that only runs when the root manifest is missing, using the issue's own suggested approach (option 1, the simplest viable one — avoids needing to correlate against AST-parsed
.rsfile locations). It reusesgraphify.detect._is_noise_dir, the same directory-pruning logic the AST scanner already applies, so a vendored or example manifest sitting insidenode_modules/or similar never wins over the project's own. A discovered workspace manifest's ownmembersglobs are now resolved relative to its own directory rather than the outer scan root, since those two can now legitimately differ.Four regression tests: a Tauri-style subdirectory manifest is found; a discovered workspace manifest's members resolve relative to its own directory; a decoy manifest inside
node_modules/is never searched into; a manifest nested past the depth cap is correctly left unfound. All checked against pre-fix code viagit stashfirst — three of the four correctly failed pre-fix. Full suite (5718 passed) is green.🤖 Generated with Claude Code
https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh