Summary
During autopilot cycle execution, the lint phase creates a second PostgresEngine and shares the module-level db.sql singleton via engine.connect({}) (no poolSize). When the phase completes, engine.disconnect() in the finally block destroys the shared pool, rendering the worker unable to operate. All subsequent phases fail, and the worker crashes with an unhandled rejection.
Impact
- All 9 sources never completed a full cycle
- Brain score stuck at 51 (links 3/25, timeline 2/15, orphans 1/15)
- Worker crash-loops: 51 crash records, max 5 restarts before autopilot gives up
Root Cause
src/commands/lint.ts:298-319, resolveLintContentSanity():
const engine = await createEngine({...});
try {
await engine.connect({}); // no poolSize -> module singleton path
const lifted = await loadConfigWithEngine(engine, base);
} finally {
await engine.disconnect(); // -> db.disconnect() -> sql.end(); sql = null
}
engine.connect({}) without poolSize routes through the module-level db.sql singleton. The subsequent engine.disconnect() in the finally block kills the shared pool for ALL callers in the process, including the MinionWorker.
Diagnosis
Instrumented db.disconnect(), PostgresEngine.disconnect(), and getConnection() with stack traces. The stack trace confirms the disconnect originates from resolveLintContentSanity -> lint.ts:319 -> runLintCore -> runPhaseLint -> runCycle.
Fix
Pass poolSize: 2 so the lint engine gets its own instance-level pool that does not share state with the module singleton:
await engine.connect({ poolSize: 2 });
Related
The /No database connection/i pattern in retry-matcher.ts (added v0.41.2.1) marks this terminal error as retryable, producing misleading connection blip log messages and wasting a 500ms retry. Since the error means the module-level singleton is null, retrying without explicit reconnect is guaranteed to fail.
Summary
During autopilot cycle execution, the lint phase creates a second PostgresEngine and shares the module-level db.sql singleton via engine.connect({}) (no poolSize). When the phase completes, engine.disconnect() in the finally block destroys the shared pool, rendering the worker unable to operate. All subsequent phases fail, and the worker crashes with an unhandled rejection.
Impact
Root Cause
src/commands/lint.ts:298-319, resolveLintContentSanity():
engine.connect({}) without poolSize routes through the module-level db.sql singleton. The subsequent engine.disconnect() in the finally block kills the shared pool for ALL callers in the process, including the MinionWorker.
Diagnosis
Instrumented db.disconnect(), PostgresEngine.disconnect(), and getConnection() with stack traces. The stack trace confirms the disconnect originates from resolveLintContentSanity -> lint.ts:319 -> runLintCore -> runPhaseLint -> runCycle.
Fix
Pass poolSize: 2 so the lint engine gets its own instance-level pool that does not share state with the module singleton:
Related
The /No database connection/i pattern in retry-matcher.ts (added v0.41.2.1) marks this terminal error as retryable, producing misleading connection blip log messages and wasting a 500ms retry. Since the error means the module-level singleton is null, retrying without explicit reconnect is guaranteed to fail.