revert(v4.0.0): step 6d, the wait, is backed out -- two reviews found it unsound

Ruled 2026-10-08.  The engine, the nucleus and their tests are as they
were at dfabfa46, before step 6d; the code of the wait and its tests are
in history at 075385ab..2cf37aab.  The limit of MESH.md 7b.7 stands: a
node that is stuck can hold up its neighbours until Hera kills it.

MESH.md 7c is kept as the record of the design as approved, and 7c.6 says
what was built, what the two reviews found, the cause the findings share
-- a node's message machinery runs on the stacks its text is using, and a
fault abandons whatever was in progress -- and what a second attempt
must settle before anything is built.

Kept from it, in hosted-check: a line that leaves 29 values on the stack,
and WORDS with 26 values on it.  Both hung the products at some commit of
the wait.

make -C v4 test and sanitize at both widths, hosted-check, lint; three
bare-metal boots typing both.  POST 538 of 538, word_count=317,
dict_hash=0xc0769523a47b7dc3 on all six: the hash of step 6c's code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 07:31:40 -04:00
co-authored by Claude Opus 5.5
parent 10f5ffd00b
commit 6015c87157
20 changed files with 1108 additions and 1203 deletions
+15
View File
@@ -26,6 +26,7 @@ typedef struct {
int (*take)(void *self, v4_cell value); /* the node wrote `value`: 1 if it is taken, 0 if not yet */
int (*give)(void *self, v4_cell *value); /* the node is reading: 1 with a word in *value, 0 if not yet */
void *self;
int (*pending)(void *self); /* 1 if it has a word to give that has not been asked for; may be 0: it never says */
} v4_device;
/* One end of a wire. */
@@ -55,6 +56,7 @@ typedef struct {
v4_place *place;
unsigned capacity;
v4_cell gone_error; /* see v4_fabric_gone_error; 0: none */
v4_cell interrupt_error; /* see v4_fabric_interrupt_error; 0: none */
} v4_fabric;
/* An empty fabric with room for `capacity` nodes, in `places`. */
@@ -71,6 +73,19 @@ void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity);
* is how a fabric begins, nothing is raised. */
void v4_fabric_gone_error(v4_fabric *f, v4_cell code);
/* A NODE BLOCKED WRITING TO A NODE THAT DOES NOT READ. Of two neighbours
* one may write to the other without looking (docs/v4.0.0/MESH.md 7a), and
* is then blocked until the other reads; if the other never does, it is
* blocked for ever, and if it is the node the console is on, nothing can be
* typed to it again. So: when a node that can take an error is blocked
* writing to another node, on the first word of a message (node.h,
* v4_node_words_since_look: nothing of the message has gone), and a device
* on one of its own ports says it has something pending for it, the error
* `code` is raised on the node: it gives up that message and goes on, to
* read what the device has. Only a device with a `pending` function can
* do this. With `code` 0, which is how a fabric begins, it never happens. */
void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code);
/* More room: `places`, of `capacity` no less than before, takes over; every
* node keeps its number and its wiring. */
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity);
+5
View File
@@ -65,6 +65,11 @@ typedef struct {
* port". */
#define V4_ERROR_NO_ONE 18
/* The nucleus's error for a node let go of a message it was blocked on the
* first word of, because its console has a line for it (fabric.h,
* v4_fabric_interrupt_error): "Interrupted". */
#define V4_ERROR_INTERRUPTED 21
/* The description of the nucleus built from v4/capsule (the generated file
* defines it). */
extern const v4_image v4_capsule_image;
+8 -50
View File
@@ -43,9 +43,6 @@
#define V4_PORTS 8u
#endif
#define V4_PORT_ANY V4_PORTS /* not a port: "whichever port has a neighbour writing" */
#define V4_PORT_OFFER (V4_PORTS + 4u) /* not a port: the offer on port 0; the offer on port k is k further (the wait, below) */
#define V4_PORT_WAIT (2u * V4_PORTS + 4u) /* not a port: the wait */
#define V4_PORT_WAIT1 (2u * V4_PORTS + 5u) /* not a port: the wait for an offer only */
#ifndef V4_NODE_WORDS
#define V4_NODE_WORDS 1024u
@@ -114,10 +111,7 @@ typedef struct {
unsigned last_from; /* the port the last read from "any" took its word from */
unsigned writers; /* bit k: the neighbour on port k is blocked writing to this node */
unsigned readers; /* bit k: the neighbour on port k is blocked reading from this node */
unsigned offers; /* bit k: a word is offered on port k (the wait: docs/v4.0.0/MESH.md 7c) */
v4_cell offer[V4_PORTS]; /* the words offered */
int waiting; /* non-zero: the read it is blocked in is the wait */
int offer_asked; /* non-zero: `asking` stands for the offer on `ask_port` (v4_node_offer_as_write) */
unsigned since_look; /* words taken from this node since it last fetched either of those */
/* DSTACK-DEPTH and RSTACK-DEPTH (D-16). See v4_node_stack_regs_attach. */
v4_cell dstack_reg; /* its word address, or -1 */
@@ -225,6 +219,13 @@ void v4_node_port_attach(v4_node *n, v4_cell base);
/* The neighbour has taken what the node wrote. */
void v4_node_port_served(v4_node *n);
/* How many words the node has had taken since it last looked at its
* neighbours (a fetch of either of the two status addresses). A node that
* looks before it begins a message (MESH.md 7a) and is blocked writing with
* this at 0 is blocked on the first word of the message: nothing of it has
* gone. */
unsigned v4_node_words_since_look(const v4_node *n);
/* THERE IS NO ONE ON THE PORT the node is blocked at -- writing to it, or
* reading from that one port -- and there will not be. A node that can
* take an error (it has an error register and a fault table: node.h,
@@ -235,49 +236,6 @@ void v4_node_port_served(v4_node *n);
* that is not blocked at a port, or is reading "any port". */
int v4_node_port_gone(v4_node *n, v4_cell code);
/* THE WAIT (docs/v4.0.0/MESH.md 7c). After the addresses above come
* base + V4_PORT_OFFER + k the offer on port k: a store here is the word
* the node offers to write to that port. It is
* remembered and waits for nothing.
* base + V4_PORT_WAIT the wait: a fetch here blocks the node until a
* word comes for it on any port, or one of its
* offers is taken, whichever is first.
* base + V4_PORT_WAIT1 the wait for an offer only: as the wait, but
* a word that comes for the node does not end
* it, and a writer to the node is not served.
* It is how the words of a message after the
* first are written by a node that must not be
* faulted if its reader is removed.
* A store to the wait withdraws every offer and waits for nothing.
* A word that came is fetched as from "any port", and "which port" says
* where from. When an offer was taken the fetch gives 0 and "which port"
* gives V4_PORTS + k: the offer on port k. When there turns out to be
* nothing on a port it has an offer on, the fetch gives 0 and "which
* port" gives 2 * V4_PORTS + k. Whichever, every offer the node had is
* withdrawn. Whoever connects the ports does the handing over
* (fabric.h); a node in the wait is blocked reading "any port" as far as a
* writer to it can tell.
*
* 1 if the node is blocked in the wait with nothing given yet. */
int v4_node_in_wait(const v4_node *n);
/* The offer on port k has been taken: the node is unblocked and will fetch
* 0, from V4_PORTS + k. 0 if it is not in the wait or has no offer there. */
int v4_node_offer_taken(v4_node *n, unsigned k);
/* There is nothing on port k, where the node has an offer: a node in the
* wait that can take an error (v4_node_port_gone says which can) is
* unblocked and will fetch 0, from 2 * V4_PORTS + k. No error is raised:
* what the node does about it is its own to say. 0 if it was not done. */
int v4_node_offer_gone(v4_node *n, unsigned k);
/* For a host with one node, whose devices always take what is written: if
* the node is in the wait with an offer, it becomes a blocked write of the
* word offered on the lowest such port -- asking, request, ask_port -- and
* v4_node_port_served then completes the wait as v4_node_offer_taken would.
* 1 if it did. */
int v4_node_offer_as_write(v4_node *n);
/* The neighbour on `port` writes `value`: the node, blocked reading that
* port or "any", is unblocked and will fetch it. */
void v4_node_port_give(v4_node *n, unsigned port, v4_cell value);