fix(merge): respect C# type visibility across repos - #3534
DevChiniwala wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. 1 change(s) tested, no difference found (not proven).
Graphify review — findings
Applies C# namespace/using visibility rules when linking cross-repo member calls, so an unresolved receiver like FluentValidation.IValidator only binds to a candidate type when the caller's namespace, using, or alias resolves that exact name to it (#3360). link_cross_repo_member_calls builds a CsharpNameResolver from the merged graph on demand—only when parked C# entries exist—and rejects candidates whose resolved type doesn't match; non-C# languages keep their existing suffix guard.
No blocking issues surfaced. 7 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 222 functions depend on the 22 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 124 callees - new:
link_cross_repo_member_calls()— 21 callers, 8 callees - new:
global_add()— 12 callers, 9 callees - new:
test_a_cpp_header_declaration_answers_through_defines()— 0 callers, 6 callees - new:
test_a_parked_call_binds_to_the_one_declaration_in_another_repo()— 0 callers, 6 callees - new:
test_a_repo_that_stops_declaring_the_type_loses_the_edge()— 0 callers, 6 callees - new:
test_the_definition_answers_before_a_same_named_declaration()— 0 callers, 6 callees - new:
test_two_repos_declaring_the_same_name_bind_nothing()— 0 callers, 6 callees - …and 1 more — each is listed as a finding
Verification — 222 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: 49 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
4 of 276 test file(s) selected (1%) via static blast radius.
tests/test_cross_repo_external_call_guards.py— impact, changed-testtests/test_cross_repo_member_calls.py— impacttests/test_global_add_tag_inference.py— impacttests/test_global_graph.py— impact
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
No difference found (not proven): No behavior difference found in link\_cross\_repo\_member\_calls (not a proof).
The verifier ran both versions of link\_cross\_repo\_member\_calls on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). 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.
· 9 more finding(s) on lines outside this diff (see the check run).
|
Shipped in v0.9.62 (now on PyPI: |
Fixes #3360
Summary
merge-graphsfrom binding a parked C# call to an unrelated same-named typeusing, alias, and lexical-scope resolverProblem
The cross-repository member-call pass intentionally parks calls whose receiver type is absent from the current repository, then resolves them after graph composition. Its candidate guard checked the candidate's language, source file, repository, and uniqueness, but matched only the bare receiver name for C#.
That allowed an unresolved third-party type such as
FluentValidation.IValidatorto bind to an unrelatedLib.Domain.Interfaces.IValidatorfrom another merged repository. The resultingcallsedge is well-formed and plausible, but fabricates a dependency that does not exist.Fix
For parked C# calls, resolve the receiver through
CsharpNameResolverbefore emitting the cross-repository edge. The resolver already owns Graphify's C# namespace/using/alias visibility rules, so the merge pass now accepts only the exact candidate selected by those rules. Other parked languages retain their existing behavior, and source-backed C# calls resolved within a repository are unchanged.Validation
python -m pytest tests\\test_cross_repo_external_call_guards.py -q— 3 passedpython -m pytest tests\\test_cross_repo_member_calls.py tests\\test_cross_repo_external_call_guards.py tests\\test_csharp_type_resolution.py tests\\test_global_graph.py tests\\test_merge_graphs_cli.py -q— 89 passedruff check graphify\\cross_repo_calls.py tests\\test_cross_repo_external_call_guards.py— passedpython -m compileall -q graphify— passedgit diff --check— passedThe regression test first failed on the current
v8implementation (1 failed, 1 passed): the unrelated third-party receiver incorrectly resolved as one cross-repository call. It passes after the guard, including a real two-root C# extraction case.