/** * Sentient Event Chain Walker — Merkle chain verification and traversal. * * Provides two utilities for working with the Merkle-chained sentient event * log written by {@link appendSentientEvent}: * * - {@link verifyEventChain} — scans the entire event log and validates that * every `parentHash` matches the SHA-256 of the prior event's serialised * line. Returns a summary with a count of broken links and the first * broken event ID. * * - {@link walkChainFrom} — returns all events from a given `receiptId` * forward to the end of the log, in chronological (append) order. * Used by the revert ritual (T1012) to collect merge events since an anchor. * * ## Chain structure * * Each line in `.cleo/audit/sentient-events.jsonl` is a standalone JSON * object. The Merkle link is: * * ``` * event[n].parentHash = sha256(rawLine[n-1]) * ``` * * where `rawLine[n-1]` is the exact UTF-8 bytes written by * `appendSentientEvent` (no trailing newline included in the hash input — * the hash is taken over the JSON token only). * * The genesis event carries `parentHash = "0".repeat(64)`. * * @see DESIGN.md §8 T1010-S5 * @task T1025 */ import type { SentientEvent } from './events.js'; /** Error code thrown by {@link walkChainFrom} for unknown receipt IDs. */ export declare const E_RECEIPT_NOT_FOUND = "E_RECEIPT_NOT_FOUND"; /** * Result returned by {@link verifyEventChain}. * * All counts refer to events in the log at the time of the call. */ export interface ChainVerifyResult { /** Total number of events in the log. */ total: number; /** Number of events whose `parentHash` was correctly verified. */ verified: number; /** * Number of events with an incorrect `parentHash`. * * A non-zero value indicates tampering, insertion, or deletion. */ broken: number; /** * The `receiptId` of the first event whose `parentHash` does not match * the SHA-256 of the previous serialised event line. * * `undefined` when `broken === 0`. */ firstBrokenAt?: string; /** * Number of events signed by a key that is NOT in the owner allowlist. * * A non-zero value indicates that an event was signed by an unrecognised * key. In non-strict mode this is logged as a warning; in strict mode * (`CLEO_STRICT_ALLOWLIST=1`) this is treated as a chain break. */ signerNotInAllowlist: number; /** * The `receiptId` of the first event whose signer is not in the allowlist. * * `undefined` when `signerNotInAllowlist === 0`. */ firstUnknownSignerAt?: string; } /** * Verify the Merkle chain of the entire sentient event log. * * Reads every line from `/.cleo/audit/sentient-events.jsonl` * and recomputes each `parentHash`. A hash mismatch indicates that the log * was mutated after the fact (insertion, deletion, or content change). * * Returns `{ broken: 0 }` when the log is absent or empty — an empty chain * is trivially valid. * * @param projectRoot - Absolute path to the CLEO project root. * @returns A {@link ChainVerifyResult} describing chain integrity. * * @example * ```ts * import { verifyEventChain } from '@cleocode/core/sentient/chain-walker.js'; * * const result = await verifyEventChain(projectRoot); * if (result.broken > 0) { * console.error('Chain broken at:', result.firstBrokenAt); * } * ``` */ export declare function verifyEventChain(projectRoot: string): Promise; /** * Walk the event chain forward from a given receipt ID. * * Returns all events from the event identified by `receiptId` (inclusive) * through to the last event in the log, in chronological (append) order. * * This is used by the revert ritual to collect all `merge` events that * occurred after a given anchor point — the caller can then build the * squashed-revert commit from that set. * * @param projectRoot - Absolute path to the CLEO project root. * @param receiptId - The `receiptId` of the starting event (inclusive). * @returns Array of {@link SentientEvent} from `receiptId` to HEAD. * @throws `E_RECEIPT_NOT_FOUND` if no event with the given `receiptId` * exists in the log. * * @example * ```ts * import { walkChainFrom } from '@cleocode/core/sentient/chain-walker.js'; * * const mergeEvents = (await walkChainFrom(projectRoot, anchorReceiptId)) * .filter(e => e.kind === 'merge'); * ``` */ export declare function walkChainFrom(projectRoot: string, receiptId: string): Promise; //# sourceMappingURL=chain-walker.d.ts.map