"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskAttemptAbortError = exports.TaskAttemptOpenError = exports.TaskAttemptSupersedeError = exports.inspectTaskAttemptSupersessionEvidence = exports.inspectSupersessionTargetDelta = void 0;
exports.previewTaskAttemptOpenSync = previewTaskAttemptOpenSync;
exports.applyTaskAttemptOpenSync = applyTaskAttemptOpenSync;
exports.inspectTaskAttemptAbortRecoverySync = inspectTaskAttemptAbortRecoverySync;
exports.previewTaskAttemptAbortSync = previewTaskAttemptAbortSync;
exports.applyTaskAttemptAbortSync = applyTaskAttemptAbortSync;
exports.previewTaskAttemptSupersedeSync = previewTaskAttemptSupersedeSync;
exports.applyTaskAttemptSupersedeSync = applyTaskAttemptSupersedeSync;
exports.materializeTaskAttemptSummary = materializeTaskAttemptSummary;
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_util_1 = require("node:util");
const mutation_preconditions_1 = require("../filesystem/mutation-preconditions");
const repository_transaction_1 = require("../filesystem/repository-transaction");
const paths_1 = require("../paths");
const canonical_write_target_1 = require("../paths/canonical-write-target");
const task_lifecycle_1 = require("./task-lifecycle");
const validation_input_coverage_1 = require("./validation-input-coverage");
const task_lifecycle_timestamps_1 = require("./task-lifecycle-timestamps");
const supersession_1 = require("./task-attempts/supersession");
Object.defineProperty(exports, "inspectSupersessionTargetDelta", { enumerable: true, get: function () { return supersession_1.inspectSupersessionTargetDelta; } });
Object.defineProperty(exports, "inspectTaskAttemptSupersessionEvidence", { enumerable: true, get: function () { return supersession_1.inspectTaskAttemptSupersessionEvidence; } });
Object.defineProperty(exports, "TaskAttemptSupersedeError", { enumerable: true, get: function () { return supersession_1.TaskAttemptSupersedeError; } });
const ATTEMPT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{2,127}$/;
class TaskAttemptOpenError extends Error {
    code;
    constructor(code, message) {
        super(message);
        this.name = "TaskAttemptOpenError";
        this.code = code;
    }
}
exports.TaskAttemptOpenError = TaskAttemptOpenError;
class TaskAttemptAbortError extends Error {
    code;
    constructor(code, message) {
        super(message);
        this.name = "TaskAttemptAbortError";
        this.code = code;
    }
}
exports.TaskAttemptAbortError = TaskAttemptAbortError;
const plans = new WeakMap();
const abortPlans = new WeakMap();
const supersedePlans = new WeakMap();
function previewTaskAttemptOpenSync(request) {
    if (request === null || typeof request !== "object") {
        throw new TaskAttemptOpenError("invalid-input", "An attempt-open request is required.");
    }
    const attemptId = requireAttemptId(request.attemptId);
    const openedAt = requireTimestamp(request.openedAt);
    const openedAtInstant = new Date(openedAt).toISOString();
    const observedAt = currentTimestamp();
    assertAttemptOpenedAtNotFuture(openedAtInstant, observedAt);
    const pair = resolvePair(request.repositoryRoot, request.taskDefinitionPath);
    const taskText = readArtifact(pair.task.runtimePath, pair.task.repositoryRelativePath);
    const summaryText = readArtifact(pair.summary.runtimePath, pair.summary.repositoryRelativePath);
    const projection = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: summaryText
    });
    assertOpenCompatible(projection, taskText);
    const validationInputs = (0, validation_input_coverage_1.inspectTaskDocumentValidationInputCoverage)({
        repositoryRoot: pair.repositoryRoot,
        taskDefinitionPath: pair.task.repositoryRelativePath,
        taskText
    });
    if (!validationInputs.coverage.complete) {
        throw new TaskAttemptOpenError("validation-input-invalid", `Attempt opening requires every static validation path to exist or be declared as writable or generated scope: ${validationInputs.coverage.issues.map((issue) => issue.message).join(" ")}`);
    }
    const taskId = projection.task.taskId;
    const readinessReviewId = projection.task.readinessAuthorization.id;
    const readinessAuthorizationKind = projection.task.readinessAuthorization.kind;
    if (taskId === null || readinessReviewId === null || readinessAuthorizationKind === null) {
        throw new TaskAttemptOpenError("authorization-required", "Attempt opening requires canonical task identity and complete readiness authorization.");
    }
    const attempts = projection.summary?.attempts ?? [];
    if (attempts.some((attempt) => attempt.attemptId === attemptId)
        || readAttemptAbortHistory(summaryText).some((entry) => entry.priorAttemptId === attemptId)) {
        throw new TaskAttemptOpenError("attempt-conflict", `Attempt identity '${attemptId}' already exists in active or aborted history; opening is append-only and never replaces an attempt.`);
    }
    const legacy = projection.compatibilityEvidence.some((entry) => entry.code === "unmaterialized-legacy-attempt");
    let materialization;
    let predecessorAttemptId = null;
    let successorKind = null;
    let contractRevisionRecoveryId = null;
    let chronologyRecoveryId = null;
    const evidenceGaps = [];
    if (attempts.length === 0) {
        materialization = legacy ? "legacy" : "canonical-empty";
        if (legacy) {
            assertLosslessLegacyMaterialization(projection.summary?.legacyImplementationStatus ?? null);
            const legacyImplementationStatus = projection.summary?.legacyImplementationStatus ?? null;
            const legacyReviewDisposition = projection.summary?.legacyReviewDisposition ?? null;
            evidenceGaps.push([
                legacyImplementationStatus === "completed"
                    ? "Legacy completed implementation evidence was preserved on the materialized attempt."
                    : "Legacy evidence did not contain completed implementation evidence; in_progress was used for the new attempt.",
                legacyReviewDisposition === null
                    ? "No accepted-review record was inferred."
                    : `Legacy review token '${legacyReviewDisposition}' was retained only as unbound compatibility evidence; canonical review remains pending.`,
                "No baseline, validation result, or waiver was inferred."
            ].join(" "));
        }
    }
    else {
        materialization = "retry";
        const current = projection.summary?.currentAttempt ?? null;
        const latest = attempts.at(-1) ?? null;
        const predecessor = current ?? (latest?.reviewDisposition === "superseded" || (latest?.reviewDisposition === "contract_gap" &&
            latest.contractRevisionRecoveryId !== null) || (latest?.reviewDisposition === "invalid_chronology" &&
            latest.chronologyRecoveryId !== null)
            ? latest
            : null);
        if (predecessor === null
            || predecessor.attemptId === null
            || predecessor.closedAt === null
            || (predecessor.reviewDisposition !== "changes_requested"
                && predecessor.reviewDisposition !== "superseded"
                && predecessor.reviewDisposition !== "contract_gap"
                && predecessor.reviewDisposition !== "invalid_chronology")) {
            throw new TaskAttemptOpenError("attempt-conflict", "A successor attempt requires the latest predecessor to be closed with changes_requested, superseded, checkpoint-bound recovered contract_gap, or audited invalid_chronology evidence.");
        }
        const predecessorCloseBoundary = predecessor.chronologyEffectiveClosedAt ?? predecessor.closedAt;
        if (Date.parse(openedAt) < Date.parse(predecessorCloseBoundary)) {
            throw new TaskAttemptOpenError("attempt-conflict", "A successor attempt cannot open before its predecessor closed.");
        }
        predecessorAttemptId = predecessor.attemptId;
        if (predecessor.reviewDisposition === "contract_gap") {
            successorKind = "contract_revision";
            contractRevisionRecoveryId = predecessor.contractRevisionRecoveryId;
        }
        else if (predecessor.reviewDisposition === "invalid_chronology"
            || predecessor.chronologyEffectiveClosedAt !== null) {
            successorKind = "chronology_repair";
            chronologyRecoveryId = predecessor.chronologyRecoveryId;
        }
    }
    const nextSummary = materializeTaskAttemptSummary(summaryText, {
        attemptId,
        readinessReviewId,
        readinessAuthorizationKind,
        openedAt,
        predecessorAttemptId,
        successorKind,
        contractRevisionRecoveryId,
        chronologyRecoveryId,
        implementationStatus: materialization === "legacy"
            ? materializedLegacyImplementationStatus(projection.summary?.legacyImplementationStatus ?? null)
            : "in_progress",
        legacyReviewDisposition: materialization === "legacy"
            ? projection.summary?.legacyReviewDisposition ?? null
            : null
    });
    const proposed = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: nextSummary
    });
    if (proposed.blockingFindings.length > 0) {
        throw new TaskAttemptOpenError("pair-invalid", `Attempt opening would violate pair invariants: ${proposed.blockingFindings.map((finding) => finding.message).join(" ")}`);
    }
    const preconditions = [];
    for (const target of [pair.task, pair.summary]) {
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target));
        preconditions.push((0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target));
    }
    const snapshot = {
        taskId,
        taskDefinitionPath: pair.task.repositoryRelativePath,
        implementationSummaryPath: pair.summary.repositoryRelativePath,
        attemptId,
        openedAt,
        openedAtInstant,
        observedAt,
        readinessReviewId,
        readinessAuthorizationKind,
        predecessorAttemptId,
        successorKind,
        contractRevisionRecoveryId,
        chronologyRecoveryId,
        materialization,
        evidenceGaps,
        taskRevision: sha256(taskText),
        implementationSummaryRevision: sha256(summaryText),
        intendedPaths: [pair.summary.repositoryRelativePath],
        changedPaths: [],
        expected: preconditions.map(toExpectedCondition),
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null
    };
    plans.set(snapshot, {
        repositoryRoot: pair.repositoryRoot,
        summaryText: nextSummary,
        preconditions,
        snapshot: cloneResult(snapshot),
        openedAtEpochMs: Date.parse(openedAtInstant)
    });
    return snapshot;
}
function applyTaskAttemptOpenSync(preview, options = {}) {
    const plan = plans.get(preview);
    if (plan === undefined) {
        throw new TaskAttemptOpenError("stale-preview", "Attempt apply requires the original in-process preview. Refresh the preview.");
    }
    const observedAt = currentTimestamp();
    assertAttemptOpenedAtNotFuture(new Date(plan.openedAtEpochMs).toISOString(), observedAt);
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(plan.repositoryRoot, {
        writes: [{ path: plan.snapshot.implementationSummaryPath, contents: plan.summaryText }],
        preconditions: plan.preconditions
    }, options.transaction);
    return {
        ...cloneResult(plan.snapshot),
        observedAt,
        changedPaths: transaction.entries.slice(0, transaction.canonicalWrites).map((entry) => entry.path),
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath: transaction.outcome === "incomplete" ? transaction.transactionPath : null,
        failure: transaction.failure ?? (transaction.cleanupErrors.length > 0 ? transaction.cleanupErrors.join(" ") : null)
    };
}
function assertAttemptOpenedAtNotFuture(openedAtInstant, observedAt) {
    if (Date.parse(openedAtInstant) <= Date.parse(observedAt))
        return;
    throw new TaskAttemptOpenError("opened-at-in-future", `Attempt opened_at resolves to '${openedAtInstant}', but the command observed '${observedAt}'. No attempt was opened.`);
}
function currentTimestamp() {
    return new Date(Date.now()).toISOString();
}
function inspectTaskAttemptAbortRecoverySync(repositoryRoot, taskDefinitionPath, expectedAttemptId) {
    const pair = resolvePair(repositoryRoot, taskDefinitionPath);
    const taskText = readArtifact(pair.task.runtimePath, pair.task.repositoryRelativePath);
    const summaryText = readArtifact(pair.summary.runtimePath, pair.summary.repositoryRelativePath);
    assertTaskDefinitionArtifact(taskText, pair.task.repositoryRelativePath, "abort recovery");
    const projection = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: summaryText
    });
    const current = projection.summary?.currentAttempt ?? null;
    const currentAttemptId = current?.attemptId ?? null;
    const blockers = abortEligibilityBlockers(projection, summaryText, currentAttemptId, expectedAttemptId);
    return {
        taskDefinitionPath: pair.task.repositoryRelativePath,
        implementationSummaryPath: pair.summary.repositoryRelativePath,
        taskRevision: sha256(taskText),
        currentAttemptId,
        eligible: blockers.length === 0,
        blockers
    };
}
function previewTaskAttemptAbortSync(request) {
    if (request === null || typeof request !== "object") {
        throw new TaskAttemptAbortError("invalid-input", "An attempt-abort request is required.");
    }
    const attemptId = requireAbortAttemptId(request.attemptId);
    const taskRevision = requireTaskRevision(request.taskRevision);
    const recordedBy = requireAbortText(request.recordedBy, "Attempt-abort actor");
    const recordedAt = requireAbortTimestamp(request.recordedAt);
    (0, task_lifecycle_timestamps_1.requireObservedLifecycleTimestamp)({
        value: recordedAt,
        field: "recorded_at",
        label: "Attempt-abort time"
    });
    const reason = requireAbortText(request.reason, "Attempt-abort reason");
    const pair = resolvePair(request.repositoryRoot, request.taskDefinitionPath);
    const taskText = readArtifact(pair.task.runtimePath, pair.task.repositoryRelativePath);
    const summaryText = readArtifact(pair.summary.runtimePath, pair.summary.repositoryRelativePath);
    assertTaskDefinitionArtifact(taskText, pair.task.repositoryRelativePath, "attempt-abort");
    const existingTaskHistory = readAttemptAbortHistory(taskText)
        .filter((entry) => entry.priorAttemptId === attemptId);
    const existingSummaryHistory = readAttemptAbortHistory(summaryText)
        .filter((entry) => entry.priorAttemptId === attemptId);
    if (existingTaskHistory.length > 0 || existingSummaryHistory.length > 0) {
        if (existingTaskHistory.length !== 1
            || existingSummaryHistory.length !== 1
            || !sameAbortRecord(existingTaskHistory[0], existingSummaryHistory[0])
            || !matchesAbortRequest(existingTaskHistory[0], {
                attemptId,
                taskRevision,
                recordedBy,
                recordedAt,
                reason
            })) {
            throw new TaskAttemptAbortError("attempt-conflict", `Attempt '${attemptId}' already has conflicting or incomplete abort history. No files were written.`);
        }
        return {
            taskId: readTaskIdentity(taskText),
            taskDefinitionPath: pair.task.repositoryRelativePath,
            implementationSummaryPath: pair.summary.repositoryRelativePath,
            priorAttemptId: attemptId,
            abortState: "aborted",
            recordedBy,
            recordedAt,
            reason,
            boundTaskRevision: taskRevision,
            taskRevision: sha256(taskText),
            implementationSummaryRevision: sha256(summaryText),
            idempotent: true,
            evidenceGaps: [],
            intendedPaths: [],
            changedPaths: [],
            expected: [],
            writeOutcome: "no-write",
            transactionId: null,
            conflicts: [],
            recoveryPath: null,
            failure: null
        };
    }
    const observedTaskRevision = sha256(taskText);
    if (observedTaskRevision !== taskRevision) {
        throw new TaskAttemptAbortError("stale-revision", `Attempt-abort expected task revision '${taskRevision}', but current bytes are '${observedTaskRevision}'. No files were written.`);
    }
    const projection = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: summaryText
    });
    const blockers = abortEligibilityBlockers(projection, summaryText, attemptId, attemptId);
    if (blockers.length > 0) {
        const evidenceBearing = blockers.some((blocker) => blocker.startsWith("Evidence-bearing"));
        throw new TaskAttemptAbortError(evidenceBearing ? "evidence-bearing-attempt" : "attempt-conflict", `${blockers.join(" ")} No files were written.`);
    }
    const current = projection.summary?.currentAttempt;
    if (current?.openedAt !== null
        && current?.openedAt !== undefined
        && Date.parse(recordedAt) < Date.parse(current.openedAt)
        && Date.parse(current.openedAt) <= Date.now()) {
        throw new TaskAttemptAbortError("invalid-input", "Attempt-abort time cannot precede the current attempt opened_at timestamp.");
    }
    const archived = archiveCurrentAttempt(summaryText, attemptId, {
        priorAttemptId: attemptId,
        state: "aborted",
        recordedBy,
        recordedAt,
        reason,
        taskRevision
    });
    const nextTaskText = appendAttemptAbortHistory(resetTaskReadinessAuthorization(taskText), {
        priorAttemptId: attemptId,
        state: "aborted",
        recordedBy,
        recordedAt,
        reason,
        taskRevision,
        priorAttempt: archived.priorAttempt
    });
    const nextSummaryText = appendAttemptAbortHistory(archived.summaryText, {
        priorAttemptId: attemptId,
        state: "aborted",
        recordedBy,
        recordedAt,
        reason,
        taskRevision,
        priorAttempt: archived.priorAttempt
    });
    const proposed = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: nextTaskText,
        implementationSummary: nextSummaryText
    });
    if (proposed.blockingFindings.length > 0) {
        throw new TaskAttemptAbortError("pair-invalid", `Attempt-abort reset would violate pair invariants: ${proposed.blockingFindings.map((finding) => finding.message).join(" ")}`);
    }
    const preconditions = [];
    for (const target of [pair.task, pair.summary]) {
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target));
        preconditions.push((0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target));
    }
    const writes = [
        { path: pair.task.repositoryRelativePath, contents: nextTaskText },
        { path: pair.summary.repositoryRelativePath, contents: nextSummaryText }
    ].sort((left, right) => left.path.localeCompare(right.path));
    const snapshot = {
        taskId: readTaskIdentity(taskText),
        taskDefinitionPath: pair.task.repositoryRelativePath,
        implementationSummaryPath: pair.summary.repositoryRelativePath,
        priorAttemptId: attemptId,
        abortState: "aborted",
        recordedBy,
        recordedAt,
        reason,
        boundTaskRevision: taskRevision,
        taskRevision: observedTaskRevision,
        implementationSummaryRevision: sha256(summaryText),
        idempotent: false,
        evidenceGaps: [],
        intendedPaths: writes.map((write) => write.path),
        changedPaths: [],
        expected: preconditions.map(toExpectedCondition),
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null
    };
    abortPlans.set(snapshot, {
        repositoryRoot: pair.repositoryRoot,
        writes,
        preconditions,
        snapshot: cloneAbortResult(snapshot),
        recordedAt
    });
    return snapshot;
}
function applyTaskAttemptAbortSync(preview, options = {}) {
    if (preview.writeOutcome === "no-write" && preview.idempotent) {
        return cloneAbortResult(preview);
    }
    const plan = abortPlans.get(preview);
    if (plan === undefined) {
        throw new TaskAttemptAbortError("stale-preview", "Attempt-abort apply requires the original in-process preview. Refresh the preview.");
    }
    (0, task_lifecycle_timestamps_1.revalidateObservedLifecycleTimestamp)(plan.recordedAt, "recorded_at", "Attempt-abort time");
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(plan.repositoryRoot, {
        writes: plan.writes,
        preconditions: plan.preconditions
    }, options.transaction);
    return {
        ...cloneAbortResult(plan.snapshot),
        changedPaths: transaction.entries.slice(0, transaction.canonicalWrites).map((entry) => entry.path),
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath: transaction.outcome === "incomplete" ? transaction.transactionPath : null,
        failure: transaction.failure ?? (transaction.cleanupErrors.length > 0 ? transaction.cleanupErrors.join(" ") : null)
    };
}
function previewTaskAttemptSupersedeSync(request) {
    if (request === null || typeof request !== "object") {
        throw new supersession_1.TaskAttemptSupersedeError("invalid-input", "An attempt-supersede request is required.");
    }
    const attemptId = (0, supersession_1.requireSupersedeAttemptId)(request.attemptId);
    const taskRevision = (0, supersession_1.requireSupersedeTaskRevision)(request.taskRevision);
    const recordedBy = (0, supersession_1.requireSupersedeText)(request.recordedBy, "Attempt-supersede actor");
    const recordedAt = (0, supersession_1.requireSupersedeTimestamp)(request.recordedAt);
    (0, task_lifecycle_timestamps_1.requireObservedLifecycleTimestamp)({
        value: recordedAt,
        field: "recorded_at",
        label: "Attempt-supersede time"
    });
    const reason = (0, supersession_1.requireSupersedeText)(request.reason, "Attempt-supersede reason");
    const pair = resolvePair(request.repositoryRoot, request.taskDefinitionPath);
    const taskText = readArtifact(pair.task.runtimePath, pair.task.repositoryRelativePath);
    const summaryText = readArtifact(pair.summary.runtimePath, pair.summary.repositoryRelativePath);
    const observedTaskRevision = sha256(taskText);
    const observedSummaryRevision = sha256(summaryText);
    const projection = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: taskText,
        implementationSummary: summaryText
    });
    const selectedAttempt = projection.summary?.attempts.find((attempt) => attempt.attemptId === attemptId) ?? null;
    const baseline = (0, supersession_1.readSupersessionBaseline)(pair.summary.repositoryRelativePath, summaryText, attemptId);
    if (selectedAttempt?.reviewDisposition === "superseded") {
        if (selectedAttempt.dispositionBy !== recordedBy
            || selectedAttempt.dispositionAt !== recordedAt
            || selectedAttempt.closedAt !== recordedAt
            || selectedAttempt.dispositionReason !== reason
            || selectedAttempt.supersededTaskRevision !== taskRevision
            || selectedAttempt.supersededSummaryRevision === null) {
            throw new supersession_1.TaskAttemptSupersedeError("attempt-conflict", `Attempt '${attemptId}' already has conflicting supersession evidence. No files were written.`);
        }
        return {
            taskId: readTaskIdentity(taskText),
            taskDefinitionPath: pair.task.repositoryRelativePath,
            implementationSummaryPath: pair.summary.repositoryRelativePath,
            priorAttemptId: attemptId,
            supersessionState: "superseded",
            recordedBy,
            recordedAt,
            reason,
            boundTaskRevision: taskRevision,
            taskRevision: observedTaskRevision,
            implementationSummaryRevision: observedSummaryRevision,
            nextTaskRevision: observedTaskRevision,
            nextImplementationSummaryRevision: observedSummaryRevision,
            baselineId: baseline.baselineId,
            idempotent: true,
            evidenceGaps: [],
            intendedPaths: [],
            changedPaths: [],
            expected: [],
            writeOutcome: "no-write",
            transactionId: null,
            conflicts: [],
            recoveryPath: null,
            failure: null
        };
    }
    if (observedTaskRevision !== taskRevision) {
        throw new supersession_1.TaskAttemptSupersedeError("stale-revision", `Attempt-supersede expected task revision '${taskRevision}', but current bytes are '${observedTaskRevision}'. No files were written.`);
    }
    const structuralBlockers = projection.blockingFindings.filter((finding) => finding.code !== "stale-readiness-authorization"
        && finding.code !== "stale-attempt-readiness-reference");
    if (structuralBlockers.length > 0) {
        throw new supersession_1.TaskAttemptSupersedeError("pair-invalid", `Task pair is not structurally recoverable for supersession: ${structuralBlockers.map((finding) => finding.message).join(" ")}`);
    }
    const current = projection.summary?.currentAttempt ?? null;
    if (projection.task.status !== "draft"
        || projection.task.readiness !== "ready_to_implement"
        || !projection.task.readinessAuthorization.complete
        || !projection.task.readinessAuthorization.valid
        || projection.task.readinessAuthorization.applicable) {
        throw new supersession_1.TaskAttemptSupersedeError("attempt-conflict", "Attempt supersession requires a draft ready_to_implement task whose previously valid readiness authorization is now stale.");
    }
    if (current === null || current.attemptId !== attemptId) {
        throw new supersession_1.TaskAttemptSupersedeError("attempt-conflict", `Attempt-supersede selected '${attemptId}', but it is not the one open current attempt.`);
    }
    if (current.closedAt !== null
        || current.reviewDisposition !== "pending"
        || (current.implementationStatus !== "pending" && current.implementationStatus !== "in_progress")) {
        throw new supersession_1.TaskAttemptSupersedeError("evidence-bearing-attempt", "Attempt supersession requires an open pending or in_progress attempt with pending review disposition.");
    }
    if (current.openedAt !== null && Date.parse(recordedAt) < Date.parse(current.openedAt)) {
        throw new supersession_1.TaskAttemptSupersedeError("invalid-input", "Attempt-supersede time cannot precede the current attempt opened_at timestamp.");
    }
    const evidence = (0, supersession_1.inspectTaskAttemptSupersessionEvidence)(summaryText, attemptId);
    if (evidence.length > 0) {
        throw new supersession_1.TaskAttemptSupersedeError("evidence-bearing-attempt", `Evidence-bearing attempt '${attemptId}' cannot be superseded: ${evidence.join("; ")}. No files were written.`);
    }
    if (baseline.taskCycleId !== attemptId
        || baseline.checkpointId !== current.readinessReviewId
        || !baseline.capturedBeforeImplementationWrites
        || !baseline.observationsComplete) {
        throw new supersession_1.TaskAttemptSupersedeError("baseline-required", "Attempt supersession requires a complete attempt-owned baseline captured before implementation writes and bound to the current attempt/readiness identities.");
    }
    const targetDeltaBlockers = (0, supersession_1.inspectSupersessionTargetDelta)(pair.repositoryRoot, pair.task.repositoryRelativePath, taskText, baseline);
    if (targetDeltaBlockers.length > 0) {
        throw new supersession_1.TaskAttemptSupersedeError("implementation-delta", `Attempt supersession found post-baseline target evidence: ${targetDeltaBlockers.join(" ")} No files were written.`);
    }
    const nextTaskText = resetTaskReadinessAuthorization(taskText);
    const nextSummaryText = (0, supersession_1.supersedeCurrentAttempt)(summaryText, attemptId, {
        recordedBy,
        recordedAt,
        reason,
        taskRevision: observedTaskRevision,
        summaryRevision: observedSummaryRevision
    });
    const proposed = (0, task_lifecycle_1.projectTaskLifecyclePair)({
        taskDefinition: nextTaskText,
        implementationSummary: nextSummaryText
    });
    if (proposed.blockingFindings.length > 0) {
        throw new supersession_1.TaskAttemptSupersedeError("pair-invalid", `Attempt-supersede reset would violate pair invariants: ${proposed.blockingFindings.map((finding) => finding.message).join(" ")}`);
    }
    const preconditions = [];
    for (const target of [pair.task, pair.summary]) {
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target));
        preconditions.push((0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target));
    }
    const writes = [
        { path: pair.task.repositoryRelativePath, contents: nextTaskText },
        { path: pair.summary.repositoryRelativePath, contents: nextSummaryText }
    ].sort((left, right) => left.path.localeCompare(right.path));
    const snapshot = {
        taskId: readTaskIdentity(taskText),
        taskDefinitionPath: pair.task.repositoryRelativePath,
        implementationSummaryPath: pair.summary.repositoryRelativePath,
        priorAttemptId: attemptId,
        supersessionState: "superseded",
        recordedBy,
        recordedAt,
        reason,
        boundTaskRevision: taskRevision,
        taskRevision: observedTaskRevision,
        implementationSummaryRevision: observedSummaryRevision,
        nextTaskRevision: sha256(nextTaskText),
        nextImplementationSummaryRevision: sha256(nextSummaryText),
        baselineId: baseline.baselineId,
        idempotent: false,
        evidenceGaps: [],
        intendedPaths: writes.map((write) => write.path),
        changedPaths: [],
        expected: preconditions.map(toExpectedCondition),
        writeOutcome: "previewed",
        transactionId: null,
        conflicts: [],
        recoveryPath: null,
        failure: null
    };
    supersedePlans.set(snapshot, {
        repositoryRoot: pair.repositoryRoot,
        writes,
        preconditions,
        snapshot: cloneSupersedeResult(snapshot),
        recordedAt
    });
    return snapshot;
}
function applyTaskAttemptSupersedeSync(preview, options = {}) {
    if (preview.writeOutcome === "no-write" && preview.idempotent) {
        return cloneSupersedeResult(preview);
    }
    const plan = supersedePlans.get(preview);
    if (plan === undefined) {
        throw new supersession_1.TaskAttemptSupersedeError("stale-preview", "Attempt-supersede apply requires the original in-process preview. Refresh the preview.");
    }
    (0, task_lifecycle_timestamps_1.revalidateObservedLifecycleTimestamp)(plan.recordedAt, "recorded_at", "Attempt-supersede time");
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(plan.repositoryRoot, { writes: plan.writes, preconditions: plan.preconditions }, options.transaction);
    return {
        ...cloneSupersedeResult(plan.snapshot),
        changedPaths: transaction.entries.slice(0, transaction.canonicalWrites).map((entry) => entry.path),
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        recoveryPath: transaction.outcome === "incomplete" ? transaction.transactionPath : null,
        failure: transaction.failure ?? (transaction.cleanupErrors.length > 0 ? transaction.cleanupErrors.join(" ") : null)
    };
}
function assertOpenCompatible(projection, taskText) {
    if (projection.blockingFindings.length > 0) {
        const authorizationOnly = projection.blockingFindings.every((finding) => finding.code === "stale-readiness-authorization"
            || finding.code === "stale-attempt-readiness-reference");
        if (authorizationOnly) {
            throw new TaskAttemptOpenError("authorization-required", "Attempt opening requires current revision-applicable readiness authorization; the stored authorization is stale.");
        }
        throw new TaskAttemptOpenError("pair-invalid", `Task pair is invalid: ${projection.blockingFindings.map((finding) => finding.message).join(" ")}`);
    }
    if (projection.task.status !== "draft" || projection.task.readiness !== "ready_to_implement") {
        throw new TaskAttemptOpenError("authorization-required", "Attempt opening requires a draft task with readiness ready_to_implement.");
    }
    const authorization = projection.task.readinessAuthorization;
    if (!authorization.complete
        || !authorization.valid
        || !authorization.applicable
        || (authorization.kind === "review"
            && !(0, task_lifecycle_1.isTaskReadinessAuthorizationRevisionApplicable)(taskText, authorization.taskRevision))) {
        throw new TaskAttemptOpenError("authorization-required", "Attempt opening requires complete revision-applicable readiness authorization; no readiness or waiver evidence was inferred.");
    }
    if ((projection.summary?.attempts ?? []).some((attempt) => attempt.closedAt === null)) {
        throw new TaskAttemptOpenError("attempt-conflict", "At most one implementation attempt may be open.");
    }
}
function assertLosslessLegacyMaterialization(implementationStatus) {
    if (implementationStatus === "blocked") {
        throw new TaskAttemptOpenError("legacy-evidence-gap", "Legacy blocked implementation evidence cannot be rebound without blocker audit evidence. No files were written.");
    }
}
function materializedLegacyImplementationStatus(value) {
    return value === "completed" ? "completed" : "in_progress";
}
function materializeTaskAttemptSummary(markdown, attempt) {
    const newline = markdown.includes("\r\n") ? "\r\n" : "\n";
    const hadFinalNewline = markdown.endsWith("\n");
    const lines = markdown.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (lines[0] !== "---" || closing < 0) {
        throw new TaskAttemptOpenError("artifact-unreadable", "Implementation summary has malformed YAML front matter.");
    }
    const currentIndex = lines.findIndex((line, index) => index > 0 && index < closing && /^current_attempt_id:/.test(line));
    if (currentIndex >= 0) {
        lines[currentIndex] = `current_attempt_id: ${quote(attempt.attemptId)}`;
    }
    else {
        const insertion = topLevelInsertion(lines, closing);
        lines.splice(insertion, 0, `current_attempt_id: ${quote(attempt.attemptId)}`);
    }
    const legacyImplementationIndex = lines.findIndex((line, index) => index > 0 && index < closing && /^implementation_status:/.test(line));
    if (legacyImplementationIndex >= 0) {
        lines.splice(legacyImplementationIndex, 1);
    }
    const refreshedLegacyClosing = lines.findIndex((line, index) => index > 0 && line === "---");
    const legacyReviewIndex = lines.findIndex((line, index) => index > 0 && index < refreshedLegacyClosing && /^review_disposition:/.test(line));
    if (legacyReviewIndex >= 0) {
        lines.splice(legacyReviewIndex, 1);
    }
    const legacyArtifactStatus = removeLegacyTopLevelField(lines, "status");
    const legacyReadiness = removeLegacyTopLevelField(lines, "readiness");
    const legacyCompletedAt = removeLegacyTopLevelField(lines, "completed_at");
    let refreshedClosing = lines.findIndex((line, index) => index > 0 && line === "---");
    const attemptsIndex = lines.findIndex((line, index) => index > 0 && index < refreshedClosing && /^attempts:/.test(line));
    const attemptLines = renderAttempt({
        ...attempt,
        legacyArtifactStatus,
        legacyReadiness,
        legacyCompletedAt
    });
    if (attemptsIndex < 0) {
        const insertion = topLevelInsertion(lines, refreshedClosing);
        lines.splice(insertion, 0, "attempts:", ...attemptLines);
    }
    else if (/^attempts:\s*\[\]\s*$/.test(lines[attemptsIndex])) {
        lines.splice(attemptsIndex, 1, "attempts:", ...attemptLines);
    }
    else if (lines[attemptsIndex].trim() === "attempts:") {
        refreshedClosing = lines.findIndex((line, index) => index > 0 && line === "---");
        let insertion = attemptsIndex + 1;
        while (insertion < refreshedClosing && (/^\s/.test(lines[insertion]) || lines[insertion].trim() === ""))
            insertion += 1;
        lines.splice(insertion, 0, ...attemptLines);
    }
    else {
        throw new TaskAttemptOpenError("pair-invalid", "Implementation summary uses an unsupported attempts collection shape.");
    }
    const rendered = lines.join(newline);
    return hadFinalNewline && !rendered.endsWith(newline) ? `${rendered}${newline}` : rendered;
}
function renderAttempt(attempt) {
    return [
        `  - attempt_id: ${quote(attempt.attemptId)}`,
        `    readiness_review_id: ${quote(attempt.readinessReviewId)}`,
        `    readiness_authorization_kind: ${attempt.readinessAuthorizationKind}`,
        ...(attempt.readinessAuthorizationKind === "waiver"
            ? [`    readiness_waiver_id: ${quote(attempt.readinessReviewId)}`]
            : []),
        `    opened_at: ${quote(attempt.openedAt)}`,
        "    closed_at: null",
        `    implementation_status: ${attempt.implementationStatus}`,
        "    validation_results: []",
        "    deviations: []",
        "    waivers: []",
        "    blockers: []",
        ...(attempt.legacyReviewDisposition === null
            ? []
            : [`    legacy_unbound_review_disposition: ${quote(attempt.legacyReviewDisposition)}`]),
        ...(attempt.legacyArtifactStatus === null
            ? []
            : [`    legacy_unbound_artifact_status: ${attempt.legacyArtifactStatus}`]),
        ...(attempt.legacyReadiness === null
            ? []
            : [`    legacy_unbound_readiness: ${attempt.legacyReadiness}`]),
        ...(attempt.legacyCompletedAt === null
            ? []
            : [`    legacy_unbound_completed_at: ${attempt.legacyCompletedAt}`]),
        "    review_disposition: pending",
        ...(attempt.predecessorAttemptId === null
            ? []
            : [`    predecessor_attempt_id: ${quote(attempt.predecessorAttemptId)}`]),
        ...(attempt.successorKind === "review_repair"
            ? [
                "    successor_kind: review_repair",
                `    repair_reason: ${quote(attempt.repairReason ?? "")}`,
                `    repair_readiness_review_id: ${quote(attempt.repairReadinessReviewId ?? "")}`,
                `    repair_task_revision: ${quote(attempt.repairTaskRevision ?? "")}`,
                `    repair_reviewed_by: ${quote(attempt.repairReviewedBy ?? "")}`,
                `    repair_reviewed_at: ${quote(attempt.repairReviewedAt ?? "")}`
            ]
            : []),
        ...(attempt.successorKind === "scope_recovery"
            ? [
                "    successor_kind: scope_recovery",
                `    scope_recovery_id: ${quote(attempt.scopeRecoveryId ?? "")}`
            ]
            : []),
        ...(attempt.successorKind === "contract_revision"
            ? [
                "    successor_kind: contract_revision",
                `    predecessor_contract_revision_recovery_id: ${quote(attempt.contractRevisionRecoveryId ?? "")}`
            ]
            : []),
        ...(attempt.successorKind === "chronology_repair"
            ? [
                "    successor_kind: chronology_repair",
                `    predecessor_chronology_recovery_id: ${quote(attempt.chronologyRecoveryId ?? "")}`
            ]
            : [])
    ];
}
function removeLegacyTopLevelField(lines, field) {
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    const pattern = new RegExp(`^${field}:\\s*(.*)$`);
    const index = lines.findIndex((line, lineIndex) => lineIndex > 0 && lineIndex < closing && pattern.test(line));
    if (index < 0)
        return null;
    const match = lines[index].match(pattern);
    lines.splice(index, 1);
    return match?.[1].trim() || "null";
}
function abortEligibilityBlockers(projection, summaryText, currentAttemptId, expectedAttemptId) {
    const blockers = [];
    if (projection.blockingFindings.length > 0) {
        blockers.push(`Task pair is not safe for attempt recovery: ${projection.blockingFindings.map((finding) => finding.message).join(" ")}`);
        return blockers;
    }
    const current = projection.summary?.currentAttempt ?? null;
    if (projection.task.status !== "draft"
        || projection.task.readiness !== "ready_to_implement"
        || !projection.task.readinessAuthorization.complete
        || !projection.task.readinessAuthorization.valid
        || !projection.task.readinessAuthorization.applicable) {
        blockers.push("Attempt-abort requires a draft, ready_to_implement task with complete revision-applicable readiness authorization.");
    }
    if (current === null || currentAttemptId === null) {
        blockers.push("Attempt-abort requires one materialized current attempt.");
        return blockers;
    }
    if (expectedAttemptId !== undefined && currentAttemptId !== expectedAttemptId) {
        blockers.push(`Attempt-abort selected '${expectedAttemptId}', but the current attempt is '${currentAttemptId}'.`);
    }
    if (current.closedAt !== null
        || current.reviewDisposition !== "pending"
        || (current.implementationStatus !== "pending" && current.implementationStatus !== "in_progress")) {
        blockers.push("Attempt-abort requires an open pending attempt whose implementation status is pending or in_progress.");
    }
    const evidence = attemptMaterialEvidence(summaryText, currentAttemptId);
    if (evidence.length > 0) {
        blockers.push(`Evidence-bearing attempt '${currentAttemptId}' cannot be aborted: ${evidence.join("; ")}.`);
    }
    return blockers;
}
function attemptMaterialEvidence(summaryText, attemptId) {
    const lines = frontMatterLines(summaryText);
    const range = locateAttemptRange(lines, attemptId);
    if (range === null)
        return ["the current attempt is not materialized"];
    const attemptLines = lines.slice(range.start, range.end);
    const evidence = [];
    if (attemptLines.some((line) => /^\s{4}runtime_attribution_baseline:/.test(line))) {
        evidence.push("runtime attribution baseline is present");
    }
    for (const field of ["validation_results", "deviations", "waivers", "blockers"]) {
        const raw = attemptFieldRaw(attemptLines, field);
        if (raw !== null && !isEmptyCollectionScalar(raw)) {
            evidence.push(`${field} is not empty`);
        }
    }
    for (const field of [
        "disposition_by",
        "disposition_at",
        "disposition_reason",
        "blocker_reason",
        "blocker_next",
        "blocked_by",
        "blocked_at",
        "review_waiver_id"
    ]) {
        const raw = attemptFieldRaw(attemptLines, field);
        if (raw !== null && !isNullScalar(raw) && parseYamlScalar(raw).trim() !== "") {
            evidence.push(`${field} is present`);
        }
    }
    if (lines.some((line) => /^runtime_attribution:\s*$/.test(line))) {
        evidence.push("summary runtime closeout evidence is present");
    }
    return evidence;
}
function archiveCurrentAttempt(summaryText, attemptId, abort) {
    const newline = summaryText.includes("\r\n") ? "\r\n" : "\n";
    const hadFinalNewline = summaryText.endsWith("\n");
    const lines = summaryText.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (lines[0] !== "---" || closing < 0) {
        throw new TaskAttemptAbortError("artifact-unreadable", "Implementation summary has malformed YAML front matter.");
    }
    const ranges = locateAttemptRanges(lines.slice(1, closing + 1));
    const currentRange = ranges.find((range) => range.attemptId === attemptId);
    if (currentRange === undefined) {
        throw new TaskAttemptAbortError("attempt-conflict", `Current attempt '${attemptId}' is not materialized for append-only abort recovery.`);
    }
    const adjustedStart = currentRange.start + 1;
    const adjustedEnd = currentRange.end + 1;
    const priorAttempt = lines.slice(adjustedStart, adjustedEnd).join(newline);
    lines.splice(adjustedStart, adjustedEnd - adjustedStart);
    const attemptsIndex = lines.findIndex((line, index) => index > 0 && index < closing && /^attempts:\s*$/.test(line));
    if (attemptsIndex < 0) {
        throw new TaskAttemptAbortError("pair-invalid", "Implementation summary attempts collection is not canonical.");
    }
    const remainingRanges = locateAttemptRanges(lines.slice(1, lines.findIndex((line, index) => index > 0 && line === "---") + 1));
    if (remainingRanges.length === 0) {
        lines[attemptsIndex] = "attempts: []";
    }
    const currentIndex = lines.findIndex((line, index) => index > 0 && index < closing && /^current_attempt_id:/.test(line));
    if (currentIndex < 0) {
        throw new TaskAttemptAbortError("pair-invalid", "Implementation summary current_attempt_id is missing.");
    }
    const previousAttemptId = remainingRanges.at(-1)?.attemptId ?? null;
    lines[currentIndex] = `current_attempt_id: ${previousAttemptId === null ? "null" : quote(previousAttemptId)}`;
    const rendered = lines.join(newline);
    return {
        summaryText: hadFinalNewline && !rendered.endsWith(newline) ? `${rendered}${newline}` : rendered,
        priorAttempt: JSON.stringify({
            attemptId,
            state: abort.state,
            raw: priorAttempt
        })
    };
}
function resetTaskReadinessAuthorization(taskText) {
    const newline = taskText.includes("\r\n") ? "\r\n" : "\n";
    const hadFinalNewline = taskText.endsWith("\n");
    const lines = taskText.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (lines[0] !== "---" || closing < 0) {
        throw new TaskAttemptAbortError("artifact-unreadable", "Task definition has malformed YAML front matter.");
    }
    const removable = new Set([
        "readiness_review_id",
        "readiness_review_revision",
        "readiness_review_protocol_version",
        "readiness_reviewed_by",
        "readiness_reviewed_at",
        "readiness_waiver_id"
    ]);
    for (let index = closing - 1; index > 0; index -= 1) {
        const field = lines[index].match(/^([A-Za-z0-9_]+):/)?.[1];
        if (field !== undefined && removable.has(field))
            lines.splice(index, 1);
    }
    const refreshedClosing = lines.findIndex((line, index) => index > 0 && line === "---");
    const readinessIndex = lines.findIndex((line, index) => index > 0 && index < refreshedClosing && /^readiness:/.test(line));
    if (readinessIndex < 0) {
        throw new TaskAttemptAbortError("pair-invalid", "Task definition readiness field is missing.");
    }
    lines[readinessIndex] = "readiness: needs_more_evidence";
    const rendered = lines.join(newline);
    return hadFinalNewline && !rendered.endsWith(newline) ? `${rendered}${newline}` : rendered;
}
function appendAttemptAbortHistory(markdown, record) {
    const newline = markdown.includes("\r\n") ? "\r\n" : "\n";
    const hadFinalNewline = markdown.endsWith("\n");
    const lines = markdown.split(/\r?\n/);
    let closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (lines[0] !== "---" || closing < 0) {
        throw new TaskAttemptAbortError("artifact-unreadable", "Attempt-abort artifact has malformed YAML front matter.");
    }
    let historyIndex = lines.findIndex((line, index) => index > 0 && index < closing && /^attempt_abort_history:\s*$/.test(line));
    const itemLines = [
        `  - prior_attempt_id: ${quote(record.priorAttemptId)}`,
        "    state: aborted",
        `    aborted_by: ${quote(record.recordedBy)}`,
        `    aborted_at: ${quote(record.recordedAt)}`,
        `    abort_reason: ${quote(record.reason)}`,
        `    task_revision: ${quote(record.taskRevision)}`,
        ...(record.priorAttempt === null
            ? []
            : [`    prior_attempt: ${quote(record.priorAttempt)}`])
    ];
    if (historyIndex < 0) {
        const insertion = topLevelInsertion(lines, closing);
        lines.splice(insertion, 0, "attempt_abort_history:", ...itemLines);
    }
    else {
        let insertion = historyIndex + 1;
        while (insertion < closing
            && (!/^[^\s]/.test(lines[insertion]) || lines[insertion].trim() === "")) {
            insertion += 1;
        }
        lines.splice(insertion, 0, ...itemLines);
    }
    closing = lines.findIndex((line, index) => index > 0 && line === "---");
    if (closing < 0) {
        throw new TaskAttemptAbortError("artifact-unreadable", "Attempt-abort artifact lost its front matter boundary.");
    }
    const rendered = lines.join(newline);
    return hadFinalNewline && !rendered.endsWith(newline) ? `${rendered}${newline}` : rendered;
}
function readAttemptAbortHistory(markdown) {
    const lines = frontMatterLines(markdown);
    const historyIndex = lines.findIndex((line) => /^attempt_abort_history:\s*$/.test(line));
    if (historyIndex < 0)
        return [];
    const records = [];
    for (let index = historyIndex + 1; index < lines.length; index += 1) {
        if (/^[^\s]/.test(lines[index]))
            break;
        if (!/^\s{2}-\s+prior_attempt_id:/.test(lines[index]))
            continue;
        let end = index + 1;
        while (end < lines.length
            && !/^[^\s]/.test(lines[end])
            && !/^\s{2}-\s+/.test(lines[end])) {
            end += 1;
        }
        const item = lines.slice(index, end);
        const priorAttemptId = parseHistoryField(item, "prior_attempt_id");
        const state = parseHistoryField(item, "state");
        const recordedBy = parseHistoryField(item, "aborted_by");
        const recordedAt = parseHistoryField(item, "aborted_at");
        const reason = parseHistoryField(item, "abort_reason");
        const taskRevision = parseHistoryField(item, "task_revision");
        const priorAttempt = parseHistoryField(item, "prior_attempt");
        if (priorAttemptId !== null
            && state === "aborted"
            && recordedBy !== null
            && recordedAt !== null
            && reason !== null
            && taskRevision !== null) {
            records.push({
                priorAttemptId,
                state,
                recordedBy,
                recordedAt,
                reason,
                taskRevision,
                priorAttempt
            });
        }
        index = end - 1;
    }
    return records;
}
function parseHistoryField(lines, field) {
    for (const line of lines) {
        const match = line.match(new RegExp(`^\\s+(?:-\\s+)?${field}:\\s*(.*)$`));
        if (match !== null)
            return parseYamlScalar(match[1]);
    }
    return null;
}
function sameAbortRecord(left, right) {
    return left.priorAttemptId === right.priorAttemptId
        && left.state === right.state
        && left.recordedBy === right.recordedBy
        && left.recordedAt === right.recordedAt
        && left.reason === right.reason
        && left.taskRevision === right.taskRevision;
}
function matchesAbortRequest(record, request) {
    return record.priorAttemptId === request.attemptId
        && record.taskRevision === request.taskRevision
        && record.recordedBy === request.recordedBy
        && record.recordedAt === request.recordedAt
        && record.reason === request.reason;
}
function frontMatterLines(markdown) {
    const lines = markdown.split(/\r?\n/);
    const closing = lines.findIndex((line, index) => index > 0 && line === "---");
    return lines[0] === "---" && closing >= 0 ? lines.slice(1, closing) : [];
}
function locateAttemptRanges(lines) {
    const attemptsIndex = lines.findIndex((line) => /^attempts:\s*$/.test(line));
    if (attemptsIndex < 0)
        return [];
    const ranges = [];
    for (let index = attemptsIndex + 1; index < lines.length; index += 1) {
        if (/^[^\s]/.test(lines[index]))
            break;
        const match = lines[index].match(/^\s{2}-\s+attempt_id:\s*(.*)$/);
        if (match === null)
            continue;
        let end = index + 1;
        while (end < lines.length && !/^[^\s]/.test(lines[end]) && !/^\s{2}-\s+/.test(lines[end])) {
            end += 1;
        }
        ranges.push({ attemptId: parseYamlScalar(match[1]), start: index, end });
        index = end - 1;
    }
    return ranges;
}
function locateAttemptRange(lines, attemptId) {
    const range = locateAttemptRanges(lines).find((entry) => entry.attemptId === attemptId);
    return range === undefined ? null : { start: range.start, end: range.end };
}
function attemptFieldRaw(lines, field) {
    const pattern = new RegExp(`^\\s{4}${field}:\\s*(.*)$`);
    const line = lines.find((candidate) => pattern.test(candidate));
    return line?.match(pattern)?.[1] ?? null;
}
function isEmptyCollectionScalar(raw) {
    const normalized = parseYamlScalar(raw).trim();
    if (normalized === "[]")
        return true;
    try {
        const decoded = JSON.parse(normalized);
        return Array.isArray(decoded) && decoded.length === 0;
    }
    catch {
        return false;
    }
}
function isNullScalar(raw) {
    const normalized = raw.trim();
    return normalized === "null" || normalized === "~";
}
function assertTaskDefinitionArtifact(taskText, taskDefinitionPath, action) {
    const artifactType = frontMatterLines(taskText)
        .map((line) => line.match(/^artifact_type:\s*(.*)$/))
        .find((match) => match !== null);
    if (artifactType === undefined
        || artifactType === null
        || parseYamlScalar(artifactType[1]) !== "task_definition") {
        throw new TaskAttemptAbortError("invalid-input", `Task ${action} selector '${taskDefinitionPath}' must identify an artifact_type task_definition.`);
    }
}
function readTaskIdentity(taskText) {
    const lines = frontMatterLines(taskText);
    for (const field of ["id", "task"]) {
        const match = lines
            .map((line) => line.match(new RegExp(`^${field}:\\s*(.*)$`)))
            .find((entry) => entry !== null);
        if (match !== undefined && match !== null)
            return parseYamlScalar(match[1]);
    }
    throw new TaskAttemptAbortError("pair-invalid", "Task identity is missing.");
}
function resolvePair(repositoryRoot, taskDefinitionPath) {
    const root = node_fs_1.default.realpathSync(node_path_1.default.resolve(requireText(repositoryRoot, "Repository root")));
    let parsed;
    try {
        parsed = (0, paths_1.parseRepositoryRelativePath)(taskDefinitionPath);
    }
    catch (error) {
        throw new TaskAttemptOpenError("invalid-input", error instanceof Error ? error.message : "Invalid task path.");
    }
    if (parsed.segments.at(-1) !== "task-definition.md") {
        throw new TaskAttemptOpenError("invalid-input", "Attempt-open paths must end in task-definition.md.");
    }
    const task = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(root, parsed.normalizedPath);
    const summary = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(root, [...parsed.segments.slice(0, -1), "implementation-summary.md"].join("/"));
    if (!task.exists || !summary.exists) {
        throw new TaskAttemptOpenError("artifact-unreadable", "Both task-definition.md and implementation-summary.md must exist.");
    }
    return { repositoryRoot: root, task, summary };
}
function readArtifact(runtimePath, repositoryRelativePath) {
    const stats = node_fs_1.default.statSync(runtimePath, { throwIfNoEntry: false });
    if (stats === undefined || !stats.isFile()) {
        throw new TaskAttemptOpenError("artifact-unreadable", `Attempt artifact '${repositoryRelativePath}' must be a regular file.`);
    }
    try {
        return new node_util_1.TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(node_fs_1.default.readFileSync(runtimePath));
    }
    catch (error) {
        throw new TaskAttemptOpenError("artifact-unreadable", `Attempt artifact '${repositoryRelativePath}' must contain valid UTF-8: ${error instanceof Error ? error.message : String(error)}`);
    }
}
function topLevelInsertion(lines, closing) {
    const upstream = lines.findIndex((line, index) => index > 0 && index < closing && line === "upstream:");
    return upstream >= 0 ? upstream : closing;
}
function requireAttemptId(value) {
    const attemptId = requireText(value, "Attempt identity");
    if (!ATTEMPT_ID_PATTERN.test(attemptId)) {
        throw new TaskAttemptOpenError("invalid-input", "Attempt identity must use 3-128 machine-safe identity characters.");
    }
    return attemptId;
}
function requireTimestamp(value) {
    const timestamp = requireText(value, "Attempt open time");
    if (!(0, task_lifecycle_1.isTaskLifecycleTimestamp)(timestamp)) {
        throw new TaskAttemptOpenError("invalid-input", "Attempt open time must be an ISO-8601 timestamp with an explicit timezone.");
    }
    return timestamp;
}
function requireAbortAttemptId(value) {
    const attemptId = requireAbortText(value, "Attempt identity");
    if (!ATTEMPT_ID_PATTERN.test(attemptId)) {
        throw new TaskAttemptAbortError("invalid-input", "Attempt identity must use 3-128 machine-safe identity characters.");
    }
    return attemptId;
}
function requireTaskRevision(value) {
    const revision = requireAbortText(value, "Task revision");
    if (!/^[a-f0-9]{64}$/.test(revision)) {
        throw new TaskAttemptAbortError("invalid-input", "Task revision must be the exact 64-character lowercase SHA-256 revision emitted for the selected task.");
    }
    return revision;
}
function requireAbortTimestamp(value) {
    const timestamp = requireAbortText(value, "Attempt-abort time");
    if (!(0, task_lifecycle_1.isTaskLifecycleTimestamp)(timestamp)) {
        throw new TaskAttemptAbortError("invalid-input", "Attempt-abort time must be an ISO-8601 timestamp with an explicit timezone.");
    }
    return timestamp;
}
function requireAbortText(value, label) {
    if (typeof value !== "string" || value.trim() === "") {
        throw new TaskAttemptAbortError("invalid-input", `${label} must be non-empty.`);
    }
    return value.trim();
}
function requireText(value, label) {
    if (typeof value !== "string" || value.trim() === "") {
        throw new TaskAttemptOpenError("invalid-input", `${label} must be non-empty.`);
    }
    return value.trim();
}
function sha256(contents) {
    return (0, node_crypto_1.createHash)("sha256").update(contents).digest("hex");
}
function quote(value) {
    return JSON.stringify(value);
}
function parseYamlScalar(value) {
    const trimmed = value.trim();
    if (trimmed.startsWith("\"") && trimmed.endsWith("\"")) {
        try {
            const parsed = JSON.parse(trimmed);
            return typeof parsed === "string" ? parsed : trimmed;
        }
        catch {
            return trimmed.slice(1, -1);
        }
    }
    if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
        return trimmed.slice(1, -1).replace(/''/g, "'");
    }
    return trimmed;
}
function toExpectedCondition(precondition) {
    return {
        path: precondition.repositoryRelativePath,
        kind: precondition.kind,
        expectedState: precondition.kind === "content-revision"
            ? precondition.expectedRevision
            : precondition.expectedPresence
    };
}
function cloneResult(result) {
    return {
        ...result,
        evidenceGaps: [...result.evidenceGaps],
        intendedPaths: [...result.intendedPaths],
        changedPaths: [...result.changedPaths],
        expected: result.expected.map((entry) => ({ ...entry })),
        conflicts: result.conflicts.map((entry) => ({ ...entry }))
    };
}
function cloneAbortResult(result) {
    return {
        ...result,
        evidenceGaps: [...result.evidenceGaps],
        intendedPaths: [...result.intendedPaths],
        changedPaths: [...result.changedPaths],
        expected: result.expected.map((entry) => ({ ...entry })),
        conflicts: result.conflicts.map((entry) => ({ ...entry }))
    };
}
function cloneSupersedeResult(result) {
    return {
        ...result,
        evidenceGaps: [...result.evidenceGaps],
        intendedPaths: [...result.intendedPaths],
        changedPaths: [...result.changedPaths],
        expected: result.expected.map((entry) => ({ ...entry })),
        conflicts: result.conflicts.map((entry) => ({ ...entry }))
    };
}
