From 566d3e2f757e7c8b60938d0637f1f2576e56ac40 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 23 Jul 2026 15:38:32 -0700 Subject: [PATCH] fix(doctor): exclude soft-deleted pages from raw_provenance check Sibling frontmatter checks (quarantined_pages, flagged_pages) filter deleted_at IS NULL; without it a deleted synthesized page keeps warning (and its slug keeps being named) through the 72h recovery window with no way to clear the warn. Co-Authored-By: Claude Fable 5 --- src/commands/doctor.ts | 3 ++- test/doctor-raw-provenance.test.ts | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index 9cdc54742..5b917f9fa 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -549,7 +549,8 @@ export async function childTableOrphansCheck(engine: BrainEngine): Promise { const where = ` - (COALESCE(p.frontmatter->>'dream_generated', '') = 'true' OR p.type = 'synthesis') + p.deleted_at IS NULL + AND (COALESCE(p.frontmatter->>'dream_generated', '') = 'true' OR p.type = 'synthesis') AND NOT (COALESCE(p.frontmatter, '{}'::jsonb) ?| ARRAY['raw_trace', 'raw_source', 'source_uri', 'raw_trace_exempt']) AND NOT EXISTS (SELECT 1 FROM raw_data rd WHERE rd.page_id = p.id) AND NOT EXISTS (SELECT 1 FROM synthesis_evidence se WHERE se.synthesis_page_id = p.id)`; diff --git a/test/doctor-raw-provenance.test.ts b/test/doctor-raw-provenance.test.ts index 81745207a..93397d56f 100644 --- a/test/doctor-raw-provenance.test.ts +++ b/test/doctor-raw-provenance.test.ts @@ -85,6 +85,18 @@ describe('rawProvenanceCheck (#1978, warn-only v1)', () => { expect(result.status).toBe('ok'); }); + test('soft-deleted violators are not flagged', async () => { + await engine.putPage('wiki/derived/deleted-no-trace', { + type: 'note', title: 'Deleted violator', compiled_truth: 'body', timeline: '', + frontmatter: { dream_generated: true }, + }); + expect((await rawProvenanceCheck(engine as unknown as BrainEngine)).status).toBe('warn'); + await engine.executeRaw( + `UPDATE pages SET deleted_at = now() WHERE slug = 'wiki/derived/deleted-no-trace'`, + ); + expect((await rawProvenanceCheck(engine as unknown as BrainEngine)).status).toBe('ok'); + }); + test('query failure degrades to warn, never throws', async () => { const broken = { executeRaw: async () => { throw new Error('boom'); } } as unknown as BrainEngine; const result = await rawProvenanceCheck(broken);