mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-30 19:49:14 +00:00
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>