From 7eb545f3872f0649c136bb1bb605a285ff5d00b2 Mon Sep 17 00:00:00 2001 From: rajames Date: Thu, 8 Oct 2026 12:47:55 -0400 Subject: [PATCH] docs(v4.0.0): step 6e -- messages on the wire: the second attempt at the wait MESH.md 7d: the rulings, the wire, what a node asks of the fabric, the nucleus, the products, the limits, the acceptance, and the later step of keeping the wires in the system's blocks. Co-Authored-By: Claude Opus 5.5 --- docs/v4.0.0/MESH.md | 211 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/docs/v4.0.0/MESH.md b/docs/v4.0.0/MESH.md index a9f7bfa2..98f1cc31 100644 --- a/docs/v4.0.0/MESH.md +++ b/docs/v4.0.0/MESH.md @@ -463,6 +463,8 @@ Two types, beside text (1), output (2) and done (3): ## 7c. The wait (ruled 2026-10-07; built, found unsound, and backed out 2026-10-08) +*(The second attempt is section 7d.)* + **This section is a record, not what the code does.** The wait was built (step 6d), two independent reviews in a row found it unsound, and Captain Bob ruled it backed out: the engine and nucleus are as they were before @@ -702,6 +704,212 @@ a line. POST 538 of 538, `word_count=317`, `-120624` and `-121117` are amd64 boots of the same code in which the typed session did not put the wait on a deep stack; they are kept.) +## 7d. Messages on the wire (ruled 2026-10-08): the second attempt at step 6d + +**What it is for.** The same end as section 7c: a node that is stuck holds +up no other node. Section 7c.6 and 7c.7 say why the first attempt failed. +Three things made it unsound, and this design removes each instead of +guarding it: + +1. A message could be half moved: it went a word at a time, and a fault + after the first word left both ends out of step. +2. A node kept other nodes' messages in a ring in its own memory, which + it had to turn; a fault in the middle left the ring in pieces, and a + stuck neighbour's traffic could fill it. +3. All of it ran on the stacks the node's text was using. + +**v3's way** (`kernel/src/vm/kernel_hermes.c`, read again for this). A +send is one call to the kernel, `sk_hermes_send_one(from, to, ...)`: it +delivers to exactly one VM, by its id. The kernel copies the whole +message into its own pool and puts it on the target's queue; if anything +is full the send is refused at once and nothing has changed. A VM never +passes a message on for another, never holds another's, and never has +one half moved. v3 has none of the three problems. + +**What is taken from v3, and what is not.** Taken: whole messages, moved +by something that is not the node's own text; a send that is accepted or +refused at once; nothing in transit held by a node. Not taken: delivery +by id from one place that knows where every node is. A node is still +wired only to its neighbours and messages still go from neighbour to +neighbour, which is what a grid of nodes needs (ruling 1). + +### 7d.1 The rulings + +1. **The fabric moves whole messages between neighbours.** Put to Captain + Bob with v3's way in full and with leaving step 6d undone. +2. **A message waits on the wire, in the fabric**, not in a node. Each + wire has a queue each way. A node holds nothing in transit. +3. **What a text prints waits for room; everything else is refused at + once.** `SEND`, an answer, a NACK and a GONE either go or are refused. + Printing waits, so that output is not lost. +4. **A wire holds 1,024 cells each way**, a build parameter, as the number + of ports and the sizes of the stacks are. +5. **The wires' memory is the fabric's own, for now, behind one + interface**; given only to ports that are wired. Backing it with the + system's blocks is a later step (7d.8). + +The stacks stay at 32 (ruled the same day): section 7c.7 showed their +size was never the cause. + +### 7d.2 The wire + +- Between two nodes that are wired, the fabric keeps two queues of whole + messages, one each way, of `V4_WIRE_CELLS` cells (1,024). +- A message is what section 6 says: seven words and its text, four + characters to a word. On a wire it takes seven cells and one for each + word of text. +- **Putting a message on a wire, and taking one off, is each one step: + all of it or none.** There is no state in which part of a message has + moved. +- A wire is full when the message offered does not fit. One with 200 + cells free takes a short message and refuses a long one. +- A wire to a device -- the console, the kernel -- is the same to the + node. Whatever is on the other end puts and takes whole messages + through the fabric. +- When a node is removed, or a wire cut, what was waiting on its wires is + let go. + +### 7d.3 What a node asks of the fabric + +Addresses after the node's ports and the two words of section 7a. None +is memory while the ports are attached. Each operation is one step of +the engine and happens whole. + +| Address | What | +|---|---| +| `base + V4_PORTS + 4` | Wire: store the number of a port. What follows is about that wire. | +| `base + V4_PORTS + 5` | A: store a value an operation needs | +| `base + V4_PORTS + 6` | B: store a second | +| `base + V4_PORTS + 7` | Do: store the number of an operation | +| `base + V4_PORTS + 8` | How it went: fetch. 0 done; 1 no room; 2 nothing on that port; 3 no such message; 4 not a message | +| `base + V4_PORTS + 9` | Which wires have a message waiting: fetch, a bit to a port | + +| Operation | What it does | +|---|---| +| 1, look | The seven words of the message at the front of the wire are copied to the word address in A. Nothing is taken. | +| 2, take | The message is copied out, its seven words to A and its text to B, and is off the wire. | +| 3, move | The message goes to the back of the wire of the port in A, with one fewer in its fourth word (how many more nodes may pass it on). | +| 4, drop | The message is off the wire and gone. | +| 5, put | The message whose seven words are at A and whose text is at B goes to the back of the wire. | +| 6, find | The first message on the wire that is to the node in B and of the type in A becomes the one that look, take and drop are about, wherever it is in the queue. | +| 7, next | The same, from after the one found last. | +| 8, sleep | The node is blocked until one of its wires has a message. | +| 9, sleep for room | The node is blocked until the wire has A cells free, or one of its wires has a message, whichever is first. | + +- Look, take, move and drop are about the message at the front, unless + find or next has named another. +- Only 8 and 9 block. A node blocked there executes nothing. +- The ports themselves stay as they are, a word at a time, for the two + things that are not messages: a newborn node being sent its nucleus + (section 5), and a node's requests to the kernel (section 8). +- The looking words of section 7a, and their lower-number rule, are no + longer used by the nucleus. + +### 7d.4 The nucleus + +A node keeps no messages but the one it is doing. The ring of messages +waiting, the words that turned it, the list of NACKs owed, and +`(GATE)` go. + +- *With nothing to do* it sleeps (8). Woken, it looks at the front of + each wire that has a message. + - *For another node:* it is moved to the wire that leads there. If + there is no way, or nothing is on that port, or the wire is full, or + it has been passed on 16 times, it is dropped, counted in `(LOST)`, + and a NACK is put on the wire back toward its sender. A NACK or a + GONE that cannot go is dropped and counted; nothing is owed for it. + - *For itself:* it is taken and dealt with as now: text is done; a + NACK is counted; a GONE from its centre is believed. +- *`SEND`, how text ended, a NACK, a GONE* are built in the node's own + memory and put. Refused, a `SEND` is error 19, "Message refused"; the + others are counted in `(LOST)`. +- *What text prints* is put when the output buffer fills and when the + text ends. If the wire has no room the node sleeps for room (9). Woken + by a message instead, it passes on what is for other nodes, as above, + and sleeps again; text for itself from its console ends the text it is + doing in error 21, "Interrupted"; anything else for itself stays on + the wire. +- *`AWAIT`* sleeps (8) and, woken, passes on what is for other nodes and + looks for what would end its wait with find and next: the answer, a + NACK or a believed GONE about the node waited for, or text from its + console. Other messages for itself stay on the wire, in their order. +- *Before text begins any of these* it tries the stack it will need, + as `(ROOM)` does now (7c.7). Between texts the rule of 28 values + stands. + +### 7d.5 The products + +The lone node on the hosted and bare-metal products is given the same +addresses by its host (`v4/system/boot.c`): its two wires are the +console and the kernel. Nothing else changes for it: the kernel's +requests stay a word at a time. + +### 7d.6 What will be limits + +- A burst to a node that is busy, beyond what its wire holds, is refused + where today it waits. +- An answer whose way back is full is dropped and counted, and whoever + waits for it is not told: that wait ends as any wait on a node that + does not answer does, by Hera's kill or from the console. +- A text whose printing cannot reach the console, because a stuck node + is on the way and its wire has filled, waits until that node is + killed. It holds up no one else, and passes on meanwhile. +- A message for a node sits at the front of a wire until that node + takes it. A node that is stuck never does: its wires fill, and from + then on whoever sends to it is told at once. + +### 7d.7 Acceptance + +1. *Whole or not at all.* At no step of the engine is part of a message + on a wire or part of one taken. +2. *Refused at once.* A put to a full wire, to a port with nothing on + it, and to a wire with room, each answers in the step it is asked. +3. *A stuck node holds up no one.* With a node stuck in a loop: every + other node goes on doing what it is sent and passing on; what is sent + to the stuck node is taken until its wire is full and refused from + then on, the sender told; a node that owes it a NACK is not held. +4. *Hera.* She can be typed to whatever any other node is doing, and + `KILL` of one stuck node is not held by another. +5. *Printing is not lost.* A text that prints more than a wire holds, to + a console's node that is slow to take it, prints all of it in order. +6. *A node removed at any step* of any message leaves every other node + at rest and answering. +7. *Every depth of both stacks.* Each message path -- printing, `SEND`, + `AWAIT` and a line typed during it, passing on, a refusal -- on the + products and on the mesh, with the data stack at every depth and from + every depth of calls: each line typed is answered and every node comes + back. +8. *Order.* What one node sends another arrives in the order it was + sent; what a text prints, and then how it ended, reach the console in + that order. +9. *Nothing else changes.* POST 538 of 538; the products give what the + commit before gives on the same input, but where 7d.6 says otherwise; + `sanitize`, `hosted-check`, lint, three boots, one hash on all six. + +### 7d.8 A later step, not built: the wires in the system's blocks + +Captain Bob, 2026-10-08. The system has blocks set aside for it -- the +first 32 RAM blocks, hidden from the user, and the first 32 of every +disk (`BLK_FORTH_SYS_RESERVED`, `BLK_DISK_SYS_RESERVED`, +`v3/include/block_subsystem.h`) -- and each device has at its top a +system area that starts at 128 device blocks and grows down +(`BLK_META_FENCE_INIT`). The wires' queues could be kept in the reserved +blocks, with a pool in that area for what does not fit: a kind of +virtual memory for them, and messages that outlast a restart. + +- What is there today: the 32 hidden RAM blocks would hold four queues + of 1,024 cells at 64 bits; a unit of five nodes has sixteen. +- What it waits on: a device v4 may write. The virtio driver writes + (`kernel/src/virtio/virtio_blk.c`, `vblk_write`); what refuses a write + on the v4 boot is the block subsystem, which holds a disk it does not + know as provisional until its owner says it may be formatted + (`blk_subsys_confirm_format`), and in v3 that owner is Artemis. v4 has + no Artemis yet. +- To be ruled then: what a message that outlasts a restart means; and + what, if anything, already uses those blocks and that area. +- What makes it possible without touching a node: ruling 5. The fabric + reaches a queue through one interface. + ## 8. Storage **Ruled 2026-10-06 and 2026-10-07** (Captain Bob). On 2026-10-07 he found @@ -1326,6 +1534,9 @@ Each is tested, committed and pushed before the next. the hash of step 6c's mended code. The boots of `logs/20261008-01*` and `-06*` are of the wait as built and are kept as its record. + **6e. Messages on the wire (section 7d).** Ruled 2026-10-08: the + second attempt at 6d. Not built. + 7. **A second unit; scaling while running; sleep, wake and kill by command.** 8. **The hosted product is the five nodes**, on three ISAs: acceptance 1