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:
co-authored by
Claude Opus 5.5
parent
4a505a154d
commit
26a0748455
+95
-117
@@ -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
|
||||
is v3's Hermes message with what it carries, so v3's messaging rules are
|
||||
not dropped: they go with the message.
|
||||
2. **Some nodes have storage of their own**, in addition to or instead of
|
||||
the common SSD. Some have none.
|
||||
2. ~~Some nodes have storage of their own, in addition to or instead of
|
||||
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.
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
same capsules through its port from Hera, and passes POST. Each prints a
|
||||
parity line; the four outer nodes' dictionary hashes are identical.
|
||||
the four outer nodes while running; each is born empty and takes in the
|
||||
same capsules through its port from Hera. Each prints a parity line;
|
||||
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
|
||||
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
|
||||
forwarded by a node in between.
|
||||
3. **They share the SSD.** A block written by one node is read by another.
|
||||
One outer node has a drive of its own and uses it. One has no storage,
|
||||
and `BLOCK` on it is an error with a message.
|
||||
3. **They share the SSD.** Every node asks the kernel for its blocks. A
|
||||
block written by one node is read by another. (Changed 2026-10-07: no
|
||||
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
|
||||
centre to centre. A message crosses from one unit to the other. The
|
||||
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
|
||||
|
||||
**Ruled 2026-10-06** (Captain Bob), in the order the rulings were given.
|
||||
What is marked *step 6* is built there; what is marked *step 6a* is ruled
|
||||
and waits for that step.
|
||||
**Ruled 2026-10-06 and 2026-10-07** (Captain Bob). On 2026-10-07 he found
|
||||
this section to have left the OS as designed, and brought it back: every
|
||||
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
|
||||
block is a message — read block *n*, or write block *n* with 1024
|
||||
characters — and the answer is a message back.
|
||||
2. **A node only ever asks for a block by number, and knows nothing else.**
|
||||
It has one way to storage, as it has routes: a port, or nothing. This
|
||||
replaces the earlier proposal that a node be told ranges of block
|
||||
numbers. Nobody chooses ranges.
|
||||
1. **A node only ever asks for a block by number, and it asks the kernel.**
|
||||
`V3-PARITY.md` 1d and `ENGINE.md` 3.3: a kernel request, written to the
|
||||
port where the node's kernel is, served between the node's opcodes. No
|
||||
node asks another node for a block, and none passes such a request on.
|
||||
2. **Every node has blocks, always.** There is no node without storage.
|
||||
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
|
||||
stands between them.
|
||||
use. A physical block number is a place on a real device. The kernel's
|
||||
mapper stands between them.
|
||||
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
|
||||
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
|
||||
zero there: not yet given one. With them a device is known when it
|
||||
returns, wherever it is plugged in.
|
||||
7. **The mapper is the kernel's.** `V3-PARITY.md` section 1d stands: the
|
||||
device chain, the metadata, first-touch claim, ACL, migration and the
|
||||
Stadium touch stay in the kernel's block subsystem, which is v3's C
|
||||
code. What a node finds on a storage port is that subsystem, speaking
|
||||
messages in logical block numbers. (The mapper was first ruled to be a
|
||||
capsule on the node that holds the devices; that contradicted 1d, and on
|
||||
being shown the contradiction Captain Bob ruled that 1d stands.)
|
||||
8. **A node's own drive is private.** It is a second chain in the kernel,
|
||||
wired to that node's port, and its blocks are nobody else's. A node may
|
||||
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.
|
||||
7. **The mapper is the kernel's**: the device chain, the metadata,
|
||||
first-touch claim, ACL, migration and the Stadium touch stay in the
|
||||
kernel's block subsystem, which is v3's C code.
|
||||
8. **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)*
|
||||
|
||||
`BLOCK`, `BUFFER`, `UPDATE` and `SAVE-BUFFERS` keep their two buffers and
|
||||
their FORTH-79 behaviour. The one word beneath them in
|
||||
`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.
|
||||
- A node that is not sends the same message toward the node that is, and
|
||||
it is passed on like any other (section 7).
|
||||
- A node with no way to storage has none: `BLOCK` is an error with a
|
||||
message, and the node is back at its prompt.
|
||||
There are two requests, read a block and write a block. Their numbers are
|
||||
the same for every node and are below zero; the requests a host names for
|
||||
its own words (`KERNEL-WORD`) count up from 1.
|
||||
|
||||
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 |
|
||||
|---|---|---|
|
||||
| Block read | the block number, one word | Block data, or Block done with an error |
|
||||
| Block write | the block number, one word; a Block data message follows it | Block done |
|
||||
| Block data | 1024 characters | |
|
||||
| Block done | one word: 0 it worked, 1 there is no storage, 2 it was refused, 3 there is no such block | |
|
||||
|
||||
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.
|
||||
`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
|
||||
node's data stack, checks that the 256 cells are in the node's memory, and
|
||||
reads or writes the block through v3's block subsystem
|
||||
(`v3/src/block_subsystem.c`), four characters to a cell, the first lowest.
|
||||
The engine (`v4/src`) knows nothing of it.
|
||||
|
||||
- v3's code does what it does: header, allocation map, block cards,
|
||||
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,
|
||||
the virtio disk on bare metal.
|
||||
- Blocks 0 to 2047 are the chain's fast RAM, as in v3; nodes that share
|
||||
the common store share those too.
|
||||
- The device holds a **view**: the common chain, or a private chain, or
|
||||
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.
|
||||
- There is one chain, as in v3: fast RAM at blocks 0 to 2047, then the
|
||||
devices. Every node sees the same blocks at the same numbers.
|
||||
- The devices are v3's own back ends: RAM and a file when hosted, the
|
||||
virtio disk on bare metal. A hosted program started with no disk has the
|
||||
fast RAM alone, as hosted v3 has.
|
||||
|
||||
**A change to v3's C.** Its block subsystem is one global chain. For a
|
||||
second chain its state becomes something there can be two of. The change
|
||||
is mechanical and the one chain v3 uses behaves as it did. (Approved.)
|
||||
`blk_subsys_init` took a v3 `VM`, stored it and never used it; the hosted
|
||||
v4 system has none to give. **Ruled 2026-10-06:** the argument is removed.
|
||||
|
||||
`blk_subsys_init` must be given a v3 `VM`, and refuses without one, though
|
||||
the subsystem stores it and never uses it (`block_subsystem.c` line 651 is
|
||||
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
|
||||
**On bare metal** the node's blocks are 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_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`
|
||||
the chain does not exist today. Step 6 has the kernel set it up before the
|
||||
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
|
||||
card's ACL and the Stadium touch need the node's identity, which is the
|
||||
message's ACL tag (`V3-PARITY.md` 1d). Blocks are read and written
|
||||
through v3's subsystem with nobody's claim on them. Not as intended yet.
|
||||
card's ACL and the Stadium touch need the node's identity
|
||||
(`V3-PARITY.md` 1d). Blocks are read and written through v3's subsystem
|
||||
with nobody's claim on them. Not as intended yet.
|
||||
- **Chains of more than one device, identities, release and holes** are
|
||||
step 6a.
|
||||
- **Cloud stores and real USB drives** wait for their drivers. The format
|
||||
and the messages already fit them.
|
||||
- **Cloud stores and real USB drives** wait for their drivers.
|
||||
|
||||
### 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
|
||||
common store. With no common store, its blocks from 2048 upward, a
|
||||
capsule's among them, can only be on its own drive; when the common store
|
||||
appears those numbers are claimed twice. Not ruled.
|
||||
Each of these was ruled on 2026-10-06 or stood in this document, and each
|
||||
left v3's design. Captain Bob: "something is really off. it sounds like a
|
||||
divergence from the os as designed"; and of the three below, "all three,
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
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.
|
||||
- The suite now takes about four minutes, eight under the sanitizers:
|
||||
five POSTs.
|
||||
6. **Storage (section 8): the disk speaks messages, the kernel's mapper
|
||||
answers, private drives.** Sections 8.2 to 8.4. Tests: a node reads and
|
||||
writes blocks through a port, and a disk image v3's code formatted
|
||||
reads back; in the unit of five, one outer node writes a block and
|
||||
another reads it, one uses a drive of its own at numbers from the top
|
||||
down, and one has no way to storage and `BLOCK` on it is an error with
|
||||
a message (acceptance 3); POST 538 of 538 with `blocks.v4` changed, at
|
||||
both widths and under the sanitizers; `hosted-check`; the three
|
||||
bare-metal boots.
|
||||
6. **Storage (section 8): every node asks the kernel for its blocks.**
|
||||
Sections 8.2 and 8.3. Tests: a node reads and writes blocks by kernel
|
||||
request, and what v3's own calls wrote reads back; in the unit of five,
|
||||
one node writes a block and another reads it (acceptance 3); Hera no
|
||||
longer sends POST to the nodes she births; POST 538 of 538 on Hera with
|
||||
`blocks.v4` changed, at 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
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user