"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.captureTaskCycleRuntimeBaseline = captureTaskCycleRuntimeBaseline;
exports.readTaskCycleRuntimeBaseline = readTaskCycleRuntimeBaseline;
exports.deriveTaskCycleRuntimeAttribution = deriveTaskCycleRuntimeAttribution;
exports.injectRuntimeAttributionSummaryFrontMatter = injectRuntimeAttributionSummaryFrontMatter;
exports.reviewTaskCycleRuntimeAttribution = reviewTaskCycleRuntimeAttribution;
exports.readRuntimeAttributionEvidence = readRuntimeAttributionEvidence;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_child_process_1 = require("node:child_process");
const errors_1 = require("../errors");
const command_write_summary_1 = require("../license/command-write-summary");
const paths_1 = require("../paths");
const runtime_contract_1 = require("../runtime/runtime-contract");
const documentation_path_classifier_1 = require("../validation/documentation-path-classifier");
const declared_target_paths_1 = require("../validation/declared-target-paths");
const planning_document_utils_1 = require("./planning-document-utils");
const runtime_acceptance_1 = require("./runtime-acceptance");
const IDENTITY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{2,127}$/;
const CONTENT_HASH_PATTERN = /^sha256:[0-9a-f]{64}$/;
const SOURCE_REVISION_PATTERN = /^[0-9a-f]{40,64}$/;
const MAX_HASHED_FILES = 5_000;
const MAX_HASHED_BYTES = 128_000_000;
const BASELINE_BLOCK = "runtime_attribution_baseline";
const SUMMARY_BLOCK = "runtime_attribution";
function captureTaskCycleRuntimeBaseline(repositoryRoot, options) {
    const taskDefinitionPath = (0, paths_1.parseRepositoryRelativePath)(options.taskDefinitionPath).normalizedPath;
    const taskDefinitionAbsolute = node_path_1.default.join(repositoryRoot, taskDefinitionPath);
    if (!node_fs_1.default.existsSync(taskDefinitionAbsolute)) {
        throw (0, errors_1.createUsageError)(`Task definition not found at '${taskDefinitionPath}'.`);
    }
    assertIdentity("task-cycle", options.taskCycleId);
    assertIdentity("checkpoint", options.checkpointId);
    const taskText = node_fs_1.default.readFileSync(taskDefinitionAbsolute, "utf8");
    const parsed = (0, planning_document_utils_1.parseMarkdownFrontMatter)(taskText);
    if (!parsed.hasFrontMatter || (0, planning_document_utils_1.readTopLevelField)(parsed.frontMatterLines, "artifact_type") !== "task_definition") {
        throw (0, errors_1.createUsageError)(`Artifact '${taskDefinitionPath}' must be a task_definition.`);
    }
    const existing = readTaskCycleRuntimeBaseline(taskDefinitionPath, taskText);
    if (existing !== null) {
        if (options.resume !== true) {
            throw (0, errors_1.createUsageError)(`Task definition '${taskDefinitionPath}' already records baseline '${existing.baselineId}'.`, ["Use --resume with the exact stored --task-cycle-id and --checkpoint-id; baseline replacement is not supported."]);
        }
        if (existing.taskCycleId !== options.taskCycleId || existing.checkpointId !== options.checkpointId) {
            throw (0, errors_1.createUsageError)(`Resume identity does not match the stored task-cycle baseline at '${taskDefinitionPath}'.`, [
                `Stored task-cycle ID: ${existing.taskCycleId}`,
                `Stored checkpoint ID: ${existing.checkpointId}`,
                "No files were written."
            ]);
        }
        return baselineCaptureResult(taskDefinitionPath, existing, "reused", false);
    }
    if (options.resume === true) {
        throw (0, errors_1.createUsageError)(`Task definition '${taskDefinitionPath}' has no baseline to resume.`, ["Capture the first baseline without --resume after readiness succeeds and before implementation writes begin."]);
    }
    const readiness = (0, planning_document_utils_1.readTopLevelField)(parsed.frontMatterLines, "readiness")?.trim();
    if (readiness !== "ready to implement") {
        throw (0, errors_1.createUsageError)(`Task baseline capture requires readiness 'ready to implement', found '${readiness ?? "(missing)"}'.`, ["Run task readiness-review, then apply the explicit readiness update before baseline capture."]);
    }
    const executionMode = (0, planning_document_utils_1.readTopLevelField)(parsed.frontMatterLines, "execution_mode")?.trim();
    if (executionMode !== "runtime" && executionMode !== "hybrid") {
        throw (0, errors_1.createUsageError)(`Task baseline capture requires execution_mode runtime or hybrid, found '${executionMode ?? "(missing)"}'.`);
    }
    if ((0, planning_document_utils_1.readTopLevelField)(parsed.frontMatterLines, "runtime_attribution_required")?.trim() !== "true") {
        throw (0, errors_1.createUsageError)(`Task baseline capture requires explicit runtime_attribution_required: true at '${taskDefinitionPath}'.`);
    }
    const acceptance = (0, runtime_acceptance_1.inspectRuntimeAcceptance)({
        artifactPath: taskDefinitionPath,
        artifactKind: "task",
        frontMatterLines: parsed.frontMatterLines,
        markdownText: taskText,
        requireExplicitForExecutableEvidence: true
    });
    if (acceptance.issues.length > 0 || acceptance.metadata === null || !acceptance.metadata.required) {
        throw (0, errors_1.createUsageError)(`Task baseline capture requires a valid runtime_acceptance contract at '${taskDefinitionPath}'.`, acceptance.issues.length > 0 ? [...acceptance.issues] : ["runtime_acceptance.required must be true."]);
    }
    const declaredTargets = (0, declared_target_paths_1.readTaskDeclaredTargetPathEvidence)(taskDefinitionPath, taskText);
    const targetIssues = declaredTargets.evidence.filter((entry) => entry.state !== "explicit");
    if (declaredTargets.explicitTargetPaths.length === 0 || targetIssues.length > 0) {
        throw (0, errors_1.createUsageError)(`Task baseline capture requires concrete, unique declared target paths at '${taskDefinitionPath}'.`, targetIssues.map((entry) => entry.message));
    }
    const adoptionByPath = parseAdoptions(options.adoptions ?? [], declaredTargets.explicitTargetPaths);
    const targetEvidence = declaredTargets.explicitTargetPaths.map((targetPath) => inspectTarget(repositoryRoot, targetPath, adoptionByPath.get(targetPath) ?? null));
    const sourceRevision = runGit(repositoryRoot, ["rev-parse", "--verify", "HEAD"]);
    if (sourceRevision === null || !SOURCE_REVISION_PATTERN.test(sourceRevision)) {
        throw (0, errors_1.createUsageError)("Task baseline capture requires a readable Git HEAD revision.", ["No files were written."]);
    }
    const provenance = (0, runtime_contract_1.getRuntimeProvenance)();
    const baselineSeed = {
        schemaVersion: 1,
        taskCycleId: options.taskCycleId,
        checkpointId: options.checkpointId,
        capturedAfterReadiness: true,
        capturedBeforeImplementationWrites: true,
        sourceRevision,
        repositoryDirtyState: targetEvidence.some((entry) => entry.dirty) || provenance.repositoryDirtyState === "dirty"
            ? "dirty"
            : "clean",
        cliRuntimeSource: provenance.runtimeSource,
        cliBuildIdentity: provenance.buildIdentity,
        declaredTargets: targetEvidence
    };
    const baseline = {
        ...baselineSeed,
        baselineId: hashCanonical(baselineSeed)
    };
    const nextText = replaceFrontMatterBlock(taskText, BASELINE_BLOCK, renderBaselineBlock(baseline));
    writeFileAtomically(taskDefinitionAbsolute, nextText);
    return baselineCaptureResult(taskDefinitionPath, baseline, "captured", true);
}
function readTaskCycleRuntimeBaseline(artifactPath, markdownText) {
    const parsed = (0, planning_document_utils_1.parseMarkdownFrontMatter)(markdownText);
    const lines = readFrontMatterBlock(parsed.frontMatterLines, BASELINE_BLOCK);
    if (lines === null)
        return null;
    const schemaVersion = Number(readScalar(lines, "schema_version") ?? "0");
    const baselineId = readScalar(lines, "baseline_id") ?? "";
    const taskCycleId = readScalar(lines, "task_cycle_id") ?? "";
    const checkpointId = readScalar(lines, "checkpoint_id") ?? "";
    const sourceRevision = readScalar(lines, "source_revision") ?? "";
    const repositoryDirtyState = readScalar(lines, "repository_dirty_state") ?? "";
    const cliRuntimeSource = readScalar(lines, "cli_runtime_source") ?? "";
    const cliBuildIdentity = readScalar(lines, "cli_build_identity") ?? "";
    const capturedAfterReadiness = readScalar(lines, "captured_after_readiness") === "true";
    const capturedBeforeImplementationWrites = readScalar(lines, "captured_before_implementation_writes") === "true";
    const declaredTargets = readTargetList(lines);
    const issues = [];
    if (schemaVersion !== 1)
        issues.push("schema_version must be 1.");
    if (!CONTENT_HASH_PATTERN.test(baselineId))
        issues.push("baseline_id must be a sha256 identity.");
    if (!IDENTITY_PATTERN.test(taskCycleId))
        issues.push("task_cycle_id is missing or invalid.");
    if (!IDENTITY_PATTERN.test(checkpointId))
        issues.push("checkpoint_id is missing or invalid.");
    if (!capturedAfterReadiness)
        issues.push("captured_after_readiness must be true.");
    if (!capturedBeforeImplementationWrites)
        issues.push("captured_before_implementation_writes must be true.");
    if (!SOURCE_REVISION_PATTERN.test(sourceRevision))
        issues.push("source_revision is missing or invalid.");
    if (repositoryDirtyState !== "clean" && repositoryDirtyState !== "dirty") {
        issues.push("repository_dirty_state must be clean or dirty.");
    }
    if (cliRuntimeSource === "" || cliBuildIdentity === "")
        issues.push("CLI runtime/build provenance is incomplete.");
    if (declaredTargets.length === 0)
        issues.push("declared_targets must not be empty.");
    issues.push(...validateTargetEvidence(declaredTargets));
    if (issues.length > 0) {
        throw (0, errors_1.createUsageError)(`Runtime-attribution baseline is invalid at '${(0, planning_document_utils_1.toRepositoryLikePath)(artifactPath)}'.`, issues);
    }
    return {
        schemaVersion: 1,
        baselineId,
        taskCycleId,
        checkpointId,
        capturedAfterReadiness: true,
        capturedBeforeImplementationWrites: true,
        sourceRevision,
        repositoryDirtyState: repositoryDirtyState,
        cliRuntimeSource,
        cliBuildIdentity,
        declaredTargets
    };
}
function deriveTaskCycleRuntimeAttribution(repositoryRoot, options) {
    const baseline = readTaskCycleRuntimeBaseline(options.taskDefinitionPath, options.taskMarkdownText);
    if (baseline === null)
        return null;
    const sections = (0, planning_document_utils_1.parseMarkdownSections)(options.summaryMarkdownText);
    const changedPaths = readRepositoryPathBullets(sections.get("Changed Paths") ?? "");
    const executableValidation = readExecutableCommands(sections.get("Validation Performed") ?? "");
    const acceptance = (0, runtime_acceptance_1.inspectRuntimeAcceptance)({
        artifactPath: options.taskDefinitionPath,
        artifactKind: "task",
        frontMatterLines: (0, planning_document_utils_1.parseMarkdownFrontMatter)(options.taskMarkdownText).frontMatterLines,
        markdownText: options.taskMarkdownText,
        requireExplicitForExecutableEvidence: true
    });
    const inheritedIds = acceptance.metadata?.criterionIds ?? [];
    const acceptanceResults = sections.get("Acceptance Criteria Results") ?? "";
    const satisfiedCriterionIds = inheritedIds.filter((criterionId) => acceptanceResults.includes(criterionId));
    const currentTargets = new Map(baseline.declaredTargets.map((target) => [target.path, inspectTarget(repositoryRoot, target.path, null)]));
    const freshRuntimePaths = [];
    const ineligiblePaths = [];
    for (const changedPath of changedPaths) {
        if (!(0, documentation_path_classifier_1.classifyDocumentationPath)(changedPath).runtimeEligible) {
            continue;
        }
        const baselineTarget = baseline.declaredTargets.find((target) => (0, paths_1.pathsOverlap)(changedPath, target.path));
        if (baselineTarget === undefined) {
            ineligiblePaths.push(changedPath);
            continue;
        }
        const currentTarget = currentTargets.get(baselineTarget.path);
        const changedSinceBaseline = currentTarget !== undefined
            && (currentTarget.exists !== baselineTarget.exists
                || currentTarget.kind !== baselineTarget.kind
                || currentTarget.contentSha256 !== baselineTarget.contentSha256);
        if (changedSinceBaseline || baselineTarget.preExistingClassification === "adopted-pre-staged") {
            freshRuntimePaths.push(changedPath);
        }
        else {
            ineligiblePaths.push(changedPath);
        }
    }
    const currentRevision = runGit(repositoryRoot, ["rev-parse", "--verify", "HEAD"]) ?? "unknown";
    return {
        schemaVersion: 1,
        baselineId: baseline.baselineId,
        taskCycleId: baseline.taskCycleId,
        checkpointId: baseline.checkpointId,
        sourceRevision: baseline.sourceRevision,
        currentRevision,
        freshRuntimePaths: unique(freshRuntimePaths),
        executableValidation: unique(executableValidation),
        satisfiedCriterionIds,
        adoptedPaths: baseline.declaredTargets
            .filter((target) => target.preExistingClassification === "adopted-pre-staged")
            .map((target) => ({ path: target.path, rationale: target.adoptionRationale })),
        ineligiblePaths: unique(ineligiblePaths)
    };
}
function injectRuntimeAttributionSummaryFrontMatter(summaryMarkdownText, evidence) {
    if (evidence === null)
        return removeFrontMatterBlock(summaryMarkdownText, SUMMARY_BLOCK);
    return replaceFrontMatterBlock(summaryMarkdownText, SUMMARY_BLOCK, renderSummaryBlock(evidence));
}
function reviewTaskCycleRuntimeAttribution(repositoryRoot, options) {
    const taskFrontMatter = (0, planning_document_utils_1.parseMarkdownFrontMatter)(options.taskMarkdownText).frontMatterLines;
    const executionMode = (0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "execution_mode")?.trim();
    if (executionMode !== "runtime" && executionMode !== "hybrid")
        return [];
    if ((0, planning_document_utils_1.readTopLevelField)(taskFrontMatter, "runtime_attribution_required")?.trim() !== "true")
        return [];
    const issues = [];
    let baseline = null;
    try {
        baseline = readTaskCycleRuntimeBaseline(options.taskDefinitionPath, options.taskMarkdownText);
    }
    catch (error) {
        return [error instanceof Error ? error.message : String(error)];
    }
    if (baseline === null) {
        return ["Runtime or hybrid closeout requires a structured post-readiness, pre-write task-cycle baseline on the task definition."];
    }
    const stored = readRuntimeAttributionEvidence(options.summaryMarkdownText);
    if (stored === null) {
        return ["Runtime or hybrid closeout requires structured runtime_attribution evidence on the paired implementation summary."];
    }
    const expected = deriveTaskCycleRuntimeAttribution(repositoryRoot, options);
    if (expected === null)
        return ["Unable to derive current-cycle runtime attribution from the stored baseline."];
    for (const key of ["baselineId", "taskCycleId", "checkpointId", "sourceRevision"]) {
        if (stored[key] !== expected[key]) {
            issues.push(`Implementation-summary runtime_attribution.${toSnakeCase(key)} does not match the task baseline.`);
        }
    }
    if (!sameValues(stored.freshRuntimePaths, expected.freshRuntimePaths)) {
        issues.push("Implementation-summary fresh_runtime_paths is stale or contradicts the current declared-target comparison.");
    }
    if (stored.freshRuntimePaths.length === 0) {
        issues.push("Runtime or hybrid closeout requires at least one freshly attributable runtime-eligible path.");
    }
    if (stored.freshRuntimePaths.some((entry) => !(0, documentation_path_classifier_1.classifyDocumentationPath)(entry).runtimeEligible)) {
        issues.push("Documentation-only paths cannot satisfy fresh_runtime_paths.");
    }
    if (!sameValues(stored.executableValidation, expected.executableValidation)
        || stored.executableValidation.length === 0) {
        issues.push("Implementation-summary executable_validation must preserve concrete executed commands from Validation Performed.");
    }
    const acceptance = (0, runtime_acceptance_1.inspectRuntimeAcceptance)({
        artifactPath: options.taskDefinitionPath,
        artifactKind: "task",
        frontMatterLines: taskFrontMatter,
        markdownText: options.taskMarkdownText,
        requireExplicitForExecutableEvidence: true
    });
    const inheritedIds = acceptance.metadata?.criterionIds ?? [];
    if (!sameValues(stored.satisfiedCriterionIds, inheritedIds)
        || !sameValues(expected.satisfiedCriterionIds, inheritedIds)) {
        issues.push(`Implementation-summary satisfied_criterion_ids must exactly preserve every inherited runtime-acceptance ID: ${inheritedIds.join(", ") || "(none)"}.`);
    }
    if (!sameAdoptions(stored.adoptedPaths, expected.adoptedPaths)) {
        issues.push("Implementation-summary adopted_paths does not preserve the baseline's per-path adoption evidence.");
    }
    if (stored.ineligiblePaths.length > 0 || expected.ineligiblePaths.length > 0) {
        issues.push(`Changed Paths includes current-cycle-ineligible evidence: ${unique([...stored.ineligiblePaths, ...expected.ineligiblePaths]).join(", ")}.`);
    }
    return unique(issues);
}
function readRuntimeAttributionEvidence(markdownText) {
    const lines = readFrontMatterBlock((0, planning_document_utils_1.parseMarkdownFrontMatter)(markdownText).frontMatterLines, SUMMARY_BLOCK);
    if (lines === null)
        return null;
    const adoptedPaths = readAdoptionList(lines);
    return {
        schemaVersion: Number(readScalar(lines, "schema_version") ?? "0"),
        baselineId: readScalar(lines, "baseline_id") ?? "",
        taskCycleId: readScalar(lines, "task_cycle_id") ?? "",
        checkpointId: readScalar(lines, "checkpoint_id") ?? "",
        sourceRevision: readScalar(lines, "source_revision") ?? "",
        currentRevision: readScalar(lines, "current_revision") ?? "",
        freshRuntimePaths: readScalarList(lines, "fresh_runtime_paths"),
        executableValidation: readScalarList(lines, "executable_validation"),
        satisfiedCriterionIds: readScalarList(lines, "satisfied_criterion_ids"),
        adoptedPaths,
        ineligiblePaths: readScalarList(lines, "ineligible_paths")
    };
}
function inspectTarget(repositoryRoot, targetPath, adoptionRationale) {
    const absolutePath = node_path_1.default.join(repositoryRoot, targetPath);
    const status = runGit(repositoryRoot, ["status", "--porcelain=v1", "--untracked-files=all", "--", targetPath]);
    if (status === null) {
        throw (0, errors_1.createUsageError)(`Unable to inspect Git dirty state for declared target '${targetPath}'.`);
    }
    const dirty = status !== "";
    if (adoptionRationale !== null && !dirty) {
        throw (0, errors_1.createUsageError)(`Adoption path '${targetPath}' is not dirty at baseline capture.`);
    }
    let exists = false;
    let kind = "absent";
    let contentSha256 = null;
    try {
        const stat = node_fs_1.default.lstatSync(absolutePath);
        if (stat.isSymbolicLink()) {
            throw (0, errors_1.createUsageError)(`Declared target '${targetPath}' is a symbolic link; baseline hashing requires a bounded file or directory.`);
        }
        exists = true;
        if (stat.isFile()) {
            kind = "file";
            contentSha256 = hashFile(absolutePath);
        }
        else if (stat.isDirectory()) {
            kind = "directory";
            contentSha256 = hashDirectory(absolutePath);
        }
        else {
            throw (0, errors_1.createUsageError)(`Declared target '${targetPath}' is neither a regular file nor directory.`);
        }
    }
    catch (error) {
        if (error.code !== "ENOENT")
            throw error;
    }
    const visibility = inspectRepositoryVisibility(repositoryRoot, targetPath, exists);
    return {
        path: targetPath,
        exists,
        kind,
        contentSha256,
        repositoryVisibility: visibility.state,
        ignoreRule: visibility.ignoreRule,
        dirty,
        preExistingClassification: adoptionRationale !== null
            ? "adopted-pre-staged"
            : dirty
                ? "pre-existing-unattributed"
                : "clean",
        adoptionRationale: adoptionRationale ?? ""
    };
}
function inspectRepositoryVisibility(repositoryRoot, targetPath, exists) {
    if (!exists)
        return { state: "absent", ignoreRule: null };
    if (runGit(repositoryRoot, ["ls-files", "--error-unmatch", "--", targetPath]) !== null) {
        return { state: "tracked", ignoreRule: null };
    }
    const ignored = runGit(repositoryRoot, ["check-ignore", "-v", "--no-index", "--", targetPath]);
    if (ignored !== null) {
        const firstMatch = ignored.split(/\r?\n/, 1)[0];
        const exactRule = firstMatch.split("\t", 1)[0] || firstMatch;
        const pattern = exactRule.match(/^.*?:\d+:(.*)$/)?.[1] ?? "";
        if (!pattern.startsWith("!"))
            return { state: "ignored", ignoreRule: exactRule };
    }
    return { state: "untracked", ignoreRule: null };
}
function hashFile(filePath) {
    return `sha256:${(0, node_crypto_1.createHash)("sha256").update(node_fs_1.default.readFileSync(filePath)).digest("hex")}`;
}
function hashDirectory(directoryPath) {
    const files = [];
    const pending = [directoryPath];
    let totalBytes = 0;
    while (pending.length > 0) {
        const directory = pending.pop();
        for (const name of node_fs_1.default.readdirSync(directory).sort((left, right) => right.localeCompare(left, "en"))) {
            const entryPath = node_path_1.default.join(directory, name);
            const stat = node_fs_1.default.lstatSync(entryPath);
            if (stat.isSymbolicLink())
                continue;
            if (stat.isDirectory()) {
                pending.push(entryPath);
                continue;
            }
            if (!stat.isFile())
                continue;
            files.push(entryPath);
            totalBytes += stat.size;
            if (files.length > MAX_HASHED_FILES || totalBytes > MAX_HASHED_BYTES) {
                throw (0, errors_1.createUsageError)(`Declared target directory '${directoryPath}' exceeds the bounded baseline hashing limit.`);
            }
        }
    }
    const hash = (0, node_crypto_1.createHash)("sha256");
    for (const file of files.sort((left, right) => left.localeCompare(right, "en"))) {
        const relative = (0, planning_document_utils_1.toRepositoryLikePath)(node_path_1.default.relative(directoryPath, file));
        const bytes = node_fs_1.default.readFileSync(file);
        hash.update(`${relative.length}:${relative}:${bytes.byteLength}:`);
        hash.update(bytes);
        hash.update("\n");
    }
    return `sha256:${hash.digest("hex")}`;
}
function parseAdoptions(values, declaredTargets) {
    const adoptions = new Map();
    const declared = new Set(declaredTargets);
    for (const value of values) {
        const separator = value.indexOf("::");
        if (separator <= 0) {
            throw (0, errors_1.createUsageError)(`Invalid --adopt value '${value}'.`, ["Use --adopt <declared-path>::<concrete-rationale>."]);
        }
        const targetPath = (0, paths_1.parseRepositoryRelativePath)(value.slice(0, separator).trim()).normalizedPath;
        const rationale = value.slice(separator + 2).trim();
        if (!declared.has(targetPath)) {
            throw (0, errors_1.createUsageError)(`Adoption path '${targetPath}' is not a declared task target.`);
        }
        if (rationale.length < 12 || /^(tbd|todo|pending|adopted)$/i.test(rationale)) {
            throw (0, errors_1.createUsageError)(`Adoption path '${targetPath}' requires a concrete non-placeholder rationale.`);
        }
        if (adoptions.has(targetPath)) {
            throw (0, errors_1.createUsageError)(`Adoption path '${targetPath}' was provided more than once.`);
        }
        adoptions.set(targetPath, rationale);
    }
    return adoptions;
}
function validateTargetEvidence(targets) {
    const issues = [];
    const seen = new Set();
    for (const target of targets) {
        try {
            (0, paths_1.parseRepositoryRelativePath)(target.path);
        }
        catch {
            issues.push(`Declared baseline target '${target.path}' is not repository-relative.`);
        }
        if (seen.has(target.path))
            issues.push(`Declared baseline target '${target.path}' is duplicated.`);
        seen.add(target.path);
        if (target.exists !== (target.kind !== "absent"))
            issues.push(`Target '${target.path}' has contradictory existence/kind evidence.`);
        if (!["tracked", "untracked", "ignored", "absent"].includes(target.repositoryVisibility)) {
            issues.push(`Target '${target.path}' has invalid repository visibility '${target.repositoryVisibility}'.`);
        }
        if (target.repositoryVisibility === "absent" && target.exists) {
            issues.push(`Visible target '${target.path}' cannot be classified absent.`);
        }
        if (target.repositoryVisibility !== "absent" && !target.exists) {
            issues.push(`Absent target '${target.path}' cannot be classified ${target.repositoryVisibility}.`);
        }
        if (target.repositoryVisibility === "ignored" && (target.ignoreRule === null || target.ignoreRule.trim() === "")) {
            issues.push(`Ignored target '${target.path}' requires its matching ignore rule.`);
        }
        if (target.repositoryVisibility !== "ignored" && target.ignoreRule !== null) {
            issues.push(`Non-ignored target '${target.path}' must not carry an ignore rule.`);
        }
        if (target.exists && (target.contentSha256 === null || !CONTENT_HASH_PATTERN.test(target.contentSha256))) {
            issues.push(`Target '${target.path}' requires a sha256 content hash.`);
        }
        if (!target.exists && target.contentSha256 !== null)
            issues.push(`Absent target '${target.path}' must not carry a content hash.`);
        if (target.preExistingClassification === "clean" && target.dirty)
            issues.push(`Dirty target '${target.path}' cannot be classified clean.`);
        if (target.preExistingClassification === "adopted-pre-staged" && target.adoptionRationale.trim().length < 12) {
            issues.push(`Adopted target '${target.path}' requires a concrete adoption rationale.`);
        }
        if (target.preExistingClassification !== "adopted-pre-staged" && target.adoptionRationale !== "") {
            issues.push(`Non-adopted target '${target.path}' must not carry adoption rationale.`);
        }
    }
    return issues;
}
function renderBaselineBlock(baseline) {
    return [
        `${BASELINE_BLOCK}:`,
        "  schema_version: 1",
        `  baseline_id: ${quote(baseline.baselineId)}`,
        `  task_cycle_id: ${quote(baseline.taskCycleId)}`,
        `  checkpoint_id: ${quote(baseline.checkpointId)}`,
        "  captured_after_readiness: true",
        "  captured_before_implementation_writes: true",
        `  source_revision: ${quote(baseline.sourceRevision)}`,
        `  repository_dirty_state: ${quote(baseline.repositoryDirtyState)}`,
        `  cli_runtime_source: ${quote(baseline.cliRuntimeSource)}`,
        `  cli_build_identity: ${quote(baseline.cliBuildIdentity)}`,
        "  declared_targets:",
        ...baseline.declaredTargets.flatMap((target) => [
            `    - path: ${quote(target.path)}`,
            `      exists: ${target.exists}`,
            `      kind: ${quote(target.kind)}`,
            `      content_sha256: ${target.contentSha256 === null ? "null" : quote(target.contentSha256)}`,
            `      repository_visibility: ${quote(target.repositoryVisibility)}`,
            `      ignore_rule: ${target.ignoreRule === null ? "null" : quote(target.ignoreRule)}`,
            `      dirty: ${target.dirty}`,
            `      pre_existing_classification: ${quote(target.preExistingClassification)}`,
            `      adoption_rationale: ${quote(target.adoptionRationale)}`
        ])
    ];
}
function renderSummaryBlock(evidence) {
    return [
        `${SUMMARY_BLOCK}:`,
        "  schema_version: 1",
        `  baseline_id: ${quote(evidence.baselineId)}`,
        `  task_cycle_id: ${quote(evidence.taskCycleId)}`,
        `  checkpoint_id: ${quote(evidence.checkpointId)}`,
        `  source_revision: ${quote(evidence.sourceRevision)}`,
        `  current_revision: ${quote(evidence.currentRevision)}`,
        ...renderScalarList("fresh_runtime_paths", evidence.freshRuntimePaths),
        ...renderScalarList("executable_validation", evidence.executableValidation),
        ...renderScalarList("satisfied_criterion_ids", evidence.satisfiedCriterionIds),
        "  adopted_paths:",
        ...(evidence.adoptedPaths.length === 0
            ? ["    []"]
            : evidence.adoptedPaths.flatMap((entry) => [
                `    - path: ${quote(entry.path)}`,
                `      rationale: ${quote(entry.rationale)}`
            ])),
        ...renderScalarList("ineligible_paths", evidence.ineligiblePaths)
    ];
}
function renderScalarList(key, values) {
    return values.length === 0
        ? [`  ${key}: []`]
        : [`  ${key}:`, ...values.map((value) => `    - ${quote(value)}`)];
}
function readTargetList(lines) {
    const start = lines.findIndex((line) => line === "  declared_targets:");
    if (start === -1)
        return [];
    const targets = [];
    let current = null;
    for (let index = start + 1; index < lines.length; index += 1) {
        const line = lines[index];
        const first = line.match(/^    - path:\s*(.+)$/);
        if (first !== null) {
            if (current !== null)
                targets.push(targetFromRecord(current));
            current = { path: (0, planning_document_utils_1.parseScalar)(first[1]) };
            continue;
        }
        const field = line.match(/^      ([a-z0-9_]+):\s*(.*)$/);
        if (field !== null && current !== null) {
            current[field[1]] = (0, planning_document_utils_1.parseScalar)(field[2]);
            continue;
        }
        if (line.trim() !== "")
            break;
    }
    if (current !== null)
        targets.push(targetFromRecord(current));
    return targets;
}
function targetFromRecord(record) {
    return {
        path: record.path ?? "",
        exists: record.exists === "true",
        kind: (record.kind ?? "absent"),
        contentSha256: record.content_sha256 === "null" || record.content_sha256 === undefined
            ? null
            : record.content_sha256,
        repositoryVisibility: (record.repository_visibility
            ?? (record.exists === "true" ? "tracked" : "absent")),
        ignoreRule: record.ignore_rule === "null" || record.ignore_rule === undefined ? null : record.ignore_rule,
        dirty: record.dirty === "true",
        preExistingClassification: (record.pre_existing_classification ?? ""),
        adoptionRationale: record.adoption_rationale ?? ""
    };
}
function readAdoptionList(lines) {
    const start = lines.findIndex((line) => line === "  adopted_paths:");
    if (start === -1 || lines[start + 1]?.trim() === "[]")
        return [];
    const entries = [];
    for (let index = start + 1; index < lines.length; index += 1) {
        const match = lines[index].match(/^    - path:\s*(.+)$/);
        if (match === null) {
            if (lines[index].trim() !== "")
                break;
            continue;
        }
        const rationale = lines[index + 1]?.match(/^      rationale:\s*(.*)$/);
        entries.push({ path: (0, planning_document_utils_1.parseScalar)(match[1]), rationale: (0, planning_document_utils_1.parseScalar)(rationale?.[1] ?? "") });
        index += 1;
    }
    return entries;
}
function readScalarList(lines, key) {
    const inline = lines.find((line) => line.startsWith(`  ${key}:`));
    if (inline === undefined)
        return [];
    if (inline.trim() === `${key}: []`)
        return [];
    const start = lines.indexOf(inline);
    const values = [];
    for (let index = start + 1; index < lines.length; index += 1) {
        const match = lines[index].match(/^    -\s+(.+)$/);
        if (match === null)
            break;
        values.push((0, planning_document_utils_1.parseScalar)(match[1]));
    }
    return values;
}
function readScalar(lines, key) {
    const match = lines.find((line) => line.startsWith(`  ${key}:`))?.match(/^  [a-z_]+:\s*(.*)$/);
    return match === undefined || match === null ? undefined : (0, planning_document_utils_1.parseScalar)(match[1]);
}
function readFrontMatterBlock(lines, name) {
    const start = lines.findIndex((line) => line === `${name}:`);
    if (start === -1)
        return null;
    let end = lines.length;
    for (let index = start + 1; index < lines.length; index += 1) {
        if (lines[index] !== "" && !/^\s/.test(lines[index])) {
            end = index;
            break;
        }
    }
    return lines.slice(start + 1, end);
}
function replaceFrontMatterBlock(markdownText, name, blockLines) {
    const lines = markdownText.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (lines[0] !== "---" || closing === -1)
        throw (0, errors_1.createUsageError)("Planning artifact front matter is malformed.");
    const existing = lines.findIndex((line, index) => index > 0 && index < closing && line === `${name}:`);
    if (existing !== -1) {
        let end = closing;
        for (let index = existing + 1; index < closing; index += 1) {
            if (lines[index] !== "" && !/^\s/.test(lines[index])) {
                end = index;
                break;
            }
        }
        lines.splice(existing, end - existing, ...blockLines);
        return lines.join("\n");
    }
    const upstream = lines.findIndex((line, index) => index > 0 && index < closing && line === "upstream:");
    lines.splice(upstream === -1 ? closing : upstream, 0, ...blockLines);
    return lines.join("\n");
}
function removeFrontMatterBlock(markdownText, name) {
    const lines = markdownText.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    const start = lines.findIndex((line, index) => index > 0 && index < closing && line === `${name}:`);
    if (start === -1)
        return markdownText;
    let end = closing;
    for (let index = start + 1; index < closing; index += 1) {
        if (lines[index] !== "" && !/^\s/.test(lines[index])) {
            end = index;
            break;
        }
    }
    lines.splice(start, end - start);
    return lines.join("\n");
}
function readRepositoryPathBullets(text) {
    const paths = [];
    for (const line of text.split(/\r?\n/)) {
        const match = line.trim().match(/^-\s+(?:`([^`]+)`|([^\s]+))$/);
        const raw = match?.[1] ?? match?.[2];
        if (raw === undefined)
            continue;
        try {
            paths.push((0, paths_1.parseRepositoryRelativePath)(raw).normalizedPath);
        }
        catch {
            continue;
        }
    }
    return unique(paths);
}
function readExecutableCommands(text) {
    const commands = [];
    for (const match of text.matchAll(/`([^`\n]+)`/g)) {
        const command = match[1].trim();
        if (/^(?:node|pnpm|npm|yarn|bun|deno|cargo|go|pytest|python\d*|git\s+diff\s+--check)\b/.test(command)) {
            commands.push(command);
        }
    }
    return unique(commands);
}
function runGit(repositoryRoot, args) {
    const result = (0, node_child_process_1.spawnSync)("git", ["-C", repositoryRoot, ...args], {
        encoding: "utf8",
        stdio: ["ignore", "pipe", "ignore"],
        timeout: 5_000,
        maxBuffer: 2_000_000
    });
    return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() : null;
}
function writeFileAtomically(filePath, text) {
    const temporaryPath = `${filePath}.runtime-attribution-${process.pid}.tmp`;
    try {
        node_fs_1.default.writeFileSync(temporaryPath, text, { encoding: "utf8", mode: node_fs_1.default.statSync(filePath).mode });
        node_fs_1.default.renameSync(temporaryPath, filePath);
    }
    finally {
        if (node_fs_1.default.existsSync(temporaryPath))
            node_fs_1.default.unlinkSync(temporaryPath);
    }
}
function baselineCaptureResult(taskDefinitionPath, baseline, action, changed) {
    return {
        taskDefinitionPath,
        action,
        changed,
        writeApplied: changed,
        baseline,
        commandWriteSummary: (0, command_write_summary_1.normalizeCommandWriteSummary)({
            commandFamily: "metadata_update",
            primaryOutputArtifacts: [taskDefinitionPath],
            updatedArtifacts: [{
                    path: taskDefinitionPath,
                    action: changed ? "changed" : "kept",
                    reason: changed ? "provided_material" : "no_write"
                }]
        })
    };
}
function assertIdentity(label, value) {
    if (!IDENTITY_PATTERN.test(value)) {
        throw (0, errors_1.createUsageError)(`Invalid ${label} identity '${value}'.`, ["Use 3-128 printable identity characters: letters, digits, dot, underscore, colon, or hyphen."]);
    }
}
function hashCanonical(value) {
    return `sha256:${(0, node_crypto_1.createHash)("sha256").update(JSON.stringify(value)).digest("hex")}`;
}
function quote(value) {
    return JSON.stringify(value);
}
function unique(values) {
    return [...new Set(values)];
}
function sameValues(left, right) {
    return left.length === right.length && left.every((value, index) => value === right[index]);
}
function sameAdoptions(left, right) {
    return left.length === right.length
        && left.every((entry, index) => entry.path === right[index]?.path && entry.rationale === right[index]?.rationale);
}
function toSnakeCase(value) {
    return value.replace(/[A-Z]/g, (character) => `_${character.toLowerCase()}`);
}
