refactor(extraction): one-purpose size-stamp reader, comments in operation order

`readSourceOrStamp` took a `stats` argument no caller passed and returned
stats no caller read; it now returns the text or stamp change detection
hashes. The batch reader's two comments are back in the order its code runs:
the size gate, then the MPEG-TS head check. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
danusha2345
2026-09-23 14:42:06 +00:00
committed by Forge
co-authored by Claude Opus 5.5
parent cf66c2148f
commit a36a9e1013
+11 -14
View File
@@ -167,14 +167,12 @@ export function oversizeStamp(size: number): string {
}
/**
* Read a file for hashing/indexing: the whole text when it is under the size
* limit, the size stamp when it is over — the caller never decodes an oversize
* file. `stats` is what the caller already has; without it the file is stat'ed.
* What change detection hashes for a file: its text when it is under the size
* limit, the size stamp when it is over — an oversize file is never decoded.
*/
function readSourceOrStamp(fullPath: string, stats?: fs.Stats): { content: string; stats: fs.Stats } {
const st = stats ?? fs.statSync(fullPath);
if (st.size > MAX_SOURCE_FILE_SIZE_BYTES) return { content: oversizeStamp(st.size), stats: st };
return { content: fs.readFileSync(fullPath, 'utf-8'), stats: st };
function readSourceOrStamp(fullPath: string): string {
const size = fs.statSync(fullPath).size;
return size > MAX_SOURCE_FILE_SIZE_BYTES ? oversizeStamp(size) : fs.readFileSync(fullPath, 'utf-8');
}
/**
@@ -2321,10 +2319,6 @@ export class ExtractionOrchestrator {
logWarn('Path traversal blocked in batch reader', { filePath: fp });
return { filePath: fp, content: null as string | null, stats: null as fs.Stats | null, error: new Error('Path traversal blocked') };
}
// Read bytes, not text: a `.ts` that is really an MPEG transport
// stream (#1910) is recognised from its head here, at no extra I/O,
// and never decoded or parsed. The scan already drops these; this
// guards the paths that hand files in by name (sync, watcher).
// Stat first: a file over the size limit is stored as skipped
// without ever being read or decoded (#1910), so ten oversize
// fixtures in one I/O batch no longer cost their size in RSS.
@@ -2332,6 +2326,9 @@ export class ExtractionOrchestrator {
if (stats.size > MAX_SOURCE_FILE_SIZE_BYTES) {
return { filePath: fp, content: oversizeStamp(stats.size), stats, error: null as Error | null };
}
// Read bytes, not text: a `.ts` that is really an MPEG transport
// stream (#1910) is recognised from its head here, at no extra I/O,
// and never decoded or parsed.
const bytes = await fsp.readFile(fullPath);
if (hasMpegTsExtension(fp) && isMpegTransportStream(bytes.subarray(0, MPEG_TS_SNIFF_BYTES))) {
logDebug('Skipping MPEG transport stream named .ts — not TypeScript', { filePath: fp });
@@ -3287,7 +3284,7 @@ export class ExtractionOrchestrator {
// (An oversize file hashes as its size stamp, unread — #1910.)
let content: string;
try {
content = readSourceOrStamp(fullPath).content;
content = readSourceOrStamp(fullPath);
} catch (error) {
logDebug('Skipping unreadable file during sync', { filePath, error: String(error) });
failedFilePaths.push(filePath);
@@ -3452,7 +3449,7 @@ export class ExtractionOrchestrator {
continue;
}
let content: string;
try { content = readSourceOrStamp(fullPath).content; }
try { content = readSourceOrStamp(fullPath); }
catch (error) {
logDebug('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
continue;
@@ -3490,7 +3487,7 @@ export class ExtractionOrchestrator {
const fullPath = path.join(this.rootDir, filePath);
let content: string;
try {
content = readSourceOrStamp(fullPath).content;
content = readSourceOrStamp(fullPath);
} catch (error) {
logDebug('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
continue;