fix(v4.0.0): step 6c mended after its review -- what a stuck or gone node can and cannot hold up
The review of step 6c found it did not keep its rule. Ruled: fix them all; 16 hops. - Paying a NACK no longer waits on a lower-numbered neighbour; a node that owes one does not sleep, and goes on taking in what it is sent. - AWAIT looks first through the messages already waiting. - A node waiting to write to a removed neighbour gets error 18: the word that says who is reading also says which ports have anything on them. - A console line lets Hera go when she is blocked on the first word of a message (v4_fabric_interrupt_error, a device's `pending`). - A refused answer is told to the node that waits, not the one that answered; one owed to the node itself goes to its own queue. - A message is passed on by at most 16 nodes, then refused. - A GONE is believed only when it says it is from the node's centre. - Tests: the check that tested nothing is replaced; no room for a waiting sender; the limit that remains is tested as a limit. - MESH.md 7b's rule reworded to what holds, 7b.7 says where it falls short; README likewise. make -C v4 test, sanitize, hosted-check; three bare-metal boots. POST 538 of 538, word_count=317, dict_hash=0xc0769523a47b7dc3 on all six. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d343001dea
commit
59727f762a
+103
-8
@@ -295,9 +295,16 @@ kernel-Hermes's work in v3 and is not decided for the mesh.
|
||||
|
||||
## 7b. Refusals and waits (ruled 2026-10-07)
|
||||
|
||||
**The rule of this section: no message is lost without its sender being
|
||||
told, and no node waits for ever.** It closes two defects found in what
|
||||
was built: a message arriving at a node with no room for it was dropped
|
||||
**The rule of this section (reworded 2026-10-07, after the review of step
|
||||
6c): a node is never left waiting, or going round, on a node that is
|
||||
gone; and a wait on a node that is alive and stuck is ended by Hera's
|
||||
killing that node, or from the console. A message that is refused is
|
||||
told to whoever waits on it, while the node that refuses it has room to
|
||||
remember that it owes the telling.** As first written the rule was "no
|
||||
message is lost without its sender being told, and no node waits for
|
||||
ever"; the review showed that was more than what was built could keep,
|
||||
and section 7b.7 says exactly where it falls short. It closes two defects
|
||||
found in what was built: a message arriving at a node with no room for it was dropped
|
||||
and counted, and its sender never knew; and a node waiting for an answer
|
||||
(`AWAIT`) waited for ever if none came. Captain Bob: "no bad code is ever
|
||||
released".
|
||||
@@ -354,6 +361,23 @@ Two types, beside text (1), output (2) and done (3):
|
||||
to do: the moment it finds it has no room is the moment it is taking
|
||||
messages in so as to be free to write (section 7a), and it cannot begin
|
||||
a message of its own there.
|
||||
- When the message refused is a node's answer (type 3), the NACK is owed
|
||||
to the node the answer was for, which is the one that waits, and is
|
||||
about the node that answered.
|
||||
- A NACK owed to this node itself -- its own message came back to it and
|
||||
was let go here -- is put with its messages waiting, as if it had come
|
||||
by a port.
|
||||
- Paying one: if the neighbour it goes by is reading, it is sent. If not,
|
||||
and that neighbour's number is the higher, it is written all the same,
|
||||
as any message to it is (section 7a). If its number is the lower, the
|
||||
NACK stays owed; the node goes on taking in what is written to it and
|
||||
tries again, and does not sleep while it owes one. One there is no way
|
||||
for, or whose way is a port with nothing on it, is dropped and counted.
|
||||
- A message is passed on by at most 16 nodes. Its fourth word, the TTL,
|
||||
carries how many more may pass it on; the node that would be the
|
||||
sixteenth refuses it as it would one it had no way for. (Ruled
|
||||
2026-10-07: 16.) This is what stops a message going round for ever
|
||||
between two nodes each of which believes the way is through the other.
|
||||
- A NACK or a GONE that cannot be taken or passed on is dropped and
|
||||
counted, and nothing is owed for it: there is no NACK for a NACK.
|
||||
- Part of the queue is kept for NACK and GONE alone, so that ordinary
|
||||
@@ -365,9 +389,18 @@ Two types, beside text (1), output (2) and done (3):
|
||||
in an error: 19 "Message refused", or 20 "Node gone".
|
||||
- If it is not, a NACK is counted in `(REFUSED)`, and a GONE makes it
|
||||
forget the way to that node.
|
||||
- It acts on a GONE only if it came by the port that leads to everything
|
||||
the node has no other way to — its centre — so that only Hera can
|
||||
declare a node gone. Hera herself has no such port and sends them.
|
||||
- It acts on a GONE only if the message says it is from the node's centre:
|
||||
the node on the port that leads to everything it has no other way to,
|
||||
whose number it was told (`NEIGHBOUR`). One that comes by another port,
|
||||
or by that port from another node, is not believed. Hera herself has no
|
||||
centre and sends them. (As first built a node looked only at the port
|
||||
the GONE came by, and so believed one that any node sent by way of its
|
||||
centre.) A message's "from" word is written by its sender and nothing
|
||||
yet proves it: that is the ACL tag's work, in the later step named in
|
||||
section 3.
|
||||
- What ends a wait is looked for first among the messages already
|
||||
waiting: an answer, a NACK or a GONE may have been taken in before the
|
||||
wait began.
|
||||
|
||||
### 7b.5 Hera
|
||||
|
||||
@@ -385,6 +418,18 @@ Two types, beside text (1), output (2) and done (3):
|
||||
as usual.
|
||||
- On the two products there is one node, and nobody but the console could
|
||||
ever answer it: a line typed while it waits does the same.
|
||||
- **A blocked write (ruled 2026-10-07).** Hera has the lowest number, so
|
||||
she writes to a neighbour without looking and is blocked until it reads
|
||||
(section 7a); if it never does, nothing could be typed to her again. So
|
||||
when a node is blocked writing the first word of a message to another
|
||||
node, and its console has a line for it, the fabric raises error 21 on
|
||||
it: it gives that message up and goes on to read the line. Only on the
|
||||
first word, so that half a message is never left on a wire
|
||||
(`v4_fabric_interrupt_error`, `v4/include/v4/fabric.h`).
|
||||
- **A node waiting to write to a neighbour that has been removed** is told:
|
||||
the word that says which neighbours are reading also says which ports
|
||||
have anything on them at all, and with nothing there the wait ends in
|
||||
error 18, "No one on that port".
|
||||
|
||||
### 7b.7 Limits
|
||||
|
||||
@@ -394,6 +439,23 @@ Two types, beside text (1), output (2) and done (3):
|
||||
console. v3's pool is finite too, 32 messages, and a send beyond it is
|
||||
refused.
|
||||
- A node whose neighbour is asleep waits until it is woken (section 4.1).
|
||||
- **A node that is stuck can hold up its neighbours until it is killed.**
|
||||
A node cannot tell a neighbour that is busy for a moment from one that
|
||||
is stuck for good, and there is no clock (ruling 2). So:
|
||||
- a node that owes a NACK to a stuck neighbour whose number is the
|
||||
higher is blocked writing it;
|
||||
- a node that owes one to a stuck neighbour whose number is the lower
|
||||
goes on taking in what lower-numbered neighbours write to it, but does
|
||||
not sleep, and a higher-numbered neighbour with something for it
|
||||
waits;
|
||||
- a node with a message for a stuck neighbour waits to write it.
|
||||
|
||||
Each ends when Hera kills the stuck node: the wire is then empty, the
|
||||
waiting node is told so (error 18) and goes on. Hera herself can always
|
||||
be typed to (7b.6). None of this can happen on a node that is gone.
|
||||
- A node that is waiting for an answer keeps what comes for other nodes
|
||||
and passes it on when its wait ends, not before.
|
||||
- A node that was never told who is on its centre's port believes no GONE.
|
||||
|
||||
## 8. Storage
|
||||
|
||||
@@ -920,7 +982,8 @@ Each is tested, committed and pushed before the next.
|
||||
6. *The suite.* `make -C v4 test` and `sanitize` pass at both widths;
|
||||
`mkcapsule --lint capsules/` is clean.
|
||||
|
||||
**6c. Refusals and waits (section 7b).** **Done 2026-10-07.**
|
||||
**6c. Refusals and waits (section 7b).** **Done 2026-10-07; reviewed
|
||||
and mended the same day (below).**
|
||||
- *In the nucleus* (`v4/capsule/core.v4`, `quit.v4`): `(OWE)` and
|
||||
`(PAY)`; the room kept for NACK and GONE; `NO-ROUTE`; `GONE`; `AWAIT`
|
||||
ending in errors 19, 20 and 21; `(REFUSED)`.
|
||||
@@ -939,7 +1002,39 @@ Each is tested, committed and pushed before the next.
|
||||
bare-metal boots, `logs/20261007-202737` (amd64), `-203230`
|
||||
(aarch64), `-203616` (riscv64). On all six: POST 538 of 538,
|
||||
`word_count=317`, `dict_hash=0x54520ade672566ad`.
|
||||
- **Found on the way, and not mended: for ruling.**
|
||||
- *Verified again after the review's mends.* `make -C v4 test`,
|
||||
`sanitize` and `hosted-check`; three bare-metal boots,
|
||||
`logs/20261007-220949` (amd64), `-221223` (aarch64), `-221549`
|
||||
(riscv64). On all six: POST 538 of 538, `word_count=317`,
|
||||
`dict_hash=0xc0769523a47b7dc3` (the nucleus changed, so the hash
|
||||
did).
|
||||
- **The review (2026-10-07) found the step did not keep its rule**, and
|
||||
Captain Bob ruled: "fix them all; 16 hops". Mended, each with a test
|
||||
that failed first or was shown to fail with the mend taken out:
|
||||
- *A stuck node stalled a neighbour that owed it a NACK.* Paying one
|
||||
no longer waits on a lower-numbered neighbour (7b.3). What is left
|
||||
of this is in 7b.7.
|
||||
- *`AWAIT` missed what had already come.* It looks through the
|
||||
messages waiting first (7b.4).
|
||||
- *A node waiting to write to a removed neighbour went round for
|
||||
ever.* It gets error 18 (7b.6).
|
||||
- *Hera blocked writing to a stuck node could not be typed to.* A
|
||||
console line lets her go, on the first word of a message (7b.6).
|
||||
- *A refused answer was told to the node that answered.* It is told
|
||||
to the node that waits (7b.3).
|
||||
- *A message could go round for ever.* 16 nodes may pass it on (7b.3).
|
||||
- *Any node could forge a GONE by way of the centre.* The sender is
|
||||
looked at, not only the port (7b.4).
|
||||
- *A check that tested nothing*, the "GONE not from its centre" one,
|
||||
is replaced by two that send one and see it disbelieved; and "no
|
||||
room" is now tested for a sender that waits.
|
||||
- *The rule claimed too much.* Reworded (7b); `v4/README.md` too.
|
||||
|
||||
The engine gained: the bits that say which ports have anything on
|
||||
them; `v4_node_words_since_look`; a device's `pending`; and
|
||||
`v4_fabric_interrupt_error`. Tests: `test_fabric.c` 78 checks,
|
||||
`test_host_mesh.c` 109, `test_host_unit.c` 79.
|
||||
- **Found on the way in the first pass (both mended above).**
|
||||
- *Hera blocked writing to a stuck node.* Hera has the lowest number,
|
||||
so by section 7a she writes to a neighbour without looking and is
|
||||
blocked until it reads. If that neighbour is stuck she is blocked
|
||||
|
||||
Reference in New Issue
Block a user