- getDelay indexed by attempt (1-based) into a 0-indexed array, so the
leading 0 was unreachable and every "after a crash" delay was shifted
up one slot. Use attempt - 1 so the documented schedule (0s → 0s →
10s → 30s → 2min → 5min → 15min cap) actually holds.
- enforceStartupBackoff runs before initDb (which creates DATA_DIR), so
on a fresh checkout fs.writeFileSync hit ENOENT. write() now
mkdirSync's DATA_DIR first.
- shutdown() didn't run resetCircuitBreaker if teardownChannelAdapters
threw, so a graceful exit with a teardown error would be counted as a
crash on the next start. Wrap teardown in try/finally.
- Adds src/circuit-breaker.test.ts: state transitions, full schedule
(parameterized), reset-window expiry, malformed file, and the
fresh-install path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>