fix: canonicalize semantic whole-file code aliases - #3249
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. No changes could be formally verified in this run.
Graphify review — findings
Adds semantic whole-file alias canonicalization (#3246): during build_from_json, _code_file_alias_remap detects LLM-minted entity nodes suffixed with _module, _script, or _file and folds them onto the matching bare-stem AST file node, keeping the AST node as the survivor with its authoritative _origin/source_file/source_location/label and merging only non-conflicting semantic attributes like rationale and summary. Edges and hyperedges pointing at the alias are rewired to the AST node, with resulting self-loops and duplicate hyperedge members dropped. Nested symbol nodes below the file stem (e.g. ..._run) and similarly named files under different paths stay distinct.
No blocking issues surfaced. 10 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1175 functions depend on the 97 functions this change touches.
Health — this change adds coupling hotspots:
- new:
_rebuild_code()— 113 callers, 50 callees - new:
build_from_json()— 199 callers, 19 callees - new:
build_merge()— 62 callers, 13 callees - new:
to_obsidian()— 36 callers, 13 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
to_wiki()— 41 callers, 7 callees - new:
extract_corpus_parallel()— 26 callers, 11 callees - new:
_call_claude_cli()— 31 callers, 9 callees - …and 38 more — each is listed as a finding
Verification — 1175 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: 775 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify build\_from\_json.
The verifier did not have enough to check build\_from\_json, 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: not verifiable: all 6 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly NameError — names the real obstacle, not a sampling gap)
· 1 grounded finding(s) anchored inline below; 45 more finding(s) on lines outside this diff (see the check run).
| return remap, attr_updates | ||
|
|
||
|
|
||
| def build_from_json(extraction: dict, *, directed: bool = False, root: str | Path | None = None) -> nx.Graph: |
There was a problem hiding this comment.
build_from_json()
fans out to 19 callees (efferent coupling); 199 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Summary
Fixes #3246.
When a code file is both AST-parsed and referenced by a semantic extraction source such as a planning document, the semantic extractor can create a suffixed alias such as
<file_stem>_module. This previously survived as a separate node from the canonical AST file node, leaving the code and documentation disconnected.This change canonicalizes recognized whole-file semantic aliases onto the existing AST file node.
What changed
Added deterministic resolution for semantic
_module,_script, and_filealiases.Only aliases whose stripped ID exactly matches an existing AST file-level node are canonicalized.
Preserves the AST node as the authoritative node for:
id_originsource_filesource_locationlabelfile_typePreserves non-conflicting semantic metadata from the alias.
Rewires incoming/outgoing edges to the canonical AST node.
Rewrites hyperedge members when an alias is removed.
Added regression coverage for the issue and safety cases.
Safety
The resolver is intentionally narrow:
_module,_script, and_file._runor_parse_argsare not affected.Validation
tests/test_semantic_code_file_alias.py— 8 passedtests/test_build.py tests/test_dedup.py— 167 passedgit diff --cached --check— cleanTotal validated: 263 tests passed.