"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructuredPromotionApplicationError = exports.BasicPromotionApplicationError = void 0;
exports.previewBasicPromotionSync = previewBasicPromotionSync;
exports.previewStructuredPromotionSync = previewStructuredPromotionSync;
exports.applyBasicPromotionSync = applyBasicPromotionSync;
exports.applyStructuredPromotionSync = applyStructuredPromotionSync;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const mutation_preconditions_1 = require("../filesystem/mutation-preconditions");
const operational_state_1 = require("../filesystem/operational-state");
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 promotion_planning_1 = require("./promotion-planning");
const promotion_records_1 = require("./promotion-records");
class BasicPromotionApplicationError extends Error {
    code;
    constructor(code, message) {
        super(message);
        this.name = "BasicPromotionApplicationError";
        this.code = code;
    }
}
exports.BasicPromotionApplicationError = BasicPromotionApplicationError;
class StructuredPromotionApplicationError extends BasicPromotionApplicationError {
    constructor(code, message) {
        super(code, message);
        this.name = "StructuredPromotionApplicationError";
    }
}
exports.StructuredPromotionApplicationError = StructuredPromotionApplicationError;
const applicationPlans = new WeakMap();
function renderPromotionRecordWithReadinessTransitions(options) {
    const record = JSON.parse((0, promotion_records_1.renderPromotionRecord)(options));
    record.readinessTransitions = options.plan.readinessTransitions;
    return `${JSON.stringify(record, null, 2)}\n`;
}
function previewBasicPromotionSync(request) {
    const repositoryRoot = requireText(request.repositoryRoot, "Repository root");
    const plan = (0, promotion_planning_1.planPromotionSync)({
        repositoryRoot,
        sourceLevel: "basic",
        targetLevel: request.targetLevel,
        sourceTaskDefinitionPath: request.sourceTaskDefinitionPath,
        specificationPaths: request.specificationPaths,
        destinationWorkId: request.destinationWorkId,
        implementationOrder: request.implementationOrder,
        governed: request.governed
    });
    if (plan.taskMappings.length !== 1) {
        throw new BasicPromotionApplicationError("invalid-request", "Basic promotion apply requires exactly one planned task mapping.");
    }
    const mapping = plan.taskMappings[0];
    const sourceTaskText = readFile(repositoryRoot, mapping.sourceTaskDefinitionPath);
    const sourceSummaryText = readFile(repositoryRoot, mapping.sourceImplementationSummaryPath);
    const taskDocument = (0, planning_document_utils_1.parseMarkdownFrontMatter)(sourceTaskText);
    const sourceTaskId = (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "task")
        ?? (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "id");
    if (!taskDocument.hasFrontMatter || sourceTaskId !== mapping.taskId) {
        throw new BasicPromotionApplicationError("invalid-request", "Basic promotion source identity changed while the apply preview was assembled.");
    }
    const policy = {
        agentMode: (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "agent_mode") ?? "guided",
        evidenceProfile: (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "evidence_profile") ?? "runtime"
    };
    const writes = [
        ...plan.requiredParents.map((parent) => ({
            path: parent.path,
            contents: renderParent(plan, parent, policy)
        })),
        {
            path: mapping.destinationTaskDefinitionPath,
            contents: (0, promotion_planning_1.applyPromotionMetadataChanges)(sourceTaskText, plan.metadataChanges.filter((change) => change.path === mapping.destinationTaskDefinitionPath))
        },
        {
            path: mapping.destinationImplementationSummaryPath,
            contents: (0, promotion_planning_1.applyPromotionMetadataChanges)(sourceSummaryText, plan.metadataChanges.filter((change) => change.path === mapping.destinationImplementationSummaryPath))
        }
    ].sort((left, right) => left.path.localeCompare(right.path));
    const retirements = [
        { path: mapping.sourceTaskDefinitionPath },
        { path: mapping.sourceImplementationSummaryPath }
    ].sort((left, right) => left.path.localeCompare(right.path));
    const preconditions = buildPreconditions(repositoryRoot, plan.expected, retirements);
    const sourcePaths = retirements.map((entry) => entry.path);
    const destinationPaths = [
        mapping.destinationTaskDefinitionPath,
        mapping.destinationImplementationSummaryPath
    ].sort();
    const createdParentPaths = plan.requiredParents.map((entry) => entry.path).sort();
    const intendedPaths = [
        ...writes.map((entry) => entry.path),
        plan.promotionRecord.path,
        ...sourcePaths
    ];
    const result = {
        plan,
        planId: plan.planId,
        sourceTaskId: mapping.taskId,
        sourcePaths,
        destinationPaths,
        createdParentPaths,
        intendedRetiredPaths: sourcePaths,
        intendedPaths,
        changedPaths: [],
        retiredPaths: [],
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        recoveryFingerprint: null,
        promotionRecordPath: plan.promotionRecord.path,
        cleanupErrors: [],
        failure: null,
        actor: null,
        reason: null,
        appliedAt: null,
        nextAction: `Review plan '${plan.planId}', then explicitly apply this exact single-use preview.`
    };
    applicationPlans.set(result, {
        repositoryRoot: node_path_1.default.resolve(repositoryRoot),
        writes,
        retirements,
        preconditions
    });
    return result;
}
function previewStructuredPromotionSync(request) {
    const repositoryRoot = requireText(request.repositoryRoot, "Repository root");
    const sourceOverviewPath = requireText(request.sourceOverviewPath, "Structured source overview path");
    const plan = (0, promotion_planning_1.planPromotionSync)({
        repositoryRoot,
        sourceLevel: "structured",
        targetLevel: "governed",
        sourceOverviewPath,
        governed: request.governed
    });
    if (plan.sourceWorkId === null || plan.taskMappings.length === 0) {
        throw new StructuredPromotionApplicationError("invalid-request", "Structured promotion apply requires one work identity and at least one planned task mapping.");
    }
    const sourceOverviewText = readFile(repositoryRoot, sourceOverviewPath);
    const overviewDocument = (0, planning_document_utils_1.parseMarkdownFrontMatter)(sourceOverviewText);
    const sourceWorkId = (0, planning_document_utils_1.readTopLevelField)(overviewDocument.frontMatterLines, "id");
    if (!overviewDocument.hasFrontMatter ||
        (0, planning_document_utils_1.readTopLevelField)(overviewDocument.frontMatterLines, "workflow_level") !== "structured" ||
        sourceWorkId !== plan.sourceWorkId) {
        throw new StructuredPromotionApplicationError("invalid-request", "Structured promotion source identity changed while the apply preview was assembled.");
    }
    const policy = {
        agentMode: (0, planning_document_utils_1.readTopLevelField)(overviewDocument.frontMatterLines, "default_agent_mode") ?? "guided",
        evidenceProfile: (0, planning_document_utils_1.readTopLevelField)(overviewDocument.frontMatterLines, "default_evidence_profile") ?? "runtime"
    };
    const taskWrites = [];
    const taskRetirements = [];
    for (const mapping of plan.taskMappings) {
        const sourceTaskText = readFile(repositoryRoot, mapping.sourceTaskDefinitionPath);
        const sourceSummaryText = readFile(repositoryRoot, mapping.sourceImplementationSummaryPath);
        const taskDocument = (0, planning_document_utils_1.parseMarkdownFrontMatter)(sourceTaskText);
        const taskId = (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "task")
            ?? (0, planning_document_utils_1.readTopLevelField)(taskDocument.frontMatterLines, "id");
        if (!taskDocument.hasFrontMatter || taskId !== mapping.taskId) {
            throw new StructuredPromotionApplicationError("invalid-request", `Structured promotion task '${mapping.taskId}' changed identity while the apply preview was assembled.`);
        }
        taskWrites.push({
            path: mapping.destinationTaskDefinitionPath,
            contents: (0, promotion_planning_1.applyPromotionMetadataChanges)(sourceTaskText, plan.metadataChanges.filter((change) => change.path === mapping.destinationTaskDefinitionPath))
        }, {
            path: mapping.destinationImplementationSummaryPath,
            contents: (0, promotion_planning_1.applyPromotionMetadataChanges)(sourceSummaryText, plan.metadataChanges.filter((change) => change.path === mapping.destinationImplementationSummaryPath))
        });
        taskRetirements.push({ path: mapping.sourceTaskDefinitionPath }, { path: mapping.sourceImplementationSummaryPath });
    }
    const writes = [
        ...plan.requiredParents.map((parent) => ({
            path: parent.path,
            contents: parent.kind === "work-overview"
                ? (0, promotion_planning_1.applyPromotionMetadataChanges)(sourceOverviewText, plan.metadataChanges.filter((change) => change.path === parent.path))
                : renderParent(plan, parent, policy)
        })),
        ...taskWrites
    ].sort((left, right) => left.path.localeCompare(right.path));
    const retirements = [
        { path: sourceOverviewPath },
        ...taskRetirements
    ].sort((left, right) => left.path.localeCompare(right.path));
    const preconditions = buildPreconditions(repositoryRoot, plan.expected, retirements);
    const sourcePaths = retirements.map((entry) => entry.path);
    const destinationPaths = plan.taskMappings.flatMap((mapping) => [
        mapping.destinationTaskDefinitionPath,
        mapping.destinationImplementationSummaryPath
    ]).sort();
    const createdParentPaths = plan.requiredParents.map((entry) => entry.path).sort();
    const result = {
        plan,
        planId: plan.planId,
        sourceWorkId,
        sourceTaskIds: plan.taskMappings.map((entry) => entry.taskId).sort(),
        sourceOverviewPath,
        sourcePaths,
        destinationPaths,
        createdParentPaths,
        intendedRetiredPaths: sourcePaths,
        intendedPaths: [
            ...writes.map((entry) => entry.path),
            plan.promotionRecord.path,
            ...sourcePaths
        ],
        changedPaths: [],
        retiredPaths: [],
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        recoveryFingerprint: null,
        promotionRecordPath: plan.promotionRecord.path,
        cleanupErrors: [],
        failure: null,
        actor: null,
        reason: null,
        appliedAt: null,
        nextAction: `Review plan '${plan.planId}', then explicitly apply this exact single-use preview.`
    };
    applicationPlans.set(result, {
        repositoryRoot: node_path_1.default.resolve(repositoryRoot),
        writes,
        retirements,
        preconditions,
        selectedSourceOverviewPath: sourceOverviewPath
    });
    return result;
}
function applyBasicPromotionSync(preview, options) {
    const application = applicationPlans.get(preview);
    if (application === undefined || preview.writeOutcome !== "previewed") {
        throw new BasicPromotionApplicationError("stale-preview", "Basic promotion apply requires the original unused in-process preview. Refresh the no-write plan.");
    }
    const planId = requireText(options?.planId, "Promotion plan id");
    if (planId !== preview.planId) {
        throw new BasicPromotionApplicationError("plan-mismatch", `Promotion apply expected exact plan id '${preview.planId}', received '${planId}'. No write was attempted.`);
    }
    const actor = requireText(options.actor, "Promotion actor");
    const reason = requireText(options.reason, "Promotion reason");
    const appliedAt = normalizeTimestamp(options.appliedAt ?? new Date().toISOString());
    const transactionId = (0, node_crypto_1.randomBytes)(18).toString("hex");
    const recordWrite = {
        path: preview.plan.promotionRecord.path,
        contents: renderPromotionRecordWithReadinessTransitions({
            plan: preview.plan,
            actor,
            reason,
            appliedAt,
            transactionId
        })
    };
    applicationPlans.delete(preview);
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(application.repositoryRoot, {
        transactionId,
        transactionKind: "promotion",
        durableRecordPath: preview.plan.promotionRecord.path,
        writes: [...application.writes, recordWrite],
        retirements: application.retirements,
        preconditions: application.preconditions
    }, withPromotionDuplicateGuard(application, preview.plan, options.transaction));
    const changedEntries = transaction.entries.slice(0, transaction.canonicalWrites);
    const changedPaths = changedEntries.map((entry) => entry.path);
    const retiredPaths = changedEntries
        .filter((entry) => entry.operation === "retire")
        .map((entry) => entry.path);
    const recoveryPath = transaction.outcome === "incomplete" ||
        transaction.cleanupErrors.length > 0
        ? transaction.transactionPath
        : null;
    return {
        ...preview,
        changedPaths,
        retiredPaths,
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath,
        recoveryFingerprint: recoveryFingerprintFor(application.repositoryRoot, transaction.transactionId, recoveryPath),
        cleanupErrors: transaction.cleanupErrors,
        failure: transaction.failure,
        actor,
        reason,
        appliedAt,
        nextAction: nextActionFor(transaction.outcome, preview.plan.targetLevel, transaction.cleanupErrors.length > 0)
    };
}
function applyStructuredPromotionSync(preview, options) {
    const application = applicationPlans.get(preview);
    if (application === undefined || preview.writeOutcome !== "previewed") {
        throw new StructuredPromotionApplicationError("stale-preview", "Structured promotion apply requires the original unused in-process preview. Refresh the no-write plan.");
    }
    const planId = requireText(options?.planId, "Promotion plan id");
    if (planId !== preview.planId) {
        throw new StructuredPromotionApplicationError("plan-mismatch", `Promotion apply expected exact plan id '${preview.planId}', received '${planId}'. No write was attempted.`);
    }
    const actor = requireText(options.actor, "Promotion actor");
    const reason = requireText(options.reason, "Promotion reason");
    const appliedAt = normalizeTimestamp(options.appliedAt ?? new Date().toISOString());
    const transactionId = (0, node_crypto_1.randomBytes)(18).toString("hex");
    const recordWrite = {
        path: preview.plan.promotionRecord.path,
        contents: renderPromotionRecordWithReadinessTransitions({
            plan: preview.plan,
            actor,
            reason,
            appliedAt,
            transactionId
        })
    };
    applicationPlans.delete(preview);
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(application.repositoryRoot, {
        transactionId,
        transactionKind: "promotion",
        durableRecordPath: preview.plan.promotionRecord.path,
        writes: [...application.writes, recordWrite],
        retirements: application.retirements,
        preconditions: application.preconditions
    }, withPromotionDuplicateGuard(application, preview.plan, options.transaction));
    const changedEntries = transaction.entries.slice(0, transaction.canonicalWrites);
    const recoveryPath = transaction.outcome === "incomplete" ||
        transaction.cleanupErrors.length > 0
        ? transaction.transactionPath
        : null;
    return {
        ...preview,
        changedPaths: changedEntries.map((entry) => entry.path),
        retiredPaths: changedEntries
            .filter((entry) => entry.operation === "retire")
            .map((entry) => entry.path),
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath,
        recoveryFingerprint: recoveryFingerprintFor(application.repositoryRoot, transaction.transactionId, recoveryPath),
        cleanupErrors: transaction.cleanupErrors,
        failure: transaction.failure,
        actor,
        reason,
        appliedAt,
        nextAction: nextActionFor(transaction.outcome, preview.plan.targetLevel, transaction.cleanupErrors.length > 0)
    };
}
function withPromotionDuplicateGuard(application, plan, transactionOptions) {
    const callerHook = transactionOptions?.hook;
    return {
        ...transactionOptions,
        hook(context) {
            if (context.phase === "after-preconditions") {
                const duplicates = (0, promotion_records_1.findDuplicateActivePromotionLocationsSync)({
                    repositoryRoot: application.repositoryRoot,
                    targetLevel: plan.targetLevel,
                    destinationWorkId: plan.destinationWorkId,
                    destinationSliceId: plan.destinationSliceId,
                    taskMappings: plan.taskMappings,
                    selectedSourceOverviewPath: application.selectedSourceOverviewPath
                });
                if (duplicates.length > 0) {
                    const distinctions = [...new Set(duplicates.map((entry) => entry.kind))].sort();
                    throw new Error(`Duplicate active promotion identity detected (${distinctions.join(", ")}); refresh the no-write plan.`);
                }
            }
            callerHook?.(context);
        }
    };
}
function recoveryFingerprintFor(repositoryRoot, transactionId, recoveryPath) {
    if (recoveryPath === null)
        return null;
    try {
        return (0, operational_state_1.inspectOperationalStateSync)(repositoryRoot).transactions.find((transaction) => transaction.transactionId === transactionId)?.evidenceFingerprint ?? null;
    }
    catch {
        return null;
    }
}
function buildPreconditions(repositoryRoot, expected, retirements) {
    const preconditions = expected.map((condition) => {
        const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, condition.path);
        return condition.kind === "content-revision"
            ? {
                kind: "content-revision",
                repositoryRelativePath: target.repositoryRelativePath,
                runtimePath: target.runtimePath,
                expectedRevision: condition.expectedState
            }
            : {
                kind: "destination-presence",
                repositoryRelativePath: target.repositoryRelativePath,
                runtimePath: target.runtimePath,
                expectedPresence: condition.expectedState === "present" ? "present" : "absent"
            };
    });
    for (const retirement of retirements) {
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)((0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, retirement.path)));
    }
    const seen = new Set();
    return preconditions.filter((precondition) => {
        const key = `${precondition.kind}:${precondition.repositoryRelativePath}`;
        if (seen.has(key))
            return false;
        seen.add(key);
        return true;
    });
}
function renderParent(plan, parent, policy) {
    const identities = governedIdentities(plan);
    const specs = renderSpecFrontMatter(plan);
    const provenance = `day-shift ${plan.sourceLevel === "structured" ? "work" : "task"} promote --to ${plan.targetLevel} --plan-id ${plan.planId} --apply`;
    if (parent.kind === "work-overview") {
        if (plan.destinationWorkId === undefined) {
            throw new BasicPromotionApplicationError("invalid-request", "Governed promotion cannot render a destination work overview.");
        }
        return [
            "---",
            "artifact_schema_version: 1",
            "artifact_type: work_overview",
            `id: ${JSON.stringify(plan.destinationWorkId)}`,
            `implementation_order: ${JSON.stringify(plan.destinationImplementationOrder)}`,
            `workflow_level: ${plan.targetLevel}`,
            `default_agent_mode: ${JSON.stringify(policy.agentMode)}`,
            `default_evidence_profile: ${JSON.stringify(policy.evidenceProfile)}`,
            "status: draft",
            "upstream:",
            "  specs:",
            ...specs,
            "---",
            "",
            `# ${title(plan.targetLevel)} Work: ${plan.destinationWorkId}`,
            "",
            "## Purpose",
            "",
            "Organize promoted work while preserving canonical source specification and task evidence.",
            "",
            "## Promotion Mapping",
            "",
            `- Plan id: \`${plan.planId}\`.`,
            `- Source root: \`${plan.sourceRootPath}\`.`,
            `- Target level: \`${plan.targetLevel}\`.`,
            "",
            "## Open Questions",
            "",
            "- None currently.",
            ""
        ].join("\n");
    }
    if (identities === null) {
        throw new BasicPromotionApplicationError("invalid-request", `Structured promotion plan contains unexpected parent '${parent.kind}'.`);
    }
    const milestone = milestoneSlugForParent(parent);
    const common = [
        "artifact_schema_version: 1",
        `workflow_level: governed`,
        `default_agent_mode: ${JSON.stringify(policy.agentMode)}`,
        `default_evidence_profile: ${JSON.stringify(policy.evidenceProfile)}`,
        `workflow_provenance: cli`,
        `workflow_cli_command: ${JSON.stringify(provenance)}`,
        "status: draft"
    ];
    if (parent.kind === "slice-overview") {
        return artifact([
            common[0],
            "artifact_type: slice_overview",
            `slice: ${identities.slice}`,
            "planning_depth: standard",
            ...common.slice(1),
            "upstream:",
            "  specs:",
            ...specs
        ], `# ${title(identities.slice)}\n\n## Purpose\n\nContain the promoted Governed phase while preserving the source work and specification identities.\n\n## Phases\n\n- \`${identities.phase}\`: promoted work.\n\n## Open Questions\n\n- None currently.`);
    }
    if (parent.kind === "phase-overview") {
        const milestones = milestoneSlugs(plan);
        return artifact([
            common[0],
            "artifact_type: phase_overview",
            `slice: ${identities.slice}`,
            `phase: ${identities.phase}`,
            "planning_depth: standard",
            ...common.slice(1),
            "upstream:",
            "  specs:",
            ...specs,
            `  slice_overview: ${JSON.stringify(identities.sliceOverview)}`
        ], `# ${title(identities.phase)}\n\n## Purpose\n\nContain the explicitly mapped promotion milestones.\n\n## Milestones\n\n${milestones.map((entry) => `- \`${entry}\`: explicitly mapped promoted tasks.`).join("\n")}\n\n## Open Questions\n\n- None currently.`);
    }
    if (parent.kind === "milestone-overview") {
        if (milestone === null) {
            throw new BasicPromotionApplicationError("invalid-request", `Promotion milestone parent path '${parent.path}' is malformed.`);
        }
        const mappings = plan.taskMappings.filter((entry) => entry.destinationMilestoneSlug === milestone);
        return artifact([
            common[0],
            "artifact_type: milestone_overview",
            `slice: ${identities.slice}`,
            `phase: ${identities.phase}`,
            `milestone: ${milestone}`,
            "planning_depth: standard",
            ...common.slice(1),
            "upstream:",
            "  specs:",
            ...specs,
            `  slice_overview: ${JSON.stringify(identities.sliceOverview)}`,
            `  phase_overview: ${JSON.stringify(identities.phaseOverview)}`
        ], `# ${title(milestone)}\n\n## Purpose\n\nOwn the explicitly mapped promoted task evidence.\n\n## Tasks\n\n${mappings.map((entry) => `- \`${entry.taskId}\`: preserved promotion mapping.`).join("\n")}\n\nTarget task count: ${mappings.length}\n\nDecomposition rationale: each explicitly mapped source task remains one stable task identity under this destination milestone.\n\n## Open Questions\n\n- None currently.`);
    }
    if (milestone === null) {
        throw new BasicPromotionApplicationError("invalid-request", `Promotion reconciliation parent path '${parent.path}' is malformed.`);
    }
    const milestoneOverview = plan.requiredParents.find((entry) => entry.kind === "milestone-overview" &&
        milestoneSlugForParent(entry) === milestone)?.path;
    if (milestoneOverview === undefined) {
        throw new BasicPromotionApplicationError("invalid-request", `Promotion reconciliation '${parent.path}' has no planned milestone overview.`);
    }
    return artifact([
        common[0],
        "artifact_type: reconciliation",
        `slice: ${identities.slice}`,
        `phase: ${identities.phase}`,
        `milestone: ${milestone}`,
        "planning_depth: standard",
        ...common.slice(1, -1),
        "reconciliation_status: pending",
        "status: draft",
        "upstream:",
        "  specs:",
        ...specs,
        `  slice_overview: ${JSON.stringify(identities.sliceOverview)}`,
        `  phase_overview: ${JSON.stringify(identities.phaseOverview)}`,
        `  milestone_overview: ${JSON.stringify(milestoneOverview)}`
    ], `# ${title(milestone)} Reconciliation\n\n## Review Status\n\nPending promoted-task implementation evidence.\n\n## Completed Task Summaries\n\nNone yet.\n\n## Open Questions\n\n- None currently.`);
}
function artifact(frontMatter, body) {
    return ["---", ...frontMatter, "---", "", body, ""].join("\n");
}
function renderSpecFrontMatter(plan) {
    return plan.specifications.flatMap((specification) => [
        `    - id: ${JSON.stringify(specification.specId)}`,
        `      ref: ${JSON.stringify(specification.specPath)}`,
        `      revision: ${JSON.stringify(specification.revision)}`,
        `      readiness: ${JSON.stringify(specification.readiness)}`
    ]);
}
function governedIdentities(plan) {
    const sliceOverview = plan.requiredParents.find((entry) => entry.kind === "slice-overview")?.path;
    const phaseOverview = plan.requiredParents.find((entry) => entry.kind === "phase-overview")?.path;
    if (sliceOverview === undefined || phaseOverview === undefined) {
        return null;
    }
    const directSlice = sliceOverview.match(/^\.day-shift\/planning\/governed\/([^/]+)\/slice-overview\.md$/)?.[1];
    const phase = phaseOverview.match(/\/phases\/([^/]+)\/phase-overview\.md$/)?.[1];
    return directSlice === undefined || phase === undefined
        ? null
        : { slice: directSlice, phase, sliceOverview, phaseOverview };
}
function milestoneSlugForParent(parent) {
    return parent.path.match(/\/milestones\/([^/]+)\/(?:milestone-overview|reconciliation)\.md$/)?.[1]
        ?? null;
}
function milestoneSlugs(plan) {
    return [...new Set(plan.taskMappings.flatMap((entry) => entry.destinationMilestoneSlug === null ? [] : [entry.destinationMilestoneSlug]))].sort();
}
function readFile(repositoryRoot, repositoryRelativePath) {
    const target = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, repositoryRelativePath);
    if (!target.exists || !node_fs_1.default.statSync(target.runtimePath).isFile()) {
        throw new BasicPromotionApplicationError("invalid-request", `Promotion source '${target.repositoryRelativePath}' is missing.`);
    }
    return node_fs_1.default.readFileSync(target.runtimePath, "utf8");
}
function nextActionFor(outcome, targetLevel, cleanupIncomplete = false) {
    if (cleanupIncomplete) {
        return "Canonical work may already be complete; inspect the reported transaction and cleanup errors before any retry or cleanup.";
    }
    if (outcome === "committed") {
        return `Review the promoted ${title(targetLevel)} parent hierarchy and preserved task evidence.`;
    }
    if (outcome === "conflict") {
        return "Discard this authorization, inspect changed source/destination evidence, and generate a refreshed no-write plan.";
    }
    if (outcome === "incomplete") {
        return "Inspect the retained transaction before any retry, roll-forward, restoration, or cleanup.";
    }
    return "Generate a refreshed no-write promotion plan before retrying.";
}
function normalizeTimestamp(value) {
    if (!Number.isFinite(Date.parse(value)) || !/(?:Z|[+-]\d{2}:\d{2})$/.test(value)) {
        throw new BasicPromotionApplicationError("invalid-request", "Promotion apply time must be an ISO-8601 timestamp with an explicit timezone.");
    }
    return value;
}
function requireText(value, label) {
    if (typeof value !== "string" || value.trim() === "") {
        throw new BasicPromotionApplicationError("invalid-request", `${label} is required.`);
    }
    return value.trim();
}
function title(value) {
    return value.split("-").map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(" ");
}
