Server-side monotonic guard for versioned async query/result exchange — the piece that upgrades the Channel contract from convention to construction (CHANNEL_CONTRACT.md; combobox spike verdict 1).
A client emits queries stamped with a monotonically increasing version. Results may complete out of order (async work, network). The rule: the server render path must refuse to render results for a superseded version. A client-side version check alone only detects staleness after the DOM was already wrong; this guard prevents it from ever reaching the render.
Usage in a LiveView
def mount(_, _, socket), do: {:ok, assign(socket, channel: Channel.new(), results: [])}
def handle_event("query", %{"q" => q, "v" => v}, socket) do
channel = Channel.note_query(socket.assigns.channel, v)
# ... compute or start async work for {q, v} ...
{:noreply, assign(socket, channel: channel)}
end
# When a result set for version v is ready to render (sync or async):
case Channel.accept(socket.assigns.channel, v) do
{:ok, channel} -> assign(socket, channel: channel, results: results)
{:stale, channel} -> assign(socket, channel: channel) # dropped, by construction
endThe component stamps the rendered version into the DOM
(data-version={@channel.rendered_version}) so the client can detect — as
telemetry, not authority — if a stale render ever slips through.
Summary
Functions
The guard. Ask whether a result set for version v may render.
Fresh channel state (put it in an assign).
Record that a query stamped v was seen. Call on every incoming query event.
Accepts integer or numeric-string versions (LiveView params are strings).
Types
@type t() :: %LiveInteractionContracts.Channel{ rendered_version: non_neg_integer(), stale_drops: non_neg_integer(), version_seen: non_neg_integer() }
Functions
The guard. Ask whether a result set for version v may render.
Returns {:ok, channel} (render it; the channel records it as the rendered
version) or {:stale, channel} (a newer query has been seen — do NOT assign the
results; the drop is counted).
Fresh channel state (put it in an assign).
Record that a query stamped v was seen. Call on every incoming query event.
Accepts integer or numeric-string versions (LiveView params are strings).