Pure probe reducer -- the clock seam (04 design §1b).
step(state, event) where event is {:input, bytes}, {:clock, monotonic_ms}, or :start. No time is read inside step and no
process sleeps anywhere: the silence timeout is driven entirely by
injected clock events, so every timing case is a table row, not a
flake. The real driver wraps this with a receive/after loop feeding
System.monotonic_time(:millisecond) as {:clock, now} events.
Sentinel discipline (F0 §2): the batched query ends with Primary DA
(CSI c). Every VT-class terminal answers DA1, so read-to-sentinel
converts "did it ignore me?" into a bounded wait -- any wanted reply
that did not arrive before the sentinel is unsupported. Silence past
the deadline is the failure mode, answered with a conservative default.
Deadline policy (F0 §7 step 3): ~100 ms local, ~1 s when $SSH_* is
present; extended AT MOST ONCE when a first byte is seen but the
sentinel is not. After the sentinel, one drain window stays open until
the next clock event so reordered replies (a documented terminal bug)
are still parsed; after :done, late replies are drained, never
reclassified, and never leaked as keystrokes.
Summary
Functions
Builds a probe from the env seed.
The exact batched query the probe emits on :start.
Probe outcome: :pending or {:done, %Capabilities{}}.
Advances the reducer by one event. Returns {state, actions}.
Types
@type action() :: {:write, iodata()} | {:passthrough, iodata()} | {:extend_deadline, non_neg_integer()} | {:leak_free, binary()} | {:done, Raxol.Terminal.Capabilities.t()}
@type phase() :: :init | :awaiting | :draining | :done
@type t() :: %Raxol.Terminal.Capabilities.Probe{ budget_ms: pos_integer(), caps: Raxol.Terminal.Capabilities.t() | nil, deadline: integer() | nil, env: map(), extend_ms: pos_integer(), extended?: boolean(), now0: integer(), opts: keyword(), phase: phase(), scanner: Raxol.Terminal.Capabilities.ReplyScanner.t(), seen_input?: boolean(), tty?: boolean() }
Functions
Builds a probe from the env seed.
Options:
:budget_ms-- override the silence deadline (default ~100 ms local, ~1 s when any$SSH_*var is present):extend_ms-- the one-time extension budget (default = budget):now_ms-- clock origin the deadline is computed from (default 0; the driver passesSystem.monotonic_time(:millisecond)):tty?--false= non-TTY path: Core-minus, ZERO queries emitted:tmux_passthrough?-- re-issue identity/color queries wrapped for the outer terminal (only meaningful when$TMUXis set):platform-- forwarded to the classifier (:windowsgates)
@spec query_sequence() :: binary()
The exact batched query the probe emits on :start.
@spec result(t()) :: :pending | {:done, Raxol.Terminal.Capabilities.t()}
Probe outcome: :pending or {:done, %Capabilities{}}.
Advances the reducer by one event. Returns {state, actions}.