fix(v4.0.0): step 6d after its review -- no error in the middle of the messages waiting, no offer left standing

Ruled 2026-10-08: A, B, C, D and the guard for a half message.  Each with
a scene in test_host_mesh.c that failed first.

A. The words of a message after its first are written from the passes
   over the messages waiting by (!W): an offer and a wait for that offer
   only (a new engine address).  A reader removed in mid-message makes no
   error; the rest is let go and counted.  Before, the error left the
   messages waiting in pieces and the node going round for ever.
B. A store to the wait withdraws every offer; (GATE1) and (PAY-SET) do it
   first.  Before, text begun after a node went round without sleeping
   could go to the port of an older offer: text for one node was done by
   another.
C. What a finished text printed is put with the messages waiting, as how
   it ended is.  With no room either is let go and counted; neither is
   begun as a message from (FINISH) any more, where a stuck node on the
   way held the whole node.
D. Only what a sender is owed from an earlier text -- its output, how it
   ended -- holds that sender's next text back; a GONE does not; and what
   cannot be noted holds nothing.  A node's own messages keep the order
   they were made in.
-  A message half taken in when its writer is removed is let go
   ((MQ-MEND)), not kept as if whole.
-  Smaller: a refused line no longer ends a waiting text 'Interrupted';
   a node's own queued messages may be passed on by 16 nodes, not 15; no
   value is left on the stack when a port goes in mid-refusal.

make -C v4 test and sanitize at both widths, hosted-check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 06:34:15 -04:00
co-authored by Claude Opus 5.5
parent 380f1cc6ec
commit 2cf37aab4f
9 changed files with 289 additions and 62 deletions
+8 -6
View File
@@ -99,6 +99,7 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
n->offers |= 1u << k;
return;
}
if (port == (int)V4_PORT_WAIT) { n->offers = 0; return; } /* a store to the wait: every offer is withdrawn */
if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any", "which port" and the rest are not written to */
}
/* The stack registers: a store empties the stack. -1 when not attached. */
@@ -128,7 +129,7 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr)
if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from;
if (port == (int)V4_PORTS + 2) return (v4_cell)n->writers;
if (port == (int)V4_PORTS + 3) return (v4_cell)n->readers;
if (port == (int)V4_PORT_WAIT) {
if (port == (int)V4_PORT_WAIT || port == (int)V4_PORT_WAIT1) {
/* the wait: the word that came, or 0 for an offer taken */
if (!n->given) return 0;
n->given = 0;
@@ -206,18 +207,19 @@ void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers)
int v4_node_port_index(const v4_node *n, v4_cell addr)
{
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT) return -1;
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT1) return -1;
return (int)(addr - n->port);
}
int v4_node_read_ready(v4_node *n, v4_cell addr)
{
int port = v4_node_port_index(n, addr);
if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT)) return 1;
if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT && port != (int)V4_PORT_WAIT1)) return 1;
if (n->given && (port >= (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1;
n->reading = 1;
n->waiting = port == (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing */
n->read_port = n->waiting ? V4_PORT_ANY : (unsigned)port;
n->waiting = port >= (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing; */
n->read_port = port == (int)V4_PORT_WAIT ? V4_PORT_ANY /* the wait for an offer only reads no port at all */
: (unsigned)port;
return 0;
}
@@ -288,7 +290,7 @@ int v4_node_port_gone(v4_node *n, v4_cell code)
return 1;
}
if (n->asking) n->asking = 0;
else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0;
else if (n->reading && !n->given && n->read_port < V4_PORTS) n->reading = 0;
else return 0;
v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */
return 1;