/**
 * CoherenceJournalReader — the bounded, merged READ path for the coherence
 * journal (P1.2 of multi-machine coherence).
 *
 * Spec: docs/specs/COHERENCE-JOURNAL-SPEC.md §3.5 (Read API — bounded, honest
 * about trust and time) and §3.1 (stream layout).
 *
 * DELIBERATELY SEPARATE from the writer (`CoherenceJournal`): §3.9's
 * actuation-ban lint targets imports of THIS module — no actuating code path
 * (kill / spawn / place / transfer / reap) may consume journal data. Keeping
 * the reader its own module gives that lint a single, precise symbol to grep.
 *
 * Read-side discipline (§3.5):
 *  - `machine` / `kind` query params are NEVER used to build a file path. They
 *    are matched against the enumerated on-disk stream set (a directory
 *    listing), so a traversal-shaped param simply matches nothing — the
 *    read-side mirror of the write-side sanitization.
 *  - Reads are reverse-tail (reuse `readTailTolerant`), O(limit) not O(file).
 *  - `limit` is server-capped (≤500). Each query has a total byte ceiling
 *    (default 4MB) and a generic per-stream archive-file scan cap (default 8)
 *    — EXCEPT `kind=topic-placement` queries, which are ANSWER-COMPLETE: they
 *    scan all placement archives newest-first until `limit` is satisfied (the
 *    byte ceiling stays the hard bound). Over any bound → partial +
 *    `truncated: true`.
 *  - Merged ordering: `(epoch, ts)` for topic-placement (epoch from
 *    `data.epoch`); `(ts, machineId, seq)` for other kinds. The opaque
 *    base64url cursor encodes THE QUERY'S order key — a cursor over a different
 *    key than the sort order would skip/duplicate at boundaries. A malformed
 *    cursor is rejected with a clean error, never a crash.
 *  - topic-placement entries sharing one `(topic, epoch)` collapse to
 *    first-seen (defense-in-depth dedupe, §3.1).
 *  - Per-line tolerant parsing everywhere; corrupt lines skipped + counted.
 *  - Replication states (`behind`/`gapped`/`suspect`/`reset`) arrive in P1.3;
 *    P1.2 reports status `current` for every present stream.
 */
import { type JournalEntry, type JournalFs } from './CoherenceJournal.js';
/** Server-side caps (§3.5). */
export declare const READER_MAX_LIMIT = 500;
export declare const READER_DEFAULT_LIMIT = 100;
/** Per-query total byte ceiling — the hard bound across ALL streams scanned. */
export declare const READER_DEFAULT_BYTE_CEILING: number;
/** Generic archive-file scan cap per stream (NOT applied to topic-placement). */
export declare const READER_DEFAULT_ARCHIVE_CAP = 8;
export type StreamSource = 'own' | 'replica';
/** P1.2 reports `current`; the rest land with the P1.3 replication states. */
export type StreamStatusName = 'current' | 'behind' | 'gapped' | 'suspect' | 'reset';
/** A merged entry as returned by the read API. */
export interface ReaderEntry extends JournalEntry {
    source: StreamSource;
    /** When THIS machine learned a replicated entry (replica streams only). */
    recvTs?: string;
}
/** One row of the response `streams` map. */
export interface ReaderStreamStatus {
    incarnation?: string;
    lastSeq: number;
    lastTs: string | null;
    source: StreamSource;
    status: StreamStatusName;
    stalenessMs: number | null;
}
export interface ReaderQueryOpts {
    topic?: number;
    kind?: string;
    machine?: string;
    limit?: number;
    cursor?: string;
}
export interface ReaderQueryResult {
    entries: ReaderEntry[];
    streams: Record<string, ReaderStreamStatus>;
    skippedCorrupt: number;
    truncated: boolean;
}
/**
 * Own-stream autonomous-run evidence for ONE topic (P2 §3.1 source 2).
 * Own stream ONLY by construction — `query()`'s merged own+replica view is
 * deliberately not used: replicas NOMINATE, they never feed THIS machine's
 * manifest (WORKING-SET-HANDOFF-SPEC §3.1).
 */
