import type { Database } from '@cancerindex/database'; import { computeTrialIntelligence } from './trial-intelligence.js'; import { computeTrialSiteCounts } from './trial-sites.js'; import { computeDrugPipeline } from './drug-pipeline.js'; import { computeResearchGap } from './research-gap.js'; export interface IntelligenceResult { trialIntelligenceRows: number; trialSiteCountryRows: number; drugPipelineRows: number; researchGapRows: number; ms: number; } /** * Derived "intelligence" layer (SPEC §10-11, §15, §34): recomputed after counters, before rankings. * Each part is independent and deterministic; a failure in one part is reported, not hidden, and * does not prevent the others from running. */ export async function computeIntelligence(db: Database, log: (msg: string, extra?: Record) => void = () => {}): Promise { const t0 = Date.now(); const out: IntelligenceResult = { trialIntelligenceRows: 0, trialSiteCountryRows: 0, drugPipelineRows: 0, researchGapRows: 0, ms: 0 }; const errors: string[] = []; try { const r = await computeTrialIntelligence(db); out.trialIntelligenceRows = r.rows; log('trial intelligence computed', { ...r }); } catch (e) { errors.push(`trial-intelligence: ${(e as Error).message}`); } try { const r = await computeTrialSiteCounts(db); out.trialSiteCountryRows = r.rows; log('trial site country counts computed', { ...r }); } catch (e) { errors.push(`trial-sites: ${(e as Error).message}`); } try { const r = await computeDrugPipeline(db); out.drugPipelineRows = r.rows; log('drug pipeline computed', { ...r }); } catch (e) { errors.push(`drug-pipeline: ${(e as Error).message}`); } try { const r = await computeResearchGap(db); out.researchGapRows = r.rows; log('research gap components computed', { ...r }); } catch (e) { errors.push(`research-gap: ${(e as Error).message}`); } out.ms = Date.now() - t0; if (errors.length) throw new Error(`intelligence partially failed: ${errors.join(' | ')}`); return out; }