Wave 2 · record #4domain.factservice.request
#4 · the request crosses the membrane
CellSpace indexes it under its name. When the membrane passes it, a controller claims it by its shape; the runtime hands it out and waits; the world answers once, and the answer enters the log as #5.
Came fromthe machineThe machine wrote it while the engine took #3: the doer note.ask acted — and its act is a request. step 26
when the engine took #4
27The engine takes #4ENGINE.CURSOR · propagate
a wave is settlingengine: working on #4membrane: waiting at #2
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- end of the log
The engine What before after pointer — the next record to take #4 #5 The engine moves on to #4 — the request the doer has just written into the log.
Where it happens
takeNextTuple()Vol. 02 §4.1The engine's step: take the record under its pointer and move the pointer on — or stop, if the pointer has reached the end.
- Specification
- Vol. 02 §4.1
- Code
takeNextTuple()incore/registers/take-next-tuple.ts, line 15: at the end of the log, the engine stops- Journal
- #4 ·
ENGINE.CURSOR · propagate· offset: 4 · by engine - Picture
- pointer — the next record to take: #4 → #5
core/registers/take-next-tuple.ts· build 043cc8b// ENGINE.CURSOR advance (Vol. 02 §4.1) — the machine's instruction pointer:// returns the tuple at the cursor and moves it forward exactly once, or null// at quiescence. Advancing IS the context switch: the ambient wave context// moves to the propagated tuple in the same movement, so every transition// journalled during its propagation is attributed to it — the cube's spine.// The cursor never rewinds.import type { WaveTuple } from "../wave/gate";import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";import { setDriver, setWaveContext } from "./set-wave-context";export function takeNextTuple(file: RegisterFile): WaveTuple | null {const engine = file.registers.engine;if (engine.cursor >= engine.base + engine.window.length) return null;↑ at the end of the log, the engine stopsconst tuple = engine.window[engine.cursor - engine.base];engine.cursor += 1;↑ the engine's pointer moves on by onesetWaveContext(file, { offset: tuple.offset, phase: "propagate" });setDriver(file, "engine");recordTransition(file, "engine", "ENGINE.CURSOR", "propagate", { offset: tuple.offset });↑ the change is written into the journalreturn tuple;}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in 6730f58 (2026-09-13)
28The request is indexed under its nameREQUESTS · index-request
a wave is settlingengine: working on #4membrane: waiting at #2
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- end of the log
CellSpace What before after requests empty note.ask#1CellSpace keeps every request that leaves for the world under its name:
note.ask#1belongs tonote.ask. Whatever comes back later — an answer or a failure — finds its doer through this index. No Cell is involved here: this is the plain case.Where it happens
indexCausalRequest()Vol. 12 §5.1Indexes a request the moment it is written, under its intention's name — so that whatever answers it later finds the doer it belongs to.
- Specification
- Vol. 12 §5.1
- Code
indexCausalRequest()incore/registers/index-causal-request.ts, line 12: the request is kept under its name- Journal
- #4 ·
REQUESTS · index-request· uid: note.ask#1, bindId: note.ask · by cellspace - Picture
- requests: empty →
note.ask#1
core/registers/index-causal-request.ts· build 043cc8b// REQUESTS write (Vol. 12 §5.1): every committed service intention is// indexed by uid so later proposals prove their causal authority against a// real, unconsumed, same-key request — admission is an act, not a lookup// (KEY_ARCHITECTURE §5).import type { CausalRequest } from "../cells/gate";import type { RegisterFile } from "./register-file";import { cellsRegion } from "./cells-region";import { recordTransition } from "./record-transition";export function indexCausalRequest(file: RegisterFile, request: CausalRequest): void {cellsRegion(file).requests.set(request.uid, request);↑ the request is kept under its namerecordTransition(file, "cellspace", "REQUESTS", "index-request", {↑ the change is written into the journaluid: request.uid,bindId: request.bindId});}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in f36e70d (2026-08-18)
when the membrane passed #4
31The membrane passes #4MEMBRANE.CURSOR · sweep
a wave is settlingengine: at the endmembrane: passing #4
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- end of the log
The membrane What before after pointer — the next record to pass #4 #5 #4 is different: it is a request. The membrane's pointer moves past it — and the membrane looks for someone in the world who will take it.
Where it happens
sweepNextTuple()Vol. 02 §4.6 · Vol. 07 §3The membrane's step: pass over the record under its pointer and move the pointer on — exactly once per record.
- Specification
- Vol. 02 §4.6 · Vol. 07 §3
- Code
sweepNextTuple()incore/registers/sweep-next-tuple.ts, line 16: the membrane's pointer moves on by one- Journal
- #4 ·
MEMBRANE.CURSOR · sweep· offset: 4 · by membrane - Picture
- pointer — the next record to pass: #4 → #5
core/registers/sweep-next-tuple.ts· build 043cc8b// MEMBRANE.CURSOR advance (Vol. 02 §4.6, Vol. 07 §3): the membrane's own// reading of the one log — the second reception of one publication, never a// second truth. The cursor advances exactly once per offset per machine:// the exactly-once discharge guarantee lives in this movement.import type { WaveTuple } from "../wave/gate";import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";import { setDriver, setWaveContext } from "./set-wave-context";export function sweepNextTuple(file: RegisterFile): WaveTuple | null {const engine = file.registers.engine;const membrane = file.registers.membrane;if (membrane.cursor >= engine.base + engine.window.length) return null;const tuple = engine.window[membrane.cursor - engine.base];membrane.cursor += 1;↑ the membrane's pointer moves on by onesetWaveContext(file, { offset: tuple.offset, phase: "sweep" });setDriver(file, "membrane");recordTransition(file, "membrane", "MEMBRANE.CURSOR", "sweep", { offset: tuple.offset });↑ the change is written into the journalreturn tuple;}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in 6730f58 (2026-09-13)
32The request is handed to the worldDISCHARGE.TABLE · track-discharge
a wave is settlingengine: at the endmembrane: passing #4
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- end of the log
The runtime No register changed its value.
A controller — the world's only station — claims #4 by its shape. The runtime notes the hand-out as discharge 1: the machine now waits for what comes back. This is the only place the machine touches the world.
Where it happens
trackDischarge()Vol. 02 §4.6 · Vol. 08 §3Notes, at the membrane, that a record has been handed to the world, and keeps it among those the machine still waits on.
- Specification
- Vol. 02 §4.6 · Vol. 08 §3
- Code
trackDischarge()incore/registers/track-discharge.ts, line 19: the hand-out gets the next number- Journal
- #4 ·
DISCHARGE.TABLE · track-discharge· id: 1, controller: controller.schema.double, offset: 4 · by runtime - Picture
- no register changed its value
core/registers/track-discharge.ts· build 043cc8b// DISCHARGE.TABLE entry (Vol. 02 §4.6, Vol. 08 §3): an in-flight discharge// joins the table under a fresh slot id. The defect path is part of the// entry's own movement: a rejected discharge leaves the table as the// rejection propagates, so the machine stays usable for the next wave// (refimpl 06 §1; host ADR-011 finding 2).import type { WaveEmission } from "../wave/gate";import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";import { setDriver, setWaveContext } from "./set-wave-context";export function trackDischarge(file: RegisterFile,claim: { controller: string; offset: number },discharge: Promise<readonly WaveEmission[]>): void {setWaveContext(file, { offset: claim.offset, phase: "sweep" }); // attribute to the claimed tuplesetDriver(file, "runtime");file.ephemeral.nextDischargeId += 1;↑ the hand-out gets the next numberconst id = file.ephemeral.nextDischargeId;file.ephemeral.inFlight.set(↑ it is kept among those still out in the worldid,discharge.then((emissions) => ({ id, controller: claim.controller, offset: claim.offset, emissions }),(defect: unknown) => {file.ephemeral.inFlight.delete(id);recordTransition(file, "runtime", "DISCHARGE.TABLE", "discharge-defect", { id, ...claim });↑ the change is written into the journalthrow defect;}));recordTransition(file, "runtime", "DISCHARGE.TABLE", "track-discharge", { id, ...claim });↑ the change is written into the journal}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in 6730f58 (2026-09-13)
when the world answered
33The world answersDISCHARGE.TABLE · resolve-discharge
a wave is settlingengine: at the endmembrane: passing #4
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- end of the log
The runtime No register changed its value.
The controller returns one answer, and the runtime closes discharge 1. The answer is not a record yet: it waits at the edge until the log takes it. A failure would come back the same way, under the same name.
Where it happens
resolveDischarge()Vol. 08 §3 · Vol. 03 §3.3Notes that the world has answered: the hand-out is closed, and what came back is ready to enter the log.
- Specification
- Vol. 08 §3 · Vol. 03 §3.3
- Code
resolveDischarge()incore/registers/resolve-discharge.ts, line 14: no longer waiting on the world- Journal
- #4 ·
DISCHARGE.TABLE · resolve-discharge· id: 1, emissions: 1, controller: controller.schema.double, offset: 4 · by runtime - Picture
- no register changed its value
core/registers/resolve-discharge.ts· build 043cc8b// DISCHARGE.TABLE settlement (Vol. 08 §3): the earliest completed discharge// leaves the table and its answers re-enter the wave as the next run's// seeds. Earliest completion wins; consumers rely on correlation, never// adjacency (Vol. 03 §3.3).import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";// The resolution names the claim it answers (controller · the swept tuple)// and is journaled under THAT tuple's wave context, so the tuple's own// journal states which discharge answered it (ADR-004 d17); the answer's// emissions are then appended under the same attribution.export function resolveDischarge(file: RegisterFile, id: number, emissionCount: number, claim?: { controller: string; offset: number }): void {file.ephemeral.inFlight.delete(id);↑ no longer waiting on the worldrecordTransition(file, "runtime", "DISCHARGE.TABLE", "resolve-discharge", { id, emissions: emissionCount, ...(claim ?? {}) });↑ the change is written into the journal}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in de79653 (2026-09-11)
34The answer enters the log as #5LOG · append
a wave is settlingengine: next: #5membrane: waiting at #5
The log - #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- #5the answernew
- end of the log
The log What before after records in the log 5 6 #5 — the answer · note.answeredThe answer is written at the end of the log as #5 — a fact of the type the doer asked for,
note.answered, carrying the doer's name and the intention's name. It came from the world, not from the doer.Where it happens
appendEmissions()Vol. 02 §4.1 · Vol. 03 §1The only function that adds records to the log. Each new record gets the next free number, at the end.
- Specification
- Vol. 02 §4.1 · Vol. 03 §1
- Code
appendEmissions()incore/registers/append-emissions.ts, line 14: the new record gets the next free number- Journal
- #4 ·
LOG · append· offset: 5, kind: domain.fact · by engine - Picture
- records in the log: 5 → 6
core/registers/append-emissions.ts· build 043cc8b// The one LOG writer (Vol. 02 §4.1, Vol. 03 §1): emissions become tuples by// receiving the next dense absolute offset — `base + window.length` — and// nothing else ever grows the log. Each append is journalled under the// ambient context, so a batch born of a propagated tuple carries that// tuple's offset as its cause — the cube's provenance line (ADR-002).import type { WaveEmission, WaveTuple } from "../wave/gate";import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";export function appendEmissions(file: RegisterFile, emissions: readonly WaveEmission[]): void {const engine = file.registers.engine;for (const emission of emissions) {const tuple: WaveTuple = { ...emission, offset: engine.base + engine.window.length };↑ the new record gets the next free numberengine.window.push(tuple);↑ it is added at the end of the logrecordTransition(file, "engine", "LOG", "append", {↑ the change is written into the journaloffset: tuple.offset,kind: tuple.kind});}}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in f36e70d (2026-08-18)
Step 34: The answer enters the log as #5
34 The answer enters the log as #5
a wave is settlingengine: next: #5membrane: waiting at #5
- #0a listener
- #1a doer that asks
- #2a note
- #3readiness
- #4a request
- #5the answernew
- end of the log
| What | before | after |
|---|---|---|
| records in the log | 5 | 6 |
| #5 | — | the answer · note.answered |
The answer is written at the end of the log as #5 — a fact of the type the doer asked for, note.answered, carrying the doer's name and the intention's name. It came from the world, not from the doer.
Where it happens · appendEmissions()
The only function that adds records to the log. Each new record gets the next free number, at the end.
- Specification
- Vol. 02 §4.1 · Vol. 03 §1
- Code
appendEmissions()incore/registers/append-emissions.ts, line 14: the new record gets the next free number- Journal
- #4 ·
LOG · append· offset: 5, kind: domain.fact · by engine - Picture
- records in the log: 5 → 6
core/registers/append-emissions.ts · build 043cc8b// The one LOG writer (Vol. 02 §4.1, Vol. 03 §1): emissions become tuples by// receiving the next dense absolute offset — `base + window.length` — and// nothing else ever grows the log. Each append is journalled under the// ambient context, so a batch born of a propagated tuple carries that// tuple's offset as its cause — the cube's provenance line (ADR-002).import type { WaveEmission, WaveTuple } from "../wave/gate";import type { RegisterFile } from "./register-file";import { recordTransition } from "./record-transition";export function appendEmissions(file: RegisterFile, emissions: readonly WaveEmission[]): void {const engine = file.registers.engine;for (const emission of emissions) {const tuple: WaveTuple = { ...emission, offset: engine.base + engine.window.length };↑ the new record gets the next free numberengine.window.push(tuple);↑ it is added at the end of the logrecordTransition(file, "engine", "LOG", "append", {↑ the change is written into the journaloffset: tuple.offset,kind: tuple.kind});}}
AGPL-3.0-onlyThe Lab's demonstration environment, as this fragment ran it (build 043cc8b). The code may change, and may differ from the code of a working machine.
Nest VM core, incubated in the CoAgnes garden · build 043cc8b (2026-09-21) · this file last changed in f36e70d (2026-08-18)
A fact: a request to the world
What a doer writes when it needs the world — complete in itself: what to do, about what, in which shape the answer must come, and under which type it will be written. The membrane hands it to whichever controller claims it; the doer is never told who.
#4domain.factservice.request the machine
| envelope | |
|---|---|
offset | 4Its place in the log — the only address a record has. The engine gives it when the record is added, the next free number, and it never changes. |
kind | domain.factWhich of the four kinds of record the machine knows. The kind decides what the payload holds. |
key | fragment-one-crossing-detThe lane it is asked on — the lane of the readiness that woke the doer. The answer comes back on the same lane. |
| payload | |
factType | service.requestThe fact type, service.request — the shape a controller of this kind claims. |
| payload.data | |
bindId | note.askThe doer that asks. |
uid | note.ask#1The intention's name: the doer's name and a number. The answer must carry it back. |
instruction | «Answer the note in one plain sentence.»What the world is asked to do. |
scope | activationWhat it is about: the doer's scope at the moment it acted — here, under activation, what the listener understood. |
schema | type · properties · required ×1The shape the answer must have. |
| payload.data.emit | |
writes | note.answeredThe type the answer will be written as. |
end · #4
In the specificationVol. 03 §1Vol. 03 §4Vol. 03 §5Vol. 04 §5.1Vol. 06 §3Vol. 07 §4.2
Names it shares with other records
note.ask— also on #1 a doer that asks, #5 the answernote.ask#1— also on #5 the answer
The record as the machine keeps it
{
"offset": 4,
"kind": "domain.fact",
"key": "fragment-one-crossing-det",
"payload": {
"factType": "service.request",
"data": {
"bindId": "note.ask",
"uid": "note.ask#1",
"instruction": "Answer the note in one plain sentence.",
"scope": {
"activation": {
"note": "Is a request to the world a record of the log, or something outside it?"
}
},
"schema": {
"type": "object",
"properties": {
"answer": {
"type": "string"
}
},
"required": [
"answer"
]
},
"emit": {
"writes": "note.answered"
}
}
}
}