Part 1 · 1.3 Functional Specification

The specification: the same picture, with its real names

Where and how flows form, in the machine's own vocabulary.

Source: lib/core/wave/, lib/core/topology/, lib/core/runtime/, lib/TOPOLOGY.md (NestVM Vol. 02–08, incubated in this repository).

§The list is the log; an entry is a tuple

The "list" of 1.1 is the wave log — append-only, dense (no gaps), never edited. One entry is a tuple, and it always has exactly four fields:

ts
type WaveTuple = Readonly<{
  offset: number;         // its position, assigned only by the engine
  kind: string;           // one of four fixed kinds — see below
  key: string | null;     // which lane it travels on; null = lane-less
  payload: unknown;       // what it actually says
}>;

There are exactly four kinds of tuple, and nothing else: sys.knot.defined and sys.descriptor.defined register a listener or a doer (this is authoring, covered fully in Part 3); domain.fact is an ordinary committed fact — a person's words, a machine's answer, anything of substance; sys.knot.ready is a listener's own announcement that it has everything it needs. A record submitted for the log without its offset yet is called an emission; the engine assigns the offset the instant it actually appends.

§Listeners are knots, doers are binds

A knot is the listener of 1.1. Its behaviour is exactly five small operations, and every knot in the system — however complicated the study built from it looks — is only ever these five: does this tuple match what I collect (matches); if so, fold it into what I've collected (wind); has what I've collected now satisfied my condition (test); if so, what exactly did I collect (understanding — this becomes the readiness announcement's own content); and once I've announced, do I keep what I collected or start clean (reset).

A bind is the doer. The specification names two shapes for it: an operator bind waits for one or more knots' readiness (its demands) and, once every one of them has fired at least once since it last acted, does its one thing — exactly the "barrier" behaviour named in Part 2. An emit descriptor is simpler still: it has no demands at all, and republishes a single knot's readiness, verbatim, as a fact of a declared type, every single time that knot fires.

§The rhythm of one wave

One full pass — the specification's word is a wave — is: take the next unprocessed tuple; hand it to the machine's one processor; if any listener's condition is now satisfied, announce its readiness (itself a new tuple, appended immediately, seen by the very next step of the same pass); if any doer's barrier is now satisfied, let it act (again, new tuples, appended immediately); keep going until nothing is left to process. That final state — nothing left, no doer waiting on an outside answer either — is called quiescence, and a wave is only ever considered finished once quiescence is reached, never partway through.

§Crossing to the outside world

Some doers need something the machine itself cannot supply — a language model's answer, most often. For that there is exactly one crossing point, the membrane: a second, independent reader of the very same log, offering each tuple once to every registered controller (a language-model connection, a deterministic stand-in, and so on). A controller that recognises a tuple as its own kind of request answers it asynchronously; when that answer arrives, it re-enters the log as new tuples, and the wave continues from there — so a delegated question and its eventual answer are still, in the end, just two more entries on the one list, correlated by an id carried in both, never by which one happened to come right after the other (the specification is explicit that position in the log is never itself evidence of a causal link — 2.3 returns to exactly why).