what travels, and the rule that keeps it safe

The wire: snapshots, diffs, events

Every frame on the socket is a Prism Document. There are three kinds, one envelope of metadata on the root, and one algebraic identity that makes a sparse diff always safe to apply or safe to discard.

Everything on the wire is a Document

There is no separate protocol format. Every frame the server pushes and every event the client sends is a serialized Prism Document (binary .prism on the socket). The transport is one WebSocket per session; the framing is kinogaki::ws, a small RFC 6455 implementation in Kinogaki Platform that also enforces the safety limits (frame-size cap, required masking on client frames, no fragmentation).

Three message kinds

KindDirectionWhat it is
snapshotserver to clienta complete view-Document, the whole widget tree; the client adopts it wholesale
diffserver to clienta sparse overlay, only the Elements whose values changed; the client applies it onto its running view
eventclient to servera small Document naming an action Path and its values (a press, a filter pick, a form submit)

A fresh connection gets a snapshot. After that, the server sends a diff when the view's structure is unchanged (same ordered Paths and types, only values differ) and a snapshot when the structure changed (an Element added, removed, reordered, or retyped). The reason is precise: Prism's overlay appends new Elements, so it cannot express a mid-sequence insert in place; a structural change must therefore be a full snapshot. This is the LiveView fingerprint rule, expressed in Prism's own composition.

The envelope

A diff is only safe to apply onto the exact base it was computed against. So the root Element of every frame carries an envelope of metadata that the client reads before it acts:

FieldMeaning
kindsnapshot or diff; a frame with no kind is a liveness pong, not a view
epochthe server launch; a new epoch means the client full-resyncs
revthis frame's revision, monotonic
base_revthe revision a diff applies onto
countthe Element count after applying, a cheap post-apply divergence check

The client applies a diff only when epoch matches and base_rev equals its current rev; otherwise it has diverged (a dropped or stale frame) and asks for a snapshot. After applying, if the resolved Element count does not match count, it resyncs. A diff layer often does not include the root (its content did not change), so the channel stamps a metadata-only root onto the layer; it overlays harmlessly onto the client's root.

The oracle

The whole scheme rests on one algebraic identity in Kinogaki Core:

overlay(base, diff(base, target)) == target

diff(base, target) is the minimal sparse layer; applying it onto the base reproduces the target exactly. Two consequences make the protocol safe:

A concrete frame

A field edit on the issue board produces a diff of a few hundred bytes instead of the roughly 90 KB full view: only the changed Element travels, with the stamped envelope on the root. A filter switch changes the structure (the card list is replaced), so it ships as a snapshot. Both are ordinary Prism Documents; you can save either to a .prisma file and read it.

Events going back

An event is the same idea in the other direction: a small Document with an action Path (/issue/new, a filter pick) and any named string values (form fields). A form submit carries a monotonic sequence number so a submit can be matched to its acknowledgement. The client sends it now if connected, or queues it in the outbox to flush on reconnect (see the loop). The server reads the action, mutates the state, and the cycle closes.

Why Prism makes this cheap

A bespoke protocol would have to invent an identity scheme, a diff format, a serialization, and a resync story. Kinogaki invents none of them: identity is the Path, the diff format is overlay, the serialization is the Document codec, and resync is "send a snapshot." The wire is thin because the model is doing the work.