Files
gbrain/docs
Garry TanandClaude Opus 5 f68e8c3941 fix(embed): stop one bad chunk darkening a page, and exit non-zero on failures (#3037)
Sub-problem 2 (blast radius): all three embed paths (embedPage, embedAll
--all, embedAllStale) sent a page's chunks in ONE embedBatch call inside a
catch that only logged to stderr — one bad chunk left every sibling chunk
NULL. They now route through embedPageTexts: batch first, and on a
PERMANENT request-shaped failure (non-429, non-AITransientError, non-auth)
retry once per chunk so one bad chunk costs one chunk. Rate-limit and
outage errors do NOT fan out (embedBatchWithBackoff already owns 429
backoff; isolating during an outage would just multiply failing calls).
Failed chunks stay embedding IS NULL for the next --stale pass; a
partially-failed page is never signature-stamped.

Sub-problem 3 (silent exit 0): EmbedResult gains additive failures +
failure_samples (capped at 10) fields, incremented at every catch site;
src/cli.ts's embed case mirrors the import case's errors>0 guard and sets
a non-zero exit verdict on failures > 0 instead of discarding the result.
runEmbed prints a one-line stderr summary; the catch-up remaining-stale
warning now reads the same counter.

Tests fail on unmodified master behaviorally (upsert never runs, exit 0
on total failure) and pass here:
- test/embed-partial-failure-3037.serial.test.ts — sibling isolation on
  --stale and --all, failure counting, no-fan-out cost bounds.
- test/embed-exit-code-3037.serial.test.ts — real spawned CLI against a
  tmpdir PGLite brain + mock llama-server: exit != 0 while the provider
  fails, exit 0 once healthy (same brain converges).

Sub-problem 1 of #3037 (chunker char-vs-token cap) is deliberately NOT
touched here (#3477 landed the code-chunker half; #3496 was closed).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 13:13:03 -07:00
..