import { describe, expect, it } from 'vitest'; import { buildPolicyAnalysisOverview, type BuildPolicyAnalysisOverviewInput } from '../../src/domain/policy-analysis-overview'; const timestamp = '2026-08-04T15:00:00.000Z'; function syntheticInput(): BuildPolicyAnalysisOverviewInput { return { projectId: 'synthetic-project', generatedAt: timestamp, profiles: [{ version: 1, id: 'profile-1', projectId: 'synthetic-project', name: 'Synthetic Windows', revision: 1, createdAt: timestamp, contexts: [{ version: 1, id: 'context-1', kind: 'operating-system', productFamily: 'Windows Server', productVersion: '2025', role: 'Member Server', scope: 'computer' }] }], identityAnalyses: [{ run: { version: 1, id: 'identity-run-1', projectId: 'synthetic-project', artifactId: 'artifact-1', sourceProcessingRunId: 'processing-1', analyzer: { id: 'gpo-policy-identity-analysis', version: '1' }, identityResolver: { id: 'resolver', version: '1' }, status: 'partial', observationCount: 1, resolvedCount: 0, diagnosticCodes: ['gpo-policy-identity-analysis-partial'], startedAt: timestamp, completedAt: timestamp }, resolutions: [{ version: 1, id: 'resolution-1', projectId: 'synthetic-project', analysisRunId: 'identity-run-1', sourceProcessingRunId: 'processing-1', backupInstanceId: 'backup-1', observationId: 'observation-1', resolution: { version: 1, status: 'unresolved', reasonCode: 'gpo-policy-identity-unsupported-observation' } }] }], aggregations: [{ version: 1, run: { version: 1, id: 'aggregation-1', projectId: 'synthetic-project', environmentProfileId: 'profile-1', sourceAnalysisRunIds: ['identity-run-1'], snapshotId: 'snapshot-1', aggregator: { id: 'gpo-policy-snapshot-aggregation', version: '1.0.0' }, status: 'partial', stateCount: 1, conflictCount: 1, unresolvedIdentityCount: 1, reviewHintCount: 1, permitsFindingGeneration: false, diagnosticCodes: ['policy-snapshot-incomplete'], startedAt: timestamp, completedAt: timestamp }, snapshot: { version: 1, id: 'snapshot-1', projectId: 'synthetic-project', domain: { version: 1, dnsName: 'synthetic.invalid', evidence: 'backup-metadata' }, instanceIds: ['backup-1'], status: 'indeterminate', completeness: 'selected-subset', permitsSetAbsenceConclusions: false, diagnosticCodes: [], createdAt: timestamp }, states: [{ version: 1, id: 'state-1', aggregationRunId: 'aggregation-1', identity: { version: 1, id: 'identity-1' }, deliveryMechanism: 'registry-policy', status: 'conflicted', values: [{ kind: 'registry', type: 'REG_DWORD', value: 1 }], observationIds: ['observation-1'], backupInstanceIds: ['backup-1'], applicableContextIds: ['context-1'], ordering: 'cross-gpo-conflict', targeting: 'none', completeness: 'complete', effectiveState: 'unknown', diagnosticCodes: ['policy-snapshot-customer-conflict'] }], reviewHints: [{ version: 1, id: 'hint-1', code: 'policy-targeting-unknown', identityId: 'identity-1', observationIds: ['observation-1'], backupInstanceIds: ['backup-1'] }] }], evaluations: [{ version: 1, run: { version: 1, id: 'evaluation-1', projectId: 'synthetic-project', aggregationRunId: 'aggregation-1', environmentProfileId: 'profile-1', baselineAnalysisIds: ['baseline-analysis-1'], evaluator: { id: 'policy-baseline-evaluation', version: '1.1.0' }, comparatorCatalog: { id: 'policy-comparator-catalog', version: '1.1.0' }, dependencyRules: { id: 'policy-dependency-rules', version: '1.1.0' }, riskRules: { id: 'policy-risk-rules', version: '1.1.0' }, ruleCatalog: { version: 1, id: 'rules', catalog: { id: 'rules', version: '1' }, status: 'released', rules: [] }, status: 'partial', resultCount: 2, matchCount: 0, deviationCount: 1, notApplicableCount: 0, reviewCount: 1, projectedFindingCount: 0, diagnosticCodes: ['policy-evaluation-partial'], startedAt: timestamp, completedAt: timestamp }, results: [{ version: 1, id: 'evaluation-result-review', evaluationRunId: 'evaluation-1', aggregationStateId: 'state-1', identity: { version: 1, id: 'identity-1' }, classification: 'review_required', comparator: { version: 1, comparator: { kind: 'equality' }, relation: 'incomparable', diagnosticCodes: [] }, baselineState: 'catalog-gap', contextIds: ['context-1'], ruleIds: [], dependencyRuleIds: [], riskRuleIds: [], observationIds: ['observation-1'], backupInstanceIds: ['backup-1'], baselineAnalysisIds: [], baselineSettingIds: [], findingEligibility: 'ineligible', effectiveState: 'unknown', diagnosticCodes: ['policy-evaluation-baseline-missing'] }], evidence: [] }], findingRuns: [{ version: 1, run: { version: 1, id: 'finding-run-1', projectId: 'synthetic-project', evaluationRunId: 'evaluation-1', factory: { id: 'policy-finding-factory', version: '1.0.0' }, status: 'partial', eligibleResultCount: 2, findingCount: 1, rejectedResultCount: 1, startedAt: timestamp, completedAt: timestamp }, definitions: [], occurrences: [{} as never], rejections: [{ version: 1, evaluationResultId: 'evaluation-result-rejected', diagnosticCodes: ['policy-finding-evidence-incomplete'] }] }] } as unknown as BuildPolicyAnalysisOverviewInput; } describe('policy analysis overview', () => { it('keeps confirmed findings separate from deviations and all review-only evidence', () => { const overview = buildPolicyAnalysisOverview(syntheticInput()); expect(overview.summary.confirmedDeviations).toBe(1); expect(overview.summary.policyFindings).toBe(1); expect(overview.summary.conflicts).toBe(1); expect(overview.summary.unresolvedIdentities).toBe(1); expect(overview.summary.catalogGaps).toBe(1); expect(overview.summary.partialRuns).toBe(4); expect(overview.current.summary).toEqual(overview.summary); expect(overview.current.evaluationRunIds).toEqual(['evaluation-1']); expect(overview.current.findingRunIds).toEqual(['finding-run-1']); expect(overview.reviewItems.map(item => item.category)).toEqual(expect.arrayContaining([ 'conflict', 'unresolved-identity', 'catalog-gap', 'partial-analysis', 'targeting-unknown', 'incomplete-evidence' ])); expect(overview.evaluations[0]).toMatchObject({ findingCount: 1, rejectedFindingCount: 1, reviewCount: 1 }); }); it('returns an empty, deterministic project view without inventing findings', () => { const overview = buildPolicyAnalysisOverview({ projectId: 'empty-project', generatedAt: timestamp, identityAnalyses: [], profiles: [], aggregations: [], evaluations: [], findingRuns: [] }); expect(overview).toMatchObject({ version: 1, projectId: 'empty-project', generatedAt: timestamp, summary: { policyFindings: 0, reviewItems: 0, conflicts: 0, partialRuns: 0 }, current: { version: 1, summary: { policyFindings: 0, reviewItems: 0, conflicts: 0, partialRuns: 0 }, evaluationRunIds: [], findingRunIds: [], reviewItems: [] }, evaluations: [], reviewItems: [] }); }); it('keeps superseded processing chains in history but excludes them from the current snapshot', () => { const input = syntheticInput(); const currentTimestamp = '2026-08-05T15:00:00.000Z'; input.identityAnalyses.push({ run: { ...input.identityAnalyses[0].run, id: 'identity-run-2', sourceProcessingRunId: 'processing-2', supersedesAnalysisRunId: 'identity-run-1', status: 'complete', resolvedCount: 1, diagnosticCodes: [], startedAt: currentTimestamp, completedAt: currentTimestamp }, resolutions: [] }); input.aggregations.push({ ...input.aggregations[0], run: { ...input.aggregations[0].run, id: 'aggregation-2', sourceAnalysisRunIds: ['identity-run-2'], snapshotId: 'snapshot-2', status: 'complete', conflictCount: 0, unresolvedIdentityCount: 0, reviewHintCount: 0, diagnosticCodes: [], startedAt: currentTimestamp, completedAt: currentTimestamp }, snapshot: { ...input.aggregations[0].snapshot, id: 'snapshot-2', status: 'consistent', completeness: 'complete' }, states: [], reviewHints: [] }); input.evaluations.push({ ...input.evaluations[0], run: { ...input.evaluations[0].run, id: 'evaluation-2', aggregationRunId: 'aggregation-2', status: 'complete', matchCount: 3, deviationCount: 2, reviewCount: 0, diagnosticCodes: [], startedAt: currentTimestamp, completedAt: currentTimestamp }, results: [], evidence: [] }); input.findingRuns.push({ ...input.findingRuns[0], run: { ...input.findingRuns[0].run, id: 'finding-run-2', evaluationRunId: 'evaluation-2', status: 'complete', eligibleResultCount: 2, findingCount: 2, rejectedResultCount: 0, startedAt: currentTimestamp, completedAt: currentTimestamp }, occurrences: [{}, {}] as never[], rejections: [] }); const overview = buildPolicyAnalysisOverview(input); expect(overview.summary).toMatchObject({ identityAnalysisRuns: 2, aggregationRuns: 2, evaluationRuns: 2, findingRuns: 2, confirmedDeviations: 3, policyFindings: 3 }); expect(overview.current.summary).toMatchObject({ identityAnalysisRuns: 1, aggregationRuns: 1, evaluationRuns: 1, findingRuns: 1, configuredMatches: 3, confirmedDeviations: 2, policyFindings: 2, reviewItems: 0, conflicts: 0, unresolvedIdentities: 0, partialRuns: 0 }); expect(overview.current.evaluationRunIds).toEqual(['evaluation-2']); expect(overview.current.findingRunIds).toEqual(['finding-run-2']); expect(overview.current.reviewItems).toEqual([]); expect(overview.reviewItems.length).toBeGreaterThan(0); expect(overview.actions.evaluate.map(action => action.aggregationRunId)).toEqual(['aggregation-2']); expect(overview.actions.createFindings.map(action => action.evaluationRunId)).toEqual(['evaluation-2']); }); });