"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.previewPhaseScaffoldMigrationSync = previewPhaseScaffoldMigrationSync;
exports.applyPhaseScaffoldMigrationSync = applyPhaseScaffoldMigrationSync;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_util_1 = require("node:util");
const errors_1 = require("../errors");
const mutation_preconditions_1 = require("../filesystem/mutation-preconditions");
const repository_transaction_1 = require("../filesystem/repository-transaction");
const paths_1 = require("../paths");
const authoring_policy_1 = require("./authoring-policy");
const front_matter_utils_1 = require("./front-matter-utils");
const authored_scaffold_1 = require("./milestone-generation/authored-scaffold");
const projection_1 = require("./milestone-generation/projection");
const phase_parsing_1 = require("./milestone-generation/phase-parsing");
const scaffold_target_path_policy_1 = require("./scaffold-target-path-policy");
const plans = new WeakMap();
const MIGRATION_KEYS = new Set(["dependency", "target", "targets", "adapter", "validation", "rollback"]);
function previewPhaseScaffoldMigrationSync(options) {
    const phasePath = (0, phase_parsing_1.resolvePhaseOverviewPath)(options.repositoryRoot, options.phaseOverviewPath);
    const phaseText = readRegularFile(phasePath.absolute, phasePath.relative);
    const milestoneSlugs = (0, authoring_policy_1.declaredPlanningChildSlugs)(phaseText, "Milestones");
    if (milestoneSlugs.length === 0) {
        throw new Error("Phase scaffold migration requires at least one declared milestone.");
    }
    const invalidMilestoneSlug = milestoneSlugs.find((slug) => !(0, paths_1.isCanonicalSlug)(slug));
    if (invalidMilestoneSlug !== undefined) {
        throw new Error(`Phase scaffold migration requires canonical milestone slugs; found '${invalidMilestoneSlug}'.`);
    }
    const pathPolicy = (0, scaffold_target_path_policy_1.readPlanningScaffoldTargetPathPolicy)(options.repositoryRoot);
    const observedMilestones = new Map();
    for (const milestoneSlug of milestoneSlugs) {
        const milestonePath = (0, front_matter_utils_1.toRepositoryLikePath)(node_path_1.default.join(node_path_1.default.dirname(phasePath.relative), "milestones", milestoneSlug, "milestone-overview.md"));
        const absolute = node_path_1.default.join(options.repositoryRoot, milestonePath);
        const text = readRegularFile(absolute, milestonePath);
        observedMilestones.set(milestoneSlug, {
            path: milestonePath,
            text,
            projection: (0, authoring_policy_1.projectPlanningScaffoldContract)(text, "milestone")
        });
    }
    let destinationPhaseText = phaseText;
    const sourceProvidedFields = new Map();
    const inferredMilestoneEvidence = [];
    for (const milestoneSlug of milestoneSlugs) {
        const current = (0, authoring_policy_1.inspectChildScaffoldEvidence)({
            markdownText: suppressGlobalMilestoneEvidence(destinationPhaseText),
            childKind: "milestone",
            childSlug: milestoneSlug,
            declaredChildSlugs: milestoneSlugs,
            runtimeEvidencePathPolicy: pathPolicy
        });
        const observed = observedMilestones.get(milestoneSlug);
        if (observed === undefined)
            throw new Error(`Missing materialized milestone '${milestoneSlug}'.`);
        const inferred = inferMilestoneEvidence(current, observed.projection);
        sourceProvidedFields.set(milestoneSlug, providedProjectionFields(current));
        const additions = evidenceAdditions(current, inferred);
        if (additions.length > 0) {
            destinationPhaseText = insertScopedMilestoneEvidence(destinationPhaseText, milestoneSlug, additions);
        }
        const destinationEvidence = (0, authoring_policy_1.inspectChildScaffoldEvidence)({
            markdownText: destinationPhaseText,
            childKind: "milestone",
            childSlug: milestoneSlug,
            declaredChildSlugs: milestoneSlugs,
            runtimeEvidencePathPolicy: pathPolicy
        });
        if (!destinationEvidence.complete) {
            throw new Error(`Milestone '${milestoneSlug}' cannot be migrated because scoped evidence remains incomplete: ${destinationEvidence.missingEvidence.join(", ")}.`);
        }
        inferredMilestoneEvidence.push({
            milestoneSlug,
            addedEvidenceKinds: [...new Set(additions.map((entry) => entry.kind))],
            ownership: [...destinationEvidence.ownership],
            dependencies: [...destinationEvidence.dependencies],
            targetPaths: [...destinationEvidence.targetPaths],
            adapterPaths: [...destinationEvidence.adapterPaths],
            validationCommands: [...destinationEvidence.validationCommands],
            rollback: [...destinationEvidence.rollback]
        });
    }
    const legacyPhaseText = stripScopedMigrationEvidence(phaseText, milestoneSlugs);
    const destinationParsed = (0, phase_parsing_1.parsePhaseOverview)(phasePath.absolute, destinationPhaseText);
    const legacyParsed = (0, phase_parsing_1.parsePhaseOverview)(phasePath.absolute, legacyPhaseText);
    const artifacts = [];
    const writes = [];
    if (destinationPhaseText !== phaseText) {
        writes.push({ path: phasePath.relative, contents: destinationPhaseText });
        artifacts.push({
            path: phasePath.relative,
            artifactKind: "phase",
            action: "backfill-evidence",
            oldProjectionRevision: null,
            newProjectionRevision: null,
            historicalProjectionFormat: null,
            lifecycleStatus: readTopLevelScalar(phaseText, "status"),
            bodyPreserved: false
        });
    }
    for (const milestoneSlug of milestoneSlugs) {
        const legacyEvidence = (0, authoring_policy_1.inspectChildScaffoldEvidence)({
            markdownText: legacyPhaseText,
            childKind: "milestone",
            childSlug: milestoneSlug,
            declaredChildSlugs: milestoneSlugs,
            runtimeEvidencePathPolicy: pathPolicy,
            compatibilityMode: "legacy-unscoped"
        });
        if (!legacyEvidence.complete) {
            throw new Error(`Milestone '${milestoneSlug}' does not contain a complete recognized legacy scaffold projection.`);
        }
        const destinationEvidence = (0, authoring_policy_1.inspectChildScaffoldEvidence)({
            markdownText: destinationPhaseText,
            childKind: "milestone",
            childSlug: milestoneSlug,
            declaredChildSlugs: milestoneSlugs,
            runtimeEvidencePathPolicy: pathPolicy
        });
        const legacyAuthored = (0, authored_scaffold_1.inspectAuthoredMilestoneScaffold)({
            parentPath: phasePath.relative,
            phaseMarkdownText: legacyPhaseText,
            milestoneSlug,
            declaredMilestoneSlugs: milestoneSlugs,
            milestoneDescription: legacyParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            phaseAcceptanceCriteria: legacyParsed.acceptanceCriteria,
            authoritativeCriterionIds: legacyParsed.runtimeAcceptance?.required === true
                ? legacyParsed.runtimeAcceptance.criterionIds
                : [],
            scaffoldEvidence: legacyEvidence,
            runtimeEvidencePathPolicy: pathPolicy
        });
        const destinationAuthored = (0, authored_scaffold_1.inspectAuthoredMilestoneScaffold)({
            parentPath: phasePath.relative,
            phaseMarkdownText: destinationPhaseText,
            milestoneSlug,
            declaredMilestoneSlugs: milestoneSlugs,
            milestoneDescription: destinationParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            phaseAcceptanceCriteria: destinationParsed.acceptanceCriteria,
            authoritativeCriterionIds: destinationParsed.runtimeAcceptance?.required === true
                ? destinationParsed.runtimeAcceptance.criterionIds
                : [],
            scaffoldEvidence: destinationEvidence,
            runtimeEvidencePathPolicy: pathPolicy
        });
        const legacyExpected = (0, projection_1.projectExpectedMaterializedPhaseScaffolds)({
            repositoryRoot: options.repositoryRoot,
            phaseOverviewPath: phasePath.relative,
            parsedPhaseOverview: legacyParsed,
            milestoneDescription: legacyParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            milestoneEvidence: phaseMilestoneEvidence(milestoneSlug, legacyEvidence, legacyAuthored),
            authoredMilestoneScaffold: legacyAuthored,
            compatibilityMode: "legacy-unscoped"
        });
        const dayShift0211Expected = (0, projection_1.projectExpectedMaterializedPhaseScaffolds)({
            repositoryRoot: options.repositoryRoot,
            phaseOverviewPath: phasePath.relative,
            parsedPhaseOverview: legacyParsed,
            milestoneDescription: legacyParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            milestoneEvidence: phaseMilestoneEvidence(milestoneSlug, legacyEvidence, legacyAuthored),
            authoredMilestoneScaffold: legacyAuthored,
            compatibilityMode: "legacy-unscoped",
            projectionReader: "day-shift-0.2.11"
        });
        const dayShift0211ParentCriteriaExpected = (0, projection_1.projectExpectedMaterializedPhaseScaffolds)({
            repositoryRoot: options.repositoryRoot,
            phaseOverviewPath: phasePath.relative,
            parsedPhaseOverview: legacyParsed,
            milestoneDescription: legacyParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            milestoneEvidence: phaseMilestoneEvidence(milestoneSlug, legacyEvidence, legacyAuthored),
            authoredMilestoneScaffold: legacyAuthored,
            compatibilityMode: "legacy-unscoped",
            projectionReader: "day-shift-0.2.11",
            taskCriterionProjection: "parent-fallback"
        });
        const destinationExpected = (0, projection_1.projectExpectedMaterializedPhaseScaffolds)({
            repositoryRoot: options.repositoryRoot,
            phaseOverviewPath: phasePath.relative,
            parsedPhaseOverview: destinationParsed,
            milestoneDescription: destinationParsed.milestoneDescriptions.get(milestoneSlug) ?? "",
            milestoneEvidence: phaseMilestoneEvidence(milestoneSlug, destinationEvidence, destinationAuthored),
            authoredMilestoneScaffold: destinationAuthored
        });
        collectProjectionWrites({
            repositoryRoot: options.repositoryRoot,
            historicalCandidates: [
                {
                    format: "day-shift/0.2.11",
                    projections: dayShift0211Expected
                },
                {
                    format: "day-shift/0.2.11-parent-task-criteria",
                    projections: dayShift0211ParentCriteriaExpected
                },
                {
                    format: "pre-scoped-evidence/current-reader",
                    projections: legacyExpected
                }
            ],
            destinationExpected,
            requiredAdoptionFields: sourceProvidedFields.get(milestoneSlug) ?? new Set(),
            writes,
            artifacts
        });
    }
    const artifactWrites = uniqueWritesByPath(writes);
    if (artifactWrites.length === 0) {
        throw new Error("No legacy scoped-evidence migration is required for this phase.");
    }
    const artifactPreconditions = artifactWrites.map((write) => {
        const runtimePath = node_path_1.default.join(options.repositoryRoot, write.path);
        return (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)({
            repositoryRelativePath: write.path,
            runtimePath
        });
    });
    const recordId = (0, node_crypto_1.createHash)("sha256").update(JSON.stringify({
        phaseOverviewPath: phasePath.relative,
        preconditions: artifactPreconditions.map(mutation_preconditions_1.serializeMutationPrecondition),
        projections: artifacts.map((entry) => ({
            path: entry.path,
            oldProjectionRevision: entry.oldProjectionRevision,
            newProjectionRevision: entry.newProjectionRevision
        }))
    })).digest("hex").slice(0, 32);
    const durableRecordPath = `.day-shift/state/scaffold-migrations/${recordId}.json`;
    const durableRecord = `${JSON.stringify({
        schemaVersion: 1,
        migrationId: `phase-scaffold-migration-${recordId}`,
        phaseOverviewPath: phasePath.relative,
        legacyEvidenceDetected: true,
        inferredMilestoneEvidence,
        affectedArtifacts: artifacts,
        preservedHistoricalEvidence: true
    }, null, 2)}\n`;
    const uniqueWrites = uniqueWritesByPath([
        ...artifactWrites,
        { path: durableRecordPath, contents: durableRecord }
    ]);
    const preconditions = uniqueWrites.flatMap((write) => {
        const runtimePath = node_path_1.default.join(options.repositoryRoot, write.path);
        const target = { repositoryRelativePath: write.path, runtimePath };
        const presence = (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target);
        return node_fs_1.default.existsSync(runtimePath)
            ? [presence, (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target)]
            : [presence];
    });
    if (!uniqueWrites.some((write) => write.path === phasePath.relative)) {
        const phaseTarget = {
            repositoryRelativePath: phasePath.relative,
            runtimePath: phasePath.absolute
        };
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(phaseTarget), (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(phaseTarget));
    }
    const planDigest = migrationPlanDigest({
        phaseOverviewPath: phasePath.relative,
        writes: uniqueWrites,
        preconditions
    });
    const snapshot = {
        phaseOverviewPath: phasePath.relative,
        legacyEvidenceDetected: artifacts.some((entry) => entry.action === "rebind-projection"),
        inferredMilestoneEvidence,
        affectedArtifacts: artifacts.sort((left, right) => left.path.localeCompare(right.path)),
        intendedPaths: uniqueWrites.map((entry) => entry.path),
        expected: preconditions.map(mutation_preconditions_1.serializeMutationPrecondition),
        planDigest,
        writeOutcome: "previewed",
        changedPaths: [],
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null
    };
    plans.set(snapshot, {
        repositoryRoot: options.repositoryRoot,
        durableRecordPath,
        writes: uniqueWrites,
        preconditions,
        snapshot
    });
    return snapshot;
}
function applyPhaseScaffoldMigrationSync(preview, expectedPlanDigest) {
    const plan = plans.get(preview);
    if (plan === undefined)
        throw new Error("Phase scaffold migration apply requires a current in-process preview.");
    if (expectedPlanDigest !== preview.planDigest) {
        throw new Error(`Phase scaffold migration expected plan digest '${expectedPlanDigest}', but the current preview is '${preview.planDigest}'.`);
    }
    const result = (0, repository_transaction_1.executeRepositoryTransactionSync)(plan.repositoryRoot, {
        transactionId: `phase-scaffold-migration-${(0, node_crypto_1.randomBytes)(12).toString("hex")}`,
        transactionKind: "migration",
        durableRecordPath: plan.durableRecordPath,
        writes: plan.writes,
        preconditions: plan.preconditions
    });
    return {
        ...preview,
        writeOutcome: result.outcome,
        changedPaths: result.entries
            .filter((entry) => entry.observedAfterRevision === entry.intendedRevision)
            .map((entry) => entry.path),
        transactionId: result.transactionId,
        conflicts: result.conflicts,
        recoveryPath: result.outcome === "incomplete" ? result.transactionPath : null,
        failure: result.failure
    };
}
function collectProjectionWrites(options) {
    const destinationByPath = new Map(options.destinationExpected.map((entry) => [entry.path, entry]));
    const historicalPaths = options.historicalCandidates[0]?.projections ?? [];
    for (const historicalPath of historicalPaths) {
        const destination = destinationByPath.get(historicalPath.path);
        if (destination === undefined
            || destination.artifactKind !== historicalPath.artifactKind) {
            throw new Error(`Destination projection is missing for '${historicalPath.path}'.`);
        }
        const runtimePath = node_path_1.default.join(options.repositoryRoot, historicalPath.path);
        if (historicalPath.artifactKind === "task"
            && node_fs_1.default.lstatSync(runtimePath, { throwIfNoEntry: false }) === undefined) {
            continue;
        }
        const observedText = readRegularFile(runtimePath, historicalPath.path);
        const observedRaw = (0, authoring_policy_1.projectPlanningScaffoldContract)(observedText, historicalPath.artifactKind);
        const observed = historicalPath.artifactKind === "task"
            ? comparableTaskProjection(observedRaw)
            : observedRaw;
        const destinationProjection = historicalPath.artifactKind === "task"
            ? comparableTaskProjection(destination.projection)
            : destination.projection;
        const destinationRevision = (0, authoring_policy_1.planningScaffoldProjectionRevision)(destinationProjection);
        const recordedRevision = (0, authoring_policy_1.readPlanningScaffoldProjectionRevision)(observedText);
        const candidates = options.historicalCandidates.map((candidate) => {
            const projected = candidate.projections.find((entry) => entry.path === historicalPath.path
                && entry.artifactKind === historicalPath.artifactKind);
            if (projected === undefined) {
                throw new Error(`Historical projection format '${candidate.format}' is missing '${historicalPath.path}'.`);
            }
            const projection = historicalPath.artifactKind === "task"
                ? comparableTaskProjection(projected.projection)
                : projected.projection;
            return {
                format: candidate.format,
                projection,
                revision: (0, authoring_policy_1.planningScaffoldProjectionRevision)(projection)
            };
        });
        const allowed = refinementFields(historicalPath.artifactKind);
        const destinationObserved = (0, authoring_policy_1.comparePlanningScaffoldProjections)(destinationProjection, observed);
        const unsafeDestinationDrift = destinationObserved.drift.filter((entry) => !isRefinementField(historicalPath.artifactKind, entry.field, allowed));
        if (unsafeDestinationDrift.length > 0) {
            throw new Error(`Materialized child '${historicalPath.path}' has non-refinement destination drift at: ${unsafeDestinationDrift.map((entry) => entry.field).join(", ")}.`);
        }
        if (recordedRevision === destinationRevision)
            continue;
        const matched = candidates.find((candidate) => candidate.revision === recordedRevision);
        if (matched === undefined) {
            throw unsupportedHistoricalProjectionError({
                path: historicalPath.path,
                artifactKind: historicalPath.artifactKind,
                recordedRevision,
                candidates: candidates.map((candidate) => ({
                    format: candidate.format,
                    revision: candidate.revision,
                    bodyCompatible: historicalBodyCompatible({
                        artifactKind: historicalPath.artifactKind,
                        historical: candidate.projection,
                        destination: destinationProjection,
                        observed,
                        allowed
                    })
                }))
            });
        }
        const legacyProjection = matched.projection;
        const legacyObserved = (0, authoring_policy_1.comparePlanningScaffoldProjections)(legacyProjection, observed);
        const changedProjectionFields = new Set((0, authoring_policy_1.comparePlanningScaffoldProjections)(legacyProjection, destinationProjection)
            .drift.map((entry) => entry.field));
        const destinationDriftFields = new Set(destinationObserved.drift.map((entry) => entry.field));
        const unsafeLegacyDrift = legacyObserved.drift.filter((entry) => !isRefinementField(historicalPath.artifactKind, entry.field, allowed)
            && !isVerifiedDestinationAdoption(entry.field, changedProjectionFields, destinationDriftFields));
        if (unsafeLegacyDrift.length > 0) {
            throw new Error(`Materialized child '${historicalPath.path}' has non-refinement legacy drift at: ${unsafeLegacyDrift.map((entry) => entry.field).join(", ")}.`);
        }
        const unsafeAdoption = destinationObserved.drift.filter((entry) => changedProjectionFields.has(entry.field)
            && options.requiredAdoptionFields.has(entry.field)
            && !migrationEquivalent(entry.field, entry.expected, entry.observed));
        if (unsafeAdoption.length > 0) {
            throw new Error(`Materialized child '${historicalPath.path}' cannot adopt changed parent evidence that differs from its preserved body at: ${unsafeAdoption.map((entry) => entry.field).join(", ")}.`);
        }
        const reboundText = (0, authoring_policy_1.rebindPlanningScaffoldProjectionRevision)(observedText, destinationRevision);
        options.writes.push({ path: historicalPath.path, contents: reboundText });
        options.artifacts.push({
            path: historicalPath.path,
            artifactKind: historicalPath.artifactKind,
            action: "rebind-projection",
            oldProjectionRevision: recordedRevision,
            newProjectionRevision: destinationRevision,
            historicalProjectionFormat: matched.format,
            lifecycleStatus: readTopLevelScalar(observedText, "status")
                ?? readTopLevelScalar(observedText, "readiness"),
            bodyPreserved: stripProjectionStamp(observedText) === stripProjectionStamp(reboundText)
        });
    }
}
function historicalBodyCompatible(options) {
    const changedProjectionFields = new Set((0, authoring_policy_1.comparePlanningScaffoldProjections)(options.historical, options.destination)
        .drift.map((entry) => entry.field));
    const destinationDriftFields = new Set((0, authoring_policy_1.comparePlanningScaffoldProjections)(options.destination, options.observed)
        .drift.map((entry) => entry.field));
    return (0, authoring_policy_1.comparePlanningScaffoldProjections)(options.historical, options.observed)
        .drift.every((entry) => isRefinementField(options.artifactKind, entry.field, options.allowed)
        || isVerifiedDestinationAdoption(entry.field, changedProjectionFields, destinationDriftFields));
}
function isVerifiedDestinationAdoption(field, changedProjectionFields, destinationDriftFields) {
    return field === "criterionIds"
        && changedProjectionFields.has(field)
        && !destinationDriftFields.has(field);
}
function unsupportedHistoricalProjectionError(options) {
    return new errors_1.RuntimeError({
        message: `Materialized child '${options.path}' has unsupported historical projection stamp '${options.recordedRevision ?? "(missing)"}'.`,
        code: "PLANNING_SCAFFOLD_LEGACY_PROJECTION_UNSUPPORTED",
        exitCode: errors_1.RuntimeExitCode.UNSUPPORTED_CAPABILITY,
        details: [
            `Artifact kind: ${options.artifactKind}.`,
            `Recorded stamp: ${options.recordedRevision ?? "(missing)"}.`,
            ...options.candidates.map((candidate) => `Recognized candidate ${candidate.format}: ${candidate.revision}; body compatibility: ${candidate.bodyCompatible ? "passed" : "failed"}.`),
            "No phase, milestone, task, reconciliation, lifecycle-run, or historical evidence write was attempted."
        ],
        recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                id: "recovery.phase-scaffold-projection-unsupported",
                explanation: "Install a Day Shift release that recognizes this historical projection format, then rerun the same migration preview.",
                reason: "An unmatched stamp cannot be rebound safely without a recognized historical projection reader."
            })]
    });
}
function phaseMilestoneEvidence(milestoneSlug, scaffoldEvidence, authored) {
    return {
        milestoneSlug,
        scaffoldEvidence,
        criterionIds: [...authored.criterionIds],
        taskIdentities: authored.tasks.map((task) => {
            const ownership = task.ownership.length > 0
                ? task.ownership
                : scaffoldEvidence.ownership;
            const dependencies = task.dependencies.length > 0
                ? task.dependencies
                : scaffoldEvidence.dependencies;
            const targetPaths = task.targetPaths.length > 0
                ? task.targetPaths
                : scaffoldEvidence.targetPaths;
            const explicitAdapterPaths = task.adapterPaths.length > 0
                ? task.adapterPaths
                : scaffoldEvidence.adapterPaths;
            const validationCommands = task.validationCommands.length > 0
                ? task.validationCommands
                : scaffoldEvidence.validationCommands;
            const rollback = task.rollback.length > 0
                ? task.rollback
                : scaffoldEvidence.rollback;
            const projectedEvidence = (0, authoring_policy_1.inspectProjectedTaskScaffoldEvidence)({
                prose: [
                    task.description,
                    ...task.acceptanceCriteria,
                    task.currentBehavior ?? "",
                    task.desiredBehavior,
                    ...ownership
                ],
                ownership,
                dependencies,
                targetPaths,
                explicitAdapterPaths,
                validationCommands,
                rollback
            });
            return {
                taskSlug: task.slug,
                description: task.description,
                criterionIds: [...task.criterionIds],
                sharedCriterionIds: [...task.sharedCriterionIds],
                currentBehavior: task.currentBehavior,
                desiredBehavior: task.desiredBehavior,
                ownership: [...ownership],
                dependencies: [...dependencies],
                targetPaths: [...targetPaths],
                adapterPaths: [...projectedEvidence.adapterPaths],
                requiredAdapter: projectedEvidence.requiredAdapter,
                adapterRequirementReasons: [
                    ...projectedEvidence.adapterRequirementReasons
                ],
                validationCommands: [...validationCommands],
                rollback: [...rollback],
                missingEvidence: [...projectedEvidence.missingEvidence],
                complete: projectedEvidence.complete
            };
        })
    };
}
function inferMilestoneEvidence(current, observed) {
    const ownership = current.ownership.length > 0
        ? [...current.ownership]
        : canonicalOwnership(observed.ownership);
    const dependencies = current.dependencies.length > 0
        ? [...current.dependencies]
        : [...observed.dependencies];
    const targetPaths = current.targetPaths.length > 0
        ? [...current.targetPaths]
        : [...observed.targetPaths];
    const adapterPaths = current.adapterPaths.length > 0
        ? [...current.adapterPaths]
        : [...observed.adapterPaths];
    const validationCommands = current.validationCommands.length > 0
        ? [...current.validationCommands]
        : [...observed.validationCommands];
    const rollback = current.rollback.length > 0
        ? canonicalRollback(current.rollback)
        : canonicalRollback(observed.rollback);
    const missingEvidence = [
        ...(ownership.length === 0 ? ["ownership"] : []),
        ...(dependencies.length === 0 ? ["dependency"] : []),
        ...(targetPaths.length === 0 ? ["target"] : []),
        ...(current.requiredAdapter && adapterPaths.length === 0 ? ["adapter"] : []),
        ...(validationCommands.length === 0 ? ["validation"] : []),
        ...(rollback.length === 0 ? ["rollback"] : [])
    ];
    return {
        ...current,
        ownership,
        dependencies,
        targetPaths,
        adapterPaths,
        validationCommands,
        rollback,
        missingEvidence,
        complete: missingEvidence.length === 0
    };
}
function evidenceAdditions(current, inferred) {
    return [
        ...(current.ownership.length === 0
            ? inferred.ownership.map((value) => ({ kind: "ownership", value }))
            : []),
        ...(current.dependencies.length === 0
            ? inferred.dependencies.map((value) => ({ kind: "dependency", value }))
            : []),
        ...(current.targetPaths.length === 0
            ? inferred.targetPaths.map((value) => ({ kind: "target", value }))
            : []),
        ...(current.adapterPaths.length === 0 && current.requiredAdapter
            ? inferred.adapterPaths.map((value) => ({ kind: "adapter", value }))
            : []),
        ...(current.validationCommands.length === 0
            ? inferred.validationCommands.map((value) => ({ kind: "validation", value }))
            : []),
        ...(current.rollback.length === 0
            ? inferred.rollback.map((value) => ({ kind: "rollback", value }))
            : [])
    ];
}
function insertScopedMilestoneEvidence(text, milestoneSlug, additions) {
    if (additions.length === 0)
        return text;
    const newline = text.includes("\r\n") ? "\r\n" : "\n";
    const lines = text.split(/\r?\n/u);
    const sectionStart = lines.findIndex((line) => line.trim() === "## Scaffold Evidence");
    if (sectionStart < 0)
        throw new Error("Phase scaffold migration requires a Scaffold Evidence section.");
    let blockStart = -1;
    let blockEnd = lines.length;
    for (let index = sectionStart + 1; index < lines.length; index += 1) {
        if (/^##\s+/u.test(lines[index])) {
            blockEnd = index;
            break;
        }
        const match = lines[index].match(/^-\s+(?:`([^`]+)`|\[([^\]]+)\])\s*:/u);
        if (match === null)
            continue;
        if (blockStart >= 0) {
            blockEnd = index;
            break;
        }
        if ((match[1] ?? match[2]) === milestoneSlug)
            blockStart = index;
    }
    if (blockStart < 0)
        throw new Error(`Scaffold Evidence is missing milestone '${milestoneSlug}'.`);
    let insertAt = blockEnd;
    for (let index = blockStart + 1; index < blockEnd; index += 1) {
        if (/^\s{2}-\s+(?:task|task_slug)\s*:/u.test(lines[index])) {
            insertAt = index;
            break;
        }
    }
    lines.splice(insertAt, 0, ...additions.map((entry) => `  - ${entry.kind}: ${entry.value}`));
    return lines.join(newline);
}
function stripScopedMigrationEvidence(text, milestoneSlugs) {
    const newline = text.includes("\r\n") ? "\r\n" : "\n";
    const lines = text.split(/\r?\n/u);
    const sectionStart = lines.findIndex((line) => line.trim() === "## Scaffold Evidence");
    if (sectionStart < 0)
        return text;
    const selected = new Set(milestoneSlugs);
    let active = false;
    for (let index = sectionStart + 1; index < lines.length; index += 1) {
        if (/^##\s+/u.test(lines[index]))
            break;
        const scope = lines[index].match(/^-\s+(?:`([^`]+)`|\[([^\]]+)\])\s*:/u);
        if (scope !== null) {
            active = selected.has(scope[1] ?? scope[2]);
            continue;
        }
        if (!active)
            continue;
        const semantic = lines[index].match(/^\s{2}-\s+([A-Za-z0-9_-]+)\s*:/u);
        if (semantic !== null && MIGRATION_KEYS.has(semantic[1].toLowerCase())) {
            lines[index] = "";
        }
    }
    return lines.filter((line, index, all) => line !== "" || all[index - 1] !== "").join(newline);
}
function suppressGlobalMilestoneEvidence(text) {
    const suppressed = new Set([
        "Scope",
        "Dependencies",
        "Implementation Target Paths",
        "Runtime Delta",
        "Validation Commands",
        "Validation Focus",
        "Validation Strategy",
        "Rollback / Recovery",
        "Rollback"
    ]);
    const newline = text.includes("\r\n") ? "\r\n" : "\n";
    const lines = text.split(/\r?\n/u);
    let suppress = false;
    return lines.map((line) => {
        const heading = line.match(/^##\s+(.+)$/u);
        if (heading !== null) {
            suppress = suppressed.has(heading[1].trim());
            return line;
        }
        return suppress ? "" : line;
    }).join(newline);
}
function refinementFields(kind) {
    return kind === "milestone"
        ? new Set(["ownership", "dependencies", "targetPaths", "adapterPaths", "validationCommands", "rollback"])
        : new Set(["dependencies", "targetPaths", "adapterPaths", "validationCommands", "rollback", "currentBehavior", "desiredBehavior"]);
}
function providedProjectionFields(evidence) {
    return new Set([
        ...(evidence.dependencies.length > 0 ? ["dependencies"] : []),
        ...(evidence.targetPaths.length > 0 ? ["targetPaths"] : []),
        ...(evidence.adapterPaths.length > 0 ? ["adapterPaths"] : []),
        ...(evidence.validationCommands.length > 0 ? ["validationCommands"] : [])
    ]);
}
function isRefinementField(artifactKind, field, directFields) {
    if (directFields.has(field))
        return true;
    return artifactKind === "milestone"
        && /^nestedEvidence\.[^.]+\.(?:ownership|dependencies|targetPaths|adapterPaths|validationCommands|rollback|currentBehavior|desiredBehavior)$/u.test(field);
}
function comparableTaskProjection(projection) {
    return {
        ...projection,
        ownership: [],
        declaredChildCount: null,
        declaredChildSlugs: [],
        nestedEvidence: []
    };
}
function migrationEquivalent(field, expected, observed) {
    if (field === "rollback" && Array.isArray(expected) && Array.isArray(observed)) {
        return (0, node_util_1.isDeepStrictEqual)(canonicalRollback(expected.filter((entry) => typeof entry === "string")), canonicalRollback(observed.filter((entry) => typeof entry === "string")));
    }
    if (field === "ownership" && Array.isArray(expected) && Array.isArray(observed)) {
        return (0, node_util_1.isDeepStrictEqual)(canonicalOwnership(expected.filter((entry) => typeof entry === "string")), canonicalOwnership(observed.filter((entry) => typeof entry === "string")));
    }
    return (0, node_util_1.isDeepStrictEqual)(expected, observed);
}
function canonicalOwnership(values) {
    return uniqueStrings(values.map((value) => value.replace(/^(?:(?:Own the child-specific implementation boundary|Deliver the declared milestone outcome):\s*)+/u, "")));
}
function canonicalRollback(values) {
    return uniqueStrings(values.map((value) => value.replace(/^(?:rollback:\s*)+/iu, "").trim()));
}
function uniqueStrings(values) {
    return [...new Set(values.map((value) => value.trim()).filter((value) => value !== ""))];
}
function uniqueWritesByPath(writes) {
    const unique = new Map();
    for (const write of writes) {
        const existing = unique.get(write.path);
        if (existing !== undefined && existing.contents !== write.contents) {
            throw new Error(`Migration produced conflicting writes for '${write.path}'.`);
        }
        unique.set(write.path, write);
    }
    return [...unique.values()].sort((left, right) => left.path.localeCompare(right.path));
}
function migrationPlanDigest(options) {
    const canonical = {
        schemaVersion: 1,
        phaseOverviewPath: options.phaseOverviewPath,
        writes: options.writes.map((write) => ({
            path: write.path,
            contentRevision: (0, node_crypto_1.createHash)("sha256").update(write.contents).digest("hex")
        })),
        preconditions: options.preconditions.map(mutation_preconditions_1.serializeMutationPrecondition)
    };
    return `sha256:${(0, node_crypto_1.createHash)("sha256").update(JSON.stringify(canonical)).digest("hex")}`;
}
function readRegularFile(runtimePath, relativePath) {
    const stats = node_fs_1.default.lstatSync(runtimePath, { throwIfNoEntry: false });
    if (stats === undefined || !stats.isFile() || stats.isSymbolicLink()) {
        throw new Error(`Phase scaffold migration requires regular file '${relativePath}'.`);
    }
    return node_fs_1.default.readFileSync(runtimePath, "utf8");
}
function readTopLevelScalar(text, field) {
    const escaped = field.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
    return text.match(new RegExp(`^${escaped}:\\s*(.*)$`, "mu"))?.[1]?.trim() ?? null;
}
function stripProjectionStamp(text) {
    return text.replace(/^scaffold_projection_revision:\s*.*$/mu, "scaffold_projection_revision: <preserved>");
}
