"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.rebindRepositoryMigrationLifecycleRevisionsSync = rebindRepositoryMigrationLifecycleRevisionsSync;
exports.remapRepositoryMigrationValidationBaselineSync = remapRepositoryMigrationValidationBaselineSync;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const mutation_preconditions_1 = require("../../filesystem/mutation-preconditions");
const repository_transaction_1 = require("../../filesystem/repository-transaction");
const canonical_write_target_1 = require("../../paths/canonical-write-target");
const planning_document_utils_1 = require("../planning-document-utils");
const task_lifecycle_1 = require("../task-lifecycle");
const baseline_remap_1 = require("./baseline-remap");
const contracts_1 = require("./contracts");
const filesystem_1 = require("./filesystem");
const validation_1 = require("./validation");
function rebindRepositoryMigrationLifecycleRevisionsSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const expectedReportDigest = (0, validation_1.requireCutoverDigest)(options.expectedReportDigest);
    if (!/^\.day-shift\/state\/migrations\/workspace-structure-[a-f0-9]{16}\.json$/.test(options.migrationRecordPath)
        || !/^migration-[a-f0-9]{36}$/.test(options.expectedTransactionId)) {
        throw new contracts_1.RepositoryMigrationRehearsalError("invalid-cutover-request", "Lifecycle revision rebinding requires the exact canonical migration record path and transaction identity.");
    }
    (0, validation_1.rejectLiveRepositoryWriteLock)(repositoryRoot);
    const sourceRecordTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, options.migrationRecordPath);
    if (!sourceRecordTarget.exists || !node_fs_1.default.statSync(sourceRecordTarget.runtimePath).isFile()) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Canonical migration record '${options.migrationRecordPath}' is unavailable.`);
    }
    let sourceRecord;
    try {
        sourceRecord = JSON.parse(node_fs_1.default.readFileSync(sourceRecordTarget.runtimePath, "utf8"));
    }
    catch {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Canonical migration record '${options.migrationRecordPath}' is not valid JSON.`);
    }
    if (sourceRecord.schemaVersion !== 1
        || sourceRecord.migrationKind !== "workspace-structure"
        || sourceRecord.transactionId !== options.expectedTransactionId
        || !Array.isArray(sourceRecord.pathMappings)) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", "Canonical migration record identity or path-mapping evidence does not match the committed cutover.");
    }
    const report = (0, validation_1.readRepositoryMigrationRehearsalReportSync)(repositoryRoot);
    if (report.reportDigest !== expectedReportDigest
        || sourceRecord.planDigest !== report.authorization.planDigest) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", "Lifecycle revision rebinding requires the exact accepted cutover report and plan recorded by the durable path authority.");
    }
    const changes = [];
    const reviewResultsById = (0, validation_1.readLocalReadinessReviewEvidence)(repositoryRoot);
    for (const entry of sourceRecord.pathMappings) {
        if (typeof entry !== "object"
            || entry === null
            || !("role" in entry)
            || !("sourcePath" in entry)
            || !("destinationPath" in entry)
            || entry.role !== "task-definition"
            || typeof entry.sourcePath !== "string"
            || typeof entry.destinationPath !== "string") {
            continue;
        }
        if (!/^\.day-shift\/planning\/(?:basic|structured|governed)\//.test(entry.destinationPath)
            || !entry.destinationPath.endsWith("/task-definition.md")) {
            throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Migration task destination '${entry.destinationPath}' is outside canonical planning roots.`);
        }
        const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, entry.destinationPath);
        if (!target.exists || !node_fs_1.default.statSync(target.runtimePath).isFile()) {
            throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", `Mapped canonical task '${entry.destinationPath}' is missing.`);
        }
        const currentText = node_fs_1.default.readFileSync(target.runtimePath, "utf8");
        const parsed = (0, planning_document_utils_1.parseMarkdownFrontMatter)(currentText);
        const readinessReviewId = (0, planning_document_utils_1.readTopLevelField)(parsed.frontMatterLines, "readiness_review_id") ?? null;
        const authorizationEnvelope = parsed.frontMatterLines.filter((line) => /^readiness_(?:review_id|review_revision|review_protocol_version|reviewed_by|reviewed_at):/.test(line));
        const rebound = (0, task_lifecycle_1.rebindTaskReadinessAuthorizationRevision)(currentText);
        if (rebound.changed
            && rebound.previousRevision !== null
            && rebound.revision !== null
            && readinessReviewId !== null) {
            const summaryTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, entry.destinationPath.replace(/\/task-definition\.md$/, "/implementation-summary.md"));
            const dependentAttemptReadinessReviewIds = summaryTarget.exists && node_fs_1.default.statSync(summaryTarget.runtimePath).isFile()
                ? [...node_fs_1.default.readFileSync(summaryTarget.runtimePath, "utf8").matchAll(/^\s+readiness_review_id:\s*["']?([^"'\s]+)["']?\s*$/gm)].map((match) => match[1])
                : [];
            const reviewResult = reviewResultsById.get(readinessReviewId) ?? null;
            changes.push({
                path: entry.destinationPath,
                sourcePath: entry.sourcePath,
                contents: rebound.text,
                previousRevision: rebound.previousRevision,
                revision: rebound.revision,
                previousTaskContentDigest: (0, filesystem_1.sha256)(currentText),
                reboundTaskContentDigest: (0, filesystem_1.sha256)(rebound.text),
                readinessReviewId,
                authorizationEnvelope,
                authorizationEnvelopeDigest: (0, filesystem_1.sha256)(Buffer.from(authorizationEnvelope.join("\n"), "utf8")),
                dependentAttemptReadinessReviewIds,
                reviewResultPath: reviewResult?.path ?? null,
                reviewResultDigest: reviewResult?.digest ?? null
            });
        }
    }
    const evidence = changes.map(({ path: taskPath, sourcePath, previousRevision, revision, previousTaskContentDigest, reboundTaskContentDigest, readinessReviewId, authorizationEnvelope, authorizationEnvelopeDigest, dependentAttemptReadinessReviewIds, reviewResultPath, reviewResultDigest }) => ({
        sourcePath,
        taskPath,
        pathMappingAuthority: options.migrationRecordPath,
        readinessReviewId,
        previousRevision,
        revision,
        previousTaskContentDigest,
        reboundTaskContentDigest,
        authorizationEnvelope,
        authorizationEnvelopeDigest,
        dependentAttemptReadinessReviewIds,
        reviewResultPath,
        reviewResultDigest,
        changedField: "readiness_review_revision",
        freshReadinessReviewClaimed: false
    })).sort((left, right) => left.taskPath.localeCompare(right.taskPath));
    const evidenceDigest = (0, filesystem_1.sha256)((0, filesystem_1.stableJson)({
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        sourceReportDigest: expectedReportDigest,
        sourcePlanDigest: sourceRecord.planDigest,
        evidence
    }));
    const durableRebindRecordPath = `.day-shift/state/migrations/workspace-structure-lifecycle-rebind-${evidenceDigest.slice("sha256:".length, "sha256:".length + 16)}.json`;
    const transactionId = `migration-${(0, node_crypto_1.randomBytes)(18).toString("hex")}`;
    const appliedAt = (0, validation_1.normalizeIsoTimestamp)(options.appliedAt ?? new Date().toISOString());
    const recordContents = `${JSON.stringify({
        schemaVersion: 1,
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        migrationKind: "workspace-structure-lifecycle-rebind",
        transactionState: "authorized",
        transactionId,
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        sourceReportDigest: expectedReportDigest,
        sourcePlanDigest: sourceRecord.planDigest,
        actor: options.actor ?? "phase-07-milestone-06-lifecycle-rebind",
        reason: options.reason
            ?? "Rebind readiness review revisions to the exact canonical task bytes produced by the committed structural cutover.",
        transformation: {
            kind: "canonical-coordinate-readiness-revision-rebind",
            allowedChangedField: "readiness_review_revision",
            reviewIdentityPreserved: true,
            reviewResultBytesPreserved: true,
            freshReadinessReviewClaimed: false,
            explanation: "The structural migration rewrote only approved canonical coordinates, relationships, specification refs, and workflow metadata before this revision pointer was rebound to those exact canonical task bytes."
        },
        appliedAt,
        changedTaskPaths: evidence.map((entry) => entry.taskPath),
        evidence,
        evidenceDigest
    }, null, 2)}\n`;
    const rebindRecordTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, durableRebindRecordPath);
    const taskTargets = changes.map((change) => ({
        change,
        target: (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, change.path)
    }));
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(repositoryRoot, {
        transactionId,
        transactionKind: "migration",
        durableRecordPath: durableRebindRecordPath,
        writes: [
            ...taskTargets.map(({ change }) => ({
                path: change.path,
                contents: change.contents
            })),
            {
                path: durableRebindRecordPath,
                contents: recordContents
            }
        ],
        preconditions: [
            (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(sourceRecordTarget),
            ...taskTargets.flatMap(({ target }) => [
                (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target),
                (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target)
            ]),
            (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(rebindRecordTarget)
        ]
    }, options.transaction);
    const recoveryPath = transaction.outcome === "incomplete"
        || transaction.cleanupErrors.length > 0
        ? transaction.transactionPath
        : null;
    const committed = transaction.outcome === "committed";
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        operation: "rebind-lifecycle-revisions",
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        durableRebindRecordPath,
        outcome: transaction.outcome,
        committed,
        transactionId: transaction.transactionId,
        changedTaskPaths: evidence.map((entry) => entry.taskPath),
        changedPathCount: transaction.canonicalWrites,
        conflicts: transaction.conflicts,
        recoveryPath,
        cleanupErrors: transaction.cleanupErrors,
        failure: transaction.failure,
        nextAction: committed
            ? "Rerun canonical task lifecycle validation from durable mapped paths."
            : "Stop ordinary planning writes and inspect the retained lifecycle-rebind transaction evidence."
    };
}
/**
 * Rebind an existing forward-only planning validation baseline to the exact
 * canonical coordinates recorded by a committed workspace migration.
 *
 * This preserves the historical observation timestamp and semantic finding
 * fields. It changes only path-bearing text and the fingerprints derived from
 * that text, and records the old/new evidence in the same expected-revision
 * transaction as the baseline write.
 */
function remapRepositoryMigrationValidationBaselineSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const expectedReportDigest = (0, validation_1.requireCutoverDigest)(options.expectedReportDigest);
    if (!/^\.day-shift\/state\/migrations\/workspace-structure-[a-f0-9]{16}\.json$/.test(options.migrationRecordPath)
        || !/^migration-[a-f0-9]{36}$/.test(options.expectedTransactionId)) {
        throw new contracts_1.RepositoryMigrationRehearsalError("invalid-cutover-request", "Validation baseline remapping requires the exact canonical migration record path and transaction identity.");
    }
    (0, validation_1.rejectLiveRepositoryWriteLock)(repositoryRoot);
    const sourceRecordTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, options.migrationRecordPath);
    if (!sourceRecordTarget.exists || !node_fs_1.default.statSync(sourceRecordTarget.runtimePath).isFile()) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Canonical migration record '${options.migrationRecordPath}' is unavailable.`);
    }
    let sourceRecord;
    try {
        sourceRecord = JSON.parse(node_fs_1.default.readFileSync(sourceRecordTarget.runtimePath, "utf8"));
    }
    catch {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Canonical migration record '${options.migrationRecordPath}' is not valid JSON.`);
    }
    if (sourceRecord.schemaVersion !== 1
        || sourceRecord.migrationKind !== "workspace-structure"
        || sourceRecord.transactionId !== options.expectedTransactionId
        || typeof sourceRecord.planDigest !== "string"
        || !Array.isArray(sourceRecord.pathMappings)) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", "Canonical migration record identity or path-mapping evidence does not match the committed cutover.");
    }
    const report = (0, validation_1.readRepositoryMigrationRehearsalReportSync)(repositoryRoot);
    if (report.reportDigest !== expectedReportDigest
        || sourceRecord.planDigest !== report.authorization.planDigest) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", "Validation baseline remapping requires the exact accepted cutover report and plan recorded by the durable path authority.");
    }
    const pathMappings = (0, baseline_remap_1.readBaselinePathMappings)(sourceRecord.pathMappings);
    const baselinePath = ".day-shift/state/planning-validation-baseline.json";
    const baselineTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, baselinePath);
    if (!baselineTarget.exists || !node_fs_1.default.statSync(baselineTarget.runtimePath).isFile()) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-blocked", `Forward-only planning validation baseline '${baselinePath}' is unavailable.`);
    }
    const previousBaselineText = node_fs_1.default.readFileSync(baselineTarget.runtimePath, "utf8");
    const previousBaseline = (0, baseline_remap_1.readPlanningValidationBaselineForRemap)(previousBaselineText);
    const remapped = (0, baseline_remap_1.remapPlanningValidationBaseline)(previousBaseline, pathMappings);
    if (remapped.evidence.length === 0) {
        throw new contracts_1.RepositoryMigrationRehearsalError("cutover-stale", "Forward-only planning validation baseline contains no numbered planning coordinates to remap.");
    }
    const baselineContents = `${JSON.stringify(remapped.baseline, null, 2)}\n`;
    const evidenceDigest = (0, filesystem_1.sha256)((0, filesystem_1.stableJson)({
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        sourceReportDigest: expectedReportDigest,
        sourcePlanDigest: sourceRecord.planDigest,
        sourceMappingDigest: report.authorization.mappingDigest,
        previousBaselineDigest: (0, filesystem_1.sha256)(previousBaselineText),
        remappedBaselineDigest: (0, filesystem_1.sha256)(baselineContents),
        evidence: remapped.evidence
    }));
    const durableRemapRecordPath = `.day-shift/state/migrations/planning-validation-baseline-remap-${evidenceDigest.slice("sha256:".length, "sha256:".length + 16)}.json`;
    const transactionId = `migration-${(0, node_crypto_1.randomBytes)(18).toString("hex")}`;
    const appliedAt = (0, validation_1.normalizeIsoTimestamp)(options.appliedAt ?? new Date().toISOString());
    const recordContents = `${JSON.stringify({
        schemaVersion: 1,
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        migrationKind: "planning-validation-baseline-remap",
        transactionState: "authorized",
        transactionId,
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        sourceReportPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_REPORT_PATH,
        sourceReportDigest: expectedReportDigest,
        sourcePlanDigest: sourceRecord.planDigest,
        sourceMappingDigest: report.authorization.mappingDigest,
        baselinePath,
        previousBaselineDigest: (0, filesystem_1.sha256)(previousBaselineText),
        remappedBaselineDigest: (0, filesystem_1.sha256)(baselineContents),
        actor: options.actor ?? "phase-07-milestone-06-baseline-remap",
        reason: options.reason
            ?? "Rebind the existing forward-only planning validation baseline to exact canonical coordinates after the committed structural cutover.",
        transformation: {
            kind: "durable-path-mapping-baseline-rebind",
            preservedCreatedAt: previousBaseline.created_at,
            semanticFieldsPreserved: ["schema_version", "created_at", "scope", "mode", "notes", "code", "severity"],
            allowedChangedFields: ["path", "message", "fingerprint"],
            provenanceMetadataChanged: false,
            provenanceFabricated: false,
            explanation: "Only planning coordinates and their deterministic fingerprints were rewritten through the committed durable path authority; historical observations and provenance claims were not changed or created."
        },
        appliedAt,
        remappedEntryCount: remapped.evidence.length,
        evidence: remapped.evidence,
        evidenceDigest
    }, null, 2)}\n`;
    const remapRecordTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, durableRemapRecordPath);
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(repositoryRoot, {
        transactionId,
        transactionKind: "migration",
        durableRecordPath: durableRemapRecordPath,
        writes: [
            {
                path: baselinePath,
                contents: baselineContents
            },
            {
                path: durableRemapRecordPath,
                contents: recordContents
            }
        ],
        preconditions: [
            (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(sourceRecordTarget),
            (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(baselineTarget),
            (0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(baselineTarget),
            (0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(remapRecordTarget)
        ]
    }, options.transaction);
    const recoveryPath = transaction.outcome === "incomplete"
        || transaction.cleanupErrors.length > 0
        ? transaction.transactionPath
        : null;
    const committed = transaction.outcome === "committed";
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        operation: "remap-validation-baseline",
        sourceMigrationRecordPath: options.migrationRecordPath,
        sourceTransactionId: options.expectedTransactionId,
        baselinePath,
        durableRemapRecordPath,
        outcome: transaction.outcome,
        committed,
        transactionId: transaction.transactionId,
        remappedEntryCount: remapped.evidence.length,
        changedPathCount: transaction.canonicalWrites,
        conflicts: transaction.conflicts,
        recoveryPath,
        cleanupErrors: transaction.cleanupErrors,
        failure: transaction.failure,
        nextAction: committed
            ? "Rerun read-only canonical planning validation smoke against the remapped forward-only baseline."
            : "Stop ordinary planning writes and inspect the retained baseline-remap transaction evidence."
    };
}
