fix(parsing): sequential gap-fill for worker-quarantined chunk files (U20.U1)

When the worker pool's Layer 3 quarantine filters one or more files
out of a chunk's dispatch, the worker results returned to
processParsing are silently narrower than the input chunk. Without
this reparse, the graph for this run would be missing every quarantined
file's symbols/imports/calls/heritage with no failure signal.

After the existing per-chunk quarantine log emits in
processParsing's worker-path try-block, run processParsingSequential
on JUST the quarantined-in-chunk files. The sequential path writes
directly to the graph, so symbols for those files land alongside
worker output for the surviving files.

Mirrors the WorkerPoolDispatchError catch-block's processParsingSequential
call shape — same signature, same args, same scopeTreeCache wiring.
Emits a structured warn naming `reparsedPaths` so operators can
observe the sequential fall-through.

This fixes the in-run side of the corruption Codex's adversarial
review of PR #1693 flagged. The cross-run side (chunk-cache
poisoning) is closed by U20.U2 in a follow-up commit.

References plan: docs/plans/2026-05-20-002-fix-chunk-cache-corruption-on-worker-quarantine-plan.md
This commit is contained in:
Gergo Magyar 2026-05-20 13:13:27 +01:00
parent a2878df5fb
commit 7dd489e997

View file

@ -931,6 +931,42 @@ export const processParsing = async (
files.length,
`${quarantinedInChunk.length} worker-quarantined file(s) skipped`,
);
// U20.U1: Sequential gap-fill. The worker pool's Layer 3
// quarantine filtered these files out of dispatch, so the
// worker results above are missing their symbols/imports/
// calls/heritage. Without this reparse, the graph for THIS
// run is silently incomplete — exactly the silent-corruption
// class the Codex adversarial review of PR #1693 flagged.
//
// Running `processParsingSequential` on JUST the quarantined
// files mirrors the WorkerPoolDispatchError catch-block
// shape below (line 961). Worker-extracted data for the
// surviving files flows through `data` to the caller's
// deferred-extraction merge; sequential output for the
// quarantined files writes directly to the graph here.
//
// The chunk-loop caller's cache write at parse-impl.ts:500-
// 507 will NOT cache this chunk because U20.U2's guard
// detects the same quarantine intersection — so next run
// gets a cache miss and a fresh pool gives the file
// another chance.
logger.warn(
{
reparsedPaths: quarantinedInChunk.map((f) => f.path),
count: quarantinedInChunk.length,
},
`Running sequential reparse for ${quarantinedInChunk.length} worker-quarantined ` +
`file(s) to keep this run's graph complete.`,
);
await processParsingSequential(
graph,
quarantinedInChunk,
symbolTable,
astCache,
scopeTreeCache,
reportProgress,
);
}
}
return data;