export function calculateActionableSpecMetrics(args) {
    return [
        groundingCoverage(args.criteria, args.groundingRecords ?? []),
        verificationCoverage(args.evidenceIndex),
        ambiguityCount(args.ambiguityFindings ?? []),
        driftRisk(args.driftIssues ?? []),
    ].filter((metric) => metric !== null);
}
export function shouldExposeMetric(metric) {
    return metric.inputs.length > 0 && metric.nextAction.trim().length > 0;
}
function groundingCoverage(criteria, records) {
    const missing = criteria.filter((criterion) => !records.some((record) => normalize(record.text) === normalize(criterion) &&
        record.source !== 'ungrounded_advisory' &&
        record.evidence.length > 0));
    if (criteria.length === 0 || missing.length === 0) {
        return null;
    }
    return {
        name: 'groundingCoverage',
        value: Math.round(((criteria.length - missing.length) / criteria.length) * 100),
        inputs: missing,
        nextAction: 'Add grounding evidence or move ungrounded criteria to discovery/advisory output.',
    };
}
function verificationCoverage(index) {
    if (!index) {
        return null;
    }
    const missing = index.criteria.filter((entry) => !entry.evidence.some((record) => record.kind === 'validation' && record.status === 'valid'));
    if (index.criteria.length === 0 || missing.length === 0) {
        return null;
    }
    return {
        name: 'verificationCoverage',
        value: Math.round(((index.criteria.length - missing.length) / index.criteria.length) * 100),
        inputs: missing.map((entry) => entry.criterion),
        nextAction: 'Attach validation evidence mapped to each uncovered criterion.',
    };
}
function ambiguityCount(findings) {
    if (findings.length === 0) {
        return null;
    }
    return {
        name: 'ambiguityCount',
        value: findings.length,
        inputs: [...findings],
        nextAction: 'Resolve each ambiguity or mark it explicitly out of scope before implementation.',
    };
}
function driftRisk(issues) {
    const driftIssues = issues.filter((issue) => issue.code.startsWith('done_drift_'));
    if (driftIssues.length === 0) {
        return null;
    }
    return {
        name: 'driftRisk',
        value: driftIssues.some((issue) => issue.code === 'done_drift_unapproved_scope')
            ? 'high'
            : 'medium',
        inputs: driftIssues.map((issue) => issue.message),
        nextAction: 'Reconcile scope, replace stale evidence, or map validation to the affected criteria.',
    };
}
function normalize(value) {
    return value.replace(/\s+/g, ' ').trim().toLowerCase();
}
//# sourceMappingURL=actionable-metrics.js.map