Expand description
The DOM patch stream: the byte format a compiled program writes and a host applies.
Tristen’s constraint is that the browser runs compiled LOGOS and JavaScript is a host SHIM,
not a layer of the framework. For the DOM that means a BULK stream: the program builds a
buffer of operations and the host applies it in a for loop, deciding nothing. The stream
is the interface — every decision that used to live in runtime.js belongs to the side that
emits it.
§The format
Little-endian, byte-oriented, self-delimiting. One record is a 1-byte OPCODE followed by its operands, each of which is one of:
- a NODE,
u32— the creation ordinal every tier already agrees on, sou32::MAX(the “no such element” sentinel) rides through intact; - a FLAG, one byte,
0or1; - an
i64, 8 bytes — an opaque host handle; - TEXT, a
u32byte length then that many UTF-8 bytes. LENGTH-PREFIXED, never delimited, so no byte is special: a NUL, a newline and a quote are ordinary content, and an EMPTY string is a string rather than an absence (setAttribute(el, "disabled", "")is how a boolean attribute is written).
§Why the decoder is strict
Its input comes from linear memory a compiled program wrote. A truncated record, a length that overruns the buffer, an unknown opcode or invalid UTF-8 all mean A BUG SOMEWHERE — so the decoder REFUSES rather than reading past the end, guessing, or lossily converting. A U+FFFD substituted for a bad byte would put a character on the page that nobody wrote.
§Why the opcode table is append-only
The emitter is compiled into a wasm module; the decoder ships in a host. They are updated at
DIFFERENT TIMES, so renumbering an opcode silently reinterprets every stream a
previously-built module emits. New operations go on the END, and OPCODES is pinned by
patch_stream_lock so that has to be deliberate.
Constants§
- OPCODES
- The opcode table, in wire order. Append-only — see the module note.
- RETIRED_
OPCODES - The opcodes no emitter writes any more, each with why. Each keeps its number, so no later opcode
is renumbered, and both decoders refuse it by name (
retired_opcode) rather than as an unknown code.
Functions§
- apply
- Apply a decoded stream to the recorder — the DUMB SHIM, in Rust.
- bytes_
from_ value - Read a patch buffer out of a LOGOS value — a
Seq of Intwhose every element is a byte. - decode
- Decode a patch stream, or say exactly what is wrong with it.
- decode_
words - Decode a
(words, strings)pair —encode_words’s inverse, and what a native tier appliesvdom.lg’s ownvdCommitoutput through. - encode
- Encode
opsas a patch stream. - encode_
words - Word-oriented wire format v2: the same opcodes as
encode/decode, but every operand is ani64WORD and every string is a 1-based index into a separate STRING TABLE — the shapevdom.lg’s own emitter naturally produces (Seq of Intfor the words,Seq of Textfor the strings), with no byte-level length-prefixing to hand-roll in LOGOS.words/stringstravel as a pair; a decoder given one without its matching other cannot make sense of either. - strings_
from_ value - The first
countstrings of aSeq of Text— the string half of the word-oriented wire format. - words_
from_ value - The first
countwords of aSeq of Int— the word half of the word-oriented wire format, asvdom.lg’svdApplyhands it over.