Captain Bob, 2026-10-14: "change to PC, not SER5. it's not supposed to be
specific, but PC generic." boards/ser5 -> boards/pc, TARGET=PC,
lithos-pc.img; the image was never specific to one machine (the generic
UEFI/ACPI path, FABRIC-3 III). The Beelink SER5 stays named where the text
means the unit on the bench (its Secure Boot, BIOS, serial header) and in
the records. Built: lithos-pc.img, system=v4, with its SBOM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captain Bob, 2026-10-14: "v4 is the default build", "no, qemu to v4
too ... we are effectively trying to retire v3", "the 32 bit build needs
to go into the acceptance test too", "i don't care about v3".
- STARFORTH_V4 defaults on (Kconfig default y) and V4_DEFAULT=1
everywhere: every kernel carries v4 and v3 and boots v4; system=v3 boots
v3; STARFORTH_V4=0 builds v3 alone. Board images write system=v4.
- Acceptance (CLAUDE.md): the three ISAs as built (v4, POST passed,
V4_SYSTEM dict_hash equal) and make -C v4 test-32. v3 is not part of
it.
Acceptance run: amd64, aarch64, riscv64 -- PARITY:V4_POST 538/538,
dict_hash=0xe5a57f3eb72ff94a on all three, no unknown word; test-32: 30
suites, 0 failures. The SER5 image under OVMF boots v4 as built, v3 after
the one-word edit. README, BRINGUP, FABRIC-3 XLIII, the register updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
make boot_image now ends by writing build/boards/<board>/<image>.spdx(.json):
the image and every file copied off it, each with its SHA-256 -- the SBOM
of what is on the medium. It also refreshes sbom.spdx(.json), the source
SBOM: the tracked files the product is built from (kernel, v3, v4,
capsules, boards, tooling, proofs), staged to build/sbom/src so nothing
untracked in the working directory is swept in. Versioned as the kernel
version and git describe. mk/syft.yaml turns on file cataloging with
SHA-256 (a C tree has almost no packages for syft to find: the old SBOM
held one file with a zero checksum). No syft: the build stops.
syft 1.52.0 installed in ~/.local/bin from its GitHub release, checked
against the release's published SHA-256.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captain Bob's rulings, 2026-10-14: "delete" -- the duplicates listed in
DELETE-CANDIDATES.md are removed (the list stays as the record; the
formal tier's provenance comments repointed at the maintained copies) --
and "rewrite" the README: v2.1.0, the Tripod as Hera/Artemis/Hestia,
kernel-Hermes, identities on thumbdrives, the corrected ACL overhead,
1052-test POST and the current parity line, keyboards and storage, board
images carrying both systems and how to switch, and docs/README.md as
the way in. The book is left as it is, to be reworked later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/CLAUDE.md Phase 1 output, after the reorganisation.
- docs/README.md: rewritten as the map -- where each kind of document
lives, which one to believe (CLAUDE.md, FABRIC, v4.0.0, reference/,
BRINGUP, code), how to retire a document.
- docs/INDEX.md: regenerated from the tracked tree, 489 rows, every
document with a status (the 2026-06-16 snapshot was stale).
- docs/DEAD-AND-REVISED.md (new): what was abandoned (L4Re, the hal_*
contract, ACL RWT, the Hermes VM, elevation, the knowledge factor, ...)
and what was corrected (ACL overhead, versions, block rules, parity
baseline, ...), each with its date and record.
- docs/DELETE-CANDIDATES.md: 12 duplicates, awaiting a ruling; nothing
deleted.
- CLAUDE.md: versions corrected (3.2.0 / 2.1.0).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/CLAUDE.md Phase 2, 2026-10-14. All moves by git mv; every archived
file carries a header saying what it is, why, and where to look instead.
- docs/reference/ (new): roadmap and versioning policy, M7.1, word-ACL
design, kernel args, hosted acceptance test, dictionary, primitives,
ontology, L8 table -- previously spread over docs/, docs/lithosananke/
and docs/03-architecture/.
- docs/working/archive/historical/: finished work (session plan, test-gap
audit, birthing plan, fix write-ups, the January architecture draft).
- docs/working/archive/superseded/: the Hermes-VM Tripod docs and July
Hermes designs (-> FABRIC-3.5/3.6), the StarForth roadmap, every working
doc already flagged superseded or obsolete.
- docs/working/archive/dead/: the hal_* target contract (never adopted),
L4Re, metrics-and-knobs.
- Papers and proposals into docs/working/papers/.
- References rewritten across the repo (not logs/, not docs/patent/);
CLAUDE.md's documentation section rewritten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
boards/BRINGUP.md A6, FABRIC-3 SXLIII (ruled: one image, switch at boot).
A STARFORTH_V4 kernel carries v3 too; system= in the boot arguments
chooses, else the build's default (V4_DEFAULT: 1 for plain STARFORTH_V4
builds as before, 0 for board images). make boot_image builds both and
always writes starforth.cfg / cmdline.txt with system=v3 first, and cleans
its ISA's objects first -- that clean was removing build/<arch>/SER5, not
the kernel's objects, until fixed here.
Each ISA: v3 by default (hash unchanged), v4 with system=v4 (538/538).
The SER5 image under OVMF: v3 as built, v4 after a one-word edit on it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
boards/BRINGUP.md A1, FABRIC-3 SXLII. xhci.c keeps a table of controllers
(up to 8) and services each; kernel_main brings up index 0, 1, ... until
there is none. repl.c's and blkio_usb.c's per-slot state is per
controller now (a slot ID is a controller's own), and each USB keyboard
keeps its own last report and lights; an unplugged keyboard releases what
it held.
Test first: keyboard and identity on a second controller behind a bridge,
Zuse on the first -- before, only Zuse; after, all three, on all three
ISAs. Hot-plug and unplug on the second controller. Acceptance unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
boards/BRINGUP.md A3 and S3, FABRIC-3 SXLI. A HID boot keyboard is
configured (interrupt IN endpoint, SET_PROTOCOL boot) and its reports
become the same Linux-keycode events as PS/2 and virtio (usb_kbd.c): the
full layout -- F-keys, navigation block, arrows, Num Lock, keypad. The
console treats Caps and Num Lock as toggles shown on the keyboard's
lights, and the keypad as digits or navigation. While a USB keyboard
runs, its event ring is serviced every tick, not once a second.
Found on the way: with no i8042 (port 0x64 reads 0xFF) the kernel hung at
boot in an endless drain -- a legacy-free PC would stop there. Detected
and skipped now; drains bounded.
QEMU, amd64 with the USB keyboard the only one: 1 2 + . on main keys and
keypad, Caps Lock, Num Lock all right; aarch64/riscv64 configure it too.
Acceptance on three ISAs unchanged; identities hot-plug.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
boards/BRINGUP.md A1, FABRIC-3 SXL. It was matched by QEMU's own IDs on
bus 0 alone, so no real board's was found. Now pci_find_class() reads
every bus/slot/function; pci_bar_size() sizes BAR0; the USB Legacy Support
capability hands the controller over from the BIOS, SMIs off; CSZ=1
contexts are placed 64 bytes apart instead of refused. XHCI_QEMU_ARGS
lets QEMU place the controller as real hardware does.
Test first: an NEC controller behind a PCIe root port -- no attach before,
Zuse minted after, on all three ISAs. Standard acceptance unchanged; five
hot-plugged identities attach. Not rehearsable: firmware handoff, CSZ=1.
Still open: only the first controller found is used.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
boards/BRINGUP.md R2/R3, FABRIC-3 SXXXIX. The entry stub cleans the cache
over the image, builds an identity map (the image's GiB Normal, the rest
Device) and enables MMU and caches at EL2 (or EL1); rpi5_mmu.c makes the
devicetree's RAM Normal and the framebuffer uncached. Mailbox waits give
up after one second; the buffer is cleaned around the exchange; the
framebuffer address goes through dma-ranges, not a Pi 4 mask.
New rpi5-rehearsal target runs the native image on QEMU virt at EL2. It
found three more that would each have stopped the board: the PL011 shift
(mine, c9519173; the host test asserted it), the GIC address not carried
through /soc's ranges (new fdt_reg_address(), checked against the real
Pi 5 DTB), and no timer IRQ at EL2 (HCR_EL2.IMO/FMO/AMO).
Rehearsal: POST 1052 passed, same parity hash as UEFI. Standard acceptance
on three ISAs: POST 1052, hash 0x82f4ae7cb2e2d424.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FABRIC-3 SXXXII.4's deferred LOG-FLUSH, built to the 2026-10-14 rulings
(SXXXVIII): everything a VM logs, at or above the log level, goes into its
own buffer; it goes to Artemis on LOG-FLUSH, when full, and at once on an
ERROR, as one kernel-Hermes LOG_BATCH message she writes on her own turn,
the source being the sender the kernel stamped. Records that cannot go yet
are counted and reported with the next flush. LOG-SHOW (Hera only) reads
the ring back -- it had no reader.
Found by the first test that filled it: ring growth overwrote the oldest
record and put blank slots inside the live range. Fixed test first.
Three ISAs: POST 1052 passed; new parity baseline word_count=526
hash=0x82f4ae7cb2e2d424 (deliberate). CLAUDE.md: Phase 8 PKI closed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Any identity could have arbitrary FORTH run as Zuse: KH-ELEVATE-SEND and
KH-BLK-ATTACH-SEND sent any text to Hera, from any VM (shown live). And the
drain popped a message after running it, so a payload calling a colon word
ran twice. Both fixed test first (FABRIC-3 SXXXVII):
- KH-BLK-ATTACH-SEND is ( dev-addr ok? -- sent? ), Artemis only; the kernel
writes the reply text. BLK-ATTACH-ACK is Hera's only.
- The drain pops before it runs.
- Elevation, ruled not needed: KH-ELEVATE-SEND, message type 8,
zuse-eligibility.4th, ZUSE-ELIGIBLE?/ZUSE-ELIGIBILITY-ADD/
ELEVATE-PUBKEY-UNPACK and the eligibility list removed; its disk area
stays reserved, unused. FABRIC-3.7 closed.
Three ISAs: POST 1052 passed; new parity baseline word_count=523
hash=0xb73b58052d591638 (deliberate).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FABRIC-3.5 SXXXII, closing FABRIC-3 SXXIX bug 2 (SXXXVI). A send marks the
receiver for the switch signal; the VM's own loop on its native stack takes
its messages and yields; Hera's idle beat makes the pending switch instead
of running other VMs' messages on her stack; every VM gets switcher turns
from birth; the drain refuses any call outside the VM's own context (the
test: it held every relayed line before, none now).
Found on the way: amd64's first-entry frame left rsp 8 bytes off the SysV
entry alignment (#GP on the first interpreter run on a VM's own stack), and
a VM yielding from its loop was marked SWITCHED_OUT, which stopped console
relay after one message and would have made KILL refuse it.
Relay of four lines to a WIREBIND identity on all three ISAs, five
hot-plugged identities, and standard acceptance (POST 1052, hash
0x08873e0f44b7cb2a) all pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checked against a scratch artemis.img, Zuse drive and five identity drives
minted together at a live prompt; the committed images are all blank since
e56974e0 and cannot show the gap either way. No code change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FABRIC-3.md XXXIV.1, traced and fixed. vm_interpret() copied each text
into the VM's one input buffer and reset the position. LOAD runs its
block by calling it, so the block replaced the line LOAD was on and
nothing after LOAD or THRU on that line was ever interpreted; the same
for -->, a capsule's EXEC and a message kernel-Hermes delivers.
vm_interpret() now keeps what the outer text had not yet read when it is
called from inside another, and puts it back after, as FORTH-79's LOAD
keeps the input stream it interrupts. In the kernel's VM and the hosted
one alike.
POST: LOAD.rest_of_line (1 LOAD 0 0 /) and THRU.rest_of_line
(1 2 THRU 0 0 /) failed without the fix (logs/20261014-061222) and pass
with it. Three-ISA acceptance: logs/20261014-061508 (amd64), -061624
(aarch64), -061837 (riscv64), 1052 tests, none failed, zuse prompt,
hash 0x08873e0f44b7cb2a unchanged. The hosted binary: 100 LOAD 1 + .
gives 8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Built with EMERGENCY_CONSOLE_ENABLED=1 and booted with no identity logged
in, the prompt printed "ok> ok" without end, 1.4 million times in 200
seconds (logs/20261013-210442). sk_console_readline() gave up at once
whenever no identity was present. The production build answers that by
going silent until a login; the bring-up build, which needs no login,
took it as an empty line and asked again. The give-up is now the
production build's only.
Found rehearsing boards/BRINGUP.md; it predates the console change of
c9519173 (the image built from the commit before that did the same).
The riscv64 bring-up build, no thumbdrive, three lines typed
(logs/20261013-235129): one prompt that waits, and 3, 56 and 81.
Acceptance of the production build, one QEMU at a time: amd64
(-235255), aarch64 (-235411), riscv64 (-235620) to the zuse prompt, no
unknown word, hash 0x08873e0f44b7cb2a on all three.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each board has one serial line that is its console, the lowest common
denominator beside the screen and keyboard. Its address was QEMU's,
fixed: on a Raspberry Pi 5 the aarch64 one is ordinary RAM, written to
with every character printed; on a Milk-V Mars the riscv64 one is the
board's UART with registers four bytes apart, and the UEFI loader would
have waited for ever on its first character; on a PC with no COM1 the
prompt read 0xFF for ever.
console_attach_serial(), called before anything prints: COM1 if a UART
answers there; elsewhere the UART that /chosen/stdout-path names
(fdt_uart.c: alias, path, the address carried up through each bus's
ranges, reg-shift and reg-io-width); with no devicetree, QEMU's. A
devicetree that names no usable console gives no line, not a guess. A
line that does not come ready is given up, not waited on. The riscv64
loader's early serial does the same.
tools/fdt_uart_test.c, run by hand, 19 checks plain and under the
sanitizers: devicetrees shaped like the Mars's, the Pi 5's and QEMU's,
what must find nothing, and a block cut short at every length; and the
Pi 5's real devicetree gives a PL011 at 0x107d001000.
Acceptance, one QEMU at a time: v3 on amd64 (logs/20261013-204436),
aarch64 (-204803) and riscv64 (-205001) to the zuse prompt, no unknown
word, hash 0x08873e0f44b7cb2a on all three as before. -204600 is an
aarch64 run during which the disk images were restored under it by a
script that had been refused a second QEMU; it passed and is kept, and
was run again. v4 on the three ISAs (-211149, -211444, -211857): POST
538 of 538, dict_hash 0xe5a57f3eb72ff94a, the typed session unchanged.
The Mars image through OpenSBI and U-Boot in QEMU took its line and its
interrupt controller from the devicetree and passed POST.
Found on the way and not mended (boards/BRINGUP.md 1.6): built with
EMERGENCY_CONSOLE_ENABLED=1 the prompt floods with empty lines. -210442
shows it; the commit before this does the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What to do on the day a board is on the bench: media, cabling, what to
watch for, what counts as a pass, what to keep. Written before any board
has been booted.
Section 1 lists what was found in the code while writing it, none of it
fixed: the USB controller driver matches QEMU's controller only; the
production build shows no prompt without a thumbdrive login; there is no
USB keyboard driver and no disk driver but virtio; on the Pi 5 the console
writes every character to QEMU's UART address, which is RAM there; on the
Mars the console's UART register layout is probably not the board's; the
board images cannot build the v4 node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The final review of step 6e, by a fresh reviewer told to break it, and
what was ruled: fix them all, test first. Each has a test that failed
before the mend.
- Two texts from one node could be begun in the wrong order when room
for their answers came between the node's look at the first and at the
second. Texts whose answers go by the same port are begun in the order
they came: (D-MASK), quit.v4. 102 of 700 timings were wrong before.
- A word written with PORT! to a node that speaks whole messages, or to
a console's port, blocked its writer for ever and cut off every node
beyond it. It is error 18 now, whether that node is asleep, running
or stuck: fabric.c, node.c.
- A node asleep for room on one wire is woken when another of its wires
is cut.
- A line there was no room for on the lone node's wire was reported as a
fault and ended the hosted program. It is Message refused, and the
prompt comes back: V4_BOOT_LINE_REFUSED. hosted-check has the case;
no bare-metal boot has typed it.
- Ruled: text behind held output for the same port is refused though it
would fit. MESH.md 7d.4 said otherwise and is corrected.
- The removal test also cuts and re-makes a wire, and has an exchange in
which output is held at a full wire: 26,814 disturbances in all.
- MESH.md and v4/README.md no longer say that a stuck node holds up no
other node, that only printing waits, or that no node is left waiting
on one that is gone; 7d.6 lists the limits and what the products do
that they did not before.
make -C v4 test and sanitize at both widths, hosted-check, lint. Three
bare-metal boots: logs/20261013-194827 (amd64), -195131 (aarch64),
-195518 (riscv64). POST 538 of 538, word_count=317,
dict_hash=0xe5a57f3eb72ff94a on all six; the three sessions are the same
character for character. The boots were built with the working tree's
uncommitted change to kernel/Makefile that adds the ISA to the kernel's
version line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_host_mesh.c, 220 checks: three exchanges on the row of three -- text
from the console for node 12 with what it prints and how it ended; node 11
SENDing node 12 text and waiting for its answer; a message node 12 has no
way for and its NACK to node 10 -- are each played once for every engine
step they take with node 11 removed at that step, and again with node 12:
17,642 removals at 64 bits. Every node left comes to rest asleep, blocked
at no port and in no operation, and answers. What is typed is a word
defined beforehand, so that the steps are the exchange's and not the
dictionary being searched.
Removed from the engine, nothing using them: v4_fabric_interrupt_error, a
device's pending hook, v4_node_words_since_look, V4_ERROR_INTERRUPTED.
MESH.md: 4.1's table has the addresses after the ports; 7a and 7b say what
of them still holds; 7b.7's limit is closed; step 6e is written up.
v4/README.md likewise.
make -C v4 test and sanitize at both widths, hosted-check, lint. Three
bare-metal boots with the typed session and a loop printing 400 numbers:
logs/20261013-165124 (amd64), -165428 (aarch64), -165818 (riscv64). POST
538 of 538, word_count=317, dict_hash=0x0951d7e02e251554 on all six, and
the three sessions are the same character for character. The boots were
built with the working tree's uncommitted change to kernel/Makefile that
adds the ISA to the kernel's version line; nothing else differs from this
commit.
The plan's final review is not done yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-root stale references to actual locations: (shared engine/hosted) and (LithosAnanke). Update source tree diagram accordingly, correct / counts, and remove the obsolete bullet. Also fix include paths (, ).
Surgical correction only; no behavioral changes.
- docs/lithosananke/README.md + ROADMAP.md: correct branch topology (no
lithosananke branch post-split; master is the sole line), mark M7.1 as
live, and fix build commands (kernel/Makefile, not Makefile.starkernel)
- docs/README.md: refresh current active work (Tripod = Hera/Artemis/Hestia,
M7.1 live, StarForth v4) and flag INDEX.md as stale
- docs/INDEX.md: add dated-snapshot staleness banner
- Add TARGET-HAL / OBSOLETE / SUPERSEDED banners to stale HAL, physics,
heartbeat, and DoE docs under docs/working/ (annotation only, no deletions)
- 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>
- The result of every take is looked at: a wire cut between the look and
the take leaves nothing acted on (the text before run again, a refusal
counted, a wait ended by an old answer, a way forgotten).
- A node with no room to pass on what another printed, or its word of how
text ended, leaves it on the wire it came by and moves it when there is
room; what is behind it for the same port waits too. Sleep for room (9)
is woken by room on any of the node's wires (engine; MESH.md 7d.3).
- The lone node's host keeps no queue for the kernel's port: a message to
it is error 18. The step limit is counted while the node waits for room.
- A text waiting for room to print is not interrupted by console text;
AWAIT is, as before. (BREAK?) is gone.
- A GONE is believed only by the centre's port; unawaited answers let go
are counted; nothing past a message's last character goes on a wire;
AWAIT sets (AWAIT-FROM) only once the stack has been tried.
- test_host_depth.c: ten paths, each run works or ends in one named stack
error; it fails with (ROOM) or (ROOM-SERVE) taken out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step 6e, tasks 2 and 3 (docs/v4.0.0/MESH.md 7d). The nucleus puts, looks
at, takes, moves and drops whole messages through the six addresses after
its ports; its own ring of messages waiting, the refusals owed, (GATE) and
the looking words' use are gone. SEND, an answer, a NACK and a GONE go or
are refused at once; what a text prints waits for room; a text is not
begun until the wire its answer goes by has room for it, and that room is
kept. The lone node's host (v4/system/boot.c) keeps its two wires and
does its operations; the test hosts' consoles put and take whole messages
through the fabric. New: tests/test_host_depth.c, every message path of
a mesh node at every depth of both stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Queues of whole messages on the wires between nodes (v4/wire.h), the six
addresses and ten operations a node asks of the fabric (MESH.md 7d.3), and the
fabric's pool of queues. Engine only: the nucleus does not use any of it yet.
The ports in the host map move to BUF0_W - 140 so that the new addresses are
not among the nucleus variables, with a compile-time check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One doe-<arch>-<time>.csv is written by each QEMU boot; the 96 from the
boots of steps 6 to 6d were untracked. Committed so that the tree is
clean before step 6e begins: this commit is its rollback point.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MESH.md 7d.3 amended while the plan was written: first and next in place
of find by type; sleep is woken by a message coming, not by one being
there; operation 10, room. 7d.4: room for a text's answer is kept on
the wire back. 7d.9: a ping across hops, thought about and not ruled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MESH.md 7d: the rulings, the wire, what a node asks of the fabric, the
nucleus, the products, the limits, the acceptance, and the later step of
keeping the wires in the system's blocks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MESH.md 7c.7: the stacks doubled in scratch and each path measured -- the
size was never the cause; EMIT's overrun of the output buffer, and a
message's first word moving before there was room for the rest; what is
left for a second design; the depth sweep.
Three bare-metal boots of 0d91608f typing the deep-stack lines: POST 538
of 538, word_count=317, dict_hash=0x3629660aa2dc6823 on all six. Three
earlier amd64 boots of the same code, whose typed session was wrong, are
kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two root causes behind what the reviews of the wait found, both in
the code as it stands. Each with a check that failed first.
EMIT stored its character and only then looked whether the buffer was
exactly full. A flush that ended in a fault -- the stack too deep to
begin a message -- left the buffer full, and the fault's own message was
then put past its end, with (OUT^) never again at the end to be flushed.
The 28 cells after the buffer happen to be unused, so nothing showed;
the wait had put the ports there, and the node blocked writing to one.
EMIT now sends a buffer it finds full before it stores.
AWAIT, and (GATE) when a neighbour is writing, read a message's first
word and then used stack that was not known to be there. With 27 or 28
values on the stack, or 28 or 29 calls deep, a line typed during AWAIT
was taken and never answered. (ROOM) tries six cells and four return
entries first: if they are not there the text ends 'Stack overflow' with
nothing read. (GATE) tries the three cells its writing needs before a
first word goes; it was safe before only by the order things were done.
v4/tools/depthsweep.py runs every message path of the hosted product at
every depth of both stacks: each line typed must be answered and the
node must come back. hosted-check runs it.
make -C v4 test and sanitize at both widths, hosted-check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
MESH.md 4.1, 7a, 7c.2, 7c.3, 7c.4 and step 6d say what the code now does,
what the review found and how each was mended, and what is small and not
mended. The README no longer says the aim is unmet; it says the mended
code has not been reviewed again.
Three bare-metal boots on 2cf37aab, typing 29 values on a line: POST 538
of 538, word_count=317, dict_hash=0xd41a6ac9448fff60 on all six.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
The review of step 6d found it not sound. Mended here, with a check
that failed first: a text that left 29 values on the stack hung the
node for ever, on the products too -- the passes over the messages
waiting that follow every text need four cells, and a stack fault in the
middle of one left the messages in pieces. Such a text ends 'Stack
overflow', as before step 6d. hosted-check types it.
The other findings are open and are written under step 6d in MESH.md
section 10; the README no longer says the aim is met.
make -C v4 test and sanitize at both widths, hosted-check. The bare
metal boots have not been made again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The engine's console release (v4_fabric_interrupt_error), a device's
pending, and the count of words since a look are removed: nothing uses
them. MESH.md 4.1, 7b and 7c say what was built, where it differs from
what was approved and why, and what is still a limit; step 6d is marked
built, with the defects found on the way.
make -C v4 test and sanitize at both widths, hosted-check, lint; three
bare-metal boots. POST 538 of 538, word_count=317,
dict_hash=0x6a39c0bb9d183418 on all six.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>