"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runValidationLinksCheckReport = runValidationLinksCheckReport;
exports.createValidationLinksCheckSummary = createValidationLinksCheckSummary;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../errors");
const config_contract_1 = require("../config/config-contract");
const output_1 = require("../output");
const validation_links_discovery_1 = require("../planning/validation-links-discovery");
const validation_links_resolution_1 = require("../planning/validation-links-resolution");
const workflow_provenance_1 = require("../planning/workflow-provenance");
const paths_1 = require("../paths");
const trace_link_dispositions_1 = require("../trace-link-dispositions");
function runValidationLinksCheckReport(options) {
    const artifactPath = normalizeOptionalArtifactPath(options.artifactPath);
    const resolvedConfig = (0, config_contract_1.resolveDayShiftConfig)({
        repositoryContext: {
            root: options.repositoryRoot,
            detectionSource: 'explicit',
            warnedAboutFallback: false,
        },
    });
    const discovery = (0, validation_links_discovery_1.discoverValidationLinksArtifacts)({
        repositoryRoot: options.repositoryRoot,
        artifactPath,
        planningRootPath: (0, paths_1.toRepositoryRelativePath)(options.repositoryRoot, resolvedConfig.derived.planningRootPath),
        specIndexPath: (0, paths_1.toRepositoryRelativePath)(options.repositoryRoot, resolvedConfig.derived.specIndexPath),
    });
    const dispositionState = readTraceLinkDispositionState(options.repositoryRoot);
    const resolution = applyDispositionEvidenceToResolution({
        resolution: (0, validation_links_resolution_1.evaluateValidationLinksResolution)(discovery),
        dispositionState,
        discovery,
    });
    const findings = createValidationLinksCheckFindings({
        discovery,
        resolution,
        repositoryRoot: options.repositoryRoot,
        dispositionState,
    });
    return {
        repositoryRoot: options.repositoryRoot,
        artifact: artifactPath,
        discovery,
        resolution,
        dispositionStorage: dispositionStateToReport(dispositionState),
        findings,
    };
}
function normalizeOptionalArtifactPath(input) {
    if (input === undefined || input === null || input === '') {
        return null;
    }
    if (typeof input !== 'string') {
        throw (0, errors_1.createUsageError)('Validation links-check artifact path must be a repository-relative path.', [
            `Received: ${String(input)}`,
        ]);
    }
    try {
        return (0, paths_1.parseRepositoryRelativePath)(input).normalizedPath;
    }
    catch (error) {
        if (error instanceof RangeError) {
            throw (0, errors_1.createUsageError)('Validation links-check artifact path must be a repository-relative path.', [
                error.message,
            ]);
        }
        throw error;
    }
}
function createValidationLinksCheckFindings(options) {
    return [
        ...createDiscoveryFindings(options),
        ...createDispositionStorageFindings(options),
        ...createMissingRequiredFieldFindings(options),
        ...options.resolution.valueResolutions.flatMap((evidence) => createValueResolutionFinding(evidence, options.repositoryRoot)),
        ...options.resolution.valueResolutions.flatMap((evidence) => createLinkedSliceScaffoldFinding(evidence, options.repositoryRoot)),
        ...options.resolution.hierarchyChecks.flatMap((evidence) => createHierarchyFinding(evidence, options.repositoryRoot)),
        ...options.resolution.pairingChecks.flatMap((evidence) => createPairingFinding(evidence, options.repositoryRoot)),
    ];
}
function readTraceLinkDispositionState(repositoryRoot) {
    const absoluteStoragePath = node_path_1.default.join(repositoryRoot, trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH);
    if (!node_fs_1.default.existsSync(absoluteStoragePath)) {
        return {
            status: 'absent',
            storagePath: trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH,
            dispositions: [],
        };
    }
    try {
        const document = (0, trace_link_dispositions_1.parseTraceLinkDispositionStorageDocument)(node_fs_1.default.readFileSync(absoluteStoragePath, 'utf8'));
        return {
            status: 'loaded',
            storagePath: trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH,
            dispositions: document.dispositions,
        };
    }
    catch (error) {
        return {
            status: 'malformed',
            storagePath: trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH,
            error: error instanceof Error ? error.message : 'Trace-link disposition storage could not be parsed.',
            dispositions: [],
        };
    }
}
function dispositionStateToReport(state) {
    return {
        status: state.status,
        storagePath: state.storagePath,
        dispositionCount: state.dispositions.length,
        ...(state.status === 'malformed' ? { error: state.error } : {}),
    };
}
function createDispositionStorageFindings(options) {
    if (options.dispositionState.status !== 'malformed') {
        return [];
    }
    return [
        (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId: 'LINKS_MALFORMED_DISPOSITION_STORAGE',
            artifact: {
                family: 'other',
                path: options.dispositionState.storagePath,
            },
            affectedPath: {
                role: 'trace-link',
                path: options.dispositionState.storagePath,
                description: 'Trace-link disposition storage could not be parsed.',
            },
            relationship: 'trace-link-disposition-storage',
            field: trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH,
            traceValue: options.dispositionState.storagePath,
            detail: options.dispositionState.error,
            repositoryRoot: options.repositoryRoot,
        }),
    ];
}
function applyDispositionEvidenceToResolution(options) {
    if (options.dispositionState.status !== 'loaded') {
        return options.resolution;
    }
    const dispositionsByTarget = new Map(options.dispositionState.dispositions.map((disposition) => [disposition.target.normalizedPath, disposition]));
    const lifecycleByArtifact = new Map(options.discovery.artifacts.map((artifact) => [artifact.path, artifact.lifecycle]));
    const valueResolutions = options.resolution.valueResolutions.map((evidence) => {
        if (evidence.resolution.status !== 'missing-local-target' || evidence.resolution.normalizedPath === undefined) {
            return evidence;
        }
        const disposition = dispositionsByTarget.get(evidence.resolution.normalizedPath);
        if (disposition === undefined) {
            return evidence;
        }
        const applyEvidenceStatus = classifyApplyEvidenceForArtifact(disposition, evidence.sourceArtifactPath);
        const lifecycle = lifecycleByArtifact.get(evidence.sourceArtifactPath);
        return {
            ...evidence,
            severity: classifyDispositionEvidenceSeverity({
                disposition,
                applyEvidenceStatus,
                sourceTerminal: lifecycle?.terminal === true,
            }),
            disposition: {
                id: disposition.id,
                status: disposition.status,
                storagePath: trace_link_dispositions_1.TRACE_LINK_DISPOSITION_STORAGE_PATH,
                originalTarget: disposition.target.normalizedPath,
                ...('replacementTarget' in disposition
                    ? {
                        replacementTarget: disposition.replacementTarget.normalizedPath,
                        recommendedCommand: `day-shift link disposition preview --target ${disposition.target.normalizedPath}`,
                    }
                    : {}),
                applyEvidenceStatus,
            },
        };
    });
    return {
        ...options.resolution,
        valueResolutions,
        summary: summarizeResolution(valueResolutions, options.resolution.hierarchyChecks, options.resolution.pairingChecks),
    };
}
function classifyApplyEvidenceForArtifact(disposition, artifactPath) {
    if (disposition.applyEvidence === undefined) {
        return 'absent';
    }
    const comparablePaths = new Set([artifactPath, artifactPath.split('#', 1)[0]]);
    if (disposition.applyEvidence.changedPaths.some((candidate) => comparablePaths.has(candidate))) {
        return 'changed';
    }
    if (disposition.applyEvidence.skippedPaths.some((candidate) => comparablePaths.has(candidate))) {
        return 'skipped';
    }
    if (disposition.applyEvidence.conflictPaths.some((candidate) => comparablePaths.has(candidate))) {
        return 'conflict';
    }
    if (disposition.applyEvidence.unresolvedPaths.some((candidate) => comparablePaths.has(candidate))) {
        return 'unresolved';
    }
    return 'absent';
}
function classifyDispositionEvidenceSeverity(options) {
    if (options.applyEvidenceStatus === 'conflict' || options.applyEvidenceStatus === 'unresolved') {
        return 'advisory';
    }
    if (options.sourceTerminal &&
        (options.disposition.status === 'retired' || options.disposition.status === 'deleted')) {
        return 'none';
    }
    if (options.disposition.status === 'migrated' && options.applyEvidenceStatus === 'changed') {
        return 'none';
    }
    return 'advisory';
}
function summarizeResolution(valueResolutions, hierarchyChecks, pairingChecks) {
    const blockingEvidenceCount = [...valueResolutions, ...hierarchyChecks, ...pairingChecks].filter((entry) => entry.severity === 'blocking').length;
    const advisoryEvidenceCount = [...valueResolutions, ...hierarchyChecks, ...pairingChecks].filter((entry) => entry.severity === 'advisory').length;
    return {
        valueResolutionCount: valueResolutions.length,
        resolvedLocalTargetCount: valueResolutions.filter((entry) => entry.resolution.status === 'resolved-local-target')
            .length,
        resolvedNonLocalSourceCount: valueResolutions.filter((entry) => entry.resolution.status === 'resolved-non-local-source').length,
        missingLocalTargetCount: valueResolutions.filter((entry) => entry.resolution.status === 'missing-local-target')
            .length,
        malformedLocalLinkCount: valueResolutions.filter((entry) => entry.resolution.status === 'malformed-local-link')
            .length,
        outsideTraversalBoundaryCount: valueResolutions.filter((entry) => entry.resolution.status === 'outside-traversal-boundary').length,
        unsupportedReferenceCount: valueResolutions.filter((entry) => entry.resolution.status === 'unsupported-external-reference').length,
        plannedTargetCount: valueResolutions.filter((entry) => entry.resolution.status === 'planned-local-target').length,
        requiredTargetCount: valueResolutions.filter((entry) => entry.missingTargetPolicy === 'required').length,
        unresolvedRequiredTargetCount: valueResolutions.filter((entry) => entry.missingTargetPolicy === 'required' &&
            entry.resolution.status !== 'resolved-local-target' &&
            entry.resolution.status !== 'resolved-non-local-source' &&
            entry.resolution.status !== 'planned-local-target').length,
        hierarchyCheckCount: hierarchyChecks.length,
        hierarchyMismatchCount: hierarchyChecks.filter((entry) => entry.comparison.status === 'hierarchy-mismatch').length,
        staleLinkCount: hierarchyChecks.filter((entry) => entry.comparison.status === 'stale-link').length,
        pairingCheckCount: pairingChecks.length,
        pairingMismatchCount: pairingChecks.filter((entry) => entry.severity !== 'none').length,
        blockingEvidenceCount,
        advisoryEvidenceCount,
        dispositionLifecycleEvidenceCount: valueResolutions.filter((entry) => entry.severity === 'none' &&
            (entry.disposition?.status === 'retired' || entry.disposition?.status === 'deleted')).length,
    };
}
function createLinkedSliceScaffoldFinding(evidence, repositoryRoot) {
    if (evidence.family !== 'spec_index_entry' ||
        evidence.field !== 'linked_slice.path' ||
        evidence.resolution.status !== 'resolved-local-target' ||
        evidence.resolution.normalizedPath === undefined) {
        return [];
    }
    const sliceOverviewPath = node_path_1.default.join(repositoryRoot, evidence.resolution.normalizedPath);
    const missingCompanions = [
        node_path_1.default.join(node_path_1.default.dirname(sliceOverviewPath), 'decisions', '.gitkeep'),
        node_path_1.default.join(node_path_1.default.dirname(sliceOverviewPath), 'notes', '.gitkeep'),
    ].filter((candidate) => !node_fs_1.default.existsSync(candidate));
    const provenance = readPlanningWorkflowProvenance(sliceOverviewPath);
    const hasValidProvenance = (provenance.workflowProvenance === 'cli' &&
        /^day-shift slice new|^node dist\/cli\/index\.js slice new/u.test(provenance.workflowCliCommand)) ||
        (provenance.workflowProvenance === 'manual-exception' &&
            (0, workflow_provenance_1.isAllowedManualWorkflowException)(provenance.workflowManualException) &&
            /^day-shift slice new|^node dist\/cli\/index\.js slice new/u.test(provenance.workflowCliCommand)) ||
        isRecordedWorkspaceMigrationDestination(repositoryRoot, evidence.resolution.normalizedPath);
    if (missingCompanions.length === 0 && hasValidProvenance) {
        return [];
    }
    const reasons = [
        ...(!hasValidProvenance
            ? [
                `workflow provenance is not valid CLI, allowed manual-exception, or applied workspace-migration evidence (found '${provenance.workflowProvenance || '<missing>'}')`,
            ]
            : []),
        ...(!hasValidProvenance &&
            !/^day-shift slice new|^node dist\/cli\/index\.js slice new/u.test(provenance.workflowCliCommand)
            ? [
                `workflow_cli_command is '${provenance.workflowCliCommand || '<missing>'}' instead of a slice scaffold command`,
            ]
            : []),
        ...missingCompanions.map((companion) => `missing ${(0, paths_1.toRepositoryRelativePath)(repositoryRoot, companion)}`),
    ];
    return [
        (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId: 'LINKS_STALE_EXPLICIT_LINK',
            artifact: {
                family: 'other',
                path: evidence.sourceArtifactPath,
            },
            affectedPath: {
                role: 'trace-link',
                path: evidence.resolution.normalizedPath,
                description: 'linked_slice.path target is missing valid scaffold or migration evidence.',
            },
            relationship: evidence.relationship,
            field: evidence.field,
            traceValue: evidence.originalValue,
            expectedPath: 'validated slice overview with decisions/.gitkeep and notes/.gitkeep',
            hierarchyStatus: 'stale-link',
            detail: `linked_slice.path must reference a CLI-scaffolded, allowed manual-recovery, or applied-migration slice overview with required companion artifacts: ${reasons.join('; ')}.`,
            repositoryRoot,
        }),
    ];
}
function readPlanningWorkflowProvenance(sliceOverviewPath) {
    try {
        const content = node_fs_1.default.readFileSync(sliceOverviewPath, 'utf8');
        const lines = content.split(/\r?\n/);
        const closingIndex = lines.findIndex((line, index) => index > 0 && line === '---');
        if (!content.startsWith('---') || closingIndex === -1) {
            return { workflowProvenance: '', workflowCliCommand: '', workflowManualException: '' };
        }
        const frontMatterLines = lines.slice(1, closingIndex);
        return {
            workflowProvenance: readTopLevelScalar(frontMatterLines, 'workflow_provenance'),
            workflowCliCommand: readTopLevelScalar(frontMatterLines, 'workflow_cli_command'),
            workflowManualException: readTopLevelScalar(frontMatterLines, 'workflow_manual_exception'),
        };
    }
    catch {
        return { workflowProvenance: '', workflowCliCommand: '', workflowManualException: '' };
    }
}
function isRecordedWorkspaceMigrationDestination(repositoryRoot, artifactPath) {
    const migrationDirectory = node_path_1.default.join(repositoryRoot, '.day-shift', 'state', 'migrations');
    if (!node_fs_1.default.existsSync(migrationDirectory)) {
        return false;
    }
    for (const entry of node_fs_1.default.readdirSync(migrationDirectory, { withFileTypes: true })) {
        if (!entry.isFile() || !/^workspace-structure-[a-f0-9]{16}\.json$/u.test(entry.name)) {
            continue;
        }
        try {
            const record = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(migrationDirectory, entry.name), 'utf8'));
            if (record.schemaVersion !== 1 ||
                record.migrationKind !== 'workspace-structure' ||
                record.transactionState !== 'authorized' ||
                !Array.isArray(record.pathMappings)) {
                continue;
            }
            if (record.pathMappings.some((mapping) => typeof mapping === 'object' &&
                mapping !== null &&
                !Array.isArray(mapping) &&
                mapping.destinationPath === artifactPath)) {
                return true;
            }
        }
        catch {
            // Malformed or unrelated migration evidence cannot satisfy linked-slice validation.
        }
    }
    return false;
}
function readTopLevelScalar(lines, key) {
    for (const line of lines) {
        if (/^\s/u.test(line)) {
            continue;
        }
        const match = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/u);
        if (match === null || match[1] !== key) {
            continue;
        }
        return match[2].trim().replace(/^"|"$/gu, '');
    }
    return '';
}
function createDiscoveryFindings(options) {
    if (options.discovery.mode !== 'artifact') {
        return [];
    }
    return options.discovery.evidence
        .filter((evidence) => evidence.status === 'missing')
        .map((evidence) => (0, output_1.createTraceLinkValidationFinding)({
        taxonomyId: 'LINKS_REQUIRED_TARGET_MISSING',
        artifact: {
            family: 'other',
            artifactType: evidence.artifactType ?? undefined,
            path: evidence.path,
        },
        affectedPath: {
            role: 'trace-link',
            path: evidence.path,
            description: evidence.message,
        },
        relationship: 'focused-artifact-input',
        field: '--artifact',
        traceValue: evidence.path,
        resolutionStatus: 'missing-local-target',
        detail: `Focused links-check artifact is missing: ${evidence.path}.`,
        repositoryRoot: options.repositoryRoot,
    }));
}
function createMissingRequiredFieldFindings(options) {
    return options.discovery.artifacts.flatMap((artifact) => {
        if (artifact.parseStatus !== 'parsed') {
            return [];
        }
        return artifact.traceFields
            .filter((field) => shouldEmitMissingRequiredFieldFinding(field))
            .map((field) => (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId: 'LINKS_REQUIRED_FIELD_MISSING',
            artifact: {
                family: toValidationFindingArtifactFamily(artifact.family),
                artifactType: artifact.artifactType ?? undefined,
                path: artifact.path,
            },
            affectedPath: {
                role: 'finding-location',
                path: artifact.path,
                description: `Required trace field '${field.field}' is missing.`,
            },
            relationship: field.relationship,
            field: field.field,
            detail: `Required trace field '${field.field}' is missing from ${artifact.path}.`,
            repositoryRoot: options.repositoryRoot,
        }));
    });
}
function shouldEmitMissingRequiredFieldFinding(field) {
    if (field.requirement !== 'required' || field.present) {
        return false;
    }
    // The readiness/rollup metadata validators own missing spec provenance.
    // Links-check validates trace values that are present, plus structural parent links.
    return field.field !== 'upstream.specs';
}
function createValueResolutionFinding(evidence, repositoryRoot) {
    if (evidence.severity === 'none') {
        return [];
    }
    if (evidence.severity === 'advisory' &&
        evidence.resolution.status !== 'unsupported-external-reference' &&
        !(evidence.resolution.status === 'planned-local-target' &&
            evidence.structuredTaskDeclaration?.mappingStatus === 'valid') &&
        evidence.disposition === undefined) {
        return [];
    }
    const taxonomyId = traceFindingIdForValueResolution(evidence);
    if (taxonomyId === null) {
        return [];
    }
    const targetPath = evidence.resolution.normalizedPath ?? evidence.sourceArtifactPath;
    const pendingTaskCommand = evidence.resolution.status === 'planned-local-target' &&
        evidence.structuredTaskDeclaration?.mappingStatus === 'valid'
        ? `day-shift work task create --overview ${evidence.sourceArtifactPath}`
        : null;
    return [
        (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId,
            artifact: {
                family: toValidationFindingArtifactFamily(evidence.family),
                path: evidence.sourceArtifactPath,
            },
            affectedPath: {
                role: 'trace-link',
                path: targetPath,
                description: evidence.resolution.message,
            },
            relationship: evidence.relationship,
            field: evidence.field,
            traceValue: evidence.originalValue,
            resolutionStatus: evidence.resolution.status,
            evidenceDetails: {
                ...dispositionEvidenceDetails(evidence.disposition),
                ...(evidence.structuredTaskDeclaration === undefined
                    ? {}
                    : {
                        taskId: evidence.structuredTaskDeclaration.taskId,
                        sequence: evidence.structuredTaskDeclaration.sequence,
                        sequencePrefix: evidence.structuredTaskDeclaration.sequencePrefix,
                        orderedTaskRootName: evidence.structuredTaskDeclaration.orderedTaskRootName,
                        taskPlanSyntax: evidence.structuredTaskDeclaration.syntax,
                        mappingStatus: evidence.structuredTaskDeclaration.mappingStatus,
                        mappingIssues: evidence.structuredTaskDeclaration.issues,
                    }),
                ...(pendingTaskCommand === null ? {} : { recommendedCommand: pendingTaskCommand }),
            },
            detail: valueResolutionDetail(evidence),
            ...(pendingTaskCommand === null
                ? {}
                : {
                    recovery: [
                        `Create task '${evidence.structuredTaskDeclaration?.taskId}' with ${pendingTaskCommand} and its complete --task JSON contract.`,
                        `The command must preserve sequence ${evidence.structuredTaskDeclaration?.sequence} and ordered root '${evidence.structuredTaskDeclaration?.orderedTaskRootName}'.`,
                        'Rerun the read-only links check after the canonical task pair is created.',
                    ],
                }),
            repositoryRoot,
        }),
    ];
}
function traceFindingIdForValueResolution(evidence) {
    if (evidence.disposition !== undefined) {
        switch (evidence.disposition.status) {
            case 'retired':
                return 'LINKS_RETIRED_TARGET';
            case 'deleted':
                return 'LINKS_DELETED_TARGET';
            case 'migrated':
                return 'LINKS_MIGRATION_AVAILABLE';
        }
    }
    if (evidence.resolution.status === 'planned-local-target' &&
        evidence.structuredTaskDeclaration?.mappingStatus === 'valid') {
        return 'LINKS_TASK_PENDING_CREATION';
    }
    return traceFindingIdForResolutionStatus(evidence.resolution.status);
}
function dispositionEvidenceDetails(disposition) {
    if (disposition === undefined) {
        return undefined;
    }
    return {
        dispositionId: disposition.id,
        dispositionStatus: disposition.status,
        dispositionStoragePath: disposition.storagePath,
        originalTarget: disposition.originalTarget,
        ...(disposition.replacementTarget !== undefined ? { replacementTarget: disposition.replacementTarget } : {}),
        ...(disposition.recommendedCommand !== undefined ? { recommendedCommand: disposition.recommendedCommand } : {}),
        ...(disposition.applyEvidenceStatus !== undefined ? { applyEvidenceStatus: disposition.applyEvidenceStatus } : {}),
    };
}
function valueResolutionDetail(evidence) {
    const base = `${evidence.relationship} in ${evidence.sourceArtifactPath}: ${evidence.resolution.message}`;
    if (evidence.disposition === undefined) {
        return base;
    }
    if (evidence.disposition.status === 'migrated' && evidence.disposition.replacementTarget !== undefined) {
        return `${base} Recorded migrated disposition points to ${evidence.disposition.replacementTarget}.`;
    }
    return `${base} Recorded ${evidence.disposition.status} disposition found in ${evidence.disposition.storagePath}.`;
}
function createHierarchyFinding(evidence, repositoryRoot) {
    if (evidence.severity === 'none') {
        return [];
    }
    return [
        (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId: evidence.comparison.status === 'stale-link' ? 'LINKS_STALE_EXPLICIT_LINK' : 'LINKS_OUT_OF_HIERARCHY',
            artifact: {
                family: toValidationFindingArtifactFamily(evidence.family),
                path: evidence.sourceArtifactPath,
            },
            affectedPath: {
                role: 'trace-link',
                path: evidence.comparison.normalizedActualPath,
                description: evidence.comparison.message,
            },
            relationship: evidence.relationship,
            field: evidence.field,
            traceValue: evidence.comparison.originalValue,
            expectedPath: evidence.expectedPath,
            hierarchyStatus: evidence.comparison.status,
            detail: `${evidence.relationship} expected ${evidence.expectedPath}, received ${evidence.comparison.normalizedActualPath}.`,
            repositoryRoot,
        }),
    ];
}
function createPairingFinding(evidence, repositoryRoot) {
    if (evidence.severity === 'none') {
        return [];
    }
    return [
        (0, output_1.createTraceLinkValidationFinding)({
            taxonomyId: 'LINKS_REQUIRED_TARGET_MISSING',
            artifact: {
                family: evidence.family,
                path: evidence.sourceArtifactPath,
            },
            affectedPath: {
                role: 'trace-link',
                path: evidence.expectedPath,
                description: evidence.message,
            },
            relationship: evidence.relationship,
            field: 'pairedArtifact',
            traceValue: evidence.expectedPath,
            resolutionStatus: 'missing-local-target',
            detail: `${evidence.relationship} expected paired artifact ${evidence.expectedPath}: ${evidence.message}`,
            repositoryRoot,
        }),
    ];
}
function toValidationFindingArtifactFamily(family) {
    return family === 'spec_index_entry' || family === 'unsupported' ? 'other' : family;
}
function traceFindingIdForResolutionStatus(status) {
    switch (status) {
        case 'missing-local-target':
            return 'LINKS_REQUIRED_TARGET_MISSING';
        case 'malformed-local-link':
        case 'outside-traversal-boundary':
            return 'LINKS_MALFORMED_LOCAL_VALUE';
        case 'unsupported-external-reference':
            return 'LINKS_UNSUPPORTED_REFERENCE';
        case 'resolved-non-local-source':
        case 'resolved-local-target':
        case 'planned-local-target':
            return null;
    }
}
function createValidationLinksCheckSummary(discovery, resolution, findings) {
    return {
        checkedArtifactCount: discovery.summary.artifactCount,
        checkedRelationshipCount: resolution.summary.valueResolutionCount +
            resolution.summary.hierarchyCheckCount +
            resolution.summary.pairingCheckCount,
        traceLinkFindingCount: findings.length,
        blockingFindingCount: findings.filter((finding) => finding.severity === 'error').length,
        advisoryFindingCount: findings.filter((finding) => finding.severity !== 'error').length,
        discoveryEvidenceCount: discovery.summary.evidenceCount,
        valueResolutionCount: resolution.summary.valueResolutionCount,
        resolvedNonLocalSourceCount: resolution.summary.resolvedNonLocalSourceCount,
        dispositionLifecycleEvidenceCount: resolution.summary.dispositionLifecycleEvidenceCount,
        hierarchyCheckCount: resolution.summary.hierarchyCheckCount,
        pairingCheckCount: resolution.summary.pairingCheckCount,
    };
}
