Assessor_2.0/src/domain/result-db-materialization.ts

59 lines
2.5 KiB
TypeScript

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<string, ResultDbIdentityGuard>,
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<ResultDbMaterializationStatus, 'sourceRevision' | 'disclosurePolicyVersion' | 'identityGuardVersion'> | undefined, repositoryRevision: number): boolean {
return status?.sourceRevision === repositoryRevision
&& status.disclosurePolicyVersion === RESULT_DB_DISCLOSURE_POLICY_VERSION
&& status.identityGuardVersion === RESULT_DB_IDENTITY_GUARD_VERSION;
}