import type { AssessorRepository } from '../persistence/assessor-repository'; /** Declared read-only port of the Comparison Engine: it reads the Core and never writes to it. */ export type ComparisonReadMethods = Pick; export interface ComparisonReadPort extends ComparisonReadMethods { currentRevision(): Promise } /** Bounded per method; models and policy evaluations are large. */ const MAX_ENTRIES = 8; /** * Reads are shared within one repository revision: both timeslots of a request load the same project-wide * policy evaluations and backups, and switching A or B reloads the same models. Any committed change starts * a new revision and drops every entry, so a read never serves an outdated state. Failed reads are not kept. */ export function comparisonReadPortFrom(repository: ComparisonReadMethods, revision: () => Promise): ComparisonReadPort { let cachedRevision: number | undefined; const caches = new Map>>(); const shared = (name: string, read: (...args: A) => Promise) => async (...args: A): Promise => { const current = await revision(); if (current !== cachedRevision) { caches.clear(); cachedRevision = current; } const cache = caches.get(name) ?? caches.set(name, new Map()).get(name)!; const key = JSON.stringify(args); let pending = cache.get(key) as Promise | undefined; if (!pending) { if (cache.size >= MAX_ENTRIES) cache.delete(cache.keys().next().value!); pending = read(...args); cache.set(key, pending); pending.catch(() => { if (cache.get(key) === pending) cache.delete(key); }); } return pending; }; return Object.freeze({ currentRevision: revision, getProject: repository.getProject.bind(repository), listAssessments: shared('assessments', repository.listAssessments.bind(repository)), loadAssessmentModel: shared('model', repository.loadAssessmentModel.bind(repository)), queryUnifiedResults: shared('results', repository.queryUnifiedResults.bind(repository)), listPolicyEvaluations: shared('evaluations', repository.listPolicyEvaluations.bind(repository)), listGpoBackupInstances: shared('backups', repository.listGpoBackupInstances.bind(repository)) }); }