/** * Session 64 — nightly backup scheduler. * * The S62 backup script was mechanism-verified but never installed, so the * database went unbacked every night. These lock the arming semantics that make * "deploy == installed" true, and the honesty rules around durability. */ const sched = require('../../src/backupScheduler'); describe('arming (opt-OUT, because opt-in is what failed)', () => { test('armed whenever SUPABASE_DB_URL is present', () => { expect(sched.shouldArm({ SUPABASE_DB_URL: 'postgres://x' }).armed).toBe(true); }); test('BACKUP_CRON=0 is the kill switch', () => { const r = sched.shouldArm({ SUPABASE_DB_URL: 'postgres://x', BACKUP_CRON: '0' }); expect(r.armed).toBe(false); expect(r.reason).toMatch(/kill switch/); }); test('no SUPABASE_DB_URL → disarmed with a reason (nothing to dump)', () => { const r = sched.shouldArm({}); expect(r.armed).toBe(false); expect(r.reason).toMatch(/SUPABASE_DB_URL/); }); test('does NOT require an opt-in env var to arm', () => { // The whole S62 failure: BACKUP_CRON=1 was never set by anyone. expect(sched.shouldArm({ SUPABASE_DB_URL: 'postgres://x' }).armed).toBe(true); }); }); describe('durability honesty', () => { test('warns when neither a volume nor an off-box target is configured', () => { expect(sched.durabilityWarning({})).toMatch(/ephemeral/); }); test('no warning once BACKUP_REMOTE is set', () => { expect(sched.durabilityWarning({ BACKUP_REMOTE: 'u1@box:vyndr/' })).toBeNull(); }); test('no warning once BACKUP_DIR is set (persistent volume)', () => { expect(sched.durabilityWarning({ BACKUP_DIR: '/var/backups/vyndr' })).toBeNull(); }); }); describe('scheduling', () => { const env = { SUPABASE_DB_URL: 'postgres://x', BACKUP_REMOTE: 'u1@box:v/' }; test('runs at the configured minute, and only once per day', async () => { const runs = []; const at = (h, m, day = 19) => new Date(Date.UTC(2026, 6, day, h, m)); let clock = at(3, 10); const s = sched.startBackupScheduler({ env, now: () => clock, notify: async () => {}, runBackup: async () => { runs.push(clock.toISOString()); return { ok: true, code: 0, ms: 1 }; }, }); await s.tick(); await s.tick(); // same minute again — must not re-run expect(runs).toHaveLength(1); clock = at(3, 10, 20); // next day await s.tick(); expect(runs).toHaveLength(2); }); test('does nothing outside the scheduled minute', async () => { const runs = []; const s = sched.startBackupScheduler({ env, now: () => new Date(Date.UTC(2026, 6, 19, 14, 0)), notify: async () => {}, runBackup: async () => { runs.push(1); return { ok: true, code: 0, ms: 1 }; }, }); await s.tick(); expect(runs).toHaveLength(0); }); test('a failed backup pages high priority — silence is the danger', async () => { const alerts = []; const s = sched.startBackupScheduler({ env, now: () => new Date(Date.UTC(2026, 6, 19, 3, 10)), notify: async (msg, opts) => { alerts.push({ msg, opts }); }, runBackup: async () => ({ ok: false, code: 2, ms: 5 }), }); await s.tick(); expect(alerts).toHaveLength(1); expect(alerts[0].opts.priority).toBe('high'); expect(alerts[0].msg).toMatch(/FAILED/); }); test('disarmed scheduler returns null and schedules nothing', () => { expect(sched.startBackupScheduler({ env: {}, notify: async () => {} })).toBeNull(); }); });