From 41653e32992e228d7f88ce36e21a741b27c1f49b Mon Sep 17 00:00:00 2001 From: ShahriarLak Date: Fri, 31 Jul 2026 01:07:56 +0100 Subject: [PATCH] fix(gbrain): make --full do a full code walk, not a delta one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `runCodeImport()` walked with a bare `gbrain sync --strategy code --source X`. The strategy is right, but that walk is incremental: it only revisits files changed since the source's checkpoint. A file missed at the ORIGINAL import is therefore never revisited and stays out of the index indefinitely. The reindex-code pass below cannot rescue it. It re-chunks pages that already exist and never walks the filesystem — the same property the comment directly above already relies on when explaining why the walk has to run first. That fix landed one flag short: it made a fresh source get pages at all, but left `--full` unable to discover a file the first walk skipped. Net effect: `/sync-gbrain --full` did not perform a full walk, and re-running it never re-detected the gap. The failure is silent, which is what makes it expensive. Nothing errors, nothing warns, and the verdict block still reports OK while `gbrain search` and `gbrain code-def` answer out of a partial index. It reads as "gbrain is weak at code questions" rather than "the index is incomplete". Measured on two local code sources before and after this change, counting exported functions resolvable via `gbrain code-def`: one went from 61/201 (30%) to 180/201 (89%), importing 79 files that had no page at all; the other had whole source files missing entirely and reached 93%. Both had been serving search from a partial index for weeks. Scoped to `--full` so incremental runs stay fast. `--yes` because this spawns non-interactively and a full walk otherwise prompts to confirm import cost. Anyone can check their own brain without applying this: gbrain sync --source --strategy code --full --dry-run and compare "N file(s) would be imported" against that source's page_count. Worth knowing while doing so: the default strategy is markdown and --strategy is per-invocation, never persisted on the source, so dropping the flag reports strategy=markdown and a handful of files. --- bin/gstack-gbrain-sync.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/bin/gstack-gbrain-sync.ts b/bin/gstack-gbrain-sync.ts index 07a94af3f4..2570e58cd5 100644 --- a/bin/gstack-gbrain-sync.ts +++ b/bin/gstack-gbrain-sync.ts @@ -895,7 +895,25 @@ async function runCodeImport(args: CliArgs): Promise { }; } - const walkResult = spawnGbrain(["sync", "--strategy", "code", "--source", sourceId], { + // `--full` must do a FULL walk, not a delta one. + // + // A bare `sync --strategy code` is incremental: it only revisits files that + // changed since the source's checkpoint. So a file missed at the ORIGINAL + // import is never revisited and stays invisible indefinitely — and the + // reindex-code pass below cannot rescue it, because it re-chunks pages that + // already exist and never walks the filesystem (the same property the comment + // above already relies on). + // + // The failure is silent: no error, no warning, and the verdict block still + // reports OK while `gbrain search` and `gbrain code-def` answer out of a + // partial index. It presents as "gbrain is weak at code questions" rather + // than "the index is incomplete", which is what makes it hard to spot. + // + // --yes because this is spawned non-interactively; a full walk otherwise + // prompts to confirm the import cost. + const walkArgs = ["sync", "--strategy", "code", "--source", sourceId]; + if (args.mode === "full") walkArgs.push("--full", "--yes"); + const walkResult = spawnGbrain(walkArgs, { stdio: args.quiet ? ["ignore", "ignore", "ignore"] : ["ignore", "inherit", "inherit"], timeout: codeTimeoutMs, baseEnv: gbrainEnv, @@ -907,7 +925,7 @@ async function runCodeImport(args: CliArgs): Promise { ran: true, ok: false, duration_ms: Date.now() - t0, - summary: `gbrain sync --strategy code --source ${sourceId} exited ${walkResult.status}`, + summary: `gbrain ${walkArgs.join(" ")} exited ${walkResult.status}`, detail: { source_id: sourceId, source_path: root, status: "failed" }, }; }