import { discloseResultDbProjectionWithTrace, RESULT_DB_DISCLOSURE_POLICY_VERSION } from './result-db-disclosure'; import { RESULT_DB_IDENTITY_GUARD_VERSION, type ResultDbIdentityGuard } from './result-db-identity-guard'; import type { UnifiedResultProjection } from './unified-result'; /** * Materialized Result DB (user decision 2026-09-28): rows are disclosed, checked and stored when the * source data changes. UI, API and JSONL export read only these stored rows, so what is shown is * exactly what is delivered; each row carries its content-free redaction trace. */ export interface ResultDbMaterializationStatus { /** `current`: stored rows match the current repository revision and policy versions. */ state: 'current' | 'outdated' | 'not-built'; sourceRevision?: number; repositoryRevision: number; disclosurePolicyVersion?: string; identityGuardVersion?: string; materializedAt?: string; rowCount: number; redactionCount: number; /** Rows in which the identity guard withheld at least one complete field. */ guardWithheldRowCount: number; } export interface MaterializedResultDb { rows: UnifiedResultProjection[]; status: ResultDbMaterializationStatus; } export function materializeResultDb( sourceResults: UnifiedResultProjection[], guards: Map, sourceRevision: number, materializedAt: string ): MaterializedResultDb { const rows = sourceResults.map(item => discloseResultDbProjectionWithTrace(item, guards.get(item.projectId))); return { rows, status: { state: 'current', sourceRevision, repositoryRevision: sourceRevision, disclosurePolicyVersion: RESULT_DB_DISCLOSURE_POLICY_VERSION, identityGuardVersion: RESULT_DB_IDENTITY_GUARD_VERSION, materializedAt, rowCount: rows.length, redactionCount: rows.reduce((sum, row) => sum + (row.disclosureTrace?.redactions.reduce((total, entry) => total + entry.count, 0) ?? 0), 0), guardWithheldRowCount: rows.filter(row => row.disclosureTrace?.guardWithheldFields.length).length } }; } /** A stored state is current only for the same repository revision and the same policy versions. */ export function isResultDbCurrent(status: Pick | undefined, repositoryRevision: number): boolean { return status?.sourceRevision === repositoryRevision && status.disclosurePolicyVersion === RESULT_DB_DISCLOSURE_POLICY_VERSION && status.identityGuardVersion === RESULT_DB_IDENTITY_GUARD_VERSION; }