fix(v4.0.0): POST leaves nothing, as v3 really does; and what the review of step 6b found

Captain Bob was told that v3 leaves the words POST's cases define in the
dictionary, and ruled that v4 should.  That was false: v3's run_test_suite
puts the dictionary back after each word's cases (test_common.c:333,
:365).  Shown that, he ruled that POST leaves nothing.  The boot now
seals the system, runs POST, and has the node do COLD, whose printing is
not shown; PARITY:V4_SYSTEM is the system as sealed.

A case the node does not come back from ends POST there, named, with how
many were not run: it would have stalled the boot for hours, where the
capsule had ended it.  The runner's test of it now uses a word that
really never ends.

hosted-check also requires that RS1 and T{ are unknown after boot, and
boots a program whose POST has failing cases (tests/post_cases_fail.c):
PARITY:FAIL, POST: FAILED, no prompt, none of a case's printing shown.

Comments and documents that still named the POST capsule or its two
hooks are brought up to date; NUCLEUS.md 6.3 says what v3 does, with the
lines, and how the wrong ruling came about.

make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and
riscv64 boot, POST 538 of 538, word_count=314, dict_hash
0x220ab283a504a3b3 on all six: logs/20261007-112638, -112901, -113220.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-07 11:40:20 -04:00
co-authored by Claude Opus 5.5
parent eda6577a53
commit 18adf59091
17 changed files with 669 additions and 65 deletions
+2 -2
View File
@@ -194,7 +194,7 @@ program with the node as its interpreter. That is withdrawn. From here:
**What the two share (confirmed by Captain Bob the same day, "yes,
exactly"):** the engine in `v4/src`; the FORTH-79 capsule,
`capsules/v4/forth79.4th`; and its POST, `capsules/v4/post79.4th`. **The
`capsules/v4/forth79.4th`; and its POST (then `capsules/v4/post79.4th`; since `MESH.md` step 6b, 2026-10-07, the kernel's cases, `v4/system/post_cases.c`). **The
nuclei are separate.** The bare-metal nucleus needs word IDs in its
headers and words that are called where the hosted one compiles them in
line; the hosted nucleus need not have either. The hosted product may
@@ -346,7 +346,7 @@ not written yet. Nothing of it is built.
| `v4/system/boot.c`: its own capsule loader and `PARITY:V4_*` lines | Stays for the hosted product. On bare metal v3's birth protocol loads the capsules and prints v3's parity lines (step 4). |
| The node's prompt loop, and the code that strips ` ok` from its output | Goes at step 1. |
| `capsules/v4/forth79.4th`, `post79.4th`, `mkpost.py`, the rules | Stay. POST is the gate for every word moved out of the nucleus. |
| `(CATCH)`, `(EMIT-HOOK)`, `NODE-ERROR` by name | Stay; POST uses them. |
| `(CATCH)`, `(EMIT-HOOK)`, `NODE-ERROR` by name | `NODE-ERROR` stays. `(CATCH)` and `(EMIT-HOOK)` went with the POST capsule, `MESH.md` step 6b, 2026-10-07: POST is the kernel's and needs neither. |
| The per-call-target count (`v4/src/heat.c`, `call[]`) | Goes at step 3, when the node does at `call` what v3 does. |
| The hosted Linux product (`v4/tools/hosted.c`, `v4/system/boot.c`) | Stays, as its own product (3c). |
+18 -10
View File
@@ -753,15 +753,21 @@ Each is tested, committed and pushed before the next.
- *The boot* (`v4/system/boot.c`) runs it after the capsules, prints
`PARITY:V4_SYSTEM`, and seals. `capsules/v4/post79.4th`, `(CATCH)` and
`(EMIT-HOOK)` are gone.
- *First built* with what the cases define left in the dictionary
(`4bdb210a`; `logs/20261007-105118`, `-105335`, `-105651`).
- *Review, 2026-10-07*, by a fresh reviewer. It found that v3 does not
leave them (above, and `NUCLEUS.md` 6.3), and that a case the node did
not come back from would have stalled the boot for hours where the
capsule had ended it. Changed: the boot seals, runs POST, and has the
node do `COLD`; the runner ends POST at such a case and names it;
`hosted-check` boots a program whose POST has failing cases
(`v4/tests/post_cases_fail.c`) and requires `PARITY:FAIL`, `POST:
FAILED`, no prompt, and none of a case's printing on the console.
- *Verified.* `make -C v4 test`, `sanitize` and `hosted-check`; three
bare-metal boots, `logs/20261007-105118` (amd64), `-105335`
(aarch64), `-105651` (riscv64). On all six: POST 538 of 538,
`word_count=411`, `dict_hash=0x6fb1d09418b189ee`. At the prompt `T{`
is unknown, and `RS1`, which a case defines, prints `42 42` before and
after `COLD`. A hosted program built with one case's expected output
changed names the case and ends `PARITY:FAIL`, `POST: FAILED`.
- What the cases define takes 1,385 cells of the dictionary space's
5,632.
bare-metal boots, `logs/20261007-112638` (amd64), `-112901`
(aarch64), `-113220` (riscv64). On all six: POST 538 of 538,
`word_count=314`, `dict_hash=0x220ab283a504a3b3`. At the prompt `T{`
and `RS1` are unknown words, and `HERE` is 8300.
Acceptance, as approved:
1. *Same verdict.* The three hosted programs and the three bare-metal
@@ -771,8 +777,10 @@ Each is tested, committed and pushed before the next.
2. *Nothing of the harness is on the node.* At the prompt `T{` is an
unknown word, and `(CATCH)` and `(EMIT-HOOK)` are gone from the
nucleus.
3. *What the cases define is there.* A word a case defines can be used
at the prompt after boot, and survives `COLD`.
3. ~~What the cases define is there.~~ **Reversed 2026-10-07:** *POST
leaves nothing.* A word a case defines is unknown at the prompt
after boot. (The first form rested on a false statement about v3;
`NUCLEUS.md` 6.3.)
4. *The judge can fail.* Given a case with a wrong expected stack, one
with wrong expected output, one that must end in an error and does
not, and one that ends in an error and must not, the runner reports
+28 -10
View File
@@ -76,7 +76,7 @@ moved.
| File | Capsule name | Contents |
|---|---|---|
| `capsules/v4/forth79.4th` | `v4:forth79.4th` | The Required Word Set as colon definitions |
| `capsules/v4/post79.4th` | `v4:post79.4th` | The POST harness and its cases |
| ~~`capsules/v4/post79.4th`~~ | | Gone 2026-10-07: POST is the kernel's (6.3); its cases are `v4/system/post_cases.c` |
Both are ordinary `.4th` capsules: `Block N` headers, lines of at most 64
characters, at most 16 lines to a block. `tools/mkcapsule.c` bakes them into
@@ -168,8 +168,10 @@ for the record.
the interpreter, reads the VM's error flag, and puts the VM's stack
pointers, error and mode back (`test_common.c`, `run_single_test`). It
runs once at boot on the first VM, against block RAM of POST's own, and
the parity line is taken afterwards. Whatever the cases define stays in
the dictionary.
the parity line is taken afterwards. What the cases define does not stay:
`run_test_suite` saves the dictionary before each word's cases and puts it
back after them, "to remove test-created words" (`test_common.c:333`,
`:365`).
**v4.**
@@ -190,12 +192,28 @@ the dictionary.
ended in an error if any of its lines did.
- *What it prints.* For a failing case, `POST FAIL: name out<...>
stack<...>`. Then `PARITY:V4_POST tests=N pass=N fail=N`.
- *What is left.* What the cases define stays in the dictionary, as in
v3 (ruled 2026-10-07, on being told that the capsule had ended with
`FORGET` and left nothing). The system is sealed after POST, so `COLD`
comes back to those words and `FORGET` will not go below them. Measured
2026-10-07: they take about 1,290 cells of the 5,632 in the dictionary
space.
- *What is left: nothing*, as in v3. The system is sealed before POST,
and after the last case the kernel has the node do `COLD`, which comes
back to the system as sealed; what `COLD` prints is not shown. The
dictionary is put back once, after all the cases, and not after each
word's as v3 does: the expected results were taken from one v3 session
in which nothing was put back between cases (6.4), and the capsule did
the same with its one `FORGET` at the end.
**How this came to be ruled twice.** On 2026-10-07 Captain Bob was told
that v3 leaves the cases' definitions in the dictionary, and ruled "as
v3: they stay". That was false: it was read from `run_single_test`,
which puts back only the stacks, without reading `run_test_suite`. It
was built so, and the review of the step found it; shown what v3 does,
he ruled that POST leaves nothing.
- *A case the node does not come back from* — it has stopped, or runs for
ever — fails, and POST ends there: the runner names it and says how many
cases were not run.
- *What use still changes.* After POST and `COLD`, `HERE` and `LATEST` are
where they were, but the dictionary hash is not what it was before POST:
each word POST had interpreted has a different TTL in its entry, the
count of uses left before its access is checked again
(`v4/capsule/compile.v4`, `(ACL?)`). 138 cells, measured 2026-10-07. It
is the same on every system, so the six still agree.
- *Gone:* `capsules/v4/post79.4th` and its blocks 7000 up; the harness
words; `(CATCH)` and `(EMIT-HOOK)`, with what `EMIT` and the prompt
loop did for them.
@@ -332,7 +350,7 @@ check for the FPGA gateway and is not part of this acceptance.
| Hosted builds per ISA | `v4/Makefile` | Cross-compiler targets for aarch64 and riscv64 |
New: the shared v4 boot sequence (one file), the v4 dictionary hash, the
case-extraction script, `forth79.4th` and `post79.4th`.
case-extraction script, `forth79.4th` and `post79.4th` (the last gone since step 6b, 6.3).
The v3 boot is untouched: `STARFORTH_V4` defaults to off.