Summary
gbrain embed --stale --catch-up is meant to run until countStaleChunks() returns 0. Instead it aborts almost immediately after the first batch, so large stale backlogs never get embedded.
Cause
In embedAllStale (src/commands/embed.ts), the --catch-up path sets the wall-clock budget to an effectively-unbounded value and passes it directly to setTimeout to arm the budget AbortController:
const BUDGET_MS = staleOpts?.catchUp ? Number.MAX_SAFE_INTEGER : /* 30 min default */;
const budgetTimer = setTimeout(() => budgetController.abort(), BUDGET_MS);
JS timer delays are stored as signed 32-bit milliseconds (max 2,147,483,647 ms ≈ 24.8 days). Number.MAX_SAFE_INTEGER overflows that; Node/Bun clamp it and the timer fires almost immediately, so the controller aborts the run after the first batch.
Impact
On a brain with a large stale backlog, --catch-up never catches up — it silently stops and the backlog persists across runs.
Expected
--catch-up runs until there are no stale chunks left.
Fix
Arm the deadline via a helper that never passes an out-of-range delay to setTimeout (re-arm within the 32-bit cap). PR incoming.
Summary
gbrain embed --stale --catch-upis meant to run untilcountStaleChunks()returns 0. Instead it aborts almost immediately after the first batch, so large stale backlogs never get embedded.Cause
In
embedAllStale(src/commands/embed.ts), the--catch-uppath sets the wall-clock budget to an effectively-unbounded value and passes it directly tosetTimeoutto arm the budgetAbortController:JS timer delays are stored as signed 32-bit milliseconds (max 2,147,483,647 ms ≈ 24.8 days).
Number.MAX_SAFE_INTEGERoverflows that; Node/Bun clamp it and the timer fires almost immediately, so the controller aborts the run after the first batch.Impact
On a brain with a large stale backlog,
--catch-upnever catches up — it silently stops and the backlog persists across runs.Expected
--catch-upruns until there are no stale chunks left.Fix
Arm the deadline via a helper that never passes an out-of-range delay to
setTimeout(re-arm within the 32-bit cap). PR incoming.