feat(v4.0.0): every message begins through the wait -- a stuck node holds up no one

(GATE) offers a message's first word and sleeps until it is taken, taking
in whatever is written to the node meanwhile; (PAY) offers every refusal
owed at once, one to a port; a node that owes one sleeps in the wait.
Writing without looking, looking again and again, and the lower-number
rule are gone.  Text from the console for a node whose own text waits to
begin a message ends that text Interrupted.  The lone node's hosts serve
an offer as a write.  MESH.md 7c; plan step 6d task 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-07 23:38:07 -04:00
co-authored by Claude Opus 5.5
parent 075385ab63
commit 482cc75faf
8 changed files with 188 additions and 113 deletions
+68 -22
View File
@@ -112,6 +112,10 @@ static unsigned starforth_node(unsigned k)
return (unsigned)id;
}
/* The same, answering with what has been printed: for when a node is
* spinning and the fabric never comes to rest. */
static const char *said(v4_cell node, const char *text) { (void)tell(node, text); return printed; }
static int waiting(unsigned id)
{
const v4_node *n = &v4_fabric_node_at(&f, id)->n;
@@ -364,9 +368,10 @@ int main(void)
{
CHECK(is_empty(tell(11, "0 GOT !")) && is_empty(tell(11, "12 AWAIT .")) && pool[1].n.mem[AWAIT_FROM] == 12, "node 11 waits on 12 again");
CHECK(is_empty(tell(10, ": F40 40 0 DO S\" HIT\" 11 SEND LOOP ; F40")) && pool[1].n.mem[OWED_COUNT] == 0, "node 10 sends it as many messages as it has room for");
(void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 11 AWAIT . ; ONE");
/* node 11 does what it has kept before it pays what it owes (7b.3): forty answers come first */
(void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 41 0 DO 11 AWAIT DROP LOOP ; ONE");
CHECK(strstr(printed, "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0,
"it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answer: its own wait ends, the message refused: \"%s\"", printed);
"it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answers: after the forty, its wait ends, the message refused: \"%s\"", printed);
CHECK(strtol(tell(11, "GOT @ ."), NULL, 10) == 40 && is_empty(tell(10, "12 3 ROUTE")) && is_empty(tell(11, "12 3 ROUTE")), "node 11 did the forty it had kept; the ways are told again");
}
@@ -393,34 +398,75 @@ int main(void)
CHECK(is_empty(tell(10, "66 NO-ROUTE")) && waiting(hera) && waiting(mid) && waiting(far), "the way is forgotten, and all three are at rest");
}
/* a node that owes a refusal to a node that is stuck is not stuck itself */
CHECK(is_empty(tell(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(tell(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12");
/* ---- a node that is stuck holds up no one (MESH.md 7c) ------------------- */
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
/* From here a node is spinning, so the fabric never comes to rest: said()
* is tell(), answering with what was printed by the time it gave up. */
/* a refusal owed to a stuck node whose number is the lower */
CHECK(is_empty(said(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(said(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12");
CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message and is then stuck in a loop");
CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 12 owes node 11 a refusal, and cannot give it: node 11 is not reading");
(void)tell(12, "7 8 * .");
CHECK(strcmp(printed, "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed);
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed);
{
v4_uheat_t clock = pool[2].es.anticlock;
unsigned k;
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
CHECK(v4_node_in_wait(&pool[2].n) && pool[2].es.anticlock == clock && pool[2].n.mem[OWED_COUNT] == 1, "between times it sleeps in the wait, still owing, and executes nothing");
}
CHECK(strcmp(said(10, ": X12 S\" 66 EMIT\" 12 SEND ; X12"), "B") == 0 && printed_from == 12, "another node writes to it and is answered: \"%s\"", printed);
/* a node that is waiting to write to a node finds out when that node is removed */
(void)tell(12, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11");
CHECK(ended == 0, "node 12 sends node 11 a message: node 11 is not reading, and node 12 waits to write to it");
/* two refusals owed: one to the stuck node, one to a node that waits for it */
CHECK(is_empty(said(10, "77 3 ROUTE")), "node 10 is told the way to 77 is by node 12, which has none");
CHECK(strstr(said(10, ": W77B S\" 1 DROP\" 77 SEND 77 AWAIT . ; W77B"), "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0 && pool[2].n.mem[OWED_COUNT] == 1,
"node 10 sends 77 a message and waits: node 12, which still owes the stuck node, tells node 10 it was refused: \"%s\"", printed);
CHECK(is_empty(said(10, "77 NO-ROUTE")), "the way is forgotten");
/* a line that must begin a message to the stuck node waits, and the node takes in what comes */
CHECK(is_empty(said(10, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n) && !pool[0].n.asking,
"node 10 sends the stuck node a message: its line waits in the wait, not blocked writing");
{
v4_cell kept = pool[0].n.mem[MQ_COUNT];
CHECK(is_empty(said(12, "7 8 * .")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n),
"text from the console for node 12 comes to node 10: it keeps it, and its line goes on waiting");
}
{
const char *r = said(10, "66 EMIT");
CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "A") == NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B"),
"text from the console for node 10 itself ends the line that waited, with an error that says so, and is then done: \"%s\"", r);
CHECK(strstr(r, "56 ") != NULL && ended == 3, "and what it kept for node 12 is passed on and done: \"%s\", %d ended", r, ended);
}
/* the stuck node is removed while a line waits to begin a message to it */
CHECK(is_empty(said(10, "TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n), "node 10's line waits on the stuck node again");
CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed");
(void)tell(10, "1 DROP");
CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL, "node 12's line ends in an error that says no one is there: \"%s\"", printed);
{
unsigned k;
for (k = 0; k < 200000 && ended == 0; k++) (void)v4_fabric_step(&f);
CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL && ended == 1, "the line ends in an error that says no one is there: \"%s\"", printed);
}
step_cap = 20000000;
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && waiting(hera),
"it goes on, the refusal it owed node 11 let go: it owes nothing and is at rest");
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera),
"node 12 goes on, the refusal it owed node 11 let go: it owes nothing and is at rest");
/* THE LIMIT (MESH.md 7b.7): a refusal owed to a neighbour whose number is the higher is written
* without looking, as any message to it is, so a node that is stuck holds up a neighbour that owes
* it one -- until it is removed */
/* a refusal owed to a stuck node whose number is the higher */
step_cap = 3000000;
CHECK(is_empty(tell(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none");
CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.asking && pool[0].n.mem[OWED_COUNT] == 1,
"node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, writes it, and is blocked");
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed");
CHECK(is_empty(said(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none");
CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.mem[OWED_COUNT] == 1 && !pool[0].n.asking,
"node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, and is not blocked writing it");
step_cap = 20000000;
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera), "node 10 is let go, lets the refusal go, and goes on: \"%s\"", printed);
CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 1, "node 10 goes on doing what it is sent, still owing: \"%s\"", printed);
{
v4_uheat_t clock;
unsigned k;
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
clock = pool[0].es.anticlock;
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
CHECK(v4_node_in_wait(&pool[0].n) && pool[0].es.anticlock == clock, "and sleeps in the wait between times");
}
CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed");
CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera) && !v4_node_in_wait(&pool[0].n), "node 10 lets the refusal go and is at rest: \"%s\"", printed);
printf(" %d checks, %d failures\n", checks, failures);
return failures != 0;