fix(llm): hoist the covered-files set out of the uncovered-files loop - #2827
fix(llm): hoist the covered-files set out of the uncovered-files loop#2827sub4biz 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. No changes could be formally verified in this run.
Graphify review — findings
Hoists the covered set resolution out of the uncovered generator in extract_corpus_parallel, so resolve() runs once per entry instead of rebuilding the resolved set for every dispatched item. Fixes the O(dispatched × covered) blowup that stalled large-corpus runs for hours.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 675 functions depend on the 155 functions this change touches.
Health — this change adds coupling hotspots:
- new:
deduplicate_entities()— 63 callers, 20 callees - new:
build_merge()— 43 callers, 14 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
_call_claude_cli()— 31 callers, 9 callees - new:
extract_corpus_parallel()— 26 callers, 10 callees - new:
dispatch_command()— 2 callers, 117 callees - new:
_call_llm()— 11 callers, 17 callees - new:
_call_openai_compat()— 23 callers, 8 callees - …and 14 more — each is listed as a finding
Verification — 675 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: 422 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify extract\_corpus\_parallel.
The verifier did not have enough to check extract\_corpus\_parallel, 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 `root` is annotated `Path` — outside the synthesizable primitive/collection set
· 22 more finding(s) on lines outside this diff (see the check run).
extract_corpus_parallel's uncovered-files reconciliation rebuilt
{c.resolve() for c in covered} from scratch inside the generator, once
per item in `dispatched` -- O(len(dispatched) * len(covered)) resolve()
syscalls instead of O(len(dispatched) + len(covered)). Confirmed live
via py-spy: a real ~23k-file semantic run sat in this exact call chain
continuously for over an hour, CPU still climbing, before being
interrupted -- the interrupt traceback pointed at this exact line.
Measured (N=1000 dispatched/covered, scaled down from the real ~23000):
old 76.85s vs new 0.246s (~312x). Quadratic growth means the real corpus
size projects to roughly 11+ hours on this one step alone before this
fix. Existing test_chunking.py coverage (checkpoint scoping,
out-of-scope node dropping, uncovered-files detection) passes unchanged
-- pure hoist of a loop-invariant computation, same result set.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3df5b6e to
111c03b
Compare
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).
Graphify review — findings
Hoists the covered resolution out of the uncovered generator in extract_corpus_parallel, precomputing _covered_resolved once instead of rebuilding the resolved set per dispatched file. Cuts resolve() syscalls from O(dispatched × covered) to O(dispatched + covered), fixing a multi-hour hang on large corpora.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 675 functions depend on the 155 functions this change touches.
Health — this change adds coupling hotspots:
- new:
deduplicate_entities()— 63 callers, 20 callees - new:
build_merge()— 43 callers, 14 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
_call_claude_cli()— 31 callers, 9 callees - new:
extract_corpus_parallel()— 26 callers, 10 callees - new:
dispatch_command()— 2 callers, 117 callees - new:
_call_llm()— 11 callers, 17 callees - new:
_call_openai_compat()— 23 callers, 8 callees - …and 14 more — each is listed as a finding
Verification — 675 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: 422 function(s) in the blast radius were not formally verified this run
· 22 more finding(s) on lines outside this diff (see the check run).
Summary
extract_corpus_parallel's uncovered-files reconciliation (graphify/llm.py, ~line 2508-2517) rebuilds{c.resolve() for c in covered}from scratch inside the generator passed tosorted(), once per item indispatched:That's O(len(dispatched) × len(covered))
Path.resolve()calls (each a realrealpathsyscall) insteadof the obviously-intended O(len(dispatched) + len(covered)). This PR hoists the set comprehension out of the
loop so it's computed once.
Impact
Found on a real ~23,000-file semantic-extraction run: this single reconciliation step sat in this exact call
chain continuously for over an hour (confirmed live via
py-spy dumpsampling — same stack frame,climbing CPU time, no progress), before the run was interrupted rather than left to finish. The interrupt
traceback pointed at this exact line, independently confirming the
py-spydiagnosis.Measured
Quadratic growth means the real corpus size (~23x larger) projects to roughly
23² ≈ 529xworse than theN=1000 old-code number — on the order of 11+ hours for this one step alone before this fix.
Fix
Pure hoist of a loop-invariant computation — verified the result set is identical to the old code via an
assertin the reproduction script (see commit message). No behavior change, no API change.Testing
tests/test_chunking.pycoverage for this exact code path (checkpoint scoping, out-of-scope nodedropping,
uncovered_filesdetection/warning) passes unchanged.