fix(resolution): sweep orphaned unresolved refs so an interrupted index heals on sync (#1187) (#1191)
An indexing run killed mid-"Resolving refs" (crash, Ctrl-C, the #1122 watchdog kill) left the refs it never reached parked in unresolved_refs. The git-scoped sync fast path only re-resolves changed files' refs, so those files' call edges were missing permanently — a too-small blast radius clustering by package/module (the #1187 field report: 3 of 10 caller files for a Spring @Resource-injected method) — until a full re-index. - sync() now sweeps leftover unresolved refs with the batched resolver after its scoped pass, including on no-change syncs, so a bare `codegraph sync` recovers a wedged index (and heals pre-fix indexes on the first post-upgrade sync) - the scoped pass deletes unresolvable rows too (parity with the batched path), making "rows at rest" a sound orphan signal - drop the batched loop's early break that abandoned all later batches when one batch was all-unresolvable (its rows WERE consumed — that early stop could orphan the rest of the table at init) - surface the state: `codegraph status` warns, `status --json` gains index.pendingRefs, and MCP codegraph_status tells agents the blast radius is incomplete until the next sync Verified end-to-end on a 2,414-file synthetic Spring repo: SIGKILL mid-resolution reproduces the reporter's exact 3-of-10-callers state; a bare sync now heals it to 10/10 with the edge count converging to the clean-init total; a healthy-index sync stays a no-op. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7f325134e0
commit
4c15f84aa4
@@ -807,6 +807,9 @@ program
|
||||
const buildInfo = cg.getIndexBuildInfo();
|
||||
const reindexRecommended = cg.isIndexStale();
|
||||
const indexState = cg.getIndexState();
|
||||
// Zero on a healthy index; non-zero at rest means a resolution pass was
|
||||
// interrupted, so some files' call edges are missing (#1187).
|
||||
const pendingRefs = cg.getPendingReferenceCount();
|
||||
|
||||
// JSON output mode
|
||||
if (options.json) {
|
||||
@@ -842,6 +845,10 @@ program
|
||||
// (a run was killed mid-index — the index is truncated) |
|
||||
// 'failed' | null (predates the marker).
|
||||
state: indexState,
|
||||
// References awaiting resolution. Non-zero at rest means an
|
||||
// interrupted resolution pass left edges missing; the next
|
||||
// sync sweeps them (#1187).
|
||||
pendingRefs,
|
||||
},
|
||||
}));
|
||||
cg.destroy();
|
||||
@@ -862,6 +869,9 @@ program
|
||||
} else if (indexState === 'failed') {
|
||||
warn('The last index run failed — results may be incomplete. Re-run "codegraph index".');
|
||||
}
|
||||
if (pendingRefs > 0) {
|
||||
warn(`${formatNumber(pendingRefs)} references from an interrupted run are awaiting resolution — some callers/impact edges are missing. Run "codegraph sync" to resolve them.`);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Index stats
|
||||
|
||||
Reference in New Issue
Block a user