mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* fix: bound tree-sitter chunker + harden walker + plumb strategy
`gbrain sync --strategy code` against a 1500-file repo could pin one
thread at 99% CPU for hours with zero disk writes and a `page_count`
that stayed at 0. Three real defects, all closed in one commit:
1. **Tree-sitter chunker had no wall-clock cap.** A single pathological
file could wedge the whole sync inside WASM. New `parseWithTimeout`
helper in src/core/chunkers/code.ts wraps `parser.parse()` with
`setTimeoutMicros(timeoutMs * 1000)`, throws `ChunkerTimeoutError`
on null, and the caller's try/finally reaps parser+tree (closes the
leak codex flagged where the catch block returned without delete()).
Default 30s, override via `GBRAIN_CHUNKER_TIMEOUT_MS`. Falls back to
recursive chunks on timeout — degrades search quality on that one
file, doesn't wedge sync.
2. **Code-strategy first-sync silently no-op'd on code files.**
`performFullSync` called `runImport(repoPath)` with no strategy;
`runImport` only ever walked `.md`/`.mdx`. Now `opts.strategy`
threads end-to-end (full-sync write path AND dry-run). Code files
actually reach the dispatcher, which already routes them to
`importCodeFile` correctly.
3. **Walker was thrice-redundant.** `collectMarkdownFiles` (lstat-safe,
import path) and `walkSyncableFiles` (statSync, cost-preview path,
weaker for no good reason) collapsed into one hardened
`collectSyncableFiles` in src/commands/import.ts: lstat + symlink-
skip with canonical log line; inode-cycle Map keyed on
`${st_dev}:${st_ino}` (defense-in-depth for non-symlink loops);
`MAX_WALK_DEPTH=32` structural backstop with `GBRAIN_MAX_WALK_DEPTH`
override; `.sort()` output (codex C8: `runImport`'s checkpoint
resume is index-based against a sorted list). Walker-context
multimodal carve-out preserved at one site (codex C5).
Plus structured `[gbrain phase] <name> start/done` stderr lines on
git_pull, fullsync.import, collect_files, and per-file slow path
(>5s). When the next hang lands, log says which phase wedged.
Tests:
- `test/sync-walker-symlink.test.ts` — 7 cases (self-symlink loop,
symlink-chain inode cycle, max-depth bailout, strategy filter,
dot-dir skip, multimodal preservation, deterministic ordering)
- `test/chunker-timeout.test.ts` — 7 cases (parser-stub seam,
ChunkerTimeoutError shape, env wiring, fallback behavior, fail-loud
if setTimeoutMicros API missing, cleanup contract under exception)
Smoke against the user's actual amarillo-v2 repo: 494 code files
walked in 22ms, 2 symlinks skipped with the canonical log line.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump version 0.30.1 → 0.31.2 + CHANGELOG + TODOS
VERSION 0.31.2, package.json synced. CHANGELOG entry under [0.31.2]
with full release-summary + numbers + upgrader-cost note + To take
advantage block. v0.30.2 entry preserved below from master. TODOS.md
files the gbrain query <common-keyword> 7-day-zombie investigation
(PIDs 39429, 46624) and the deferred amarillo-shape PGLite + Postgres
E2E as v0.31.3 follow-ups.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(test): use withEnv() helper instead of direct process.env mutation
CI's check-test-isolation lint (rule R1) flagged the two new test files
for mutating process.env directly. The repo-wide convention is to wrap
env mutations in withEnv() (test/helpers/with-env.ts), which saves +
restores prior values via try/finally even when the callback throws.
Direct process.env writes leak across files in the same bun test
process (parallel runner loads multiple files into one shard process).
Both files refactored:
- test/sync-walker-symlink.test.ts (GBRAIN_EMBEDDING_MULTIMODAL)
- test/chunker-timeout.test.ts (GBRAIN_CHUNKER_TIMEOUT_MS)
All 14 cases still pass. `bun run verify` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 line
6 B
Plaintext
1 line
6 B
Plaintext
0.31.2 |