/** * Recurrence gate for celilo#1267: readiness waits in packages/e2e must poll * an observable condition (waitFor or a poll loop), never sleep a fixed * duration. * * apps/celilo/CLAUDE.md prohibits sleeping to mask race conditions, but until * now nothing enforced it in this package. respondWith slept 500ms for the * responder to boot; on a loaded host that was not enough, the next command * hit an unanswered interview, and the error read as a missing fixture value * rather than as harness timing. * * The rule here: every fixed sleep in packages/e2e/src must carry an inline * `e2e-sleep-ok:` justification on the same line or the line above. A poll * loop's cadence sleep carries one honestly; a bare readiness gate cannot, so * it fails this gate instead of failing five suites under load. */ import { describe, expect, test } from 'bun:test'; import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; import { join, resolve } from 'node:path'; const SLEEP_PATTERN = /new Promise\(\s*\(?r\)?\s*=>\s*setTimeout\(r\s*,/; function srcDir(): string { let dir = import.meta.dir; for (let i = 0; i < 8; i++) { if (existsSync(join(dir, 'apps')) && existsSync(join(dir, 'modules'))) return join(dir, 'packages', 'e2e', 'src'); dir = resolve(dir, '..'); } throw new Error('could not locate repo root (no ancestor with apps/ + modules/)'); } function tsFiles(dir: string): string[] { const out: string[] = []; for (const entry of readdirSync(dir)) { const full = join(dir, entry); if (statSync(full).isDirectory()) out.push(...tsFiles(full)); else if (entry.endsWith('.ts') && !entry.endsWith('.test.ts')) out.push(full); } return out; } interface Violation { file: string; line: number; text: string; } function unjustifiedSleeps(): Violation[] { const violations: Violation[] = []; for (const file of tsFiles(srcDir())) { const lines = readFileSync(file, 'utf-8').split('\n'); lines.forEach((text, i) => { if (!SLEEP_PATTERN.test(text)) return; const justified = text.includes('e2e-sleep-ok:') || lines[i - 1]?.includes('e2e-sleep-ok:'); if (!justified) violations.push({ file, line: i + 1, text: text.trim() }); }); } return violations; } describe('recurrence gate: no bare readiness sleeps in packages/e2e (celilo#1267)', () => { test('the scan reaches a non-trivial set of files (sanity — it actually ran)', () => { const files = tsFiles(srcDir()); expect(files.length).toBeGreaterThan(10); }); test('every fixed sleep carries an e2e-sleep-ok justification', () => { const violations = unjustifiedSleeps(); const report = violations .map( (v) => `${v.file}:${v.line}: ${v.text}\n Add an inline \`e2e-sleep-ok: \` comment on this line or the one above, or poll an observable condition with waitFor.`, ) .join('\n'); expect(violations, `Unjustified fixed sleeps:\n${report}`).toEqual([]); }); test('the known poll-cadence sleeps are still present and justified (the rule engages)', () => { // Reach probe, not reasoning: if the justified count drops to zero the // scan is matching nothing and the gate above proves nothing. const violations = unjustifiedSleeps(); const total = tsFiles(srcDir()).reduce((count, file) => { const lines = readFileSync(file, 'utf-8').split('\n'); return count + lines.filter((text) => SLEEP_PATTERN.test(text)).length; }, 0); expect(total - violations.length).toBeGreaterThan(3); }); });