feat(v4.0.0): POST passes and is part of the boot; U* and U/MOD

The boot is now nucleus, forth79.4th, POST, prompt, on both products.

- forth79.4th: U* and U/MOD, the capsule's first colon definitions.  They
  are in the FORTH-79 Required Word Set and neither v3 nor v4 had them.
- post79.4th: 550 cases, 126 of the 130 required words.  443 are v3's with
  v3's result.  The rest follow three rulings (2026-10-05): address-
  dependent cases are checked for count, not value; where v3 departs from
  FORTH-79 the standard's result is expected; words v3 has no case for get
  cases written by hand.  v4/tools/post79_rules.py holds each exception
  with its reason and docs/v4.0.0/POST79.md lists them all.
- every case starts from an empty stack, DECIMAL and FORTH DEFINITIONS
- the boot requires POST's tally line with fail=0

Verified: tests=550 pass=550 fail=0 and identical PARITY lines on hosted
amd64, aarch64 and riscv64 (make -C v4 hosted-check) and on bare metal,
clean qemu with STARFORTH_V4=1, on the same three (logs/20261005-1619xx,
-1621xx, -1625xx).  A U/MOD broken on purpose fails five cases and stops
the boot.  make -C v4 test passes.

Not shown: all words but those two are still assembled, so POST has so far
tested the assembled words.  Nothing was typed at a bare-metal prompt.
Open: PAD 42 OVER ! faults on v4 (D-1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-05 16:28:01 -04:00
co-authored by Claude Opus 5.5
parent 5d6043e37e
commit 2930349bbf
13 changed files with 1331 additions and 416 deletions
+32 -37
View File
@@ -55,58 +55,53 @@ and fails unless their output is identical and ends in `PARITY:OK`.
A capsule line the node does not answer ` ok` to ends the boot, naming the
capsule, block and line, with `PARITY:FAIL` and `POST: FAILED`.
State, 2026-10-05, after the POST work began: all six builds load
`v4:forth79.4th` and reach `ok>` with the same lines:
State, 2026-10-05: all six builds start the nucleus, load `v4:forth79.4th`,
pass POST and reach `ok>`, with the same lines:
```
PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x1ec33b48cc76a0b5
PARITY:V4_POST tests=550 pass=550 fail=0
PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x671fdd7aebf0f8d8
PARITY:OK
POST: PASSED
ok>
```
Bare-metal logs: `logs/20261005-160144/amd64/`, `logs/20261005-160234/aarch64/`,
`logs/20261005-160400/riscv64/`. Each run was ended once the prompt was in the
Bare-metal logs: `logs/20261005-161924/amd64/`, `logs/20261005-162142/aarch64/`,
`logs/20261005-162524/riscv64/`. Each run was ended once the prompt was in the
log; nothing was typed at a bare-metal prompt, so keyboard input there is not
yet verified. The capsules were unsigned (no signing key on this machine).
`forth79.4th` holds no definitions yet: every word is still in the nucleus.
**What this does not yet show.** `forth79.4th` holds two definitions, `U*`
and `U/MOD`. Every other word is still in the assembled nucleus, so POST is
so far a test of the assembled words. Moving them to the capsule, a group at
a time with POST after each, is the next step (`NUCLEUS.md` section 8).
## POST
`capsules/v4/post79.4th` is v3's POST cases for the FORTH-79 Required Word
Set, written by `v4/tools/mkpost.py` (`make -C v4 post79`): 537 cases in
blocks 7000–7112, covering 111 of the 130 required words. Each case carries
what the hosted v3 binary did with the same line — error or not, the stack,
the length and checksum of what was printed — and v4 must do the same.
`capsules/v4/post79.4th`: 550 cases in blocks 7000 up, covering 126 of the
130 words of the FORTH-79 Required Word Set. 443 are v3's cases with what
the hosted v3 binary did as the expected result. The other 107, and the 27
v3 cases left out, are listed with reasons in `docs/v4.0.0/POST79.md`.
**POST does not pass yet, so it is not in the boot.** `make -C v4 post` builds
the amd64 system with it (`-DV4_POST_AT_BOOT=1`) and boots it:
- `make -C v4 post` boots the amd64 system: the quick check after a change.
- `make -C v4 hosted-check` boots all three hosted ISAs and compares them.
- `make -C v4 post79` writes the capsule again (`tools/mkpost.py`,
`tools/post79_rules.py`); it needs the hosted v3 binary.
```
PARITY:V4_POST tests=537 pass=439 fail=98
PARITY:FAIL
POST: FAILED
```
POST is FORTH: a harness of FORTH-79 words and two nucleus hooks, `(CATCH)`
and `(EMIT-HOOK)`. It forgets itself when it has finished. The boot passes
only on seeing POST's tally line with `fail=0` (`v4/system/boot.c`). A colon
definition broken on purpose (`U/MOD` without its last `SWAP`) fails five
cases and the boot stops with `POST: FAILED`.
The 98 are not yet sorted into v4 defects and differences that need a
ruling. A first reading finds four kinds:
Not tested: `KEY`, `EXPECT`, `QUERY` (the keyboard) and `QUIT` (it returns
without ` ok`).
| Kind | About | Examples |
|---|---|---|
| The case prints or leaves a memory address, which differs between the two machines | 40 | `HERE`, `PAD`, `1 BLOCK`, `BL WORD`, `CONTEXT @ .`, `FIND` |
| v3 departs from FORTH-79 and v4 follows the standard | 35 | `PICK` and `ROLL` count from 1; `<# # #S #>` take a double number; `LEAVE` ends the loop at the next `LOOP`; `>R` `R>` only inside a definition |
| The case assumes v3's byte address units, where a v4 address unit is a cell (D-1) | 8 | `42 , HERE 8 - @`, `PAD 42 OVER !` |
| Not yet understood | 15 | vocabulary cases, `LIST`'s layout, `16 BASE ! 255 .`, `321 EMIT`, cases v3 ends in an error and v4 does not |
Open: `PAD 42 OVER !` faults on v4, because `PAD` is a byte address and `!`
takes a cell address (D-1). FORTH-79 expects it to work. The v3 case for it
is left out until that is ruled.
Required words with no v3 case, and so no POST case: `U*` `U/MOD` `?`
`EXECUTE` `KEY` `EXPECT` `QUERY` `U.` `CONVERT` `'` `."` `LITERAL` `STATE`
`COMPILE` `[COMPILE]` `(` `QUIT` `BLK` `79-STANDARD`. `U*` and `U/MOD` are
in neither v3 nor v4.
Twelve v3 cases are left out: three read the keyboard, two forget a word of
the system, two store to the search order, and five leave v3 unable to
continue in one session (`mkpost.py` prints the list).
The boot passes POST only on seeing the tally line with `fail=0`
(`v4/system/boot.c`); that no line was refused is not enough.
The Required Word Set list in `tools/mkpost.py` was written from memory of
the standard and has not been checked against the document.