Extract deterministic type-use relationships and graph gap evidence - #2949
Extract deterministic type-use relationships and graph gap evidence#2949Soumava1 wants to merge 13 commits 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 5 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds deterministic Python uses_type/EXTRACTED edges classified from Tree-sitter annotation context (parameter/return/field, plus nested variants) with aggregated per-target roles, replacing annotation-backed uses/INFERRED edges in the resolution pass. Wires the resolver to accept unchanged-corpus nodes and scan root during incremental extraction, and classifies uses_type as generic in build.py so runtime edges like calls/inherits win same-endpoint collapse. Includes an implementation plan doc and broad test coverage for extraction semantics, incremental resolution, collapse precedence, and conservative fallback on ambiguous/external/local-only references.
Worth a look
- Unbounded Markdown line fragment can crash extraction —
graphify/extractors/markdown.py:258· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Markdown extraction no longer skips non-document links —
graphify/extractors/markdown.py:358· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Duplicate bare module stems now suppress absolute import resolution —
graphify/extractors/resolution.py:1939· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Annotation-only imports no longer emit the existing uses edge —
graphify/extractors/resolution.py:2187· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Graph labels are interpolated into Markdown report without escaping —
graphify/report.py:318· 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 — 3403 functions depend on the 1653 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 482 callers, 44 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
build_from_json()— 186 callers, 18 callees - new:
build_merge()— 46 callers, 14 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
to_obsidian()— 34 callers, 12 callees - new:
to_json()— 50 callers, 7 callees - new:
extract_files_direct()— 17 callers, 20 callees - …and 94 more — each is listed as a finding
Verification — 3403 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: 3023 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify suggest\_questions.
The verifier did not have enough to check suggest\_questions, 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 200 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly ValueError — names the real obstacle, not a sampling gap)
Could not verify: Could not verify extract.
The verifier did not have enough to check extract, 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: parameter `cache_root` is annotated `Path | None` — outside the synthesizable primitive/collection set
Could not verify: Could not verify extract\_markdown.
The verifier did not have enough to check extract\_markdown, 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: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_resolve\_markdown\_link.
The verifier did not have enough to check \_resolve\_markdown\_link, 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: parameter `source_dir` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_resolve\_cross\_file\_imports.
The verifier did not have enough to check \_resolve\_cross\_file\_imports, 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: the input domain has 81 values but only 9 distinct were tested — a small finite domain must be EXHAUSTED, not sampled (an untested input could invert the result)
Could not verify: Could not verify generate.
The verifier did not have enough to check generate, 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 200 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly ValueError — names the real obstacle, not a sampling gap)
· 5 grounded finding(s) anchored inline below; 97 more finding(s) on lines outside this diff (see the check run).
| def _resolve_markdown_link(raw: str, source_dir: Path, | ||
| wikilink: bool = False) -> "Path | None": | ||
| """Resolve a markdown link target to the absolute path of a sibling document. | ||
| def _resolve_markdown_target( |
There was a problem hiding this comment.
_resolve_markdown_target()
6 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| target = _resolve_markdown_target(raw, source_dir, wikilink=wikilink) | ||
| return target.path if target is not None else None | ||
|
|
||
| def extract_markdown(path: Path) -> dict: |
There was a problem hiding this comment.
extract_markdown()
fans out to 8 callees (efferent coupling); 14 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| ) | ||
|
|
||
|
|
||
| def classify_gap_node(graph: nx.Graph, node_id: str) -> GapCategory: |
There was a problem hiding this comment.
classify_gap_node()
9 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return index | ||
|
|
||
|
|
||
| def canonicalize_python_type_aliases( |
There was a problem hiding this comment.
canonicalize_python_type_aliases()
7 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return int(match.group(1)) if match else None | ||
|
|
||
|
|
||
| def resolve_markdown_code_references( |
There was a problem hiding this comment.
resolve_markdown_code_references()
high coupling complexity (Ca·Ce = 15).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Summary
Test plan