/**
 * strategies/boundary-commit.ts
 *
 * Boundary commit — persists a compacted snapshot as a named checkpoint with
 * full lineage tracking for replay-safe session resumption.
 *
 * A boundary commit is always created after a successful compaction strategy
 * run (microcompact, collapse, autocompact, or reactive). It forms the
 * persistent anchor point that the resume-repair pipeline uses to restore
 * a session from a corrupted or partial state.
 *
 * Lineage is append-only: each commit appends its own checkpointId to the
 * parent's lineage array. This means any checkpoint can be sliced from any
 * earlier commit without re-ordering.
 */
import { randomUUID } from 'node:crypto';
/** Simple prefix for generated checkpoint IDs. */
const CHECKPOINT_PREFIX = 'cpt';
/**
 * Generates a checkpoint ID using the current timestamp and a random suffix.
 * Format: `cpt_<timestamp>_<random>`
 */
function generateCheckpointId() {
    const ts = Date.now().toString(36);
    const rand = randomUUID().slice(0, 8);
    return `${CHECKPOINT_PREFIX}_${ts}_${rand}`;
}
/**
 * Creates a new BoundaryCommit from a strategy output.
 *
 * The new commit's lineage is derived by appending its own checkpointId
 * to the parent's lineage (or starting a fresh lineage if `parent` is null).
 *
 * @param options - Commit options.
 * @returns A fully populated BoundaryCommit.
 */
export function createBoundaryCommit(options) {
    const { sessionId, strategyOutput, parent, tokensBefore } = options;
    const checkpointId = generateCheckpointId();
    const parentLineage = parent?.lineage ?? [];
    const lineage = [...parentLineage, checkpointId];
    return {
        checkpointId,
        sessionId,
        createdAt: Date.now(),
        strategy: strategyOutput.strategy,
        parentCheckpointId: parent?.checkpointId ?? null,
        lineage,
        messages: strategyOutput.messages,
        tokenCount: strategyOutput.tokensAfter,
        tokensBefore,
        summary: strategyOutput.summary,
    };
}
/**
 * Validates a BoundaryCommit for replay-safety.
 *
 * A commit is replay-safe if:
 * - It has at least one message
 * - Its lineage is ordered and contains its own checkpointId
 * - Its tokenCount is positive
 *
 * @returns An array of validation error strings (empty = valid).
 */
export function validateBoundaryCommit(commit) {
    const errors = [];
    if (commit.messages.length === 0) {
        errors.push('boundary_commit: no messages in checkpoint');
    }
    if (commit.tokenCount <= 0) {
        errors.push('boundary_commit: tokenCount must be positive');
    }
    if (!commit.lineage.includes(commit.checkpointId)) {
        errors.push('boundary_commit: checkpointId not found in lineage (lineage is corrupted)');
    }
    if (commit.lineage.length === 0) {
        errors.push('boundary_commit: lineage is empty');
    }
    return errors;
}
