diff --git a/gitnexus/src/core/ingestion/parsing-processor.ts b/gitnexus/src/core/ingestion/parsing-processor.ts index 73a72aa22..a276a0ab4 100644 --- a/gitnexus/src/core/ingestion/parsing-processor.ts +++ b/gitnexus/src/core/ingestion/parsing-processor.ts @@ -875,7 +875,7 @@ export const processParsing = async ( ); } try { - return await processParsingWithWorkers( + const data = await processParsingWithWorkers( graph, files, symbolTable, @@ -884,6 +884,28 @@ export const processParsing = async ( reportProgress, outRawResults, ); + // Session-scoped quarantine (worker-pool resilience Layer 3): surface + // any files this pool has decided are unsafe for workers so the + // operator can see what was skipped. The pool already filtered them + // out of dispatch; we only need to log + progress-report. Quarantine + // is session-scoped per pool instance — a fresh `createWorkerPool` + // call clears it. + const quarantineSet = new Set(workerPool.getQuarantinedPaths?.() ?? []); + if (quarantineSet.size > 0) { + const quarantinedInChunk = files.filter((file) => quarantineSet.has(file.path)); + if (quarantinedInChunk.length > 0) { + logger.warn( + { quarantinedFiles: quarantinedInChunk.map((file) => file.path) }, + `Worker quarantine: ${quarantinedInChunk.length} file(s) skipped in this chunk (cumulative pool quarantine: ${quarantineSet.size}).`, + ); + reportProgress?.( + lastProgress, + files.length, + `${quarantinedInChunk.length} worker-quarantined file(s) skipped`, + ); + } + } + return data; } catch (err) { const message = err instanceof Error ? err.message : String(err); let fallbackFiles = files; diff --git a/gitnexus/src/core/ingestion/workers/parse-worker.ts b/gitnexus/src/core/ingestion/workers/parse-worker.ts index da681b070..2166ca950 100644 --- a/gitnexus/src/core/ingestion/workers/parse-worker.ts +++ b/gitnexus/src/core/ingestion/workers/parse-worker.ts @@ -1401,6 +1401,13 @@ const processFileGroup = ( // Skip files larger than the max tree-sitter buffer (32 MB) if (getTreeSitterContentByteLength(file.content) > TREE_SITTER_MAX_BUFFER) continue; + // Authoritative in-flight signal for the pool: lets `WorkerPool` exclude + // exactly this file if the worker dies during parse/extract, instead of + // guessing from `items[lastProgress]` (which the language-grouped order + // here would defeat). The pool gracefully ignores this when running an + // older worker build that doesn't emit it. + if (parentPort) parentPort.postMessage({ type: 'starting-file', path: file.path }); + // Vue SFC preprocessing: extract