"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.inspectLifecycleRunContext = inspectLifecycleRunContext;
exports.projectLifecycleRunStatus = projectLifecycleRunStatus;
exports.lifecycleStatusPageCommand = lifecycleStatusPageCommand;
exports.countEnvelopeOutcomes = countEnvelopeOutcomes;
exports.countValidationStatuses = countValidationStatuses;
exports.readNestedValidationOutcome = readNestedValidationOutcome;
exports.readManifest = readManifest;
exports.validateManifest = validateManifest;
exports.parseLifecycleMetadataPosture = parseLifecycleMetadataPosture;
exports.isLifecycleMetadataPosture = isLifecycleMetadataPosture;
exports.readStructuredResult = readStructuredResult;
exports.inspectStructuredFiles = inspectStructuredFiles;
exports.collectStructuredJsonPaths = collectStructuredJsonPaths;
exports.isStructuredJsonFile = isStructuredJsonFile;
exports.isDirectBasicTaskRun = isDirectBasicTaskRun;
exports.inspectTerminalBasicTaskClose = inspectTerminalBasicTaskClose;
exports.inspectTerminalPhaseReview = inspectTerminalPhaseReview;
exports.collectInactiveLifecycleEntryIds = collectInactiveLifecycleEntryIds;
// Lifecycle run-context contracts, capture, inspection, and persistence orchestration.
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../errors");
const paths_1 = require("../paths");
const task_lifecycle_1 = require("../planning/task-lifecycle");
const task_cycle_runtime_attribution_1 = require("../planning/task-cycle-runtime-attribution");
const task_attempts_1 = require("../planning/task-attempts");
const task_chronology_recovery_evidence_1 = require("../planning/task-chronology-recovery-evidence");
const task_validation_recovery_1 = require("../planning/task-validation-recovery");
const evidence_store_1 = require("./evidence-store");
const context_capture_1 = require("./context-capture");
const context_storage_1 = require("./context-storage");
function inspectLifecycleRunContext(options) {
    const repositoryRoot = (0, context_storage_1.canonicalRoot)(options.repositoryRoot);
    const loaded = readManifest(repositoryRoot, options.runDirectory);
    const staleReasons = [];
    (0, context_storage_1.compareCurrentFile)(repositoryRoot, loaded.manifest.phasePath, loaded.manifest.phaseHash, 'phase', staleReasons);
    (0, context_storage_1.compareCurrentFile)(repositoryRoot, loaded.manifest.activeArtifactPath, loaded.manifest.activeArtifactHash, 'active artifact', staleReasons);
    for (const entry of loaded.manifest.entries) {
        try {
            (0, evidence_store_1.readLifecycleEvidenceBytesSync)({
                repositoryRoot,
                runDirectory: loaded.manifest.runDirectory,
                entry,
                maximumBytes: context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES,
            });
        }
        catch {
            staleReasons.push(`entry ${entry.entryId} evidence-missing-or-invalid:${entry.evidencePath}`);
        }
    }
    const structuredFiles = inspectStructuredFiles(repositoryRoot, loaded.manifest);
    const incompleteReasons = loaded.manifest.lifecycleProfile === 'full-cycle-strict' && structuredFiles.unexpected.length > 0
        ? structuredFiles.unexpected.map((candidate) => `unindexed-structured-evidence:${candidate}`)
        : [];
    const selectedArtifactPath = options.selectedArtifactPath == null
        ? null
        : (0, paths_1.parseRepositoryRelativePath)(options.selectedArtifactPath).normalizedPath;
    const conflict = selectedArtifactPath !== null && selectedArtifactPath !== loaded.manifest.activeArtifactPath
        ? {
            code: 'LIFECYCLE_RUN_SELECTION_CONFLICT',
            selectedArtifactPath,
            activeArtifactPath: loaded.manifest.activeArtifactPath,
            noWrite: true,
        }
        : null;
    const directBasicTaskRun = isDirectBasicTaskRun(repositoryRoot, loaded.manifest);
    const terminalReview = directBasicTaskRun
        ? inspectTerminalBasicTaskClose(repositoryRoot, loaded.manifest)
        : inspectTerminalPhaseReview(repositoryRoot, loaded.manifest);
    const state = conflict !== null
        ? 'conflict'
        : staleReasons.length > 0
            ? 'stale'
            : incompleteReasons.length > 0
                ? 'incomplete'
                : 'fresh';
    const terminalState = state === 'fresh' && terminalReview.reasons.length === 0 && terminalReview.candidateEntryId !== null
        ? directBasicTaskRun
            ? 'task_close_complete'
            : 'review_complete_read_only'
        : null;
    return {
        state,
        staleReasons: [...new Set(staleReasons)],
        conflict,
        manifestPath: loaded.manifestPath,
        manifestHash: loaded.manifestHash,
        manifest: loaded.manifest,
        structuredFileCounts: {
            indexed: structuredFiles.indexed.length,
            auxiliary: structuredFiles.auxiliary.length,
            unexpected: structuredFiles.unexpected.length,
            unindexedRequired: structuredFiles.unexpected.length,
        },
        structuredFiles: {
            ...structuredFiles,
            unindexedRequired: structuredFiles.unexpected,
        },
        manifestComplete: incompleteReasons.length === 0,
        incompleteReasons,
        terminalState,
        terminalReview,
        readOnly: true,
        authorityBoundary: 'Manifest history is evidence only; current action legality must be re-resolved from canonical repository artifacts.',
    };
}
/** Builds a bounded, decision-complete status view without changing the manifest. */
function projectLifecycleRunStatus(repositoryRootValue, inspection, options = {}) {
    const repositoryRoot = (0, context_storage_1.canonicalRoot)(repositoryRootValue);
    const inactiveEntryIds = collectInactiveLifecycleEntryIds(inspection.manifest);
    const historicalEnvelope = countEnvelopeOutcomes(inspection.manifest.entries);
    const currentEntries = inspection.manifest.entries.filter((entry) => !inactiveEntryIds.has(entry.entryId));
    const currentEnvelope = countEnvelopeOutcomes(currentEntries);
    const evidenceStorage = (0, evidence_store_1.projectLifecycleEvidenceStorageMetrics)(inspection.manifest.entries);
    const validationRecoveryAction = readLatestUnrecordableValidationRecovery(repositoryRoot, inspection, inactiveEntryIds);
    const validationRecords = [];
    const validationPreviews = [];
    let previews = 0;
    let unreadable = 0;
    for (const entry of inspection.manifest.entries) {
        if (entry.commandIdentity !== 'task validation-record')
            continue;
        const nested = readNestedValidationOutcome(repositoryRoot, inspection.manifest.runDirectory, entry);
        if (nested.kind === 'unreadable') {
            unreadable += 1;
            continue;
        }
        if (nested.kind === 'preview') {
            previews += 1;
            validationPreviews.push({
                entryId: entry.entryId,
                sequence: entry.sequence,
                gate: entry.gate,
                evidencePath: entry.evidencePath,
                currentLifecycleEntry: !inactiveEntryIds.has(entry.entryId),
            });
            continue;
        }
        validationRecords.push({
            ...nested,
            entryId: entry.entryId,
            sequence: entry.sequence,
            gate: entry.gate,
            evidencePath: entry.evidencePath,
            currentLifecycleEntry: !inactiveEntryIds.has(entry.entryId),
        });
    }
    const supersededValidationIds = new Set(validationRecords
        .map((record) => record.supersedesValidationId)
        .filter((identity) => identity !== null));
    const currentEffective = validationRecords.filter((record) => record.currentLifecycleEntry && !supersededValidationIds.has(record.validationId));
    const historicalStatuses = countValidationStatuses(validationRecords);
    const currentStatuses = countValidationStatuses(currentEffective);
    const terminalBlockers = inspection.terminalReview.candidateEntryId === null ? [] : inspection.terminalReview.reasons;
    const allBlockers = [
        ...new Set([
            ...inspection.staleReasons,
            ...inspection.incompleteReasons,
            ...(inspection.conflict === null ? [] : [inspection.conflict.code]),
            ...terminalBlockers,
        ]),
    ];
    const blockers = allBlockers.slice(0, 16);
    const nextAction = validationRecoveryAction !== null
        ? validationRecoveryAction.explanation
        : inspection.terminalState !== null
            ? 'Stop this lifecycle run at its verified terminal state.'
            : inspection.state === 'stale'
                ? 'Use an explicitly authorized bounded contract revision or start a fresh run; manifest history is evidence only.'
                : inspection.state === 'conflict'
                    ? 'Select the intended active artifact explicitly before resuming.'
                    : inspection.state === 'incomplete'
                        ? 'Index or disposition the reported unindexed required structured evidence before continuing.'
                        : 'Resolve the next permitted gate from the current canonical active artifact with resume run resume.';
    const completedEntries = currentEntries.filter((entry) => entry.status === 'ok');
    const recentCompletedEntries = completedEntries.slice(-4);
    const lastAcceptedEntry = completedEntries.at(-1) ?? null;
    const lastAcceptedGate = lastAcceptedEntry === null
        ? null
        : {
            entryId: lastAcceptedEntry.entryId,
            sequence: lastAcceptedEntry.sequence,
            gate: lastAcceptedEntry.gate,
            commandIdentity: lastAcceptedEntry.commandIdentity,
            writeOutcome: lastAcceptedEntry.writeOutcome,
            recordedAt: lastAcceptedEntry.recordedAt,
        };
    const pagingCommands = {
        entries: lifecycleStatusPageCommand(inspection.manifest.runDirectory, 'entries'),
        validations: lifecycleStatusPageCommand(inspection.manifest.runDirectory, 'validations'),
        evidence: lifecycleStatusPageCommand(inspection.manifest.runDirectory, 'evidence'),
    };
    const validationLane = [
        ...validationPreviews.map((record) => ({
            ...record,
            kind: 'preview',
            validationId: null,
            supersedesValidationId: null,
            status: null,
            currentEffective: false,
        })),
        ...validationRecords.map((record) => ({
            entryId: record.entryId,
            sequence: record.sequence,
            gate: record.gate,
            evidencePath: record.evidencePath,
            kind: 'result',
            validationId: record.validationId,
            supersedesValidationId: record.supersedesValidationId,
            status: record.status,
            currentLifecycleEntry: record.currentLifecycleEntry,
            currentEffective: record.currentLifecycleEntry && !supersededValidationIds.has(record.validationId),
        })),
    ].sort((left, right) => left.sequence - right.sequence);
    const pageLane = options.pageLane;
    return {
        state: inspection.state,
        runId: inspection.manifest.runId,
        runDirectory: inspection.manifest.runDirectory,
        manifestPath: inspection.manifestPath,
        manifestHash: inspection.manifestHash,
        currentGate: inspection.manifest.activeGate,
        activeArtifact: {
            path: inspection.manifest.activeArtifactPath,
            revision: inspection.manifest.activeArtifactHash,
        },
        lastAcceptedGate,
        terminalReview: inspection.terminalReview,
        terminalState: inspection.terminalState,
        manifestComplete: inspection.manifestComplete,
        readOnly: true,
        entryCount: inspection.manifest.entries.length,
        inactiveEntryCount: inactiveEntryIds.size,
        evidenceBytes: evidenceStorage.logicalEntryBytes,
        evidenceStorage,
        contractRevisionCount: inspection.manifest.contractRevisions.length,
        structuredFileCounts: { ...inspection.structuredFileCounts },
        conflict: inspection.conflict === null ? null : { ...inspection.conflict },
        commandEnvelopeOutcomes: {
            historical: historicalEnvelope,
            current: currentEnvelope,
        },
        validationOutcomes: {
            previews,
            passed: historicalStatuses.passed,
            failed: historicalStatuses.failed,
            other: historicalStatuses.other,
            superseded: validationRecords.filter((record) => supersededValidationIds.has(record.validationId)).length,
            unreadable,
            currentEffective: {
                total: currentEffective.length,
                ...currentStatuses,
            },
        },
        blockers,
        blockerCount: allBlockers.length,
        nextAction,
        validationRecoveryAction,
        resumeCapsule: {
            activeArtifactPath: inspection.manifest.activeArtifactPath,
            activeArtifactRevision: inspection.manifest.activeArtifactHash,
            currentGate: inspection.manifest.activeGate,
            lastAcceptedGate,
            completedActionIds: recentCompletedEntries.map((entry) => entry.entryId),
            completedActionCount: completedEntries.length,
            omittedCompletedActionCount: Math.max(0, completedEntries.length - recentCompletedEntries.length),
            doNotRepeat: 'Do not repeat current successful manifest entries; continue only through the authoritative next action.',
            nextAction,
            targetedPagingCommands: pagingCommands,
        },
        ...(pageLane === 'entries' ? { entries: inspection.manifest.entries } : {}),
        ...(pageLane === 'validations' ? { validations: validationLane } : {}),
        ...(pageLane === 'evidence'
            ? {
                evidence: inspection.manifest.entries.map((entry) => ({
                    entryId: entry.entryId,
                    sequence: entry.sequence,
                    gate: entry.gate,
                    commandIdentity: entry.commandIdentity,
                    status: entry.status,
                    evidencePath: entry.evidencePath,
                    evidenceHash: entry.evidenceHash,
                    evidenceBytes: entry.evidenceBytes,
                    evidenceKind: entry.evidenceKind,
                    recordedAt: entry.recordedAt,
                })),
            }
            : {}),
        recovery: {
            fullDetailCommand: `day-shift resume run status --run-directory ${inspection.manifest.runDirectory} --detail full --format json`,
            pagingCommand: pagingCommands.entries,
            pagingCommands,
            auditHistoryPreserved: true,
        },
        authorityBoundary: inspection.authorityBoundary,
    };
}
function lifecycleStatusPageCommand(runDirectory, lane) {
    return `day-shift resume run status --run-directory ${runDirectory} --format json --detail full --page-lane ${lane} --page-size 5`;
}
function countEnvelopeOutcomes(entries) {
    const ok = entries.filter((entry) => entry.status === 'ok').length;
    const error = entries.length - ok;
    return { ok, error, total: entries.length };
}
function countValidationStatuses(records) {
    const passed = records.filter((record) => record.status === 'passed').length;
    const failed = records.filter((record) => record.status === 'failed').length;
    return { passed, failed, other: records.length - passed - failed };
}
function readNestedValidationOutcome(repositoryRoot, runDirectory, entry) {
    try {
        const bytes = (0, evidence_store_1.readLifecycleEvidenceBytesSync)({
            repositoryRoot,
            runDirectory,
            entry,
            maximumBytes: context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES,
        }).bytes;
        if (bytes.byteLength === 0 || bytes.byteLength > context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES) {
            return { kind: 'unreadable' };
        }
        const document = (0, context_storage_1.asRecord)(JSON.parse(bytes.toString('utf8')));
        const envelope = (0, context_storage_1.asRecord)(document?.result) ?? document;
        const data = (0, context_storage_1.asRecord)(envelope?.data);
        const nestedValidation = (0, context_storage_1.asRecord)(data?.validation);
        const validation = nestedValidation ??
            (typeof data?.validationId === 'string' && typeof data.status === 'string' ? data : null);
        if (validation === null) {
            return data?.executionPlan != null || data?.writeOutcome === 'previewed'
                ? { kind: 'preview' }
                : { kind: 'unreadable' };
        }
        const validationId = typeof validation.validationId === 'string' ? validation.validationId : null;
        const status = typeof validation.status === 'string' ? validation.status : null;
        if (validationId === null || status === null)
            return { kind: 'unreadable' };
        return {
            kind: 'result',
            validationId,
            supersedesValidationId: typeof validation.supersedesValidationId === 'string' ? validation.supersedesValidationId : null,
            status,
        };
    }
    catch {
        return { kind: 'unreadable' };
    }
}
function readLatestUnrecordableValidationRecovery(repositoryRoot, inspection, inactiveEntryIds) {
    const pair = readCurrentChronologyRecoveryPair(repositoryRoot, inspection);
    if (pair?.recoveryConsumed === true)
        return null;
    for (const entry of [...inspection.manifest.entries].reverse()) {
        if (inactiveEntryIds.has(entry.entryId) ||
            entry.artifactPath !== inspection.manifest.activeArtifactPath ||
            (entry.commandIdentity !== 'task validation-record' && entry.commandIdentity !== 'task validation-set'))
            continue;
        try {
            const bytes = (0, evidence_store_1.readLifecycleEvidenceBytesSync)({
                repositoryRoot,
                runDirectory: inspection.manifest.runDirectory,
                entry,
                maximumBytes: context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES,
            }).bytes;
            const document = (0, context_storage_1.asRecord)(JSON.parse(bytes.toString('utf8')));
            const envelope = (0, context_storage_1.asRecord)(document?.result) ?? document;
            const data = (0, context_storage_1.asRecord)(envelope?.data);
            const error = (0, context_storage_1.asRecord)(envelope?.error);
            const items = Array.isArray(data?.items) ? data.items : [];
            const chronologyError = entry.commandIdentity === 'task validation-set' &&
                (entry.errorCode === 'TASK_VALIDATION_BEFORE_ATTEMPT_OPEN' ||
                    error?.code === 'TASK_VALIDATION_BEFORE_ATTEMPT_OPEN');
            const setUnrecordable = entry.commandIdentity === 'task validation-set' &&
                items.some((item) => (0, context_storage_1.asRecord)(item)?.state === 'unrecordable');
            const recordUnrecordable = entry.commandIdentity === 'task validation-record' && data?.state === 'unrecordable';
            if (!chronologyError && !setUnrecordable && !recordUnrecordable)
                continue;
            const chronologyRecovery = pair === null
                ? null
                : createCallableChronologyRecovery(repositoryRoot, inspection, entry, pair);
            if (chronologyRecovery !== null)
                return chronologyRecovery;
            const dataRecoveryActions = Array.isArray(data?.recoveryActions) ? data.recoveryActions : null;
            if (dataRecoveryActions !== null) {
                if (dataRecoveryActions.length !== 1 || !isRecoveryAction(dataRecoveryActions[0]))
                    return null;
                return dataRecoveryActions[0];
            }
            const envelopeRecoveryActions = Array.isArray(error?.recoveryActions) ? error.recoveryActions : null;
            if (envelopeRecoveryActions !== null) {
                if (envelopeRecoveryActions.length !== 1 || !isRecoveryAction(envelopeRecoveryActions[0]))
                    return null;
                return envelopeRecoveryActions[0];
            }
            if (recordUnrecordable && isLegacyUnrecordableValidationExecution(entry, data ?? {})) {
                return (0, task_validation_recovery_1.createTaskValidationUnrecordableRecoveryAction)();
            }
            if (setUnrecordable)
                return (0, task_validation_recovery_1.createTaskValidationUnrecordableRecoveryAction)();
            return null;
        }
        catch {
            return null;
        }
    }
    return null;
}
function readCurrentChronologyRecoveryPair(repositoryRoot, inspection) {
    const taskDefinitionPath = inspection.manifest.activeArtifactPath;
    if (!taskDefinitionPath.endsWith('/task-definition.md'))
        return null;
    try {
        const taskPath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, taskDefinitionPath);
        const summaryPath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, node_path_1.default.posix.join(node_path_1.default.posix.dirname(taskDefinitionPath), 'implementation-summary.md'));
        const taskText = node_fs_1.default.readFileSync(taskPath, 'utf8');
        const summaryText = node_fs_1.default.readFileSync(summaryPath, 'utf8');
        const projection = (0, task_lifecycle_1.projectTaskLifecyclePair)({ taskDefinition: taskText, implementationSummary: summaryText });
        const latest = projection.summary?.attempts.at(-1) ?? null;
        const recoveryConsumed = latest?.reviewDisposition === 'invalid_chronology' ||
            latest?.successorKind === 'chronology_repair';
        if (recoveryConsumed) {
            return {
                taskText,
                summaryText,
                taskDefinitionPath,
                attemptId: latest?.attemptId ?? '',
                attemptOpenedAt: latest?.openedAt ?? '',
                baselineCapturedAt: null,
                evidenceBearing: true,
                recoveryConsumed: true,
            };
        }
        const current = projection.summary?.currentAttempt ?? null;
        if (projection.blockingFindings.some((finding) => finding.code !== 'stale-readiness-authorization' &&
            finding.code !== 'stale-attempt-readiness-reference') ||
            current?.attemptId === null ||
            current?.attemptId === undefined ||
            current.openedAt === null ||
            current.closedAt !== null ||
            current.reviewDisposition !== 'pending')
            return null;
        const baseline = (0, task_cycle_runtime_attribution_1.readAttemptRuntimeBaseline)(node_path_1.default.posix.join(node_path_1.default.posix.dirname(taskDefinitionPath), 'implementation-summary.md'), summaryText, current.attemptId);
        return {
            taskText,
            summaryText,
            taskDefinitionPath,
            attemptId: current.attemptId,
            attemptOpenedAt: current.openedAt,
            baselineCapturedAt: baseline?.capturedAt ?? null,
            evidenceBearing: baseline !== null || (0, task_attempts_1.inspectTaskAttemptSupersessionEvidence)(summaryText, current.attemptId).length > 0,
            recoveryConsumed: false,
        };
    }
    catch {
        return null;
    }
}
function createCallableChronologyRecovery(repositoryRoot, inspection, signalEntry, pair) {
    const chronology = (0, task_chronology_recovery_evidence_1.inspectTaskChronologyEvidenceSync)({
        repositoryRoot,
        runDirectory: inspection.manifest.runDirectory,
        entries: inspection.manifest.entries,
        artifactPath: pair.taskDefinitionPath,
        attemptId: pair.attemptId,
        attemptOpenedAt: pair.attemptOpenedAt,
        baselineCapturedAt: pair.baselineCapturedAt,
    });
    if (!pair.evidenceBearing && chronology.unrecordableValidationIds.length === 0)
        return null;
    if (!chronology.eligible || chronology.blockers.length > 0)
        return null;
    return (0, task_validation_recovery_1.createTaskChronologyRecoveryAction)({
        runDirectory: inspection.manifest.runDirectory,
        taskDefinitionPath: pair.taskDefinitionPath,
        attemptId: pair.attemptId,
        taskRevision: (0, node_crypto_1.createHash)('sha256').update(pair.taskText).digest('hex'),
        recordedBy: inspection.manifest.actor,
        recordedAt: signalEntry.recordedAt,
        reason: 'Recover legacy lifecycle timestamps that conflict with immutable source-run evidence.',
    });
}
function isLegacyUnrecordableValidationExecution(entry, data) {
    return (entry.status === 'error' &&
        data.writeOutcome === 'no-writes' &&
        (data.status === 'passed' || data.status === 'failed') &&
        Number.isSafeInteger(data.exitCode) &&
        typeof data.recordedAt === 'string' &&
        (0, task_lifecycle_1.isTaskLifecycleTimestamp)(data.recordedAt) &&
        Array.isArray(data.commandArgv) &&
        data.commandArgv.length > 0 &&
        data.commandArgv.every((argument) => typeof argument === 'string' && argument.length > 0));
}
function isRecoveryAction(value) {
    const action = (0, context_storage_1.asRecord)(value);
    if (action === null ||
        typeof action.id !== 'string' ||
        typeof action.callable !== 'boolean' ||
        typeof action.explanation !== 'string') {
        return false;
    }
    if (action.callable === false) {
        return action.argv === null && typeof action.nonCallableReason === 'string';
    }
    return typeof action.command === 'string' && Array.isArray(action.argv) && action.argv.length >= 2;
}
function readManifest(repositoryRoot, runDirectoryValue) {
    const runDirectory = (0, context_storage_1.requireRunDirectory)(repositoryRoot, runDirectoryValue);
    const manifestPath = node_path_1.default.posix.join(runDirectory.relativePath, context_capture_1.LIFECYCLE_RUN_MANIFEST_NAME);
    const manifestAbsolute = node_path_1.default.join(repositoryRoot, manifestPath);
    if (!node_fs_1.default.existsSync(manifestAbsolute) || !node_fs_1.default.statSync(manifestAbsolute).isFile()) {
        throw (0, errors_1.createUsageError)(`Lifecycle run context '${manifestPath}' does not exist.`);
    }
    if (node_fs_1.default.lstatSync(manifestAbsolute).isSymbolicLink()) {
        throw (0, errors_1.createUsageError)('Lifecycle run manifests must not be symbolic links.');
    }
    const bytes = (0, context_storage_1.readBoundedFile)(manifestAbsolute, context_capture_1.MAX_LIFECYCLE_RUN_MANIFEST_BYTES, 'Lifecycle run manifest');
    const parsed = (0, context_storage_1.parseObjectJson)(bytes, 'Lifecycle run manifest');
    validateManifest(parsed, manifestPath);
    const manifest = {
        ...parsed,
        contractRevisions: Array.isArray(parsed.contractRevisions) ? parsed.contractRevisions : [],
    };
    if (manifest.runDirectory !== runDirectory.relativePath) {
        throw (0, errors_1.createUsageError)('Lifecycle run manifest directory identity does not match its selected location.');
    }
    return {
        manifestPath,
        manifestAbsolute,
        manifestHash: (0, context_storage_1.sha256)(bytes),
        manifest,
    };
}
function validateManifest(value, manifestPath) {
    if (value.schemaVersion !== 1 ||
        typeof value.runId !== 'string' ||
        typeof value.runDirectory !== 'string' ||
        typeof value.phasePath !== 'string' ||
        typeof value.phaseHash !== 'string' ||
        typeof value.lifecycleProfile !== 'string' ||
        !isLifecycleMetadataPosture(value.metadataPosture) ||
        typeof value.actor !== 'string' ||
        typeof value.activeArtifactPath !== 'string' ||
        typeof value.activeArtifactHash !== 'string' ||
        typeof value.activeGate !== 'string' ||
        typeof value.openedAt !== 'string' ||
        typeof value.updatedAt !== 'string' ||
        !Number.isSafeInteger(value.nextSequence) ||
        !Array.isArray(value.entries) ||
        (value.contractRevisions !== undefined && !Array.isArray(value.contractRevisions))) {
        throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' has an invalid schema.`);
    }
    if (value.entries.length > context_capture_1.MAX_ENTRIES) {
        throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' exceeds its entry bound.`);
    }
    const seen = new Set();
    for (const entry of value.entries) {
        if (typeof entry !== 'object' ||
            entry === null ||
            typeof entry.entryId !== 'string' ||
            typeof entry.evidencePath !== 'string' ||
            typeof entry.evidenceHash !== 'string' ||
            (entry.sourceResultPath !== undefined &&
                typeof entry.sourceResultPath !== 'string')) {
            throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' contains an invalid entry.`);
        }
        (0, evidence_store_1.validateLifecycleEvidenceEntryReference)(String(value.runDirectory), entry, `Lifecycle run manifest '${manifestPath}' entry '${String(entry.entryId)}'`);
        const identity = entry.entryId;
        if (seen.has(identity)) {
            throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' duplicates entry '${identity}'.`);
        }
        seen.add(identity);
    }
    const checkpoints = Array.isArray(value.contractRevisions) ? value.contractRevisions : [];
    if (checkpoints.length > context_capture_1.MAX_CONTRACT_REVISIONS) {
        throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' exceeds its contract revision bound.`);
    }
    const checkpointIds = new Set();
    for (const checkpointValue of checkpoints) {
        const checkpoint = (0, context_storage_1.asRecord)(checkpointValue);
        const invalidatedEntryIds = checkpoint !== null && Array.isArray(checkpoint.invalidatedEntryIds) ? checkpoint.invalidatedEntryIds : null;
        const adoptionValues = checkpoint === null
            ? []
            : [
                checkpoint.adoptionSourceRunId,
                checkpoint.adoptionSourceRunDirectory,
                checkpoint.adoptionSourceManifestHash,
                checkpoint.adoptionSourceEntryId,
                checkpoint.adoptionSourceEvidenceHash,
            ];
        const hasAdoption = adoptionValues.some((value) => value !== undefined);
        const validAdoption = !hasAdoption || (typeof checkpoint?.adoptionSourceRunId === 'string' &&
            context_capture_1.TOKEN_PATTERN.test(checkpoint.adoptionSourceRunId) &&
            typeof checkpoint.adoptionSourceRunDirectory === 'string' &&
            context_capture_1.RUN_DIRECTORY_PATTERN.test(checkpoint.adoptionSourceRunDirectory) &&
            typeof checkpoint.adoptionSourceManifestHash === 'string' &&
            context_capture_1.SHA256_PATTERN.test(checkpoint.adoptionSourceManifestHash) &&
            typeof checkpoint.adoptionSourceEntryId === 'string' &&
            context_capture_1.TOKEN_PATTERN.test(checkpoint.adoptionSourceEntryId) &&
            typeof checkpoint.adoptionSourceEvidenceHash === 'string' &&
            context_capture_1.SHA256_PATTERN.test(checkpoint.adoptionSourceEvidenceHash));
        if (checkpoint === null ||
            checkpoint.schemaVersion !== 1 ||
            typeof checkpoint.checkpointId !== 'string' ||
            !context_capture_1.TOKEN_PATTERN.test(checkpoint.checkpointId) ||
            typeof checkpoint.recordedBy !== 'string' ||
            typeof checkpoint.recordedAt !== 'string' ||
            typeof checkpoint.reason !== 'string' ||
            typeof checkpoint.rollbackGate !== 'string' ||
            !context_capture_1.LIFECYCLE_CONTRACT_REVISION_ROLLBACK_GATES.includes(checkpoint.rollbackGate) ||
            typeof checkpoint.reviewReceiptId !== 'string' ||
            typeof checkpoint.reviewSourcePath !== 'string' ||
            typeof checkpoint.reviewSourceHash !== 'string' ||
            !context_capture_1.SHA256_PATTERN.test(checkpoint.reviewSourceHash) ||
            typeof checkpoint.reviewEvidencePath !== 'string' ||
            typeof checkpoint.reviewEntryId !== 'string' ||
            typeof checkpoint.oldPhaseHash !== 'string' ||
            !context_capture_1.SHA256_PATTERN.test(checkpoint.oldPhaseHash) ||
            typeof checkpoint.newPhaseHash !== 'string' ||
            !context_capture_1.SHA256_PATTERN.test(checkpoint.newPhaseHash) ||
            typeof checkpoint.oldActiveArtifactPath !== 'string' ||
            typeof checkpoint.oldActiveArtifactHash !== 'string' ||
            !context_capture_1.SHA256_PATTERN.test(checkpoint.oldActiveArtifactHash) ||
            typeof checkpoint.newActiveArtifactPath !== 'string' ||
            typeof checkpoint.newActiveArtifactHash !== 'string' ||
            !context_capture_1.SHA256_PATTERN.test(checkpoint.newActiveArtifactHash) ||
            (checkpoint.impactDigest !== undefined &&
                (typeof checkpoint.impactDigest !== 'string' || !context_capture_1.SHA256_PATTERN.test(checkpoint.impactDigest))) ||
            (checkpoint.impactAcknowledgementId !== undefined &&
                checkpoint.impactAcknowledgementId !== null &&
                (typeof checkpoint.impactAcknowledgementId !== 'string' ||
                    !context_capture_1.TOKEN_PATTERN.test(checkpoint.impactAcknowledgementId))) ||
            !validAdoption ||
            invalidatedEntryIds === null ||
            invalidatedEntryIds.some((entryId) => typeof entryId !== 'string' || !seen.has(entryId)) ||
            new Set(invalidatedEntryIds).size !== invalidatedEntryIds.length ||
            !seen.has(checkpoint.reviewEntryId) ||
            checkpointIds.has(checkpoint.checkpointId)) {
            throw (0, errors_1.createUsageError)(`Lifecycle run manifest '${manifestPath}' contains an invalid contract revision checkpoint.`);
        }
        checkpointIds.add(checkpoint.checkpointId);
    }
}
function parseLifecycleMetadataPosture(value) {
    if (isLifecycleMetadataPosture(value)) {
        return value;
    }
    throw (0, errors_1.createUsageError)('Metadata posture must be read-only or sync-on-clean-review.', [
        `Received: ${typeof value === 'string' && value.trim() !== '' ? value : '(missing)'}`,
        'Metadata posture is recorded context and never grants write authority by itself.',
    ]);
}
function isLifecycleMetadataPosture(value) {
    return typeof value === 'string' && context_capture_1.LIFECYCLE_METADATA_POSTURES.includes(value);
}
function readStructuredResult(repositoryRoot, value) {
    const result = (0, context_storage_1.readBoundedRepositoryFile)(repositoryRoot, value, 'Structured command result', context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES);
    const bytes = node_fs_1.default.readFileSync(result.absolutePath);
    if (bytes.byteLength === 0) {
        throw (0, errors_1.createUsageError)('Structured command result must not be empty.');
    }
    const envelope = (0, context_storage_1.parseObjectJson)(bytes, 'Structured command result');
    if (envelope.status !== 'ok' && envelope.status !== 'error') {
        throw (0, errors_1.createUsageError)("Structured command result requires status 'ok' or 'error'.");
    }
    const command = typeof envelope.command === 'string' && envelope.command.trim() !== '' ? envelope.command.trim() : null;
    const error = typeof envelope.error === 'object' && envelope.error !== null ? envelope.error : null;
    const data = typeof envelope.data === 'object' && envelope.data !== null ? envelope.data : null;
    return {
        status: envelope.status,
        command,
        writeOutcome: typeof error?.writeOutcome === 'string'
            ? error.writeOutcome
            : typeof data?.writeOutcome === 'string'
                ? data.writeOutcome
                : null,
        errorCode: typeof error?.code === 'string' ? error.code : null,
        relativePath: result.relativePath,
        envelope,
    };
}
function inspectStructuredFiles(repositoryRoot, manifest) {
    const runDirectoryAbsolute = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, (0, paths_1.parseRepositoryRelativePath)(manifest.runDirectory));
    const manifestPath = node_path_1.default.posix.join(manifest.runDirectory, context_capture_1.LIFECYCLE_RUN_MANIFEST_NAME);
    const indexedPaths = new Set(manifest.entries.map((entry) => entry.evidenceStorage?.objectPath ?? entry.evidencePath));
    const auxiliaryPaths = new Set(manifest.entries.flatMap((entry) => entry.sourceResultPath === undefined || entry.sourceResultPath === entry.evidencePath
        ? []
        : [entry.sourceResultPath]));
    const observed = collectStructuredJsonPaths(runDirectoryAbsolute, manifest.runDirectory).filter((candidate) => candidate !== manifestPath);
    const indexed = [];
    const auxiliary = [];
    const unexpected = [];
    for (const candidate of observed) {
        if (indexedPaths.has(candidate)) {
            indexed.push(candidate);
        }
        else if (auxiliaryPaths.has(candidate) || candidate.startsWith(`${manifest.runDirectory}/auxiliary/`)) {
            auxiliary.push(candidate);
        }
        else {
            unexpected.push(candidate);
        }
    }
    return { indexed, auxiliary, unexpected };
}
function collectStructuredJsonPaths(runDirectoryAbsolute, runDirectoryRelative) {
    const results = [];
    const pending = [{ absolute: runDirectoryAbsolute, relative: runDirectoryRelative }];
    while (pending.length > 0) {
        const current = pending.pop();
        const children = node_fs_1.default
            .readdirSync(current.absolute, { withFileTypes: true })
            .sort((left, right) => left.name.localeCompare(right.name));
        for (const child of children) {
            if (results.length >= context_capture_1.MAX_STRUCTURED_FILES) {
                throw (0, errors_1.createUsageError)(`Lifecycle run directories may contain at most ${context_capture_1.MAX_STRUCTURED_FILES} structured JSON files.`);
            }
            const childRelative = node_path_1.default.posix.join(current.relative, child.name);
            const childAbsolute = node_path_1.default.join(current.absolute, child.name);
            if (child.isSymbolicLink())
                continue;
            if (child.isDirectory()) {
                pending.push({ absolute: childAbsolute, relative: childRelative });
                continue;
            }
            if (!child.isFile() || node_path_1.default.extname(child.name).toLowerCase() !== '.json')
                continue;
            if (isStructuredJsonFile(childAbsolute))
                results.push(childRelative);
        }
    }
    return results.sort((left, right) => left.localeCompare(right));
}
function isStructuredJsonFile(absolutePath) {
    try {
        const stat = node_fs_1.default.statSync(absolutePath);
        if (stat.size <= 0 || stat.size > context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES)
            return false;
        const parsed = JSON.parse(node_fs_1.default.readFileSync(absolutePath, 'utf8'));
        return typeof parsed === 'object' && parsed !== null;
    }
    catch {
        return false;
    }
}
function isDirectBasicTaskRun(repositoryRoot, manifest) {
    try {
        const anchor = (0, context_storage_1.readBoundedRepositoryFile)(repositoryRoot, manifest.phasePath, 'Direct lifecycle anchor');
        const text = node_fs_1.default.readFileSync(anchor.absolutePath, 'utf8');
        return ((0, context_storage_1.readFrontMatterScalar)(text, 'artifact_type') === 'task_definition' &&
            (0, context_storage_1.readFrontMatterScalar)(text, 'workflow_level') === 'basic');
    }
    catch {
        return false;
    }
}
function inspectTerminalBasicTaskClose(repositoryRoot, manifest) {
    const inactiveEntryIds = collectInactiveLifecycleEntryIds(manifest);
    const candidate = [...manifest.entries]
        .reverse()
        .find((entry) => entry.commandIdentity === 'task close' && entry.status === 'ok' && !inactiveEntryIds.has(entry.entryId));
    if (candidate === undefined) {
        return {
            candidateEntryId: null,
            reviewId: null,
            currentRevisionPaths: [],
            reasons: ['task-close-entry-missing'],
        };
    }
    const reasons = [];
    const currentRevisionPaths = [manifest.phasePath];
    let reviewId = null;
    try {
        if (!manifest.phasePath.endsWith('/task-definition.md')) {
            reasons.push('task-close-anchor-invalid');
        }
        const summaryPath = manifest.phasePath.endsWith('/task-definition.md')
            ? `${manifest.phasePath.slice(0, -'task-definition.md'.length)}implementation-summary.md`
            : '';
        const taskArtifact = (0, context_storage_1.readBoundedRepositoryFile)(repositoryRoot, manifest.phasePath, 'Direct Basic task definition');
        const summaryArtifact = (0, context_storage_1.readBoundedRepositoryFile)(repositoryRoot, summaryPath, 'Direct Basic implementation summary');
        currentRevisionPaths.push(summaryPath);
        if (taskArtifact.hash !== manifest.phaseHash) {
            reasons.push('task-close-task-revision-changed');
        }
        if (candidate.artifactPath !== summaryPath || candidate.artifactHash !== summaryArtifact.hash) {
            reasons.push('task-close-summary-revision-changed');
        }
        const taskText = node_fs_1.default.readFileSync(taskArtifact.absolutePath, 'utf8');
        const summaryText = node_fs_1.default.readFileSync(summaryArtifact.absolutePath, 'utf8');
        const pair = (0, task_lifecycle_1.projectTaskLifecyclePair)({
            taskDefinition: taskText,
            implementationSummary: summaryText,
        });
        const currentAttempt = pair.summary?.currentAttempt ?? null;
        if (pair.blockingFindings.length !== 0) {
            reasons.push('task-close-canonical-pair-invalid');
        }
        if (pair.task.status !== 'completed' || pair.task.readiness !== 'completed') {
            reasons.push('task-close-task-not-completed');
        }
        if (pair.summary?.status !== 'completed' ||
            pair.summary.completedAt === null ||
            currentAttempt?.implementationStatus !== 'completed' ||
            (currentAttempt.reviewDisposition !== 'accepted' &&
                currentAttempt.reviewDisposition !== 'accepted_with_follow_up') ||
            currentAttempt.closedAt === null) {
            reasons.push('task-close-summary-not-completed-accepted-closed');
        }
        const evidenceDocument = (0, context_storage_1.parseObjectJson)((0, evidence_store_1.readLifecycleEvidenceBytesSync)({
            repositoryRoot,
            runDirectory: manifest.runDirectory,
            entry: candidate,
            maximumBytes: context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES,
        }).bytes, 'Recorded task close evidence');
        const result = (0, context_storage_1.asRecord)(evidenceDocument.result) ??
            (evidenceDocument.status === 'ok' || evidenceDocument.status === 'error' ? evidenceDocument : null);
        const data = (0, context_storage_1.asRecord)(result?.data);
        const receipt = (0, context_storage_1.asRecord)(data?.reviewReceipt);
        reviewId = typeof receipt?.reviewReceiptId === 'string' ? receipt.reviewReceiptId : null;
        if (result?.status !== 'ok' ||
            result?.command !== 'task close' ||
            data?.transition !== 'close' ||
            data?.writeOutcome !== 'committed' ||
            data?.failure !== null ||
            !Array.isArray(data?.conflicts) ||
            data.conflicts.length !== 0) {
            reasons.push('task-close-result-invalid');
        }
        if (data?.taskDefinitionPath !== manifest.phasePath || data?.implementationSummaryPath !== summaryPath) {
            reasons.push('task-close-pair-mismatch');
        }
        const changedPaths = Array.isArray(data?.changedPaths)
            ? data.changedPaths.filter((value) => typeof value === 'string')
            : [];
        if (!changedPaths.includes(manifest.phasePath) || !changedPaths.includes(summaryPath)) {
            reasons.push('task-close-write-set-incomplete');
        }
        const authorizes = Array.isArray(receipt?.authorizes) ? receipt.authorizes : [];
        if (reviewId === null ||
            !candidate.receiptIds.includes(reviewId) ||
            receipt?.taskDefinitionPath !== manifest.phasePath ||
            receipt?.implementationSummaryPath !== summaryPath ||
            receipt?.attemptId !== pair.summary?.currentAttemptId ||
            receipt?.implementationStatus !== 'completed' ||
            (receipt?.reviewDisposition !== 'accepted' && receipt?.reviewDisposition !== 'accepted_with_follow_up') ||
            receipt?.blockerCount !== 0 ||
            !authorizes.includes('close') ||
            receipt?.taskRevision !== data?.taskRevision ||
            receipt?.implementationSummaryRevision !== data?.implementationSummaryRevision) {
            reasons.push('task-close-review-receipt-invalid');
        }
    }
    catch {
        reasons.push('task-close-evidence-invalid');
    }
    return {
        candidateEntryId: candidate.entryId,
        reviewId,
        currentRevisionPaths: [...new Set(currentRevisionPaths.filter((value) => value !== ''))].sort((left, right) => left.localeCompare(right)),
        reasons: [...new Set(reasons)],
    };
}
function inspectTerminalPhaseReview(repositoryRoot, manifest) {
    const inactiveEntryIds = collectInactiveLifecycleEntryIds(manifest);
    const candidate = [...manifest.entries]
        .reverse()
        .find((entry) => entry.commandIdentity === 'phase review' && entry.status === 'ok' && !inactiveEntryIds.has(entry.entryId));
    if (candidate === undefined) {
        return {
            candidateEntryId: null,
            reviewId: null,
            currentRevisionPaths: [],
            reasons: ['phase-review-entry-missing'],
        };
    }
    const reasons = [];
    const currentRevisionPaths = [];
    let reviewId = null;
    try {
        const evidenceDocument = (0, context_storage_1.parseObjectJson)((0, evidence_store_1.readLifecycleEvidenceBytesSync)({
            repositoryRoot,
            runDirectory: manifest.runDirectory,
            entry: candidate,
            maximumBytes: context_capture_1.MAX_LIFECYCLE_RUN_RESULT_BYTES,
        }).bytes, 'Recorded phase review evidence');
        const result = (0, context_storage_1.asRecord)(evidenceDocument.result) ??
            (evidenceDocument.status === 'ok' || evidenceDocument.status === 'error' ? evidenceDocument : null);
        const data = (0, context_storage_1.asRecord)(result?.data);
        const receipt = (0, context_storage_1.asRecord)(data?.phaseReviewReceipt);
        reviewId = typeof receipt?.reviewId === 'string' ? receipt.reviewId : null;
        if (result?.status !== 'ok' || result?.command !== 'phase review') {
            reasons.push('phase-review-result-invalid');
        }
        if (manifest.metadataPosture !== 'read-only' ||
            data?.metadataPosture !== 'read-only' ||
            receipt?.metadataPosture !== 'read-only') {
            reasons.push('phase-review-posture-not-read-only');
        }
        if (data?.phaseOverviewPath !== manifest.phasePath ||
            receipt?.phaseOverviewPath !== manifest.phasePath ||
            candidate.artifactPath !== manifest.phasePath) {
            reasons.push('phase-review-phase-mismatch');
        }
        if (data?.reviewMode !== 'evidence' ||
            receipt?.reviewMode !== 'evidence' ||
            receipt?.complete !== true ||
            receipt?.blockerCount !== 0 ||
            !Array.isArray(data?.blockingIssues) ||
            data.blockingIssues.length !== 0) {
            reasons.push('phase-review-not-clean-and-complete');
        }
        if (reviewId === null || !candidate.receiptIds.includes(reviewId)) {
            reasons.push('phase-review-receipt-not-indexed');
        }
        else {
            const receiptWithoutId = { ...receipt };
            delete receiptWithoutId.reviewId;
            const expectedReviewId = `phase-review-${(0, node_crypto_1.createHash)('sha256')
                .update(JSON.stringify(receiptWithoutId))
                .digest('hex')
                .slice(0, 24)}`;
            if (expectedReviewId !== reviewId)
                reasons.push('phase-review-receipt-id-invalid');
        }
        const transitions = Array.isArray(receipt?.metadataStatusTransitions) ? receipt.metadataStatusTransitions : [];
        const reconciliations = Array.isArray(receipt?.reconciliationEvidence) ? receipt.reconciliationEvidence : [];
        const transitionPaths = new Set();
        for (const value of transitions) {
            const transition = (0, context_storage_1.asRecord)(value);
            const artifactPath = typeof transition?.artifactPath === 'string' ? transition.artifactPath : null;
            const revision = typeof transition?.artifactRevision === 'string' ? transition.artifactRevision : null;
            if (artifactPath === null ||
                revision === null ||
                transition?.eligible !== true ||
                transitionPaths.has(artifactPath)) {
                reasons.push('phase-review-transition-invalid');
                continue;
            }
            transitionPaths.add(artifactPath);
            currentRevisionPaths.push(artifactPath);
            if (!(0, context_storage_1.currentRevisionMatches)(repositoryRoot, artifactPath, revision)) {
                reasons.push(`phase-review-descendant-changed:${artifactPath}`);
            }
        }
        if (!transitionPaths.has(manifest.phasePath)) {
            reasons.push('phase-review-phase-revision-missing');
        }
        const reconciliationMilestones = new Set();
        for (const value of reconciliations) {
            const reconciliation = (0, context_storage_1.asRecord)(value);
            const milestonePath = typeof reconciliation?.milestoneOverviewPath === 'string' ? reconciliation.milestoneOverviewPath : null;
            const reconciliationPath = typeof reconciliation?.reconciliationPath === 'string' ? reconciliation.reconciliationPath : null;
            const revision = typeof reconciliation?.reconciliationRevision === 'string' ? reconciliation.reconciliationRevision : null;
            if (milestonePath === null ||
                reconciliationPath === null ||
                revision === null ||
                reconciliation?.completedNonPlaceholder !== true ||
                reconciliationMilestones.has(milestonePath)) {
                reasons.push('phase-review-reconciliation-invalid');
                continue;
            }
            reconciliationMilestones.add(milestonePath);
            currentRevisionPaths.push(reconciliationPath);
            if (!transitionPaths.has(milestonePath)) {
                reasons.push(`phase-review-milestone-revision-missing:${milestonePath}`);
            }
            if (!(0, context_storage_1.currentRevisionMatches)(repositoryRoot, reconciliationPath, revision)) {
                reasons.push(`phase-review-descendant-changed:${reconciliationPath}`);
            }
        }
        const milestoneTransitionPaths = [...transitionPaths].filter((candidatePath) => candidatePath !== manifest.phasePath);
        if (milestoneTransitionPaths.some((candidatePath) => !reconciliationMilestones.has(candidatePath))) {
            reasons.push('phase-review-reconciliation-set-incomplete');
        }
    }
    catch {
        reasons.push('phase-review-evidence-invalid');
    }
    return {
        candidateEntryId: candidate.entryId,
        reviewId,
        currentRevisionPaths: [...new Set(currentRevisionPaths)].sort((left, right) => left.localeCompare(right)),
        reasons: [...new Set(reasons)],
    };
}
function collectInactiveLifecycleEntryIds(manifest) {
    return new Set([
        ...manifest.entries.flatMap((entry) => (entry.supersedesEntryId === null ? [] : [entry.supersedesEntryId])),
        ...manifest.contractRevisions.flatMap((checkpoint) => [
            checkpoint.reviewEntryId,
            ...checkpoint.invalidatedEntryIds,
        ]),
    ]);
}
