fix(v4.0.0): step 6e review round 2 -- only the message looked at is taken, moved or dropped; the kernel's port has no queue in a fabric; an answer nobody awaits is not a loss

- Engine: a wire keeps whether the message at its mark is the one last
  looked at; a node's take, move and drop of any other answer 3 and write
  nothing (MESH.md 7d.3).  A wire cut and made again between a look and a
  take no longer has a NACK done as text, or 256 cells written where one
  was looked for.
- Engine: v4_fabric_wire_kernel wires a kernel to a port with no queues;
  a message for it is refused at once, error 18, on a mesh as on the
  products.
- The result of a drop is looked at; a take that does not take has the
  message dropped, or gone past: nothing goes round.
- An answer nobody waits for is let go uncounted; (LOST) counts what should
  have been delivered or acted on and was not.  The flood's account is
  exact.
- Error 18 from under a word that was printing empties the data stack, as
  a fault does: that word's own values are not left there.
- Tests: the take and drop windows cut at every step, with and without
  another message put; a refusal owed to a stuck node whose wire is full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 22:36:59 -04:00
co-authored by Claude Opus 5.5
parent 6a7d0aa27f
commit f1419e739c
15 changed files with 345 additions and 63 deletions
+10
View File
@@ -134,6 +134,13 @@ v4_fabric_node *v4_fabric_node_at(const v4_fabric *f, unsigned id);
* ends. Each returns 1, or 0 if a node or a port is not there. */
int v4_fabric_wire(v4_fabric *f, unsigned a, unsigned pa, unsigned b, unsigned pb);
int v4_fabric_wire_device(v4_fabric *f, unsigned a, unsigned pa, const v4_device *device);
/* THE KERNEL ON A PORT (MESH.md 7d.5, ruled 2026-10-08). A node asks its
* kernel by words written to a port, and the kernel takes no messages: its
* port is wired to the device as above but is given no queues. Words are
* handed over as for any device; every operation on whole messages there
* answers that no one is on the port, so that a message sent to it is
* refused at once and nothing waits for it. */
int v4_fabric_wire_kernel(v4_fabric *f, unsigned a, unsigned pa, const v4_device *device);
int v4_fabric_unwire(v4_fabric *f, unsigned a, unsigned pa);
/* A node that is asleep executes nothing, and nothing is handed to it or
@@ -145,6 +152,9 @@ void v4_fabric_wake(v4_fabric *f, unsigned id);
/* WHOLE MESSAGES. A node that has stored an operation to Do (node.h) is
* blocked, and in the step in which it did the operation is done, whole, and
* the node is let go: put, take, move and drop and the rest (MESH.md 7d.3).
* Take, move and drop are done only on the message the node last looked at
* on that wire (wire.h, THE LOOK): if the mark is at any other -- the wire
* was cut and made again since -- they answer 3 and nothing is written.
* Sleep (8) and sleep for room (9) are the two that wait: the node stays
* blocked, executing nothing, until a message has come to one of its wires
* since it last fetched which wires have one. A message has "come" when a
+12 -1
View File
@@ -16,6 +16,16 @@
* and those four answer V4_WIRE_NO_MESSAGE. A message put on the back of a
* queue whose mark is at no message is the one the mark is then at.
*
* THE LOOK. Whoever reads a queue looks at a message, decides, and then
* takes it, moves it or drops it; and the queue may have been emptied and
* filled again in between -- its wire cut and made again. So the queue
* keeps whether the message its mark is at is the one last looked at:
* `looked` is set by a look that finds a message, and cleared whenever the
* mark is moved, the marked message goes, or the queue is reset. A node's
* take, move and drop are done only while it is set (fabric.c): they are
* then about the very message that was looked at, of the length the look
* gave, and no other.
*
* Nothing here allocates, and nothing uses the C library: whoever owns the
* queue supplies its memory.
*/
@@ -40,6 +50,7 @@ typedef struct {
unsigned mark; /* how many cells from the front the reader's mark is; == used: at no message */
unsigned arrived; /* not 0: a message has come since the reader last asked which wires have one */
unsigned freed; /* not 0: a message has come off since the writer was last woken from a sleep for room */
unsigned looked; /* not 0: the message the mark is at is the one last looked at: see THE LOOK */
} v4_wire_queue;
enum { V4_WIRE_DONE = 0, V4_WIRE_NO_ROOM = 1, V4_WIRE_NO_ONE = 2, V4_WIRE_NO_MESSAGE = 3, V4_WIRE_NOT_A_MESSAGE = 4 };
@@ -70,7 +81,7 @@ int v4_wire_next(v4_wire_queue *q);
* `text_cap` cells (V4_WIRE_NOT_A_MESSAGE if that is too few); taken off and
* gone. After a take or a drop the mark is at the message that followed.
* V4_WIRE_NO_MESSAGE with the mark at no message. */
int v4_wire_look(const v4_wire_queue *q, v4_cell *header7);
int v4_wire_look(v4_wire_queue *q, v4_cell *header7);
int v4_wire_take(v4_wire_queue *q, v4_cell *header7, v4_cell *text, unsigned text_cap);
int v4_wire_drop(v4_wire_queue *q);