// engine/spec-versioner.ts — Spec versioning, diff computation, and cascading logic
// Manages SpecVersion creation from ReconcileChanges, downstream spec discovery,
// and cascade notifications when a spec transitions status.
// --- Version Creation ---
/**
 * Create a new SpecVersion from a set of approved ReconcileChanges.
 * The new version number = currentVersion + 1.
 */
export function createVersion(specId, currentVersion, changes, reason, changedBy = 'reconcile_spec') {
    return {
        specId,
        version: currentVersion + 1,
        changes: computeDiff(changes),
        changedBy,
        timestamp: new Date().toISOString(),
        reason,
    };
}
// --- Diff Computation ---
/**
 * Map ReconcileChanges to semantic SpecDiffs.
 * Assigns each change to its corresponding artifact file (HU.md / FICHA-TECNICA.md / PLAN.md).
 */
export function computeDiff(changes) {
    return changes.map((c) => ({
        file: resolveFile(c.section),
        section: c.section,
        type: resolveChangeType(c.originalValue, c.newValue),
        before: c.originalValue,
        after: c.newValue,
    }));
}
function resolveFile(section) {
    if (section.startsWith('hu-') || section === 'scope' || section === 'status') {
        return 'HU.md';
    }
    if (section.startsWith('plan')) {
        return 'PLAN.md';
    }
    return 'FICHA-TECNICA.md';
}
function resolveChangeType(before, after) {
    if (!before) {
        return 'added';
    }
    if (!after) {
        return 'removed';
    }
    return 'modified';
}
// --- Version History ---
/**
 * Assemble a VersionHistory from a raw versions array.
 * Returns versions sorted ascending by version number.
 */
export function buildVersionHistory(specId, versions) {
    const sorted = [...versions].sort((a, b) => a.version - b.version);
    return {
        specId,
        versions: sorted,
        currentVersion: sorted.at(-1)?.version ?? 0,
    };
}
// --- Downstream Discovery ---
/**
 * Find all specs that declare a dependency on the given specId,
 * either through `dependencies` or `blockedBy`.
 */
export function findDownstreamSpecs(specId, allSpecs) {
    return allSpecs.filter((s) => s.dependencies.includes(specId) || s.blockedBy.includes(specId));
}
// --- Cascade Check ---
/**
 * Identify downstream specs affected when a spec transitions to a new status.
 * Returns notifications (informational only — not blocking).
 * Max cascade depth: 1 level (prevents recursive cascading).
 */
export function cascadeCheck(specId, allSpecs, newStatus) {
    const downstream = findDownstreamSpecs(specId, allSpecs);
    const notifications = downstream.map((s) => ({
        specId: s.id,
        title: s.title,
        status: s.status,
        message: `Dependency "${specId}" changed to "${newStatus}" — re-validate this spec`,
    }));
    return {
        affectedSpecs: downstream.map((s) => s.id),
        notifications,
        checkedAt: new Date().toISOString(),
    };
}
//# sourceMappingURL=spec-versioner.js.map