docs(v4.0.0): storage brought back to the OS as designed -- every node asks the kernel

Ruled 2026-10-07 (Captain Bob): POST on every node, nodes without
storage, and block requests passed from node to node had left v3's
design.  MESH.md section 8 is rewritten: a block is a kernel request, as
ENGINE.md 3.3 already had it; every node has blocks; there is one chain.
Private drives and the message device are withdrawn, and listed in 8.5
so that they are not proposed again.  Acceptance 1 and 3 change with it.
A born node is not POSTed, and the kernel is to hold POST's cases.

The plan for step 6 is revised to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-07 07:21:10 -04:00
co-authored by Claude Opus 5.5
parent 4a505a154d
commit 26a0748455
2 changed files with 176 additions and 415 deletions
+95 -117
View File
@@ -27,8 +27,9 @@ before making v4 equal v3 on bare metal (`ENGINE.md` step 4), which waits.
until the neighbour writes (`DECOMPOSITION.md` section 6). What travels until the neighbour writes (`DECOMPOSITION.md` section 6). What travels
is v3's Hermes message with what it carries, so v3's messaging rules are is v3's Hermes message with what it carries, so v3's messaging rules are
not dropped: they go with the message. not dropped: they go with the message.
2. **Some nodes have storage of their own**, in addition to or instead of 2. ~~Some nodes have storage of their own, in addition to or instead of
the common SSD. Some have none. the common SSD. Some have none.~~ **Withdrawn 2026-10-07:** every node
has blocks, and asks the kernel for them (section 8).
3. **The first set of nodes is "2x2 + 1 central"**: five. 3. **The first set of nodes is "2x2 + 1 central"**: five.
4. **The geometry is data, not design.** A node has a number of ports, and 4. **The geometry is data, not design.** A node has a number of ports, and
that number is a parameter. Which port connects to what is a table that that number is a parameter. Which port connects to what is a table that
@@ -53,16 +54,18 @@ before making v4 equal v3 on bare metal (`ENGINE.md` step 4), which waits.
1. **Five nodes come up from nothing.** Hera is born empty, takes in the 1. **Five nodes come up from nothing.** Hera is born empty, takes in the
nucleus capsule and the FORTH-79 capsule, and passes POST. She births nucleus capsule and the FORTH-79 capsule, and passes POST. She births
the four outer nodes while running; each is born empty, takes in the the four outer nodes while running; each is born empty and takes in the
same capsules through its port from Hera, and passes POST. Each prints a same capsules through its port from Hera. Each prints a parity line;
parity line; the four outer nodes' dictionary hashes are identical. the four outer nodes' dictionary hashes are identical. (Changed
2026-10-07: an outer node is not POSTed. POST is the kernel's, once, as
in v3.)
2. **They talk.** A line typed at the console reaches Hera as a message. A 2. **They talk.** A line typed at the console reaches Hera as a message. A
message from Hera runs on an outer node and its output comes back. A message from Hera runs on an outer node and its output comes back. A
message between two outer nodes that are not wired to each other is message between two outer nodes that are not wired to each other is
forwarded by a node in between. forwarded by a node in between.
3. **They share the SSD.** A block written by one node is read by another. 3. **They share the SSD.** Every node asks the kernel for its blocks. A
One outer node has a drive of its own and uses it. One has no storage, block written by one node is read by another. (Changed 2026-10-07: no
and `BLOCK` on it is an error with a message. node has a drive of its own and none is without storage.)
4. **It scales while running.** A second unit of five is born and joined 4. **It scales while running.** A second unit of five is born and joined
centre to centre. A message crosses from one unit to the other. The centre to centre. A message crosses from one unit to the other. The
second unit is removed and the first carries on. second unit is removed and the first carries on.
@@ -270,22 +273,21 @@ kernel-Hermes's work in v3 and is not decided for the mesh.
## 8. Storage ## 8. Storage
**Ruled 2026-10-06** (Captain Bob), in the order the rulings were given. **Ruled 2026-10-06 and 2026-10-07** (Captain Bob). On 2026-10-07 he found
What is marked *step 6* is built there; what is marked *step 6a* is ruled this section to have left the OS as designed, and brought it back: every
and waits for that step. node asks the kernel directly, as every v3 VM does. What that withdrew is
in 8.5, so that it is not proposed again.
### 8.1 The rulings ### 8.1 The rulings that stand
1. **A disk is a device on a port that speaks messages.** Asking for a 1. **A node only ever asks for a block by number, and it asks the kernel.**
block is a message — read block *n*, or write block *n* with 1024 `V3-PARITY.md` 1d and `ENGINE.md` 3.3: a kernel request, written to the
characters — and the answer is a message back. port where the node's kernel is, served between the node's opcodes. No
2. **A node only ever asks for a block by number, and knows nothing else.** node asks another node for a block, and none passes such a request on.
It has one way to storage, as it has routes: a port, or nothing. This 2. **Every node has blocks, always.** There is no node without storage.
replaces the earlier proposal that a node be told ranges of block
numbers. Nobody chooses ranges.
3. **Two numbers.** A logical block number is what `BLOCK n` and capsules 3. **Two numbers.** A logical block number is what `BLOCK n` and capsules
use. A physical block number is a place on a real device. A mapper use. A physical block number is a place on a real device. The kernel's
stands between them. mapper stands between them.
4. **The view is static; reality shifts to keep it so.** A logical number 4. **The view is static; reality shifts to keep it so.** A logical number
always means the same block. Devices chain one after another in physical always means the same block. Devices chain one after another in physical
space, and that chain changes as devices come and go; the mapper moves space, and that chain changes as devices come and go; the mapper moves
@@ -301,121 +303,93 @@ and waits for that step.
identity, and the identity of the chain it belongs to. A v3 disk reads identity, and the identity of the chain it belongs to. A v3 disk reads
zero there: not yet given one. With them a device is known when it zero there: not yet given one. With them a device is known when it
returns, wherever it is plugged in. returns, wherever it is plugged in.
7. **The mapper is the kernel's.** `V3-PARITY.md` section 1d stands: the 7. **The mapper is the kernel's**: the device chain, the metadata,
device chain, the metadata, first-touch claim, ACL, migration and the first-touch claim, ACL, migration and the Stadium touch stay in the
Stadium touch stay in the kernel's block subsystem, which is v3's C kernel's block subsystem, which is v3's C code.
code. What a node finds on a storage port is that subsystem, speaking 8. **A device leaves by being asked for.** *(step 6a)* Asked to release a
messages in logical block numbers. (The mapper was first ruled to be a device, the mapper moves its blocks onto the devices that remain and
capsule on the node that holds the devices; that contradicted 1d, and on then says it may be pulled; if there is no room, the release is refused
being shown the contradiction Captain Bob ruled that 1d stands.) with a message. A device pulled without asking leaves holes: its
8. **A node's own drive is private.** It is a second chain in the kernel, logical numbers stay claimed and answer "no storage" until it returns,
wired to that node's port, and its blocks are nobody else's. A node may is known by its identity, and its blocks are at the same numbers again.
have it in addition to the common store or instead of it.
9. **Common from the bottom up, private from the top down.** A block of the
common store has the same logical number on every node that shares it,
from 2048 upward. A node's private blocks are numbered from the top of
the number space downward: private block *k* is logical number
2^32 - 1 - *k*, v3's block numbers being 32 bits. The two meet only if
the whole space is used up.
10. **A device leaves by being asked for.** *(step 6a)* Asked to release a
device, the mapper moves its blocks onto the devices that remain and
then says it may be pulled; if there is no room, the release is refused
with a message. A device pulled without asking leaves holes: its
logical numbers stay claimed and answer "no storage" until it returns,
is known by its identity, and its blocks are at the same numbers again.
### 8.2 What a node does *(step 6)* ### 8.2 What a node does *(step 6)*
`BLOCK`, `BUFFER`, `UPDATE` and `SAVE-BUFFERS` keep their two buffers and `BLOCK`, `BUFFER`, `UPDATE` and `SAVE-BUFFERS` keep their two buffers and
their FORTH-79 behaviour. The one word beneath them in their FORTH-79 behaviour. The one word beneath them in
`v4/capsule/blocks.v4` that read or wrote a block by storing to four `v4/capsule/blocks.v4` that read or wrote a block by storing to four
registers sends a message and waits for the answer instead. registers makes a kernel request instead: it puts the block's number and
the word address of the buffer's 256 cells on the data stack and writes the
request's number to port 0, where its kernel is. When the write has been
served the status is on the stack in their place: 0 it worked, 2 it was
refused, 3 there is no such block.
- A node wired to storage writes the message to that port. There are two requests, read a block and write a block. Their numbers are
- A node that is not sends the same message toward the node that is, and the same for every node and are below zero; the requests a host names for
it is passed on like any other (section 7). its own words (`KERNEL-WORD`) count up from 1.
- A node with no way to storage has none: `BLOCK` is an error with a
message, and the node is back at its prompt.
The four storage registers and `v4_node_storage_attach` go from the engine. The four storage registers and `v4_node_storage_attach` go from the engine.
### 8.3 The messages *(step 6)* ### 8.3 What the kernel does *(step 6)*
Four types, beside text, output and done (section 6): Every node has its kernel on port 0, whatever else is there for it: Hera's
requests for nodes (section 9) are honoured only from Hera, and the two
block requests from every node.
| Type | Payload | Answered by | `v4/system/blocks.c`, which the hosted and the bare-metal builds and the
|---|---|---| tests share, serves them: it takes the number and the address from the
| Block read | the block number, one word | Block data, or Block done with an error | node's data stack, checks that the 256 cells are in the node's memory, and
| Block write | the block number, one word; a Block data message follows it | Block done | reads or writes the block through v3's block subsystem
| Block data | 1024 characters | | (`v3/src/block_subsystem.c`), four characters to a cell, the first lowest.
| Block done | one word: 0 it worked, 1 there is no storage, 2 it was refused, 3 there is no such block | | The engine (`v4/src`) knows nothing of it.
A write is two messages because a block is exactly the most a message
carries, so the number cannot go with the data. Whatever answers pairs the
two by who sent them.
### 8.4 What is on a storage port *(step 6)*
A device (4.3), in `v4/system/storage.c`, which the hosted and the
bare-metal builds share as they share `boot.c`. It speaks the messages of
8.3 and asks v3's block subsystem (`v3/src/block_subsystem.c`) for every
block. The engine (`v4/src`) knows nothing of it.
- v3's code does what it does: header, allocation map, block cards, - v3's code does what it does: header, allocation map, block cards,
relocation, three blocks and their cards to a 4 KiB device block. relocation, three blocks and their cards to a 4 KiB device block.
- The devices beneath are v3's own back ends: RAM and a file when hosted, - There is one chain, as in v3: fast RAM at blocks 0 to 2047, then the
the virtio disk on bare metal. devices. Every node sees the same blocks at the same numbers.
- Blocks 0 to 2047 are the chain's fast RAM, as in v3; nodes that share - The devices are v3's own back ends: RAM and a file when hosted, the
the common store share those too. virtio disk on bare metal. A hosted program started with no disk has the
- The device holds a **view**: the common chain, or a private chain, or fast RAM alone, as hosted v3 has.
both. Private block *k* is the private chain's block 2048 + *k*, its
first on a device. A number is the private chain's when *k* is less than
the blocks that chain has on devices; any other is the common chain's,
and one past its end is "no such block". Numbers below 2048 are the
common chain's fast RAM, or the private chain's if the view has no
common chain. A number that belongs to no chain the view has is "no
storage".
- Whatever is on a storage port has a number, as a node has, and is sent
to and answers like one. Whoever wires a node tells it that number
(`STORAGE`) and the way to it (`ROUTE`). A node not told has no storage.
- A block number is not signed: on 32-bit cells the numbers from the top
down are the negative ones. Only 0 is no block.
**A change to v3's C.** Its block subsystem is one global chain. For a `blk_subsys_init` took a v3 `VM`, stored it and never used it; the hosted
second chain its state becomes something there can be two of. The change v4 system has none to give. **Ruled 2026-10-06:** the argument is removed.
is mechanical and the one chain v3 uses behaves as it did. (Approved.)
`blk_subsys_init` must be given a v3 `VM`, and refuses without one, though **On bare metal** the node's blocks are the kernel's real chain — RAM, the
the subsystem stores it and never uses it (`block_subsystem.c` line 651 is ramdrive and the virtio disk — in place of the RAM array
its only mention). The hosted v4 system has no v3 `VM` to give. **Ruled
2026-10-06:** the argument is removed, in the same change; the kernel's
call of it (`kernel/src/capsule/capsule_loader.c`) changes with it.
**On bare metal** the lone node's storage port fronts the kernel's real
chain — RAM, the ramdrive and the virtio disk — in place of the RAM array
`kernel/src/v4/sk_v4.c` gives it today. (Approved.) Found 2026-10-06: `kernel/src/v4/sk_v4.c` gives it today. (Approved.) Found 2026-10-06:
`kernel_main.c` starts the v4 node (line 523) before it sets that chain up `kernel_main.c` starts the v4 node (line 523) before it sets that chain up
(lines 620 to 668), and the v4 node never returns, so under `STARFORTH_V4` (lines 620 to 668), and the v4 node never returns, so under `STARFORTH_V4`
the chain does not exist today. Step 6 has the kernel set it up before the the chain does not exist today. Step 6 has the kernel set it up before the
node starts. node starts.
### 8.5 Not in step 6 ### 8.4 Not in step 6
- **Who may have which block is not checked.** First-touch claim, the block - **Who may have which block is not checked.** First-touch claim, the block
card's ACL and the Stadium touch need the node's identity, which is the card's ACL and the Stadium touch need the node's identity
message's ACL tag (`V3-PARITY.md` 1d). Blocks are read and written (`V3-PARITY.md` 1d). Blocks are read and written through v3's subsystem
through v3's subsystem with nobody's claim on them. Not as intended yet. with nobody's claim on them. Not as intended yet.
- **Chains of more than one device, identities, release and holes** are - **Chains of more than one device, identities, release and holes** are
step 6a. step 6a.
- **Cloud stores and real USB drives** wait for their drivers. The format - **Cloud stores and real USB drives** wait for their drivers.
and the messages already fit them.
### 8.6 Open ### 8.5 Withdrawn 2026-10-07
A node that starts with only its own drive and later gains a way to the Each of these was ruled on 2026-10-06 or stood in this document, and each
common store. With no common store, its blocks from 2048 upward, a left v3's design. Captain Bob: "something is really off. it sounds like a
capsule's among them, can only be on its own drive; when the common store divergence from the os as designed"; and of the three below, "all three,
appears those numbers are claimed twice. Not ruled. every node asks the kernel directly".
- **A disk as a device on a port that speaks messages**, and a block
request passed from node to node until it reaches the node wired to the
disk. Built and tested as far as one node (commit `4a505a15`), then
withdrawn. In v3 a VM calls the kernel.
- **Nodes with no storage** (ruling 2 of section 2, and acceptance 3 as it
was). In v3 every VM has blocks.
- **A drive of a node's own**, numbered from the top of the number space
downward. In v3 there is one chain.
- **POST on every node at its birth** (acceptance 1 as it was). In v3 the
kernel runs POST once, at boot, with block RAM it supplies, and a born VM
prints its parity. See section 9.
## 9. Birth, and Hera ## 9. Birth, and Hera
@@ -428,6 +402,12 @@ same kind. Only Hera's requests are honoured.
The unit rule (ruling 5) is Hera's, in capsule code: it is what she does The unit rule (ruling 5) is Hera's, in capsule code: it is what she does
with those requests. The engine and the host do not know it. with those requests. The engine and the host do not know it.
**Ruled 2026-10-07:** a node Hera births is not POSTed. POST is the
kernel's, run once at boot on Hera, as v3's kernel runs it once on its
first VM; a born node prints its parity. And the kernel is to hold POST's
cases and feed them to Hera itself, with no POST words loaded into her
dictionary — today they are a capsule she loads (`NUCLEUS.md` section 6).
## 10. Steps ## 10. Steps
Each is tested, committed and pushed before the next. Each is tested, committed and pushed before the next.
@@ -606,17 +586,15 @@ Each is tested, committed and pushed before the next.
`BYE`, and nothing it asks is honoured, as ruled. `BYE`, and nothing it asks is honoured, as ruled.
- The suite now takes about four minutes, eight under the sanitizers: - The suite now takes about four minutes, eight under the sanitizers:
five POSTs. five POSTs.
6. **Storage (section 8): the disk speaks messages, the kernel's mapper 6. **Storage (section 8): every node asks the kernel for its blocks.**
answers, private drives.** Sections 8.2 to 8.4. Tests: a node reads and Sections 8.2 and 8.3. Tests: a node reads and writes blocks by kernel
writes blocks through a port, and a disk image v3's code formatted request, and what v3's own calls wrote reads back; in the unit of five,
reads back; in the unit of five, one outer node writes a block and one node writes a block and another reads it (acceptance 3); Hera no
another reads it, one uses a drive of its own at numbers from the top longer sends POST to the nodes she births; POST 538 of 538 on Hera with
down, and one has no way to storage and `BLOCK` on it is an error with `blocks.v4` changed, at both widths and under the sanitizers;
a message (acceptance 3); POST 538 of 538 with `blocks.v4` changed, at `hosted-check`; the three bare-metal boots.
both widths and under the sanitizers; `hosted-check`; the three
bare-metal boots.
**6a. Storage that changes while running.** Rulings 6 and 10 of **6a. Storage that changes while running.** Rulings 6 and 8 of
section 8.1: chains of several devices, the device and chain section 8.1: chains of several devices, the device and chain
identities, a device joining at the end and known when it returns, identities, a device joining at the end and known when it returns,
release by asking, holes. Its acceptance is to be approved before it is release by asking, holes. Its acceptance is to be approved before it is
File diff suppressed because it is too large Load Diff