fix(extract): resolve cross-file Rust self calls for simple generic impls - #3653
oleksii-tumanov wants to merge 1 commit into
Conversation
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.
Formal verification. 1 change(s) tested, no difference found (not proven).
Graphify review — findings
Adds generic-impl identity resolution for Rust self. member calls: _rust_simple_generic_impl_key persists a stable owner/arity marker (e.g. Bucket/1) for bare unbounded generic impls, and _resolve_rust_self_member_calls pools methods by that marker only when exactly one such declaration exists in the corpus, never falling back to bare-label pooling when marker context is absent or ambiguous. Bumps _AST_CACHE_SCHEMA to 4 and preserves the new _rust_impl_key/_rust_declaration_count markers on unchanged nodes during incremental rebuilds since they can't be reconstructed from labels.
Worth a look
- Non-generic impl blocks reset shared impl_key to None, dropping generic identity —
graphify/extractors/rust.py:452· 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 — 2825 functions depend on the 878 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 646 callers, 45 callees - new:
_rebuild_code()— 133 callers, 54 callees - new:
detect()— 112 callers, 15 callees - new:
save_semantic_cache()— 63 callers, 9 callees - new:
load_cached()— 53 callers, 7 callees - new:
extract_js()— 85 callers, 4 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
file_hash()— 51 callers, 6 callees - …and 48 more — each is listed as a finding
Verification — 2825 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: 2757 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
156 of 286 test file(s) selected (55%) via static blast radius.
tests/test_affected_cli.py— impacttests/test_agents_platform.py— impacttests/test_astro_extraction.py— impacttests/test_astro_import_ids.py— impacttests/test_build.py— impacttests/test_builtin_global_type_refs.py— impacttests/test_cache.py— impacttests/test_case_sensitive_resolution.py— impacttests/test_charmap_encoding.py— impacttests/test_chunking.py— impacttests/test_cjs_module_extension.py— impacttests/test_codebuddy.py— impacttests/test_cpp_nested_and_cli.py— impacttests/test_cpp_objc_cross_file_calls.py— impacttests/test_cross_extension_reexport_self_cycle.py— impacttests/test_cross_language_call_resolution.py— impacttests/test_cross_repo_external_call_guards.py— impacttests/test_cross_repo_member_calls.py— impacttests/test_csharp_call_site_generic_args.py— impacttests/test_csharp_enum_members.py— impacttests/test_csharp_field_generic_args.py— impacttests/test_csharp_generic_callsites.py— impacttests/test_csharp_interface_dispatch.py— impacttests/test_csharp_member_calls.py— impacttests/test_csharp_member_nodes.py— impacttests/test_csharp_object_creation.py— impacttests/test_csharp_partial_classes.py— impacttests/test_csharp_type_resolution.py— impacttests/test_definition_file_portability.py— impacttests/test_detect.py— impacttests/test_devin.py— impacttests/test_dotnet.py— impacttests/test_duplicate_annotation_edges.py— impacttests/test_elixir_import_resolution.py— impacttests/test_explain_cli.py— impacttests/test_external_stub_endpoints.py— impacttests/test_extract.py— impacttests/test_extract_cache_location.py— impacttests/test_extract_cli.py— impacttests/test_file_label_disambiguation.py— impacttests/test_file_node_id_spec.py— impacttests/test_forwarding_review_findings.py— impacttests/test_global_add_tag_inference.py— impacttests/test_go_builtin_call_targets.py— impacttests/test_go_qualified_resolution.py— impacttests/test_god_nodes_cli.py— impacttests/test_hollow_chunks_arm_shrink_guard.py— impacttests/test_hook_guard_token_match.py— impacttests/test_hook_out_of_project_paths.py— impacttests/test_hook_strict.py— impact- … and 106 more
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.
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
No difference found (not proven): No behavior difference found in \_resolve\_rust\_self\_member\_calls (not a proof).
The verifier ran both versions of \_resolve\_rust\_self\_member\_calls on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: concolic exploration (CrossHair). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify extract\_rust.
The verifier did not have enough to check extract\_rust, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_rebuild\_code.
The verifier did not have enough to check \_rebuild\_code, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: parameter `watch_path` is annotated `Path` — outside the synthesizable primitive/collection set
· 1 grounded finding(s) anchored inline below; 55 more finding(s) on lines outside this diff (see the check run).
| add_edge(func_nid, tgt, "references", line, context=ctx) | ||
|
|
||
| def walk(node, parent_impl_nid: str | None = None, parent_impl_type: str | None = None) -> None: | ||
| def walk( |
There was a problem hiding this comment.
walk()
fans out to 9 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
…the graph (#3644 follow-up) #3644 persists HCL block attributes into node metadata, which is serialized to graph.json verbatim and surfaced to the model over MCP (query/get_node) with no sanitize_metadata pass. A hardcoded credential in a .tf file (password, db_password, aws_secret_access_key, client_secret, a connection string, ...) would leak. Redact the VALUE of any attribute whose key names a secret while keeping the key visible, so instance_type/ami queries still work and a user can still see THAT a secret is set. Recurses into map values so a nested secret in a tags/connection map is redacted too. Also notes Terraform block attributes in the _AST_CACHE_SCHEMA 4 comment (they are newly-cached facts covered by the same bump #3653 introduced). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes #3652
Summary
self.method()calls across simple alpha-equivalent generic inherent impl blocks.Before and after
Before: a call in
impl<U> Bucket<U>could not reach a method defined in another file'simpl<T> Bucket<T>block.After: Graphify links the call when the generic impl family has one declaration and an unambiguous method. More complex generic shapes still produce no guessed edge.
Testing
uv run pytest tests/ -q(5,785 passed, 14 skipped)uv run ruff check graphify/cache.py graphify/cli.py graphify/extract.py graphify/extractors/rust.py graphify/watch.py tests/test_incremental.py tests/test_rust_self_member_calls.py tests/test_watch.pyuv run python -m tools.skillgen --checkuv run graphify update . --no-cluster