/** * Tests for src/core/embed-backfill-submit.ts (v0.40 D19). * * Validates the submission gate layer: * - Default path: submits with priority 5 + idempotency bucket * - Cooldown: refuses re-submission inside the window * - Active-job: refuses while a same-source job is active/waiting * - 24h spend cap: refuses when accumulated spend >= cap * - Config overrides honored (per-test cap + cooldown) * - Override knobs in opts honored (test seam) */ import { describe, test, expect, beforeAll, afterAll, beforeEach } from 'bun:test'; import { PGLiteEngine } from '../src/core/pglite-engine.ts'; import { resetPgliteState } from './helpers/reset-pglite.ts'; import { submitEmbedBackfill, COOLDOWN_CONFIG_KEY, SPEND_CAP_CONFIG_KEY, } from '../src/core/embed-backfill-submit.ts'; import { MinionQueue } from '../src/core/minions/queue.ts'; let engine: PGLiteEngine; beforeAll(async () => { engine = new PGLiteEngine(); await engine.connect({}); await engine.initSchema(); }, 30000); // 30s — PGLite WASM cold-start + 89 migrations exceeds 5s default afterAll(async () => { await engine.disconnect(); }); beforeEach(async () => { // Surgical reset (mirrors test/minions.test.ts) — full TRUNCATE wipes the // config table's `version` key that MinionQueue.ensureSchema() reads. await engine.executeRaw('DELETE FROM minion_jobs'); }); describe('submitEmbedBackfill — happy path', () => { test('submits with priority 5 + idempotency key on a clean source', async () => { const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit' }); expect(result.status).toBe('submitted'); expect(result.jobId).toBeDefined(); const queue = new MinionQueue(engine); const job = await queue.getJob(result.jobId!); expect(job).not.toBeNull(); expect(job!.name).toBe('embed-backfill'); expect(job!.priority).toBe(5); expect((job!.data as { sourceId: string }).sourceId).toBe('default'); }); test('respects opts.priority override', async () => { const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', priority: -10, }); expect(result.status).toBe('submitted'); const queue = new MinionQueue(engine); const job = await queue.getJob(result.jobId!); expect(job!.priority).toBe(-10); }); }); describe('submitEmbedBackfill — cooldown gate', () => { test('blocks re-submission while a same-source job is active', async () => { const queue = new MinionQueue(engine); // Seed an active job manually await queue.add('embed-backfill', { sourceId: 'default' }, {}); await engine.executeRaw( `UPDATE minion_jobs SET status='active' WHERE name='embed-backfill'`, ); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit' }); expect(result.status).toBe('cooldown'); expect(result.cooldownRemainingSeconds).toBeUndefined(); }); test('blocks re-submission inside the cooldown window after recent finish', async () => { const queue = new MinionQueue(engine); const job = await queue.add('embed-backfill', { sourceId: 'default' }, {}); // Mark completed 1 minute ago await engine.executeRaw( `UPDATE minion_jobs SET status='completed', finished_at=NOW() - INTERVAL '1 minute' WHERE id=$1`, [job.id], ); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', cooldownMinOverride: 10, // 10min cooldown; 1min elapsed → blocked }); expect(result.status).toBe('cooldown'); expect(result.cooldownRemainingSeconds).toBeGreaterThan(0); expect(result.cooldownRemainingSeconds).toBeLessThanOrEqual(10 * 60); }); test('allows re-submission after cooldown elapses', async () => { const queue = new MinionQueue(engine); const job = await queue.add('embed-backfill', { sourceId: 'default' }, {}); // Mark completed 11 minutes ago — past the 10-min cooldown await engine.executeRaw( `UPDATE minion_jobs SET status='completed', finished_at=NOW() - INTERVAL '11 minutes' WHERE id=$1`, [job.id], ); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', cooldownMinOverride: 10, }); expect(result.status).toBe('submitted'); }); test('config-overridable cooldown (via embed.backfill_cooldown_min)', async () => { await engine.setConfig(COOLDOWN_CONFIG_KEY, '60'); // 60min cooldown const queue = new MinionQueue(engine); const job = await queue.add('embed-backfill', { sourceId: 'default' }, {}); await engine.executeRaw( `UPDATE minion_jobs SET status='completed', finished_at=NOW() - INTERVAL '30 minutes' WHERE id=$1`, [job.id], ); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit' }); expect(result.status).toBe('cooldown'); }); }); describe('submitEmbedBackfill — 24h spend cap', () => { test('refuses when spend24hFn returns >= cap', async () => { const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', spendCapUsdOverride: 25, spend24hFn: async () => 25, }); expect(result.status).toBe('spend_capped'); expect(result.spend24hUsd).toBe(25); expect(result.spendCapUsd).toBe(25); }); test('admits when spend24hFn returns < cap', async () => { const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', spendCapUsdOverride: 25, spend24hFn: async () => 24.99, }); expect(result.status).toBe('submitted'); }); test('config-overridable spend cap (via embed.backfill_max_usd_per_source_24h)', async () => { await engine.setConfig(SPEND_CAP_CONFIG_KEY, '5'); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', spend24hFn: async () => 5, }); expect(result.status).toBe('spend_capped'); expect(result.spendCapUsd).toBe(5); }); // v0.42.42.0 (#2139): off-switch + tokenmax bypass. test('cap "off" → submits even at huge spend (Infinity cap never tripped)', async () => { await engine.setConfig(SPEND_CAP_CONFIG_KEY, 'off'); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', spend24hFn: async () => 1e9, }); expect(result.status).toBe('submitted'); }); test('0 falls back to the default cap (off semantics ≠ 0)', async () => { await engine.setConfig(SPEND_CAP_CONFIG_KEY, '0'); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', spend24hFn: async () => 25, // == default $25 → capped }); expect(result.status).toBe('spend_capped'); expect(result.spendCapUsd).toBe(25); }); test('spend.posture=tokenmax bypasses the cap, marks spendCapBypassed', async () => { const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', postureOverride: 'tokenmax', spendCapUsdOverride: 25, spend24hFn: async () => 100, // way over cap }); expect(result.status).toBe('submitted'); expect(result.spendCapBypassed).toBe(true); expect(result.spend24hUsd).toBe(100); }); test('tokenmax does NOT bypass the cooldown (axis split — churn protection stays)', async () => { const queue = new MinionQueue(engine); const job = await queue.add('embed-backfill', { sourceId: 'default' }, {}); await engine.executeRaw( `UPDATE minion_jobs SET status='completed', finished_at=NOW() - INTERVAL '1 minute' WHERE id=$1`, [job.id], ); const result = await submitEmbedBackfill(engine, 'default', { reason: 'unit', postureOverride: 'tokenmax', cooldownMinOverride: 10, spend24hFn: async () => 1e9, }); expect(result.status).toBe('cooldown'); // posture lifts the cap, NOT the cooldown }); }); describe('submitEmbedBackfill — source isolation', () => { test('cooldown is per-source, not global', async () => { await engine.executeRaw( `INSERT INTO sources (id, name, config) VALUES ('other', 'other', '{"federated":true}') ON CONFLICT (id) DO NOTHING`, ); const queue = new MinionQueue(engine); // Active job on 'default' await queue.add('embed-backfill', { sourceId: 'default' }, {}); await engine.executeRaw(`UPDATE minion_jobs SET status='active' WHERE name='embed-backfill'`); // Submit for 'other' — should NOT be blocked const result = await submitEmbedBackfill(engine, 'other', { reason: 'unit' }); expect(result.status).toBe('submitted'); }); });