"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTaskPromoteCommand = createTaskPromoteCommand;
exports.renderPromotionPlanText = renderPromotionPlanText;
exports.normalizePromotionError = normalizePromotionError;
exports.normalizeOperationalRecoveryError = normalizeOperationalRecoveryError;
exports.promotionApplicationRecoveryActions = promotionApplicationRecoveryActions;
exports.createPromotionRecoveryOutcomeError = createPromotionRecoveryOutcomeError;
exports.publicPromotionRecoveryResult = publicPromotionRecoveryResult;
exports.renderPromotionRecoveryText = renderPromotionRecoveryText;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const operational_recovery_1 = require("../../../lib/filesystem/operational-recovery");
const operational_state_1 = require("../../../lib/filesystem/operational-state");
const promotion_application_1 = require("../../../lib/planning/promotion-application");
const promotion_planning_1 = require("../../../lib/planning/promotion-planning");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
async function createTaskPromoteCommand() {
    const { Command } = await import("commander");
    const command = new Command("promote");
    command
        .description("Preview/apply a Basic promotion, or explicitly recover exact promotion evidence.")
        .option("--task-definition <path>", "Canonical repository-relative Basic task-definition.md path.")
        .option("--to <level>", "Explicit promotion target: structured or governed.")
        .option("--work-id <id>", "Lowercase kebab-case destination work identity.")
        .option("--spec <path>", "Canonical planning-ready specification path; repeat as needed.", collect, [])
        .option("--implementation-order <order>", "Two-digit Structured root or Governed slice implementation order; Structured also accepts next.")
        .option("--slice-id <id>", "Optional explicit Governed '<ordered-prefix>-<slice-slug>' identity.")
        .option("--slice <slug>", "Canonical lowercase kebab-case Governed slice slug.")
        .option("--phase <slug>", "Ordered Governed destination phase slug.")
        .option("--milestone <slug>", "Ordered Governed destination milestone slug.")
        .option("--dry-run", "Explicit no-write promotion preview.")
        .option("--apply", "Transactionally apply the exact preview identified by --plan-id.")
        .option("--plan-id <id>", "Exact promotion plan id required by --apply.")
        .option("--actor <identity>", "Non-empty audit actor required by --apply or --recover.")
        .option("--reason <text>", "Non-empty audit reason required by --apply or --recover.")
        .option("--applied-at <timestamp>", "Optional apply-only ISO-8601 application time.")
        .option("--recover <action>", "Explicit exact-evidence recovery: roll-forward or restore.")
        .option("--transaction-id <id>", "Exact retained promotion transaction id required by --recover.")
        .option("--evidence-fingerprint <sha256>", "Exact current read-only inspection fingerprint required by --recover.")
        .option("--recovered-at <timestamp>", "Optional recovery-only ISO-8601 recovery time.")
        .action((_, commandInstance) => {
        const format = (0, output_1.resolveOutputFormat)((0, global_format_1.getGlobalFormat)(commandInstance));
        if (format === null) {
            throw (0, errors_1.createUsageError)("Output format must be one of: text, json.");
        }
        const repository = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
        const options = commandInstance.opts();
        if (hasRecoveryInput(options)) {
            const proof = requireRecoveryProof(options);
            let recovery;
            try {
                recovery = (0, operational_recovery_1.recoverOperationalTransactionSync)(repository.root, proof);
            }
            catch (error) {
                throw normalizeOperationalRecoveryError(error);
            }
            if (recovery.outcome !== "recovered") {
                throw createPromotionRecoveryOutcomeError("task promote", repository.root, proof, recovery);
            }
            (0, output_1.emitSuccess)({
                command: "task promote",
                format,
                text: renderPromotionRecoveryText(recovery),
                data: {
                    detectionSource: repository.detectionSource,
                    recoveryRequested: true,
                    recovery: publicPromotionRecoveryResult(recovery)
                }
            });
            return;
        }
        const taskDefinition = requirePlanningOption(options.taskDefinition, "--task-definition");
        const targetLevel = requireTaskTarget(requirePlanningOption(options.to, "--to"));
        if (targetLevel === "governed" && options.workId !== undefined) {
            throw (0, errors_1.createUsageError)("--work-id applies only to Structured destinations; Governed promotion uses --implementation-order, --slice, and optional --slice-id.", [promotionNoWriteBoundary()]);
        }
        const workId = targetLevel === "structured"
            ? requirePlanningOption(options.workId, "--work-id")
            : undefined;
        validateApplicationOptions(options);
        const governed = targetLevel === "governed"
            ? (() => {
                const milestone = requireOption(options.milestone, "--milestone");
                const taskId = basicTaskIdFromDefinitionPath(taskDefinition);
                return {
                    sliceSlug: requireOption(options.slice, "--slice"),
                    implementationOrders: [
                        requireOption(options.implementationOrder, "--implementation-order")
                    ],
                    requestedSliceId: optionalText(options.sliceId),
                    phaseSlug: requireOption(options.phase, "--phase"),
                    milestoneSlugs: [milestone],
                    taskToMilestone: { [taskId]: milestone }
                };
            })()
            : undefined;
        let plan;
        let application = null;
        try {
            if (options.apply === true) {
                const preview = (0, promotion_application_1.previewBasicPromotionSync)({
                    repositoryRoot: repository.root,
                    targetLevel,
                    sourceTaskDefinitionPath: taskDefinition,
                    specificationPaths: options.spec,
                    destinationWorkId: workId,
                    implementationOrder: targetLevel === "structured"
                        ? options.implementationOrder ?? "next"
                        : undefined,
                    governed
                });
                application = (0, promotion_application_1.applyBasicPromotionSync)(preview, {
                    planId: requireApplyOption(options.planId, "--plan-id"),
                    actor: requireApplyOption(options.actor, "--actor"),
                    reason: requireApplyOption(options.reason, "--reason"),
                    appliedAt: options.appliedAt
                });
                plan = application.plan;
            }
            else {
                plan = (0, promotion_planning_1.planPromotionSync)({
                    repositoryRoot: repository.root,
                    sourceLevel: "basic",
                    targetLevel,
                    sourceTaskDefinitionPath: taskDefinition,
                    specificationPaths: options.spec,
                    destinationWorkId: workId,
                    implementationOrder: targetLevel === "structured"
                        ? options.implementationOrder ?? "next"
                        : undefined,
                    governed
                });
            }
        }
        catch (error) {
            throw normalizePromotionError(error);
        }
        if (application !== null &&
            (application.writeOutcome !== "committed" ||
                application.cleanupErrors.length > 0)) {
            throw createPromotionApplicationOutcomeError(application, repository.root);
        }
        (0, output_1.emitSuccess)({
            command: "task promote",
            format,
            text: application === null
                ? renderPromotionPlanText(plan)
                : renderPromotionApplicationText(application),
            data: {
                detectionSource: repository.detectionSource,
                requestedDryRun: options.dryRun === true,
                applyRequested: options.apply === true,
                recoveryRequested: false,
                noWriteBoundary: application === null ? promotionNoWriteBoundary() : null,
                ...plan,
                ...(application === null ? {} : { application: publicApplicationResult(application) })
            }
        });
    });
    return command;
}
function renderPromotionPlanText(plan) {
    return [
        "Promotion plan (read-only)",
        "",
        `Plan id: ${plan.planId}`,
        `Source level: ${plan.sourceLevel}`,
        `Target level: ${plan.targetLevel}`,
        `Target task-summary boundary: ${plan.targetTopology.taskSummaryReviewBoundary}`,
        `Target reconciliation artifact: ${plan.targetTopology.reconciliationArtifactKind ?? "none"}`,
        `Target reconciliation required: ${plan.targetTopology.reconciliationRequired ? "yes" : "no"}`,
        `Target organization parents: ${renderList(plan.targetTopology.organizationParents)}`,
        `Target project-review capability: ${plan.targetTopology.projectReviewCapability}`,
        `Source work id: ${plan.sourceWorkId ?? "none"}`,
        ...(plan.destinationWorkId === undefined
            ? []
            : [`Destination work id: ${plan.destinationWorkId}`]),
        ...(plan.destinationImplementationOrder === undefined
            ? []
            : [
                `Destination implementation order: ${plan.destinationImplementationOrder}`,
                `Destination order source: ${plan.destinationImplementationOrderSource}`,
                `Root inventory fingerprint: ${plan.rootInventoryFingerprint}`
            ]),
        ...(plan.destinationSliceId === undefined
            ? []
            : [`Destination slice id: ${plan.destinationSliceId}`]),
        `Promotion record: ${plan.promotionRecord.path}`,
        `Source root: ${plan.sourceRootPath}`,
        `Destination root: ${plan.destinationRootPath}`,
        `Specifications: ${renderList(plan.specifications.map((entry) => `${entry.specId}:${entry.specPath}:${entry.revision}:${entry.readiness}`))}`,
        `Required parents: ${renderList(plan.requiredParents.map((entry) => `${entry.kind}:${entry.path}`))}`,
        `Task mappings: ${renderList(plan.taskMappings.map((entry) => `${entry.taskId}:${entry.sourceTaskDefinitionPath}->${entry.destinationTaskDefinitionPath}`))}`,
        `Expected conditions: ${renderList(plan.expected.map((entry) => `${entry.path}:${entry.kind}:${entry.expectedState}`))}`,
        `Metadata changes: ${renderList(plan.metadataChanges.map((entry) => `${entry.path}:${entry.field}:${entry.before ?? "none"}->${entry.after}`))}`,
        `Collisions: ${renderList(plan.collisions)}`,
        `Ambiguities: ${renderList(plan.ambiguities)}`,
        `Affected paths: ${renderList(plan.affectedPaths.map((entry) => `${entry.role}:${entry.path}`))}`,
        `Preservation: ${JSON.stringify(plan.preservation)}`,
        "Read-only: yes",
        `No-write boundary: ${promotionNoWriteBoundary()}`,
        `Next action: ${plan.nextAction}`,
        `Recovery guidance: ${plan.recoveryGuidance}`
    ].join("\n");
}
function normalizePromotionError(error) {
    if (error instanceof errors_1.RuntimeError)
        return error;
    if (error instanceof promotion_application_1.BasicPromotionApplicationError) {
        const stale = error.code === "stale-preview" || error.code === "plan-mismatch";
        return new errors_1.RuntimeError({
            code: `PROMOTION_APPLICATION_${error.code.replace(/-/g, "_").toUpperCase()}`,
            exitCode: stale ? errors_1.RuntimeExitCode.STALE_EVIDENCE : errors_1.RuntimeExitCode.USAGE,
            message: error.message,
            details: [
                `applicationCode: ${error.code}`,
                "No promotion transaction write was attempted.",
                "Refresh the read-only plan and explicitly apply its exact plan id."
            ],
            cause: error
        });
    }
    if (!(error instanceof promotion_planning_1.PromotionPlanningError)) {
        return error instanceof Error
            ? (0, errors_1.createUsageError)(error.message, [promotionNoWriteBoundary()])
            : (0, errors_1.createUsageError)("Invalid promotion planning input.", [promotionNoWriteBoundary()]);
    }
    return new errors_1.RuntimeError({
        code: `PROMOTION_PLANNING_${error.code.replace(/-/g, "_").toUpperCase()}`,
        exitCode: errors_1.RuntimeExitCode.USAGE,
        message: error.message,
        details: [
            `planningCode: ${error.code}`,
            `collisions: ${renderList(error.collisions)}`,
            `ambiguities: ${renderList(error.ambiguities)}`,
            `duplicateActiveLocations: ${JSON.stringify(error.duplicateActiveLocations)}`,
            `topologyFindings: ${JSON.stringify(error.topologyFindings)}`,
            `refreshPreviewRequired: ${error.refreshPreviewRequired}`,
            promotionNoWriteBoundary(),
            "Refresh source evidence and rerun the explicit no-write plan."
        ],
        cause: error
    });
}
function requireTaskTarget(value) {
    if (value === "structured" || value === "governed")
        return value;
    throw (0, errors_1.createUsageError)("--to must be one of: structured, governed.", [
        promotionNoWriteBoundary()
    ]);
}
function requirePlanningOption(value, name) {
    if (typeof value === "string" && value.trim() !== "")
        return value.trim();
    throw (0, errors_1.createUsageError)(`${name} is required for promotion planning and apply.`, [
        promotionNoWriteBoundary(),
        "Exact-evidence recovery uses --recover with transaction id, fingerprint, actor, and reason."
    ]);
}
function requireOption(value, name) {
    if (typeof value === "string" && value.trim() !== "")
        return value.trim();
    throw (0, errors_1.createUsageError)(`${name} is required when --to governed is selected.`, [
        promotionNoWriteBoundary()
    ]);
}
function requireApplyOption(value, name) {
    if (typeof value === "string" && value.trim() !== "")
        return value.trim();
    throw (0, errors_1.createUsageError)(`${name} is required when --apply is selected.`, [
        "Run the no-write preview first, then apply its exact plan id with actor and reason."
    ]);
}
function validateApplicationOptions(options) {
    if (options.apply === true && options.dryRun === true) {
        throw (0, errors_1.createUsageError)("--dry-run and --apply cannot be selected together.", [
            "Use --dry-run for a no-write preview or --apply for the explicitly authorized transaction."
        ]);
    }
    const applicationOnly = [
        ["--plan-id", options.planId],
        ["--actor", options.actor],
        ["--reason", options.reason],
        ["--applied-at", options.appliedAt]
    ];
    if (options.apply !== true) {
        const supplied = applicationOnly
            .filter(([, value]) => value !== undefined)
            .map(([name]) => name);
        if (supplied.length > 0) {
            throw (0, errors_1.createUsageError)(`${supplied.join(", ")} require --apply.`, [
                promotionNoWriteBoundary()
            ]);
        }
    }
}
function hasRecoveryInput(options) {
    return [
        options.recover,
        options.transactionId,
        options.evidenceFingerprint,
        options.recoveredAt
    ].some((value) => value !== undefined);
}
function requireRecoveryProof(options) {
    const contradictory = [
        ["--task-definition", options.taskDefinition],
        ["--to", options.to],
        ["--work-id", options.workId],
        ["--implementation-order", options.implementationOrder],
        ["--slice-id", options.sliceId],
        ["--spec", options.spec.length > 0 ? "supplied" : undefined],
        ["--slice", options.slice],
        ["--phase", options.phase],
        ["--milestone", options.milestone],
        ["--dry-run", options.dryRun],
        ["--apply", options.apply],
        ["--plan-id", options.planId],
        ["--applied-at", options.appliedAt]
    ].filter(([, value]) => value !== undefined && value !== false);
    if (contradictory.length > 0) {
        throw (0, errors_1.createUsageError)(`Recovery cannot be combined with planning/apply inputs: ${contradictory
            .map(([name]) => name).join(", ")}.`, ["No recovery or promotion write was attempted."]);
    }
    if (options.recover !== "roll-forward" && options.recover !== "restore") {
        throw (0, errors_1.createUsageError)("--recover must be one of: roll-forward, restore.", [
            "No recovery or promotion write was attempted."
        ]);
    }
    return {
        action: options.recover,
        transactionId: requireRecoveryOption(options.transactionId, "--transaction-id"),
        evidenceFingerprint: requireRecoveryOption(options.evidenceFingerprint, "--evidence-fingerprint"),
        actor: requireRecoveryOption(options.actor, "--actor"),
        reason: requireRecoveryOption(options.reason, "--reason"),
        recoveredAt: options.recoveredAt ?? new Date().toISOString()
    };
}
function basicTaskIdFromDefinitionPath(taskDefinitionPath) {
    const normalized = taskDefinitionPath.replaceAll("\\", "/");
    const match = normalized.match(/^\.day-shift\/planning\/basic\/tasks\/(?:\d{2,}-)?([^/]+)\/task-definition\.md$/);
    if (match === null) {
        throw (0, errors_1.createUsageError)("--task-definition must be a canonical .day-shift/planning/basic/tasks/<order>-<task-id>/task-definition.md path.", [promotionNoWriteBoundary()]);
    }
    return match[1];
}
function optionalText(value) {
    return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
}
function requireRecoveryOption(value, name) {
    if (typeof value === "string" && value.trim() !== "")
        return value.trim();
    throw (0, errors_1.createUsageError)(`${name} is required when exact-evidence recovery is selected.`, [
        "Recovery inputs are all-or-nothing; no write was attempted."
    ]);
}
function normalizeOperationalRecoveryError(error) {
    if (error instanceof errors_1.RuntimeError)
        return error;
    if (!(error instanceof operational_recovery_1.OperationalRecoveryRejectedError)) {
        return error instanceof Error
            ? (0, errors_1.createUsageError)(error.message, ["No recovery or promotion write was attempted."])
            : (0, errors_1.createUsageError)("Invalid promotion recovery input.", [
                "No recovery or promotion write was attempted."
            ]);
    }
    const exitCode = error.reason === "live-lock"
        ? errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT
        : error.reason === "missing-staged-evidence"
            ? errors_1.RuntimeExitCode.UNAVAILABLE_DEPENDENCY
            : error.reason === "evidence-mismatch" ||
                error.reason === "diverged-target" ||
                error.reason === "action-unavailable" ||
                error.reason === "recovery-record-conflict"
                ? errors_1.RuntimeExitCode.STALE_EVIDENCE
                : errors_1.RuntimeExitCode.USAGE;
    return new errors_1.RuntimeError({
        code: `PROMOTION_RECOVERY_${error.reason.replace(/-/g, "_").toUpperCase()}`,
        exitCode,
        message: error.message,
        details: [
            `recoveryCode: ${error.reason}`,
            "No recovery write was attempted.",
            "Inspect current sanitized operational evidence before constructing another exact recovery request."
        ],
        cause: error
    });
}
function publicApplicationResult(result) {
    return {
        planId: result.planId,
        writeOutcome: result.writeOutcome,
        transactionId: result.transactionId,
        sourcePaths: result.sourcePaths,
        destinationPaths: result.destinationPaths,
        createdParentPaths: result.createdParentPaths,
        intendedRetiredPaths: result.intendedRetiredPaths,
        intendedPaths: result.intendedPaths,
        changedPaths: result.changedPaths,
        retiredPaths: result.retiredPaths,
        conflicts: result.conflicts,
        promotionRecordPath: result.promotionRecordPath,
        recoveryPath: result.recoveryPath,
        recoveryFingerprint: result.recoveryFingerprint,
        cleanupErrors: result.cleanupErrors,
        failure: result.failure,
        actor: result.actor,
        reason: result.reason,
        appliedAt: result.appliedAt,
        nextAction: result.nextAction
    };
}
function renderPromotionApplicationText(result) {
    return [
        `Applied Basic promotion to ${result.plan.targetLevel}.`,
        "",
        `Plan id: ${result.planId}`,
        `Write outcome: ${result.writeOutcome}`,
        `Transaction id: ${result.transactionId ?? "none"}`,
        `Source paths: ${renderList(result.sourcePaths)}`,
        `Destination paths: ${renderList(result.destinationPaths)}`,
        `Created parents: ${renderList(result.createdParentPaths)}`,
        `Changed paths: ${renderList(result.changedPaths)}`,
        `Retired paths: ${renderList(result.retiredPaths)}`,
        `Promotion record: ${result.promotionRecordPath}`,
        `Actor: ${result.actor ?? "none"}`,
        `Reason: ${result.reason ?? "none"}`,
        `Applied at: ${result.appliedAt ?? "none"}`,
        `Recovery path: ${result.recoveryPath ?? "none"}`,
        `Recovery fingerprint: ${result.recoveryFingerprint ?? "none"}`,
        `Cleanup errors: ${renderList(result.cleanupErrors)}`,
        `Next action: ${result.nextAction}`
    ].join("\n");
}
function createPromotionApplicationOutcomeError(result, repositoryRoot) {
    const details = [
        `planId: ${result.planId}`,
        `targetLevel: ${result.plan.targetLevel}`,
        `writeOutcome: ${result.writeOutcome}`,
        `sourcePaths: ${JSON.stringify(result.sourcePaths)}`,
        `destinationPaths: ${JSON.stringify(result.destinationPaths)}`,
        `createdParentPaths: ${JSON.stringify(result.createdParentPaths)}`,
        `intendedRetiredPaths: ${JSON.stringify(result.intendedRetiredPaths)}`,
        `changedPaths: ${JSON.stringify(result.changedPaths)}`,
        `retiredPaths: ${JSON.stringify(result.retiredPaths)}`,
        `conflicts: ${JSON.stringify(result.conflicts)}`,
        `promotionRecordPath: ${result.promotionRecordPath}`,
        `recoveryPath: ${result.recoveryPath ?? "null"}`,
        `recoveryFingerprint: ${result.recoveryFingerprint ?? "null"}`,
        `cleanupErrors: ${JSON.stringify(result.cleanupErrors)}`,
        `nextAction: ${result.nextAction}`
    ];
    if (result.writeOutcome === "conflict") {
        return new errors_1.RuntimeError({
            message: "Basic promotion preview is stale or conflicted.",
            code: "PROMOTION_APPLICATION_CONFLICT",
            exitCode: errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT,
            details,
            recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                    id: "recovery.refresh-basic-promotion-preview",
                    command: "task promote",
                    explanation: "Inspect source and destination evidence, then build a fresh no-write promotion plan.",
                    reason: "The original target and mapping options must be supplied again by the operator."
                })]
        });
    }
    if (result.writeOutcome === "incomplete" ||
        result.recoveryPath !== null ||
        result.cleanupErrors.length > 0) {
        return new errors_1.RuntimeError({
            message: result.writeOutcome === "committed"
                ? "Basic promotion committed, but operational cleanup remains incomplete."
                : "Basic promotion stopped with retained incomplete repository state.",
            code: "PROMOTION_APPLICATION_INCOMPLETE",
            exitCode: errors_1.RuntimeExitCode.PARTIAL_MUTATION,
            writeOutcome: "partial",
            details,
            recoveryActions: promotionApplicationRecoveryActions("task promote", repositoryRoot, result)
        });
    }
    return new errors_1.RuntimeError({
        message: "Basic promotion did not commit its intended destination and retirement changes.",
        code: "PROMOTION_APPLICATION_NO_WRITE",
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details
    });
}
function promotionApplicationRecoveryActions(command, repositoryRoot, result) {
    if (result.transactionId === null ||
        result.recoveryFingerprint === null ||
        result.actor === null ||
        result.reason === null) {
        return [(0, errors_1.createNonCallableRecoveryAction)({
                id: "recovery.inspect-promotion-transaction",
                command,
                explanation: "Inspect retained promotion transaction evidence before recovery.",
                reason: "An exact current transaction fingerprint or audit identity was unavailable."
            })];
    }
    const inspected = (0, operational_state_1.inspectOperationalStateSync)(repositoryRoot).transactions.find((transaction) => transaction.transactionId === result.transactionId &&
        transaction.evidenceFingerprint === result.recoveryFingerprint);
    if (inspected === undefined) {
        return [(0, errors_1.createNonCallableRecoveryAction)({
                id: "recovery.inspect-promotion-transaction",
                command,
                explanation: "Inspect retained promotion transaction evidence before recovery.",
                reason: "Operational evidence changed after the application result was assembled."
            })];
    }
    const actions = new Set();
    if (inspected.postconditionsVerified ||
        inspected.recovery.some((step) => step.action === "roll-forward" || step.action === "resume")) {
        actions.add("roll-forward");
    }
    if (inspected.restorationVerified ||
        inspected.recovery.some((step) => step.action === "restore")) {
        actions.add("restore");
    }
    if (actions.size === 0) {
        return [(0, errors_1.createNonCallableRecoveryAction)({
                id: "recovery.inspect-promotion-transaction",
                command,
                explanation: "Inspect retained promotion transaction evidence before recovery.",
                reason: "Current sanitized target evidence does not authorize roll-forward or restore."
            })];
    }
    return [...actions].sort().map((action) => (0, errors_1.createDescriptorBackedRecoveryAction)({
        command,
        argv: promotionRecoveryArgv(command, {
            transactionId: result.transactionId,
            evidenceFingerprint: result.recoveryFingerprint,
            action,
            actor: result.actor,
            reason: result.reason
        }),
        explanation: `${action === "roll-forward" ? "Roll forward" : "Restore"} the exact retained promotion transaction after reviewing current evidence.`
    }));
}
function createPromotionRecoveryOutcomeError(command, repositoryRoot, proof, result) {
    const current = (0, operational_state_1.inspectOperationalStateSync)(repositoryRoot).transactions.find((transaction) => transaction.transactionId === proof.transactionId);
    const recoveryActions = current === undefined
        ? [(0, errors_1.createNonCallableRecoveryAction)({
                id: "recovery.inspect-promotion-transaction",
                command,
                explanation: "Inspect retained promotion transaction evidence before another recovery.",
                reason: "A current exact transaction fingerprint was unavailable."
            })]
        : [(0, errors_1.createDescriptorBackedRecoveryAction)({
                command,
                argv: promotionRecoveryArgv(command, {
                    ...proof,
                    evidenceFingerprint: current.evidenceFingerprint
                }),
                explanation: `Resume exact ${proof.action} recovery using the newly inspected evidence fingerprint.`
            })];
    return new errors_1.RuntimeError({
        message: "Promotion recovery left incomplete operational cleanup evidence.",
        code: "PROMOTION_RECOVERY_INCOMPLETE",
        exitCode: errors_1.RuntimeExitCode.PARTIAL_MUTATION,
        writeOutcome: "partial",
        details: [
            `transactionId: ${result.transactionId}`,
            `action: ${result.action}`,
            `outcome: ${result.outcome}`,
            `changedPaths: ${JSON.stringify(result.changedPaths)}`,
            `recoveryRecordPath: ${result.recoveryRecordPath ?? "null"}`,
            `removedOperationalPaths: ${JSON.stringify(result.removedOperationalPaths)}`,
            `cleanupErrors: ${JSON.stringify(result.cleanupErrors)}`,
            `cleanupEvidenceSource: ${result.cleanupEvidenceSource}`,
            `recoveryPath: ${result.recoveryPath ?? "null"}`,
            `failure: ${result.failure ?? "null"}`,
            `actor: ${result.actor}`,
            `reason: ${result.reason}`,
            `recoveredAt: ${result.recoveredAt}`
        ],
        recoveryActions
    });
}
function publicPromotionRecoveryResult(result) {
    return {
        transactionId: result.transactionId,
        action: result.action,
        outcome: result.outcome,
        changedPaths: result.changedPaths,
        recoveryRecordPath: result.recoveryRecordPath,
        removedOperationalPaths: result.removedOperationalPaths,
        cleanupErrors: result.cleanupErrors,
        cleanupEvidenceSource: result.cleanupEvidenceSource,
        recoveryPath: result.recoveryPath,
        failure: result.failure,
        actor: result.actor,
        reason: result.reason,
        recoveredAt: result.recoveredAt
    };
}
function renderPromotionRecoveryText(result) {
    return [
        "Promotion recovery completed.",
        "",
        `Transaction id: ${result.transactionId}`,
        `Action: ${result.action}`,
        `Outcome: ${result.outcome}`,
        `Changed paths: ${renderList(result.changedPaths)}`,
        `Recovery record: ${result.recoveryRecordPath ?? "none"}`,
        `Removed operational paths: ${renderList(result.removedOperationalPaths)}`,
        `Cleanup errors: ${renderList(result.cleanupErrors)}`,
        `Cleanup evidence source: ${result.cleanupEvidenceSource}`,
        `Recovery path: ${result.recoveryPath ?? "none"}`,
        `Actor: ${result.actor}`,
        `Reason: ${result.reason}`,
        `Recovered at: ${result.recoveredAt}`
    ].join("\n");
}
function promotionRecoveryArgv(command, proof) {
    const family = command === "task promote" ? "task" : "work";
    return [
        "day-shift", family, "promote",
        "--recover", proof.action,
        "--transaction-id", proof.transactionId,
        "--evidence-fingerprint", proof.evidenceFingerprint,
        "--actor", proof.actor,
        "--reason", proof.reason
    ];
}
function promotionNoWriteBoundary() {
    return "Promotion planning without --apply never writes, moves, copies, retires, or transactionally applies source or destination artifacts.";
}
function renderList(values) {
    return values.length === 0 ? "none" : values.join(", ");
}
function collect(value, previous) {
    previous.push(value);
    return previous;
}
