/**
 * ONE TOOL CALL ATTEMPT, ONE RECORD — the occurrence.
 *
 * A tool call on one leg (one `toolCallId`, one attempt) has a single record here, and everything the engine
 * says about the call is read off it: the `tool_start` / `tool_end` frames (projected in `tool-end-body.ts`), the
 * `tool_progress` heartbeat (`tool-progress-lane.ts`), the trace row's `ok`, and the resumed leg's
 * `executionOutcome` filing. The record has three parts:
 *
 *  - the EXECUTION LIFE, monotonic: `announced` (the start frame is out) → `released` (the engine let the call go
 *    to its executor: the resumed leg right before it runs the tool body itself, a live leg at the gate's allow
 *    exit — the loop starts the body after it and the runner does not observe that moment) → `settled` or
 *    `interrupted`. A call that closes still `announced` was never let go: whatever the tool's body did, this call
 *    did not do it (`refusedBeforeRelease`, `tool-not-executed.ts`). Leaving a terminal state is an engine defect and throws;
 *  - the WAIT ON A PERSON, re-entrant: every ask put to the person's seat for this call counts one entry and one
 *    exit (several rounds of one gate pass, a confirmation asked during the execution) — a count, never a bit,
 *    because the waits nest and overlap;
 *  - the GATE ROUNDS: one record per gate exit for this call, and one more when a station AFTER the gate refuses
 *    it (the shell read admission that re-establishes what the gate judged, a resumed leg's belts). The latest
 *    record is the call's disposition: a refusal after the gate is a refusal, never a tool failure under an
 *    `allowed` record.
 *
 * WHAT IS NOT HERE: frames, clocks of a lane, the deny observer. This module is the record and its transitions;
 * the projections read it. A durable park that crosses legs is two occurrences on two tables (the parking leg's,
 * the resumed leg's), joined by the checkpoint row the resumed leg was opened from — never by a field here.
 */
import type { DeniedBy, GateOutcome } from "../gate-outcome.js";
/** The one clock the occurrence's heartbeat facts are stamped on. MONOTONIC for the reason the progress lane
 *  states: every reading is subtracted from another, and a wall-clock step backwards would silence the beat. A
 *  host without `performance` falls back to the wall clock and inherits its rollback behaviour. */
export declare const occurrenceClock: () => number;
/** Where a call's execution life stands — see the module header for the order. */
export type OccurrenceLife = "announced" | "released" | "settled" | "interrupted";
/** What opens an occurrence: the facts its start frame carries. */
export interface OccurrenceStart {
    readonly toolCallId: string;
    /** The name the frames carry — the model's spelling on a live leg, the parked row's spelling on a resumed one. */
    readonly spelledName: string;
    /** The name of the tool the call dispatches to on the live roster — the name every gate station judged (absent when
     *  the station opening the record does not know it). */
    readonly wireName?: string;
    /** The tool's display label, when it differs from the name. */
    readonly label?: string;
    /** The arguments the start frame carries (for a recovered start: the call's own input as the transcript holds it). */
    readonly args: unknown;
}
/** The record, as its readers see it. Written only through {@link ToolOccurrenceTable}. */
export interface ToolOccurrence extends OccurrenceStart {
    /** 1 for the first attempt of this id on this table, counting re-announcements of a reused id. */
    readonly attempt: number;
    readonly life: OccurrenceLife;
    /** How many asks put to the person for this call are open right now. */
    readonly awaitingUser: number;
    /** One outcome per gate exit, plus one per refusal after the gate; the last one is the call's disposition. */
    readonly gateRounds: readonly GateOutcome[];
    /** The input the latest gate exit decided on, as a FROZEN snapshot (absent when no gate saw the call). */
    readonly finalInput?: unknown;
    /** The call's start frame is out on this leg. */
    readonly startEmitted: boolean;
    /** When the call was announced, on {@link occurrenceClock} — the heartbeat's elapsed origin. */
    readonly startedAt: number;
    /** The last moment anything was heard from the call (a frame for it, or its return from a wait on the person). */
    readonly lastHeardAt: number;
    /** The heartbeat covers it. Cleared when the loop leaves the call behind at a turn end with no end of its own:
     *  the record stays (a later settlement must still know its start frame went out) but no beat describes it. */
    readonly beating: boolean;
}
/** The table of one leg's occurrences — the record's only writer. */
export interface ToolOccurrenceTable {
    /** The live (unsettled) attempt for this id, if any. */
    get(toolCallId: string): ToolOccurrence | undefined;
    /** Every live attempt, in the order they were opened. */
    live(): readonly ToolOccurrence[];
    /** Open a new attempt. A live earlier attempt for the same id is superseded: the loop left it behind without an
     *  end (a reused id can only be re-announced after its earlier call stopped producing events), and nothing can
     *  settle it any more. */
    open(start: OccurrenceStart): ToolOccurrence;
    /** The live attempt for this id, opened from `start` when there is none — a call the engine is told about
     *  before it was announced (a frame the loop's own start never preceded). */
    ensure(start: OccurrenceStart): ToolOccurrence;
    /** The call's start frame is out. */
    noteStartEmitted(toolCallId: string): void;
    /** The engine lets the call go to its executor — the one transition into `released`, whichever leg makes it. */
    release(toolCallId: string): void;
    /** A gate exit for this call: its record and the input it decided on (frozen by the gate's exit). */
    gateRound(toolCallId: string, outcome: GateOutcome, finalInput?: unknown): void;
    /** A station after the gate refused the call: one more gate record, minted as a veto of whatever the latest one
     *  settled (a person's yes stays on the settlement; the refusing layer is the disposition). Returns the record. */
    refuse(toolCallId: string, layer: DeniedBy): GateOutcome;
    /** An ask for this call is put to the person: the count rises, and the returned `resumeFromUser` lowers it once
     *  (a second call is a no-op). The pair is bound to THIS attempt — a return after the call ended, or after a
     *  reused id re-opened, touches nothing — and an ask for a call this leg does not hold counts nothing: the wait
     *  is the person's, and no bookkeeping here may turn their answer into a failure. */
    awaitUser(toolCallId: string): () => void;
    /** The one bracket every asker uses: the count rises before `ask` puts its question and lowers when the answer
     *  settles, either way. Returns `ask`'s own value, so the asker awaits exactly what it awaited before; a synchronous
     *  answer (or anything that is not a promise) was no wait at all. */
    whileAwaitingUser<T>(toolCallId: string, ask: () => T): T;
    /** A frame for the call went out: its silence clock restarts. */
    heard(toolCallId: string): void;
    /** The call ended: it leaves the table and the record is returned for the end projection. */
    close(toolCallId: string, life: "settled" | "interrupted"): ToolOccurrence | undefined;
    /** The heartbeat stops covering every live attempt (turn end, leg teardown). Records stay. */
    quiesce(): void;
    /** Called whenever an attempt opens (the heartbeat arms its timer). One listener — the leg's one lane. */
    onOpen(listener: () => void): void;
}
export declare function createToolOccurrenceTable(): ToolOccurrenceTable;
