Commit Graph
2 Commits
Author SHA1 Message Date
f868257405 v0.42.24.0 fix(minions): route lock claim/renewLock through direct session pool (#1822)
* fix(minions): route lock claim/renewLock through direct session pool

The Minion lock heartbeat (claim + renewLock) ran every UPDATE through
engine.executeRaw(), which is hardcoded to the read pool. On Supabase that
is the transaction-mode pooler (6543), which recycles connections per
transaction. A lock is held for minutes, so the pooler periodically reaps
the socket mid-heartbeat -> CONNECTION_ENDED -> the lock looks expired ->
the worker force-evicts its own job and the claim loop wedges silently.

Add BrainEngine.executeRawDirect(): same contract as executeRaw, but routes
to the direct session-mode pool (5432, GBRAIN_DIRECT_DATABASE_URL) when
dual-pool is active. No-op delegation on PGLite / non-Supabase / kill-switch.
claim/renewLock now use it. Single-statement UPDATEs only, so the double-claim
guard and the renewLock no-inline-retry contract are preserved. Statements
inside an open transaction keep their tx connection (in-transaction guard keys
on peekReadPool() !== _sql); the lock hot-path never runs inside transaction().

The Postgres impl shares its cancellation plumbing with executeRaw via a
private runUnsafe helper. New test/postgres-execute-raw-direct.test.ts covers
the routing decision (dual-pool on/off x in-tx/not + abort short-circuit)
without a live Postgres; queue-lock-retry.test.ts gains a guard that claim
can never fall back to executeRaw.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* v0.42.24.0 chore: bump version and changelog

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: update project documentation for v0.42.24.0

Document executeRawDirect on the BrainEngine contract and the
claim/renewLock direct-session-pool routing in KEY_FILES.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: make D3 executeRaw-no-retry guard refactor-aware

The DRY refactor in this PR extracted executeRaw/executeRawDirect's shared
cancellation plumbing into a private runUnsafe(conn, ...) helper, so the single
conn.unsafe() call moved out of executeRaw's body. The D3 guard read
executeRaw's source and asserted conn.unsafe( appeared exactly once there,
which now fails (it's zero — executeRaw delegates).

The D3 invariant (no per-call retry wrapper) is unchanged; it just spans the
delegate now. Update the guard to check both public methods delegate to
runUnsafe without reconnect/retry, and assert the exactly-once conn.unsafe +
cancel-only catch in runUnsafe. Also extends coverage to executeRawDirect so
the lock hot-path can't reintroduce a retry wrapper either.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 22:40:12 -07:00
766604dea0 v0.42.5.0 fix(minions): RSS watchdog opacity + pooler-reap self-heal + silent lens backlog + cycle lint DB-disconnect (#1678) (#1735)
* fix(minions): self-identifying RSS watchdog + cgroup-aware default + pooler-reap self-heal (#1678)

Problem 1: distinct WORKER_EXIT_RSS_WATCHDOG exit code + cause-keyed supervisor
breaker (bypasses the stable-run reset that hid the 400x/24h loop) + rss_watchdog
audit bucket + 80% soft-warn; cgroup-aware resolveDefaultMaxRssMb replaces the
flat 2048 default at every spawn site.

Problem 2: CONNECTION_ENDED classified retryable; postgres-engine sql getter
throws a retryable error on a reaped instance pool instead of the misleading
module-singleton fallthrough; promoteDelayed reconnect-retry; claim recovers on
the next poll tick (no double-claim); lock-renewal tick reconnect-once dep.

* feat(cycle): surface silent extract_atoms backlog + bounded --drain + fix lint clobbering the shared DB connection (#1678)

Problem 3: extract_atoms_backlog doctor check + pack_gated skip marker +
shared countExtractAtomsBacklog; `gbrain dream --phase extract_atoms --drain
[--window N]` single-hold bounded drain (same cycleLockIdFor, rediscover each
batch, reports remaining, exits non-zero while work remains).

Also fixes a real production bug found via E2E: the cycle lint phase's
resolveLintContentSanity created + disconnected a module-style engine that
nulled the shared db singleton mid-cycle, breaking every later phase with
"connect() has not been called". Lint now reuses the caller's live engine
(cycle + Minion handlers thread it; standalone CLI keeps the create-own path).

* chore: bump version and changelog (v0.41.39.0)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(#1678): pre-landing review — route transaction/withReservedConnection through the sql getter + drain treats failed count as incomplete

Codex adversarial review findings:
- #2: transaction(), withReservedConnection(), and one other site bypassed the
  v0.42.2.0 sql-getter self-heal via `this._sql || db.getConnection()`, so a
  reaped instance pool fell through to the module singleton there. Route all
  three through `this.sql` so they throw the retryable instance-pool error and
  recover consistently (MinionQueue.transaction hits this).
- #4: `gbrain dream --drain` treated a null backlog count (query failure) as
  success via `remaining ?? 0`; now null exits EXIT_DRAIN_INCOMPLETE so
  automation never believes an unverified backlog drained.
- #1 (claim orphan) + #3 (PGLite drain lock) documented as follow-ups in TODOS.

* docs: document v0.42.2.0 #1678 modules + behavior in CLAUDE.md

Adds Key Files entries for worker-exit-codes.ts, rss-default.ts, and
extract-atoms-drain.ts, plus v0.42.2.0 annotations on worker.ts,
child-worker-supervisor.ts, lock-renewal-tick.ts, and dream.ts. Regenerated
llms-full.txt to match (test/build-llms.test.ts gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: re-version v0.42.2.0 → v0.42.5.0 across VERSION/package.json/CHANGELOG/docs/comments

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 22:01:14 -07:00