mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 00:48:18 +00:00
fix(index): preserve code files containing NUL bytes (#3483)
Adversarial review: survived a hostile reviewer plus two independent refuters, each told to assume the PR was broken and to default to refuting when uncertain. 19 of 62 PRs cleared that bar. Code files containing raw NUL bytes hard-failed UTF-8 encoding on import, so they silently never indexed. Sanitized at the single choke point both callers route through, with offsets kept in one coordinate space, and exercised end-to-end on a real engine. Verified before merge: the PR's own tests fail when the production change is reverted; typecheck clean; MERGEABLE/CLEAN with 22/22 checks on the current base after batches 1-3 landed. Known gap, recorded rather than hidden: follow-up to file: reindex-code hash ping-pongs on NUL-containing files — reproduced, bounded, and causes no data loss.
This commit is contained in:
@@ -1161,6 +1161,10 @@ export async function importCodeFile(
|
||||
const title = `${relativePath} (${lang})`;
|
||||
const sourceId = opts.sourceId;
|
||||
const txOpts = sourceId ? { sourceId } : undefined;
|
||||
// PostgreSQL text columns reject U+0000 even though source files may
|
||||
// legitimately contain it inside string/regex fixtures. Preserve a visible,
|
||||
// searchable representation instead of dropping the entire code page.
|
||||
const storageContent = content.replaceAll('\0', '\\0');
|
||||
|
||||
const byteLength = Buffer.byteLength(content, 'utf-8');
|
||||
if (byteLength > MAX_FILE_SIZE) {
|
||||
@@ -1202,7 +1206,7 @@ export async function importCodeFile(
|
||||
// from the chunker (nested methods carry ['ClassName'] etc.) so the
|
||||
// chunk-grain FTS trigger picks up scope for ranking and downstream
|
||||
// Layer 5 edge resolution can use scope-qualified identity.
|
||||
const { chunks: codeChunks, edges: extractedEdges } = await chunkCodeTextFull(content, relativePath);
|
||||
const { chunks: codeChunks, edges: extractedEdges } = await chunkCodeTextFull(storageContent, relativePath);
|
||||
const chunks: ChunkInput[] = codeChunks.map((c, i) => ({
|
||||
chunk_index: i,
|
||||
chunk_text: c.text,
|
||||
@@ -1270,7 +1274,7 @@ export async function importCodeFile(
|
||||
type: 'code' as string,
|
||||
page_kind: 'code',
|
||||
title,
|
||||
compiled_truth: content,
|
||||
compiled_truth: storageContent,
|
||||
timeline: '',
|
||||
frontmatter: { language: lang, file: relativePath },
|
||||
content_hash: hash,
|
||||
@@ -1342,7 +1346,7 @@ export async function importCodeFile(
|
||||
|
||||
const edgeInputs: import('./types.ts').CodeEdgeInput[] = [];
|
||||
for (const e of extractedEdges) {
|
||||
const idx = findChunkForOffset(e.callSiteByteOffset, content, rangeList);
|
||||
const idx = findChunkForOffset(e.callSiteByteOffset, storageContent, rangeList);
|
||||
if (idx == null) continue;
|
||||
const from = rangeList[idx]!;
|
||||
if (!from.id || !from.symbol_name_qualified) continue;
|
||||
|
||||
@@ -90,6 +90,22 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
describe('importFile', () => {
|
||||
test('stores code containing NUL bytes without dropping the page', async () => {
|
||||
const filePath = join(TMP, 'nul-fixture.ts');
|
||||
writeFileSync(filePath, "export const nul = '\0';\n");
|
||||
|
||||
const engine = mockEngine();
|
||||
const result = await importFile(engine, filePath, 'src/nul-fixture.ts', { noEmbed: true });
|
||||
|
||||
expect(result.status).toBe('imported');
|
||||
const calls = (engine as any)._calls;
|
||||
const putCall = calls.find((c: any) => c.method === 'putPage');
|
||||
const chunkCall = calls.find((c: any) => c.method === 'upsertChunks');
|
||||
expect(putCall.args[1].compiled_truth).toContain("'\\0'");
|
||||
expect(putCall.args[1].compiled_truth).not.toContain('\0');
|
||||
expect(chunkCall.args[1].every((chunk: { chunk_text: string }) => !chunk.chunk_text.includes('\0'))).toBe(true);
|
||||
});
|
||||
|
||||
test('imports a valid markdown file', async () => {
|
||||
const filePath = join(TMP, 'test-page.md');
|
||||
writeFileSync(filePath, `---
|
||||
|
||||
Reference in New Issue
Block a user