/** * Durable handoff ledger shared by crew's wicked-interactive seams (task #86, Phase 7c). * * Extracted from the draft leg (draft-events.ts, PR #241) when the structural-edit leg arrived, * because both seams need the same replay-dedup discipline with DIFFERENT key grammars: * * - the DRAFT leg keys by document id — one first draft per document lifetime; * - the EDIT leg keys by `:v` — one governed edit per HANDOFF, because the same * document legitimately produces many structural handoffs over its life (versioned targeting). * * The ledger itself is key-agnostic: a durable map `key → HandoffLedgerEntry`, JSON on disk, * written atomically (tmp + rename). The bus cursor alone cannot carry this: at-least-once * delivery means the same trigger can arrive again after a crash between handling and cursor * advance, and in-memory state dies with the process. The ledger is the system of record for * "this handoff was answered"; each seam's in-flight map is just the live half. */ /** One ledger row — the lifecycle of a handoff a seam answered. */ export interface HandoffLedgerEntry { runId: string; launchedAt: string; /** Set once the closing event (draft.completed / edit.completed) was emitted. */ emittedAt?: string; /** Set when the governed run ended without a usable result; kept so a redelivered trigger * does not silently relaunch a run an operator should look at first. */ failedAt?: string; } export declare class InteractiveHandoffLedger { private readonly path; private entries; constructor(path: string); has(key: string): boolean; get(key: string): HandoffLedgerEntry | undefined; recordLaunch(key: string, runId: string): void; recordEmitted(key: string): void; recordFailure(key: string): void; size(): number; /** Every row as `[key, entry]` — a snapshot (the doc↔run index reads the binding off the key). */ rows(): Array<[string, HandoffLedgerEntry]>; /** * Drop every row belonging to one document (crew#338 — a deleted/retired doc must not leave * ghost rows that shadow its name forever). BOTH key grammars are swept, which is why this is * a prefix sweep and not a single `delete entries[docId]`: * * - the exact key `` (draft leg + the demo leg's doc-created row); * - every `:` key (edit/demo `:v`, chat `:m:` / * `:e:`). * * The `:` separator cannot appear inside a doc name (interactive's DOC_NAME grammar is * `^[a-z0-9][a-z0-9-]{0,63}$`), so the prefix can never match a sibling document's rows. * * Idempotent by construction — removing rows that are not there removes nothing — which is * what makes it safe under at-least-once redelivery of the retire fact. Persisted atomically * (tmp + rename, like every other write) and ONLY when something was actually removed, so a * sweep of a doc this ledger never answered does not create or rewrite the file. * * `keep` (EP-C2): rows of the name that are NOT this document's — a review row of the same-named * document in another project (`:review::…` carries its project) — stay. * * @returns the removed keys (empty = nothing to remove). */ removeDoc(documentId: string, keep?: (key: string) => boolean): string[]; private persist; } //# sourceMappingURL=ledger.d.ts.map