/** * v0.35.0.0+ rerank-audit JSONL round-trip. * * Pins: * - logRerankFailure → readRecentRerankFailures round-trip * - error_summary truncated to 200 chars (privacy/size) * - corrupt rows skipped (audit is informational, never breaks search) * - ISO-week filename rotation * - CDX2-F22: logRerankSuccess does NOT exist (success-events were dropped * per adversarial review — hot-path I/O churn + privacy concerns) * * Uses `withEnv()` per the test-isolation lint rule R1: never mutate * process.env directly outside `*.serial.test.ts` (process.env is global * and leaks across files in the parallel runner's shard process). */ import { describe, test, expect } from 'bun:test'; import * as fs from 'node:fs'; import * as path from 'node:path'; import * as os from 'node:os'; import { withEnv } from './helpers/with-env.ts'; import { logRerankFailure, readRecentRerankFailures, computeRerankAuditFilename, } from '../src/core/rerank-audit.ts'; /** * Run a test body inside a fresh tmp audit dir scoped to that test. Cleans * up the dir after. `withEnv` handles env-restore via try/finally. */ async function withFreshAuditDir(body: (tmpDir: string) => void | Promise): Promise { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gbrain-rerank-audit-')); try { await withEnv({ GBRAIN_AUDIT_DIR: tmpDir }, async () => { await body(tmpDir); }); } finally { try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* ignore */ } } } describe('rerank-audit JSONL round-trip', () => { test('log → read returns the same event shape', async () => { await withFreshAuditDir(() => { logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'auth', query_hash: 'a1b2c3d4', doc_count: 30, error_summary: 'invalid api key', }); const events = readRecentRerankFailures(7); expect(events.length).toBe(1); expect(events[0]).toMatchObject({ model: 'zeroentropyai:zerank-2', reason: 'auth', query_hash: 'a1b2c3d4', doc_count: 30, error_summary: 'invalid api key', severity: 'warn', }); expect(typeof events[0]!.ts).toBe('string'); }); }); test('error_summary truncated to ~200 chars', async () => { await withFreshAuditDir(() => { const longMsg = 'x'.repeat(500); logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'unknown', query_hash: 'deadbeef', doc_count: 0, error_summary: longMsg, }); const events = readRecentRerankFailures(7); expect(events[0]!.error_summary.length).toBeLessThanOrEqual(200); }); }); test('multiple failures append to same JSONL file', async () => { await withFreshAuditDir(() => { for (let i = 0; i < 5; i++) { logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'network', query_hash: `hash${i}`, doc_count: 30, error_summary: `failure ${i}`, }); } const events = readRecentRerankFailures(7); expect(events.length).toBe(5); expect(new Set(events.map(e => e.query_hash)).size).toBe(5); }); }); test('corrupt JSONL rows skipped silently', async () => { await withFreshAuditDir((tmpDir) => { const filename = computeRerankAuditFilename(); const filepath = path.join(tmpDir, filename); // First write a valid row, then garbage, then another valid row. logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'timeout', query_hash: 'good1', doc_count: 30, error_summary: 'ok 1', }); fs.appendFileSync(filepath, 'not valid json\n'); fs.appendFileSync(filepath, '{"partial":\n'); logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'timeout', query_hash: 'good2', doc_count: 30, error_summary: 'ok 2', }); const events = readRecentRerankFailures(7); expect(events.length).toBe(2); expect(events.map(e => e.query_hash)).toEqual(['good1', 'good2']); }); }); test('missing audit dir → readRecentRerankFailures returns []', async () => { // Point at a never-existing path; readRecentRerankFailures should // skip the readFileSync error and return []. const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gbrain-rerank-empty-')); try { await withEnv({ GBRAIN_AUDIT_DIR: path.join(tmpRoot, 'nonexistent') }, async () => { const events = readRecentRerankFailures(7); expect(events).toEqual([]); }); } finally { try { fs.rmSync(tmpRoot, { recursive: true, force: true }); } catch { /* ignore */ } } }); }); describe('CDX2-F22 — logRerankSuccess MUST NOT exist', () => { test('module does not export logRerankSuccess', async () => { const mod: any = await import('../src/core/rerank-audit.ts'); expect(mod.logRerankSuccess).toBeUndefined(); }); }); describe('ISO-week filename rotation', () => { test('filename format is rerank-failures-YYYY-Www.jsonl', () => { const filename = computeRerankAuditFilename(new Date('2026-05-14T00:00:00Z')); expect(filename).toMatch(/^rerank-failures-\d{4}-W\d{2}\.jsonl$/); }); test('readRecentRerankFailures walks current + previous week', async () => { await withFreshAuditDir((tmpDir) => { // Write a row in the "current" week's file. logRerankFailure({ model: 'zeroentropyai:zerank-2', reason: 'auth', query_hash: 'now', doc_count: 1, error_summary: 'recent', }); // Synthesize a "last week" row to confirm both files are walked. const lastWeek = new Date(Date.now() - 7 * 86400000); const lastWeekName = computeRerankAuditFilename(lastWeek); const lastWeekPath = path.join(tmpDir, lastWeekName); fs.appendFileSync( lastWeekPath, JSON.stringify({ ts: new Date(Date.now() - 3 * 86400000).toISOString(), model: 'zeroentropyai:zerank-2', reason: 'auth', query_hash: 'old', doc_count: 1, error_summary: 'older', severity: 'warn', }) + '\n', ); const events = readRecentRerankFailures(7); expect(events.length).toBe(2); expect(new Set(events.map(e => e.query_hash))).toEqual(new Set(['now', 'old'])); }); }); });