"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runRepositoryMigrationRehearsalSync = runRepositoryMigrationRehearsalSync;
exports.verifyRepositoryMigrationRehearsalSync = verifyRepositoryMigrationRehearsalSync;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const workspace_migration_application_1 = require("../workspace-migration-application");
const workspace_migration_planning_1 = require("../workspace-migration-planning");
const contracts_1 = require("./contracts");
const filesystem_1 = require("./filesystem");
const mapping_1 = require("./mapping");
const preservation_1 = require("./preservation");
const validation_1 = require("./validation");
function runRepositoryMigrationRehearsalSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const generatedAt = (0, validation_1.normalizeIsoTimestamp)(options.generatedAt ?? new Date().toISOString());
    const initialGuard = (0, preservation_1.computeRepositoryMigrationCanonicalGuardSync)(repositoryRoot);
    const canonicalGuards = [{
            checkpoint: "initial",
            aggregateDigest: initialGuard.aggregateDigest,
            matchedInitial: true
        }];
    const checkpoint = (name) => {
        const guard = (0, preservation_1.computeRepositoryMigrationCanonicalGuardSync)(repositoryRoot);
        const matchedInitial = guard.aggregateDigest === initialGuard.aggregateDigest;
        canonicalGuards.push({
            checkpoint: name,
            aggregateDigest: guard.aggregateDigest,
            matchedInitial
        });
        if (!matchedInitial) {
            throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", `Canonical planning/specification/configuration guard changed at '${name}'.`, false);
        }
        return guard;
    };
    const firstBuild = (0, mapping_1.buildRepositoryMigrationRehearsalSync)({ repositoryRoot });
    checkpoint("after-first-build");
    const secondBuild = (0, mapping_1.buildRepositoryMigrationRehearsalSync)({ repositoryRoot });
    checkpoint("after-second-build");
    const doubleBuildMatched = firstBuild.deterministicDigest === secondBuild.deterministicDigest
        && firstBuild.sourceManifest.aggregateDigest
            === secondBuild.sourceManifest.aggregateDigest
        && firstBuild.mappingInventory.aggregateDigest
            === secondBuild.mappingInventory.aggregateDigest;
    if (!doubleBuildMatched) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", "Two clean rehearsal builds from unchanged canonical evidence were not deterministic.", false);
    }
    const mapping = (0, mapping_1.readRepositoryMigrationMappingDocumentSync)(repositoryRoot, {
        sourceManifest: secondBuild.sourceManifest,
        mappingInventory: secondBuild.mappingInventory
    });
    const selections = (0, validation_1.mappingSelections)(mapping);
    const targetRoot = node_path_1.default.join(repositoryRoot, ...contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT.split("/"));
    const plan = (0, workspace_migration_planning_1.planWorkspaceStructureMigrationSync)({
        repositoryRoot: targetRoot,
        selections
    });
    if (plan.status !== "ready" || plan.findings.length > 0) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", `Isolated migration plan '${plan.planId}' is ${plan.status} with ${plan.findings.length} finding(s).`, false);
    }
    let invalidAttempt;
    try {
        (0, workspace_migration_application_1.applyWorkspaceStructureMigrationSync)({
            repositoryRoot: targetRoot,
            selections,
            expectedPlanDigest: `sha256:${"0".repeat(64)}`,
            actor: "phase-07-rehearsal",
            reason: "Prove stale digest authorization is rejected without writes.",
            appliedAt: generatedAt
        });
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", "Injected stale-plan migration unexpectedly returned without rejecting.", false);
    }
    catch (error) {
        if (!(error instanceof workspace_migration_application_1.WorkspaceMigrationApplicationError)
            || error.code !== "plan-mismatch"
            || error.noWrite !== true) {
            throw error;
        }
        invalidAttempt = {
            outcome: "rejected",
            code: error.code,
            noWrite: error.noWrite
        };
    }
    checkpoint("after-invalid-attempt");
    const interrupted = (0, workspace_migration_application_1.applyWorkspaceStructureMigrationSync)({
        repositoryRoot: targetRoot,
        selections,
        expectedPlanDigest: plan.planDigest,
        actor: "phase-07-rehearsal",
        reason: "Inject an interruption after the first canonical replacement.",
        appliedAt: generatedAt,
        transaction: {
            hook(context) {
                if (context.phase === "before-replacement" && context.entryIndex === 1) {
                    throw new Error("phase-07 injected transaction interruption");
                }
            }
        }
    });
    if (interrupted.outcome !== "incomplete"
        || interrupted.changedPaths.length !== 1
        || interrupted.recoveryPath === null
        || interrupted.recoveryFingerprint === null) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", `Injected interruption returned '${interrupted.outcome}' without the expected bounded recovery evidence.`, false);
    }
    const recoveryAbsolute = node_path_1.default.resolve(targetRoot, interrupted.recoveryPath);
    const retainedBeforeReset = recoveryAbsolute.startsWith(`${targetRoot}${node_path_1.default.sep}`)
        && node_fs_1.default.existsSync(recoveryAbsolute);
    if (!retainedBeforeReset) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", "Injected incomplete transaction did not retain recovery evidence inside the isolated workspace.", false);
    }
    checkpoint("after-interruption");
    const resetBuild = (0, mapping_1.buildRepositoryMigrationRehearsalSync)({ repositoryRoot });
    checkpoint("after-reset");
    const resetMatched = resetBuild.sourceManifest.aggregateDigest === secondBuild.sourceManifest.aggregateDigest
        && resetBuild.deterministicDigest === secondBuild.deterministicDigest;
    if (!resetMatched) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", "Clean guarded reset did not restore the exact deterministic pre-migration workspace.", false);
    }
    const retryPlan = (0, workspace_migration_planning_1.planWorkspaceStructureMigrationSync)({
        repositoryRoot: targetRoot,
        selections
    });
    if (retryPlan.planDigest !== plan.planDigest || retryPlan.status !== "ready") {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", "Migration retry preview did not reproduce the exact authorized plan digest.", false);
    }
    const applied = (0, workspace_migration_application_1.applyWorkspaceStructureMigrationSync)({
        repositoryRoot: targetRoot,
        selections,
        expectedPlanDigest: retryPlan.planDigest,
        actor: "phase-07-rehearsal",
        reason: "Apply the exact preview-bound migration only to the disposable isolated workspace.",
        appliedAt: generatedAt
    });
    if (applied.outcome !== "committed" || !applied.writeApplied) {
        throw new contracts_1.RepositoryMigrationRehearsalError("rehearsal-blocked", `Guarded retry returned '${applied.outcome}' instead of a committed migration.`, false);
    }
    checkpoint("after-apply");
    (0, validation_1.removeEmptyNumericPlanningRootsSync)(targetRoot);
    const migratedManifest = (0, preservation_1.createRepositoryPlanningManifestSync)(targetRoot);
    const activeNumericRootPaths = (0, validation_1.activeNumericPlanningRootPaths)(targetRoot);
    const duplicateTaskIdentities = (0, validation_1.findDuplicateTaskIdentities)(migratedManifest);
    const structuralVerification = (0, workspace_migration_planning_1.planWorkspaceStructureMigrationSync)({
        repositoryRoot: targetRoot
    });
    const structuralVerificationAccepted = structuralVerification.workUnits.every((unit) => unit.alreadyCanonical)
        && structuralVerification.workUnits.every((unit) => !unit.actionable)
        && structuralVerification.findings.length === 0;
    const preservation = (0, preservation_1.compareRepositoryMigrationPreservation)(resetBuild.sourceManifest, migratedManifest, retryPlan);
    const validationReceipts = options.skipCommandValidation === true
        ? []
        : (0, validation_1.runRehearsalValidationCommands)(repositoryRoot, targetRoot, retryPlan);
    const generatedWorkOverviewPaths = [...new Set(retryPlan.workUnits.flatMap((unit) => unit.artifactMappings
            .filter((mapping) => mapping.sourcePath === null && mapping.role === "work-overview")
            .map((mapping) => mapping.destinationPath)))].sort();
    const linkGapEvidence = (0, validation_1.inspectIsolatedLinkGapEvidence)(targetRoot);
    const inventoryReceipt = validationReceipts.find((receipt) => receipt.id === "isolated-planning-inventory");
    const workOverviewSupported = options.skipCommandValidation === true
        || (inventoryReceipt?.exitCode === 0
            && inventoryReceipt.acceptedGap === null);
    const linkLifecycleReconciled = linkGapEvidence.blockingFindingCount === 0
        && structuralVerification.findings.length === 0;
    const explicitGaps = [
        {
            id: "isolated-minimal-asset-schema-evidence",
            classification: "rehearsal-isolation",
            affectedCommands: ["day-shift agent", "ordinary isolated CLI compatibility preflight"],
            affectedPaths: [
                ".day-shift/prompts/user",
                ".day-shift/prompts/user/manifest.json",
                ".day-shift/templates/manifest.json"
            ],
            evidence: {
                findingCode: "workspace-compatibility-missing-schema-evidence",
                findingCount: 4,
                noWrite: true
            },
            rehearsalDisposition: "Accepted only for this intentionally minimal isolated copy; read-only command checks run with the documented compatibility-gate bypass.",
            milestone06Impact: "Not a canonical cutover blocker because the active repository retains prompt/template assets; M06 must not omit or replace those assets."
        },
        ...(workOverviewSupported ? [] : [{
                id: "canonical-work-overview-inventory-support",
                classification: "cutover-blocker",
                affectedCommands: [
                    "day-shift planning inventory",
                    "day-shift validation smoke"
                ],
                affectedPaths: generatedWorkOverviewPaths,
                evidence: {
                    findingCode: "unsupported-artifact-type",
                    artifactType: "work_overview",
                    generatedWorkOverviewCount: generatedWorkOverviewPaths.length,
                    representativePath: generatedWorkOverviewPaths[0] ?? null
                },
                rehearsalDisposition: "Accepted as discovered rehearsal evidence only; structural verification proves canonical/non-actionable placement but does not make inventory support release-ready.",
                milestone06Impact: "Blocks M06 canonical apply until planning inventory and dependent validation surfaces admit canonical work_overview artifacts."
            }]),
        ...(linkLifecycleReconciled ? [] : [{
                id: "migrated-link-lifecycle-reconciliation",
                classification: "cutover-blocker",
                affectedCommands: [
                    "day-shift validation links-check --scope planning",
                    "day-shift validation smoke --scope planning",
                    "post-migration structural verification"
                ],
                affectedPaths: linkGapEvidence.representativePaths,
                evidence: {
                    findingCount: linkGapEvidence.findingCount,
                    blockingFindingCount: linkGapEvidence.blockingFindingCount,
                    advisoryFindingCount: linkGapEvidence.advisoryFindingCount,
                    findingCountsByCode: linkGapEvidence.findingCountsByCode,
                    canonicalButAmbiguousWorkUnitCount: structuralVerification.findings.length,
                    canonicalButAmbiguousWorkUnitIds: structuralVerification.workUnits
                        .filter((unit) => unit.alreadyCanonical && unit.ambiguityReasons.length > 0)
                        .map((unit) => unit.workUnitId)
                        .sort()
                },
                rehearsalDisposition: "Retired-target advisories remain explicit migration evidence; missing-field, missing-target, and out-of-hierarchy errors are not silently accepted as release-ready.",
                milestone06Impact: "Blocks M06 canonical apply until blocking trace-link findings and canonical-but-ambiguous lifecycle units are repaired or explicitly dispositioned by the owning product-alignment work."
            }])
    ];
    checkpoint("after-validation");
    const allPathsIsolated = (0, validation_1.applicationPathsAreIsolated)(applied);
    const validationAccepted = validationReceipts.every((receipt) => receipt.accepted);
    const verdict = (activeNumericRootPaths.length === 0
        && duplicateTaskIdentities.length === 0
        && preservation.verdict === "accepted"
        && structuralVerificationAccepted
        && allPathsIsolated
        && validationAccepted
        && canonicalGuards.every((guard) => guard.matchedInitial)) ? "accepted" : "blocked";
    const blockingGapIds = explicitGaps
        .filter((gap) => gap.classification === "cutover-blocker")
        .map((gap) => gap.id);
    const readyForMilestone06Apply = verdict === "accepted"
        && blockingGapIds.length === 0;
    const reportWithoutDigest = {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        kind: "day-shift-phase-07-repository-migration-rehearsal",
        verdict,
        generatedAt,
        targetPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT,
        source: {
            manifestDigest: resetBuild.sourceManifest.aggregateDigest,
            entryCount: resetBuild.sourceManifest.entryCount,
            totalBytes: resetBuild.sourceManifest.totalBytes,
            deterministicBuildDigest: resetBuild.deterministicDigest,
            doubleBuildMatched
        },
        mapping: {
            path: contracts_1.REPOSITORY_MIGRATION_MAPPING_PATH,
            digest: mapping.mappingDigest,
            inventoryDigest: resetBuild.mappingInventory.aggregateDigest,
            selectionCount: mapping.selections.length
        },
        migrationBuildIdentity: resetBuild.volatile.migrationBuildIdentity,
        plan: {
            id: retryPlan.planId,
            digest: retryPlan.planDigest,
            status: retryPlan.status,
            findingCount: retryPlan.findings.length,
            expectedConditionCount: retryPlan.expected.length,
            affectedPathCount: retryPlan.affectedPaths.length
        },
        invalidAttempt,
        interruption: {
            outcome: interrupted.outcome,
            changedPathCount: interrupted.changedPaths.length,
            recoveryPath: interrupted.recoveryPath,
            recoveryFingerprint: interrupted.recoveryFingerprint,
            retainedBeforeReset
        },
        reset: {
            sourceManifestDigest: resetBuild.sourceManifest.aggregateDigest,
            deterministicBuildDigest: resetBuild.deterministicDigest,
            matchedInitialBuild: resetMatched
        },
        apply: {
            outcome: applied.outcome,
            transactionId: applied.transactionId,
            migrationRecordPath: applied.migrationRecordPath,
            changedPathCount: applied.changedPaths.length,
            retiredPathCount: applied.retiredPaths.length,
            allPathsIsolated
        },
        migrated: {
            manifestDigest: migratedManifest.aggregateDigest,
            entryCount: migratedManifest.entryCount,
            activeNumericRootPaths,
            duplicateTaskIdentities,
            structuralVerificationStatus: structuralVerificationAccepted
                ? structuralVerification.findings.length === 0
                    ? "accepted"
                    : "accepted-with-explicit-legacy-gaps"
                : "blocked",
            structuralFindingCount: structuralVerification.findings.length
        },
        preservation,
        validationReceipts,
        explicitGaps,
        cutoverDisposition: {
            readyForMilestone06Apply,
            blockingGapIds,
            nextAction: readyForMilestone06Apply
                ? "Verify this exact report just in time, then apply the canonical migration only through the report-digest-guarded Milestone 06 cutover."
                : "Resolve or explicitly disposition every cutover blocker, then rebuild/run/verify a just-in-time rehearsal before M06 canonical apply."
        },
        canonicalGuards,
        authorization: {
            sourceManifestDigest: resetBuild.sourceManifest.aggregateDigest,
            mappingDigest: mapping.mappingDigest,
            migrationBuildIdentity: resetBuild.volatile.migrationBuildIdentity,
            planDigest: retryPlan.planDigest,
            migratedManifestDigest: migratedManifest.aggregateDigest
        },
        stalePolicy: {
            milestone06RequiresJustInTimeRehearsal: true,
            invalidatedBy: [
                "canonical planning manifest drift",
                "mapping digest drift",
                "migration build identity drift",
                "expected plan authorization drift",
                "migrated manifest or report digest drift"
            ]
        }
    };
    const report = {
        ...reportWithoutDigest,
        reportDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)(reportWithoutDigest))
    };
    (0, validation_1.writeTrackedJsonSync)(repositoryRoot, contracts_1.REPOSITORY_MIGRATION_REHEARSAL_REPORT_PATH, report);
    checkpoint("after-report");
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        operation: "run",
        verdict,
        mappingPath: contracts_1.REPOSITORY_MIGRATION_MAPPING_PATH,
        reportPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_REPORT_PATH,
        report
    };
}
function verifyRepositoryMigrationRehearsalSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const reportPath = node_path_1.default.join(repositoryRoot, ...contracts_1.REPOSITORY_MIGRATION_REHEARSAL_REPORT_PATH.split("/"));
    const reasons = [];
    let report = null;
    let mapping = null;
    let sourceManifest = null;
    let currentGuard = null;
    let currentBuildIdentity = null;
    let reportDigest = null;
    try {
        (0, filesystem_1.requireFile)(reportPath, "Phase 07 migration rehearsal report");
        (0, filesystem_1.rejectSymlinkPath)(repositoryRoot, reportPath, "Phase 07 migration rehearsal report");
        report = JSON.parse(node_fs_1.default.readFileSync(reportPath, "utf8"));
        (0, validation_1.validateReportDocument)(report);
        reportDigest = report.reportDigest;
    }
    catch (error) {
        return {
            protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
            operation: "verify",
            verdict: "blocked",
            noWrite: true,
            reasons: [
                error instanceof Error ? error.message : "Rehearsal report could not be read."
            ],
            reportDigest,
            current: {
                sourceManifestDigest: null,
                mappingDigest: null,
                migrationBuildIdentity: null,
                canonicalGuardDigest: null
            },
            nextAction: "Run a fresh isolated rehearsal; do not use this report for Milestone 06."
        };
    }
    try {
        sourceManifest = (0, preservation_1.createRepositoryPlanningManifestSync)(repositoryRoot);
        const inventory = (0, preservation_1.createRepositoryMigrationMappingInventorySync)(repositoryRoot);
        mapping = (0, mapping_1.readRepositoryMigrationMappingDocumentSync)(repositoryRoot, {
            sourceManifest,
            mappingInventory: inventory
        });
    }
    catch (error) {
        reasons.push(error instanceof Error ? error.message : "Current mapping evidence is invalid.");
    }
    currentGuard = (0, preservation_1.computeRepositoryMigrationCanonicalGuardSync)(repositoryRoot);
    currentBuildIdentity = (0, filesystem_1.readVolatileEvidence)(repositoryRoot).migrationBuildIdentity;
    if (report.verdict !== "accepted")
        reasons.push("Recorded rehearsal verdict is not accepted.");
    if (!report.cutoverDisposition.readyForMilestone06Apply) {
        reasons.push("Recorded rehearsal is not authorized for Milestone 06 canonical apply.");
    }
    if (sourceManifest !== null
        && sourceManifest.aggregateDigest !== report.authorization.sourceManifestDigest) {
        reasons.push("Canonical source manifest drifted after rehearsal acceptance.");
    }
    if (mapping !== null && mapping.mappingDigest !== report.authorization.mappingDigest) {
        reasons.push("Tracked mapping digest drifted after rehearsal acceptance.");
    }
    if (currentBuildIdentity !== report.authorization.migrationBuildIdentity) {
        reasons.push("Migration build identity drifted after rehearsal acceptance.");
    }
    const initialGuard = report.canonicalGuards[0]?.aggregateDigest;
    if (currentGuard.aggregateDigest !== initialGuard) {
        reasons.push("Canonical planning/specification/configuration guard drifted.");
    }
    const targetRoot = node_path_1.default.join(repositoryRoot, ...contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT.split("/"));
    try {
        const marker = (0, preservation_1.readRepositoryMigrationRehearsalMarkerSync)(repositoryRoot);
        if (marker.disposable !== true)
            reasons.push("Rehearsal ownership marker is not disposable.");
        const migratedManifest = (0, preservation_1.createRepositoryPlanningManifestSync)(targetRoot);
        if (migratedManifest.aggregateDigest !== report.authorization.migratedManifestDigest) {
            reasons.push("Migrated isolated manifest drifted after rehearsal acceptance.");
        }
    }
    catch (error) {
        reasons.push(error instanceof Error ? error.message : "Isolated rehearsal state is unavailable.");
    }
    const verdict = reasons.length === 0 ? "accepted" : "stale";
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        operation: "verify",
        verdict,
        noWrite: true,
        reasons,
        reportDigest,
        current: {
            sourceManifestDigest: sourceManifest?.aggregateDigest ?? null,
            mappingDigest: mapping?.mappingDigest ?? null,
            migrationBuildIdentity: currentBuildIdentity,
            canonicalGuardDigest: currentGuard.aggregateDigest
        },
        nextAction: verdict === "accepted"
            ? "Authorization is current, but Milestone 06 must still run a just-in-time rehearsal immediately before canonical apply."
            : "Rebuild, rerun, and verify the isolated rehearsal just in time before any Milestone 06 apply."
    };
}