export interface OwnAutonomousRuns {
    /** Own-stream autonomous-run entries for the topic, newest-first. */
    entries: ReaderEntry[];
    /** True when the newest `started` run has no matching `stopped`. */
    liveRun: boolean;
    /** Union of jailed artifactPaths across the entries, deduped, order-stable. */
    artifactPaths: string[];
    /** Byte/archive bound hit — the answer may be missing older evidence. */
    truncated: boolean;
}
export interface CoherenceJournalReaderConfig {
    /** Absolute path to the agent's `.instar/` directory (the stateDir). */
    stateDir: string;
    /** Per-query total byte ceiling. Default 4MB. */
    byteCeiling?: number;
    /** Generic archive-file scan cap per stream. Default 8. */
    archiveCap?: number;
    /** Optional clock override (tests). */
    now?: () => Date;
    /** Optional fs seam (tests). Defaults to node:fs primitives. */
    fsImpl?: JournalFs;
}
/** Raised when a supplied cursor cannot be parsed. The route maps it to 400. */
export declare class InvalidCursorError extends Error {
    constructor(message?: string);
}
export declare class CoherenceJournalReader {
    private readonly stateDir;
    private readonly byteCeiling;
    private readonly archiveCap;
    private readonly now;
    private readonly io;
    constructor(config: CoherenceJournalReaderConfig);
    private dirPath;
    private peersDirPath;
    /**
     * Enumerate every on-disk stream file (own current + archives, peer replicas).
     * `machine` / `kind` filters are matched HERE against the discovered set —
     * never used to build a path — so a traversal-shaped param matches nothing.
     */
    private enumerate;
    private scanDir;
    private encodeCursor;
    private decodeCursor;
    query(opts?: ReaderQueryOpts): ReaderQueryResult;
    /**
     * P2 §3.1: the working-set manifest's journal-evidence source. Reads the
     * OWN stream only (source === 'own', machineId === ownMachineId — never a
     * replica, never a peer's stream that happens to sit in our own dir),
     * kind `autonomous-run`, filtered to `topic`. Bounded exactly like query()
     * (shared byte ceiling + archive cap); over-bound → truncated: true, the
     * caller treats the evidence as partial rather than failing.
     */
    readOwnAutonomousRuns(topic: number, ownMachineId: string): OwnAutonomousRuns;
    /** The opaque cursor for the LAST entry of a page (callers echo it back). */
    cursorFor(entry: ReaderEntry, isPlacement: boolean): string;
    private epochOf;
    /**
     * Merge order (§3.5):
     *  - topic-placement: (epoch, ts, machineId, seq)
     *  - other kinds:     (ts, machineId, seq)
     * Returned NEWEST-FIRST (descending) — the read API returns most-recent.
     */
    private sortMerged;
    /** Ascending compare on the query's order key. */
    private compareKey;
    /** Compare an entry against a cursor on the query's order key (ascending). */
    private compareToCursor;
    /**
     * Keyset pagination: results are NEWEST-FIRST, the cursor names the last
     * entry already returned, so the next page is everything STRICTLY BEFORE
     * the cursor in descending order (i.e. compareToCursor < 0). No skip/dup at
     * equal-ts boundaries because the full composite key disambiguates.
     */
    private dropThroughCursor;
    /** topic-placement (topic, epoch) collapse to first-seen (§3.1 dedupe). */
    private collapsePlacement;
    private groupStreams;
    /**
     * Newest-first file order for one stream: the current file (no numeric
     * stamp) first, then archives by descending numeric stamp (newest archive
     * before oldest). Archive stamps embed the rotation time (see writer).
     */
    private orderNewestFirst;
    private archiveStamp;
    /**
     * Build the response `streams` map: one row per discovered stream file's
     * logical stream (`<machineId>.<kind>`), reading the durable tail for
     * lastSeq / lastTs and meta for incarnation. P1.2 reports status `current`.
     */
    private buildStreamMap;
    /** Read the incarnation token from the stream set's meta sidecar, if present. */
    private readIncarnation;
    /**
     * recvTs for a replica file. P1.2 has no per-entry receipt stamp on disk yet
     * (that rides the P1.3 apply path); we surface the replica file's mtime as a
     * best-effort "when this machine last learned something on this stream".
     */
    private recvTsFor;
    private safeSize;
    private clampLimit;
}
//# sourceMappingURL=CoherenceJournalReader.d.ts.map