"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DOCUMENTATION_LOOP_RECOVERY_STEP_IDS = void 0;
exports.evaluateMilestoneModeBalance = evaluateMilestoneModeBalance;
exports.renderDocumentationLoopRecoveryProtocol = renderDocumentationLoopRecoveryProtocol;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const paths_1 = require("../paths");
const documentation_path_classifier_1 = require("../validation/documentation-path-classifier");
const artifact_policy_projection_1 = require("./artifact-policy-projection");
const planning_document_utils_1 = require("./planning-document-utils");
const runtime_acceptance_1 = require("./runtime-acceptance");
const task_cycle_runtime_attribution_1 = require("./task-cycle-runtime-attribution");
const task_lifecycle_1 = require("./task-lifecycle");
const task_waivers_1 = require("./task-waivers");
exports.DOCUMENTATION_LOOP_RECOVERY_STEP_IDS = [
    "detect",
    "execute-authorized-breakout",
    "verify-freshness",
    "rebuild-reconciliation",
    "rerun-milestone-review",
    "rerun-phase-review"
];
const NO_WRITE_BOUNDARY = "Mode-balance evaluation and Documentation Loop Recovery Protocol projection are read-only; they never scaffold or reorder tasks, edit source or planning artifacts, rebuild reconciliation, or mutate lifecycle metadata implicitly.";
function evaluateMilestoneModeBalance(repositoryRoot, options) {
    const milestoneOverviewPath = (0, paths_1.parseRepositoryRelativePath)(options.milestoneOverviewPath).normalizedPath;
    const milestoneAbsolute = node_path_1.default.join(repositoryRoot, milestoneOverviewPath);
    const milestoneText = node_fs_1.default.readFileSync(milestoneAbsolute, "utf8");
    const milestoneFrontMatter = (0, planning_document_utils_1.parseMarkdownFrontMatter)(milestoneText).frontMatterLines;
    const phaseOverviewPath = (0, planning_document_utils_1.readUpstreamField)(milestoneFrontMatter, "phase_overview")?.trim() || null;
    const acceptance = (0, runtime_acceptance_1.inspectRuntimeAcceptance)({
        artifactPath: milestoneOverviewPath,
        artifactKind: "milestone",
        frontMatterLines: milestoneFrontMatter,
        markdownText: milestoneText,
        requireExplicitForExecutableEvidence: false
    });
    if (acceptance.metadata === null) {
        return emptyEvaluation(milestoneOverviewPath, phaseOverviewPath, acceptance.issues, false, null);
    }
    if (!acceptance.metadata.required) {
        return emptyEvaluation(milestoneOverviewPath, phaseOverviewPath, acceptance.issues, true, false);
    }
    const declaredTaskSlugs = (0, planning_document_utils_1.readDeclaredChildSlugs)(milestoneText, "Tasks");
    const metadata = acceptance.metadata;
    const taskEvidence = declaredTaskSlugs.map((taskSlug) => {
        return readTaskEvidence(repositoryRoot, milestoneOverviewPath, taskSlug, metadata);
    });
    const breakoutEvidence = metadata.breakoutTask === null
        ? null
        : taskEvidence.find((entry) => entry.taskSlug === metadata.breakoutTask) ?? null;
    const breakoutSatisfied = breakoutEvidence?.completed === true
        && (breakoutEvidence.executionMode === "runtime" || breakoutEvidence.executionMode === "hybrid")
        && breakoutEvidence.attributionSufficient;
    const remainingCriterionIds = breakoutSatisfied ? [] : [...metadata.criterionIds];
    const completedContractStreak = countCompletedContractStreak(taskEvidence, metadata.breakoutTask);
    const breakoutPolicyIssues = (0, runtime_acceptance_1.validateMilestoneRuntimeBreakout)(metadata, declaredTaskSlugs);
    const exceptionConfigured = metadata.exception !== null;
    const exceptionValid = exceptionConfigured
        && breakoutPolicyIssues.every((issue) => !issue.includes("runtime_acceptance.exception"));
    const thresholdReached = completedContractStreak >= metadata.maxContractStreak;
    const requireBreakout = options.requireBreakoutForCloseout === true;
    const blockingIssues = [...acceptance.issues, ...breakoutPolicyIssues];
    if (!breakoutSatisfied && (thresholdReached || requireBreakout)) {
        const breakoutPath = breakoutEvidence?.taskDefinitionPath
            ?? resolveTaskDefinitionPath(milestoneOverviewPath, metadata.breakoutTask);
        const attributionDetail = breakoutEvidence === null
            ? "the declared breakout task definition or summary is missing"
            : breakoutEvidence.attributionIssues.length > 0
                ? breakoutEvidence.attributionIssues.join(" ")
                : "the declared breakout is not completed with runtime or hybrid evidence";
        blockingIssues.push(`Runtime acceptance remains pending for '${milestoneOverviewPath}' (${remainingCriterionIds.join(", ")}). Execute the already declared breakout '${breakoutPath ?? metadata.breakoutTask ?? "(missing)"}' before another contract task or closeout is accepted; ${attributionDetail}.`);
    }
    const blockingNextAction = blockingIssues.length > 0 && !breakoutSatisfied
        ? buildBlockingNextAction(metadata.breakoutTask, breakoutEvidence?.taskDefinitionPath ?? null)
        : null;
    const recoveryProtocol = blockingNextAction === null
        ? []
        : buildDocumentationLoopRecoveryProtocol({
            milestoneOverviewPath,
            phaseOverviewPath,
            breakoutTaskDefinitionPath: breakoutEvidence?.taskDefinitionPath
                ?? resolveTaskDefinitionPath(milestoneOverviewPath, metadata.breakoutTask),
            detectionTaskDefinitionPath: resolveDetectionTaskPath(taskEvidence, options.selectedTaskDefinitionPath, breakoutEvidence?.taskDefinitionPath ?? null)
        });
    return {
        optedIn: true,
        runtimeRequired: true,
        readOnly: true,
        writeCapable: false,
        noWriteBoundary: NO_WRITE_BOUNDARY,
        milestoneOverviewPath,
        phaseOverviewPath,
        criterionIds: [...metadata.criterionIds],
        remainingCriterionIds,
        maxContractStreak: metadata.maxContractStreak,
        completedContractStreak,
        breakoutTask: metadata.breakoutTask,
        breakoutTaskDefinitionPath: breakoutEvidence?.taskDefinitionPath
            ?? resolveTaskDefinitionPath(milestoneOverviewPath, metadata.breakoutTask),
        breakoutSatisfied,
        exceptionConfigured,
        exceptionValid,
        blockingNextAction,
        blockingIssues: unique(blockingIssues),
        taskEvidence,
        recoveryProtocol
    };
}
function renderDocumentationLoopRecoveryProtocol(protocol) {
    return protocol.map((step) => {
        const command = step.command === null ? "" : ` Command: \`${step.command}\`.`;
        return `${step.ordinal}. ${step.label}: ${step.instruction}${command}`;
    });
}
function readTaskEvidence(repositoryRoot, milestoneOverviewPath, taskSlug, metadata) {
    const taskDefinitionPath = resolveTaskDefinitionPath(milestoneOverviewPath, taskSlug);
    const implementationSummaryPath = (0, planning_document_utils_1.toRepositoryLikePath)(node_path_1.default.join(node_path_1.default.dirname(taskDefinitionPath), "implementation-summary.md"));
    const taskAbsolute = node_path_1.default.join(repositoryRoot, taskDefinitionPath);
    const summaryAbsolute = node_path_1.default.join(repositoryRoot, implementationSummaryPath);
    if (!node_fs_1.default.existsSync(taskAbsolute)) {
        return {
            taskSlug,
            taskDefinitionPath,
            implementationSummaryPath,
            executionMode: null,
            taskStatus: null,
            implementationStatus: null,
            summaryStatus: null,
            completed: false,
            completionEvidenceKind: null,
            legacyCompatibility: false,
            attributionPolicy: "legacy",
            attributionSufficient: false,
            attributionIssues: ["Declared breakout task definition is missing."],
            satisfiedCriterionIds: []
        };
    }
    const taskText = node_fs_1.default.readFileSync(taskAbsolute, "utf8");
    const taskFrontMatter = (0, planning_document_utils_1.parseMarkdownFrontMatter)(taskText).frontMatterLines;
    const executionMode = (0, artifact_policy_projection_1.projectArtifactPolicy)(taskText).evidenceProfile;
    const taskStatus = (0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "status")?.trim() ?? null;
    if (!node_fs_1.default.existsSync(summaryAbsolute)) {
        return {
            taskSlug,
            taskDefinitionPath,
            implementationSummaryPath,
            executionMode,
            taskStatus,
            implementationStatus: null,
            summaryStatus: null,
            completed: false,
            completionEvidenceKind: null,
            legacyCompatibility: false,
            attributionPolicy: "legacy",
            attributionSufficient: false,
            attributionIssues: ["Paired implementation summary is missing."],
            satisfiedCriterionIds: []
        };
    }
    const summaryText = node_fs_1.default.readFileSync(summaryAbsolute, "utf8");
    const summaryFrontMatter = (0, planning_document_utils_1.parseMarkdownFrontMatter)(summaryText).frontMatterLines;
    const summaryStatus = (0, planning_document_utils_1.readTopLevelField)(summaryFrontMatter, "status")?.trim() ?? null;
    const lifecycleIssues = [];
    let lifecycle;
    try {
        const preliminary = (0, task_lifecycle_1.projectImplementationSummaryLifecycle)(summaryText).value;
        const current = preliminary.currentAttempt;
        const reviewWaiverApplicable = current?.reviewDisposition === "waived"
            && current.reviewWaiverId !== null
            && (0, task_waivers_1.findApplicableTaskWaiver)(implementationSummaryPath, summaryText, {
                waiverType: "review",
                subjectId: (0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "task")?.trim()
                    ?? (0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "id")?.trim()
                    ?? "missing-task-identity",
                attemptId: current.attemptId,
                evaluatedAt: new Date().toISOString(),
                authorityRequired: true,
                waiverId: current.reviewWaiverId
            })?.applicable === true;
        lifecycle = (0, task_lifecycle_1.projectTaskLifecyclePair)({
            taskDefinition: taskText,
            implementationSummary: summaryText,
            reviewWaiverApplicable
        });
        lifecycleIssues.push(...lifecycle.blockingFindings.map((finding) => finding.message));
    }
    catch (error) {
        lifecycle = null;
        lifecycleIssues.push(`Canonical task-pair lifecycle evidence is unreadable: ${error instanceof Error ? error.message : String(error)}`);
    }
    const current = lifecycle?.summary?.currentAttempt ?? null;
    const acceptedCurrent = current?.reviewDisposition === "accepted"
        || current?.reviewDisposition === "accepted_with_follow_up"
        || (current?.reviewDisposition === "waived"
            && lifecycle?.blockingFindings.some((finding) => finding.code === "invalid-completed-task-state") !== true);
    const canonicalCompleted = lifecycleIssues.length === 0
        && lifecycle?.task.status === "completed"
        && current?.implementationStatus === "completed"
        && current.closedAt !== null
        && acceptedCurrent;
    const legacyReadable = current === null
        && taskStatus === "completed"
        && lifecycle?.summary?.legacyImplementationStatus === "completed"
        && lifecycle.summary.legacyReviewDisposition === "accepted"
        && summaryStatus === "completed";
    const implementationStatus = current?.implementationStatus
        ?? lifecycle?.summary?.legacyImplementationStatus
        ?? (0, planning_document_utils_1.readTopLevelField)(summaryFrontMatter, "implementation_status")?.trim()
        ?? null;
    const completed = canonicalCompleted || legacyReadable;
    const completionEvidenceKind = canonicalCompleted
        ? "canonical_current_attempt"
        : legacyReadable
            ? "legacy_read_only"
            : null;
    const attributionPolicy = (0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "runtime_attribution_required")?.trim() === "true"
        ? "structured"
        : "legacy";
    const attribution = (0, task_cycle_runtime_attribution_1.readRuntimeAttributionEvidence)(summaryText);
    const attributionIssues = [...lifecycleIssues];
    if (executionMode === "runtime" || executionMode === "hybrid") {
        if (attributionPolicy === "structured") {
            attributionIssues.push(...(0, task_cycle_runtime_attribution_1.reviewTaskCycleRuntimeAttribution)(repositoryRoot, {
                taskDefinitionPath,
                taskMarkdownText: taskText,
                summaryMarkdownText: summaryText
            }));
            if (attribution === null) {
                attributionIssues.push("Structured runtime_attribution evidence is missing.");
            }
            else {
                if (attribution.freshRuntimePaths.length === 0) {
                    attributionIssues.push("fresh_runtime_paths must not be empty.");
                }
                if (attribution.executableValidation.length === 0) {
                    attributionIssues.push("executable_validation must not be empty.");
                }
                if (attribution.ineligiblePaths.length > 0) {
                    attributionIssues.push(`ineligible_paths must be empty: ${attribution.ineligiblePaths.join(", ")}.`);
                }
                if (!sameValues(attribution.satisfiedCriterionIds, metadata.criterionIds)) {
                    attributionIssues.push(`satisfied_criterion_ids must exactly preserve inherited IDs: ${metadata.criterionIds.join(", ")}.`);
                }
            }
        }
        else {
            attributionIssues.push(legacyReadable && hasLegacyRuntimeEvidence(summaryText, metadata.criterionIds)
                ? "Legacy terminal runtime evidence is readable compatibility only; it cannot satisfy runtime acceptance, infer criterion IDs, or authorize mutation."
                : "Structured runtime_attribution evidence is required; legacy runtime evidence cannot satisfy runtime acceptance or authorize mutation.");
        }
    }
    if (!canonicalCompleted && !legacyReadable) {
        attributionIssues.push("Canonical completion requires task-definition status completed and the selected current attempt to be closed with completed implementation plus accepted, accepted-with-follow-up, or applicable review-waiver evidence.");
    }
    else if (legacyReadable) {
        attributionIssues.push("Legacy top-level terminal completion is retained as labeled read-only compatibility and cannot satisfy breakout acceptance or authorize mutation.");
    }
    return {
        taskSlug,
        taskDefinitionPath,
        implementationSummaryPath,
        executionMode,
        taskStatus,
        implementationStatus,
        summaryStatus,
        completed,
        completionEvidenceKind,
        legacyCompatibility: legacyReadable,
        attributionPolicy,
        attributionSufficient: canonicalCompleted
            && (executionMode === "runtime" || executionMode === "hybrid")
            && attributionPolicy === "structured"
            && attribution !== null
            && attributionIssues.length === 0,
        attributionIssues: unique(attributionIssues),
        satisfiedCriterionIds: attribution?.satisfiedCriterionIds ?? []
    };
}
function hasLegacyRuntimeEvidence(summaryText, criterionIds) {
    const sections = (0, planning_document_utils_1.parseMarkdownSections)(summaryText);
    const changedPaths = (sections.get("Changed Paths") ?? "")
        .split(/\r?\n/)
        .map((line) => line.match(/^\s*-\s+`([^`]+)`/)?.[1]?.trim() ?? "")
        .filter((entry) => entry !== "");
    const hasRuntimePath = changedPaths.some((entry) => (0, documentation_path_classifier_1.classifyDocumentationPath)(entry).runtimeEligible);
    const validation = sections.get("Validation Performed") ?? "";
    const hasExecutableValidation = /`(?:node|pnpm|npm|yarn|bun|deno|cargo|go|pytest|python|ruby|java|dotnet|make)\b[^`]*`/.test(validation);
    const acceptance = sections.get("Acceptance Criteria Results") ?? "";
    return hasRuntimePath
        && hasExecutableValidation
        && criterionIds.every((criterionId) => acceptance.includes(criterionId));
}
function buildDocumentationLoopRecoveryProtocol(options) {
    const detectionPath = options.detectionTaskDefinitionPath
        ?? options.breakoutTaskDefinitionPath
        ?? options.milestoneOverviewPath;
    const breakoutPath = options.breakoutTaskDefinitionPath ?? options.milestoneOverviewPath;
    const phasePath = options.phaseOverviewPath ?? options.milestoneOverviewPath;
    return [
        {
            id: "detect",
            ordinal: 1,
            label: "Detect",
            instruction: `Confirm the structured mode-balance blocker for '${detectionPath}' without changing artifacts.`,
            artifactPath: detectionPath,
            command: options.detectionTaskDefinitionPath === null
                ? `node dist/cli/index.js milestone review --milestone-overview ${options.milestoneOverviewPath} --format json`
                : `node dist/cli/index.js task review --task-definition ${detectionPath} --format json`,
            readOnly: true,
            implicitWrite: false
        },
        {
            id: "execute-authorized-breakout",
            ordinal: 2,
            label: "Execute the authorized breakout",
            instruction: `Implement the already declared task '${breakoutPath}' through '.day-shift/workflows/03-implement-from-task.md'; do not scaffold or reorder tasks.`,
            artifactPath: breakoutPath,
            command: null,
            readOnly: false,
            implicitWrite: false
        },
        {
            id: "verify-freshness",
            ordinal: 3,
            label: "Verify freshness",
            instruction: `Review current-cycle baseline identity, fresh runtime paths, executable validation, and exact acceptance IDs for '${breakoutPath}'.`,
            artifactPath: breakoutPath,
            command: `node dist/cli/index.js implementation-summary review --task-definition ${breakoutPath} --format json`,
            readOnly: true,
            implicitWrite: false
        },
        {
            id: "rebuild-reconciliation",
            ordinal: 4,
            label: "Rebuild reconciliation",
            instruction: `Explicitly refresh the selected milestone reconciliation only after freshness review succeeds.`,
            artifactPath: options.milestoneOverviewPath,
            command: `node dist/cli/index.js reconciliation build --milestone-overview ${options.milestoneOverviewPath} --format json`,
            readOnly: false,
            implicitWrite: false
        },
        {
            id: "rerun-milestone-review",
            ordinal: 5,
            label: "Rerun milestone review",
            instruction: `Review '${options.milestoneOverviewPath}' after reconciliation rebuild; the review remains no-write.`,
            artifactPath: options.milestoneOverviewPath,
            command: `node dist/cli/index.js milestone review --milestone-overview ${options.milestoneOverviewPath} --format json`,
            readOnly: true,
            implicitWrite: false
        },
        {
            id: "rerun-phase-review",
            ordinal: 6,
            label: "Rerun phase review",
            instruction: `Review '${phasePath}' only after milestone review clears; the review remains no-write.`,
            artifactPath: phasePath,
            command: `node dist/cli/index.js phase review --phase-overview ${phasePath} --format json`,
            readOnly: true,
            implicitWrite: false
        }
    ];
}
function countCompletedContractStreak(evidence, breakoutTask) {
    let streak = 0;
    for (const entry of evidence) {
        if (entry.taskSlug === breakoutTask && entry.attributionSufficient) {
            return 0;
        }
        if (!entry.completed) {
            continue;
        }
        if (entry.executionMode === "contract") {
            streak += 1;
            continue;
        }
        if (entry.attributionSufficient) {
            streak = 0;
        }
    }
    return streak;
}
function resolveDetectionTaskPath(taskEvidence, selectedTaskDefinitionPath, breakoutTaskDefinitionPath) {
    if (selectedTaskDefinitionPath !== undefined && selectedTaskDefinitionPath !== null) {
        return (0, paths_1.parseRepositoryRelativePath)(selectedTaskDefinitionPath).normalizedPath;
    }
    const completed = taskEvidence.filter((entry) => entry.completed);
    return completed.at(-1)?.taskDefinitionPath ?? breakoutTaskDefinitionPath;
}
function resolveTaskDefinitionPath(milestoneOverviewPath, taskSlug) {
    if (taskSlug === null)
        return null;
    return (0, planning_document_utils_1.toRepositoryLikePath)(node_path_1.default.join(node_path_1.default.dirname(milestoneOverviewPath), "tasks", taskSlug, "task-definition.md"));
}
function buildBlockingNextAction(breakoutTask, breakoutTaskDefinitionPath) {
    if (breakoutTaskDefinitionPath !== null) {
        return `Execute the already declared runtime or hybrid breakout from '${breakoutTaskDefinitionPath}'; do not advance another contract task.`;
    }
    return `Repair the milestone runtime-acceptance contract so declared breakout '${breakoutTask ?? "(missing)"}' resolves to one existing task; do not scaffold or guess a replacement.`;
}
function emptyEvaluation(milestoneOverviewPath, phaseOverviewPath, issues, optedIn, runtimeRequired) {
    return {
        optedIn,
        runtimeRequired,
        readOnly: true,
        writeCapable: false,
        noWriteBoundary: NO_WRITE_BOUNDARY,
        milestoneOverviewPath,
        phaseOverviewPath,
        criterionIds: [],
        remainingCriterionIds: [],
        maxContractStreak: null,
        completedContractStreak: 0,
        breakoutTask: null,
        breakoutTaskDefinitionPath: null,
        breakoutSatisfied: false,
        exceptionConfigured: false,
        exceptionValid: false,
        blockingNextAction: null,
        blockingIssues: unique(issues),
        taskEvidence: [],
        recoveryProtocol: []
    };
}
function sameValues(left, right) {
    return left.length === right.length && left.every((value, index) => value === right[index]);
}
function unique(values) {
    return [...new Set(values)];
}
