fix(v4.0.0): a waiting node goes on passing on and paying; KILL is not held by a stuck node

Found in the five-node test, each with a check that failed first:
- A node with answers it could not give to two stuck senders began no
  text at all.  It now holds back only text from a sender whose own
  answer is still with it.
- KILL waited to tell a stuck node, and a typed line that broke it left
  the nodes after it untold.  GONE is put with the messages waiting, as
  how text ended is, and goes when it can.
- So that 'tell, then wait' still works, AWAIT does what (IDLE) does but
  for beginning text: it looks through the messages waiting, offers what
  is to be passed on and what is owed, and sleeps in the wait.  A waiting
  node no longer keeps back what passes through it.
- A node in the wait with an offer on a port that turns out to have
  nothing on it is woken and told so (which port: 2 * V4_PORTS + k); no
  error is raised on it.  (GATE) makes it error 18; (IDLE) and AWAIT let
  the message go.  Before, removing a node raised 'No one on that port'
  on the unrelated text of a neighbour that had something queued for it.

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 01:00:33 -04:00
co-authored by Claude Opus 5.5
parent 353783726d
commit ec817a8264
9 changed files with 130 additions and 99 deletions
+10 -2
View File
@@ -251,8 +251,10 @@ int v4_node_port_gone(v4_node *n, v4_cell code);
* offers is taken, whichever is first.
* 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. Either way every offer the node
* had is withdrawn. Whoever connects the ports does the handing over
* 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.
*
@@ -263,6 +265,12 @@ int v4_node_in_wait(const v4_node *n);
* 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