/** * Graph Execution Engine v2 — Signal Bridge * * Version: 2.0 * Date: 2026-07-24 * * A read-only seam over the signal subsystem. When a graph node emits a * `signal()` call, the engine intercepts it here and: * * 1. Records the signal (type → payload) into the per-node * `NodeRuntimeState.signalsObserved` ledger. * 2. For **terminating** signals, fires the `onNodeSignalEmitted` callback * hook (implemented in a later subtask — this module only defines the * interface and the callback-injection point). * * The 8-signal vocabulary is imported from `src/signal/signal-constants.ts` * (the single source of truth), then re-exported for backward-compatible * engine-side consumption. No signal-type definitions live here — every * constant is routed through `signal-constants.ts`. * * Design reference: `.rolebox/design/engine-state-machine.md` §3.4. */ import type { EngineState, SignalLedgerSource } from "../../types.engine-v2.ts"; import { SIGNAL_TYPES, TERMINATING_SIGNALS, PAUSING_SIGNALS, HANDOFF_SIGNALS, INFO_SIGNALS, ALL_SIGNAL_TYPES, type SignalType } from "../../signal/signal-constants.ts"; export { SIGNAL_TYPES, TERMINATING_SIGNALS, PAUSING_SIGNALS, HANDOFF_SIGNALS, INFO_SIGNALS, ALL_SIGNAL_TYPES, type SignalType }; /** * Fired when a graph node emits a **terminating** signal. * * Implemented in a later subtask. This bridge defines the contract and the * injection point only — the implementation advances the node lifecycle * (running → completed/escalate), materializes results, and propagates edge * payloads. */ export type NodeSignalEmittedListener = (nodeId: string, type: SignalType, payload: unknown) => void; /** * Maximum number of signal events retained per node in * {@link SignalLedgerEntry.history} (Y19). * * The history is append-only and every non-critical flush serializes the whole * graph state, so an unbounded history made a long-running loop's ledger grow * linearly with its round count and re-serialize that growth on every write. * Retaining the most recent events bounds the graph_status stream / since * window without touching the authoritative signals / lastSignalAt fields. * Mirrors recorder.ts's CHECKPOINT_HISTORY_CAP (50) for the per-node * checkpoint trace. */ export declare const SIGNAL_LEDGER_HISTORY_LIMIT = 50; /** * Record a signal into the per-node ledger WITHOUT firing terminating * listeners. This is the single ledger-write path for the engine's synthetic * signal producers (the approval handler and the engine-advance race-guard * deferral) so `SignalLedgerEntry.history` / `lastSignalAt` stay complete for * every signal the engine records — matching live-worker signals that flow * through {@link SignalBridge.record}. * * - Writes `node.signalsObserved[type] = value` (payload normalized to `null` * when absent, mirroring `SignalBridge.record` semantics). * - Updates the graph-level `signalLedger` entry (signals, lastSignalAt, * ordered history trimmed to the most recent * {@link SIGNAL_LEDGER_HISTORY_LIMIT} events) — the single ledger-write path * that {@link SignalBridge.record} delegates to. * - Does NOT fire terminating listeners: firing is the control-flow concern * owned by {@link SignalBridge.record}. Synthetic producers must not trigger * re-entrant advancement, so they route through this pure helper instead. * * For non-signal context stashes (e.g. `approval_payload`) the node write is * performed but no ledger event is synthesized — the history backs real * signals only, per the `SignalLedgerEntry` contract in types.engine-v2.ts. * * @param state Engine state (used for the graph-level `signalLedger` write). * @param nodeId The node the signal is recorded for. * @param type Signal type (or a non-signal stash key, e.g. `approval_payload`). * @param payload Optional signal payload. * @param source Origin discriminator for the ledger event. */ export declare function recordSignalToLedger(state: EngineState, nodeId: string, type: string, payload?: unknown, source?: SignalLedgerSource): void; /** * Intercepts signal emission for graph nodes and records it into per-node * runtime state. Owns the terminating-signal callback registry so a later * subtask can register its node-advancement handler without this module * knowing the concrete behavior. */ export declare class SignalBridge { /** Registered `onNodeSignalEmitted` listeners, keyed by nothing — all fire. */ private listeners; /** * Register a terminating-signal listener. Returns an unsubscribe function. * Multiple listeners may be registered; each fires for every terminating signal. */ onNodeSignalEmitted(listener: NodeSignalEmittedListener): () => void; /** Remove all registered terminating-signal listeners. */ clearListeners(): void; /** * Record a signal for the given node, then fire terminating listeners. * * - Writes `node.signalsObserved[type] = payload ?? null` (payload is `null` * when absent, matching `signal-ledger.ts:recordSignal` semantics). * - Also updates the graph `signalLedger` entry (`lastSignalAt`) when a * state is supplied. * - Returns `true` when the signal is terminating (a listener was fired). * * @param state Engine state — required; the graph-level `signalLedger` * history entry is kept in sync from it. * @param source Origin discriminator for this signal event (dispatch / * recovery / deferred / race_guard). * @returns `true` if `type` is terminating, `false` otherwise. */ record(state: EngineState, nodeId: string, type: SignalType, payload?: unknown, source?: SignalLedgerSource): boolean; isTerminating(type: string): boolean; isPausing(type: string): boolean; isHandoff(type: string): boolean; isInfo(type: string): boolean; } //# sourceMappingURL=signal-bridge.d.ts.map