Captain Bob, 2026-10-05: v4 = v3 functionally; heat accumulates on the 32 opcodes; the opcode replaces the word as the smallest unit. Answers D-6 and the three conflicts of V3-PARITY.md 2.4. Records what follows (the per-call-target array goes; pipelining and the hot-words cache are not retired; decomposition no longer waits) and what is still open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
253 lines
13 KiB
Markdown
253 lines
13 KiB
Markdown
# StarForth v4.0.0 — Parity with v3 up to the first prompt
|
||
|
||
Started 2026-10-05. This file measures v4 against one ruling:
|
||
|
||
> v4 is exactly like v3 in functional requirements up to the first FORTH
|
||
> prompt. That is the stopping point for now. (Captain Bob, 2026-10-05)
|
||
|
||
and a second, given the same day:
|
||
|
||
> I would never stub, simulate or develop outside of functional,
|
||
> as-intended code. Piecemeal is how errors and intent get hidden.
|
||
|
||
It records what v3 does, where in v3's code, what v4 does today, and what
|
||
has to be ruled before v4 can do the same. It proposes; it decides nothing.
|
||
Nothing described here as missing has been built.
|
||
|
||
## 1. What v3 does before its first prompt
|
||
|
||
From the bare-metal boot log `logs/20261003-100613/amd64/`, in order, after
|
||
the kernel's M0–M6 hardware milestones:
|
||
|
||
| # | v3 | v4 today |
|
||
|---|---|---|
|
||
| 1 | Stadium allocated (cells, 50 VM slots); switch-signal and kernel-Hermes channel tables | Missing |
|
||
| 2 | VM arena; 530 words registered | One node; 295 assembled words and 2 from the capsule |
|
||
| 3 | Physics live whenever a word executes: per-word heat, decay, rolling window, pipelining, L8 mode selector (61 mode changes during POST), heartbeat | Missing; see section 2 |
|
||
| 4 | POST: 1050 tests, every module (FORTH-79, StarForth extensions, ACL, Mama, Q48, inference, physics freeze) | 550 cases, FORTH-79 Required Word Set only |
|
||
| 5 | `PARITY:M7.1a` word count, here, latest, dictionary hash; `PARITY:OK`; `POST: PASSED` | Present, as `PARITY:V4_*` |
|
||
| 6 | PCI; virtio-blk attached; Artemis genesis signature | Missing. Blocks are a RAM array |
|
||
| 7 | Mama init capsule `init.4th`: signature checked, executed, `PARITY:MAMA_INIT` | v4 loads its own two capsules the same way; not `init.4th` |
|
||
| 8 | ACL: `BIRTH` and `CAPSULE-BIRTH` pinned strict | Missing. The ACL words are assembled but not loaded |
|
||
| 9 | Heartbeat running; Stadium conservation checks; quota and kernel-Hermes self-tests | Missing |
|
||
| 10 | Hestia born, then Artemis (disk formatted, self-test, K figures), each with `PARITY:BIRTH` | Missing. One node, no fleet |
|
||
| 11 | Kernel-Hermes fleet self-tests; USB mass storage; Zuse genesis minted on the thumbdrive | Missing |
|
||
| 12 | Banner with versions; `[zuse@Hera] ok>` | `ok>` alone |
|
||
|
||
Rows 1, 6, 9, 10 and 11 are messaging, blocks and the console's wider
|
||
setting. They are to be discussed before anything is written about them.
|
||
Section 2 is row 3.
|
||
|
||
## 2. Row 3: physics and per-word heat
|
||
|
||
### 2.1 What v3 does
|
||
|
||
**For every word a definition executes** — the inner loop,
|
||
`kernel/src/vm/vm_core.c:757-880`, and the same on the interpreter's path at
|
||
`:1053-1110`:
|
||
|
||
1. **Decay (Loop #3).** The word's heat is reduced by the ticks since it was
|
||
last touched times the decay slope, in Q48.16
|
||
(`physics_metadata_apply_linear_decay`, `v3/src/physics_metadata.c`). Not
|
||
for a frozen word, and not while L8 has gated Loop #3 off.
|
||
2. **Heat (Loop #1).** The word's `execution_heat` is raised by one.
|
||
3. **Stadium.** The word's ID, the VM's ID and the tick go to the Stadium's
|
||
conserved heat wire (`stadium_word_dispatch`).
|
||
4. **Rolling window (Loop #2).** The word's ID is recorded
|
||
(`rolling_window_record_execution`).
|
||
5. **Pipelining (Loop #4).** The transition from the previous word is
|
||
recorded, the most likely next word is worked out, and a likely one is
|
||
promoted to the hot-words cache.
|
||
6. **ACL.** The word's TTL is counted down, or the word rechecked at zero; a
|
||
denied word stops the definition.
|
||
7. The word runs. Then its physics record is touched (temperature, time) and
|
||
the heartbeat's count of words executed is raised.
|
||
|
||
**On every heartbeat tick** — `kernel/src/vm/vm_runtime.c`, driven by the
|
||
timer interrupt: `vm_tick`; the window tuner (Loop #5, `:158`); the slope
|
||
validator (Loop #6, `:228`); background decay (`:355`); the L8 mode update
|
||
(`:400`), which turns loops on and off; the inference engine (`:579`); and a
|
||
published snapshot.
|
||
|
||
**What each word carries** — `DictEntry`, `v3/include/vm.h:342-358`:
|
||
`execution_heat`; a `DictPhysics` record (temperature, last decay tick, mass,
|
||
state flags); a pointer to its transition metrics; a stable `word_id`; the
|
||
four ACL fields; and the `WORD_FROZEN` and `WORD_PINNED` flags.
|
||
|
||
All of this is running before the first prompt. POST itself executes under
|
||
it.
|
||
|
||
### 2.2 What v4 has
|
||
|
||
- A v4 word is native code. Executing one is the `call` opcode going to its
|
||
address. There is no inner loop, so there is no place in software where
|
||
v3's seven steps could happen.
|
||
- Short words are not called at all. `DUP`, `+`, `@`, `>R` and about fifty
|
||
others are compiled in line as opcodes (`header DUP inline`,
|
||
`v4/capsule/forth.v4`). At run time nothing says "this was `DUP`".
|
||
- The engine counts three things as instructions retire (`v4/src/exec.c`):
|
||
each opcode's count (32 counters), the anti-clock, and a count for each
|
||
call target.
|
||
- **The call-target count is a stand-in, by its own account.** It is a C
|
||
array beside the node, 4096 entries, written 2026-10-02
|
||
(`v4/src/heat.c`). A call to an address of 4096 or above is silently not
|
||
counted. The nucleus runs to about word 6300 and capsule definitions start
|
||
at 8192, so some assembled words and every capsule word get nothing. No
|
||
FORTH word can read it: `ACL-HEAT@` returns 0 (`v4/capsule/acl.v4:80`).
|
||
- A dictionary entry is three cells before the code — flags, name, link
|
||
(`v4/capsule/dict.v4`). It has no heat, no physics record, no word ID.
|
||
- There is no decay, rolling window, pipelining, inference, L8, heartbeat
|
||
or Stadium wire on the node.
|
||
|
||
### 2.3 What the v4 design documents say
|
||
|
||
The documents ruled on 2026-10-01 do not say "as v3". They say:
|
||
|
||
- `JUSTIFICATION.md` section 4, item 4: "Compudynamics as a side effect of
|
||
execution. Heat counters, the anti-clock, and the heartbeat are driven by
|
||
instruction retirement in hardware. They cost no instructions."
|
||
- `DECOMPOSITION.md` section 1.4: "every `call` increments the heat counter
|
||
of its target".
|
||
- `DECOMPOSITION.md` section 7: registers `HEAT-OP[0..31]`,
|
||
`HEAT-CALL[...]`, `ANTICLOCK`, `HEARTBEAT`, `GOV-*`.
|
||
- `DECOMPOSITION.md` sections 5.19 and 5.23 use the words "heat table" for
|
||
`HEAT-CALL` (`ENTROPY@`, `FREEZE-WORD`).
|
||
- D-6, **deferred**: "Which heat structures exist in hardware: per-opcode
|
||
counters only, or also per-call-target and word-to-word transition
|
||
counters. … The golden model implements per-opcode and per-call-target
|
||
heat in the meantime."
|
||
- Section 5.22: the six `PIPELINING-*` words are retired, to return "if D-6
|
||
adds transition counters". Section 5.21: the hot-words cache words are
|
||
retired as having no equivalent on a node.
|
||
|
||
So the 4096-entry array is the "in the meantime" of D-6, and "heat table"
|
||
is these documents' own term.
|
||
|
||
### 2.4 The conflict
|
||
|
||
Today's ruling and those documents do not say the same thing, in three
|
||
places. Each needs a ruling; none is mine to settle.
|
||
|
||
**A. Where a word's heat is kept.** v3: in the word's own dictionary entry.
|
||
The documents: in the node, as a register indexed by call target.
|
||
|
||
**B. What counts as a word.** v3 counts every execution of `DUP` as
|
||
`DUP`'s. v4 compiles `DUP` in line; what is counted is the `dup` opcode,
|
||
and a word built of several opcodes in line (`2DUP` is `over over`) leaves
|
||
no count of its own. v3's per-word heat for these words cannot be had from
|
||
a v4 node as it compiles now.
|
||
|
||
**C. Which loops exist.** v3 runs all seven and L8 before the prompt. The
|
||
documents retire Loop #4 (pipelining) and the hot-words cache, and leave
|
||
the rest to registers whose behaviour is not written down beyond their
|
||
names.
|
||
|
||
### 2.5 What each answer would take
|
||
|
||
Offered so that the ruling can be made knowing its cost. Not a plan.
|
||
|
||
**If heat is kept as v3 keeps it (A, v3's way).** Each entry gains cells
|
||
before its code, beside flags, name and link: heat, last-decay tick, word
|
||
ID, and what of `DictPhysics` is kept. `dict.v4`'s entry words, the header
|
||
macro of the text assembler and every assembled `header` line account for
|
||
them. The node, on `call`, finds the entry from the target address and does
|
||
steps 1 to 5 of section 2.1. Heat is then ordinary memory: `HEAT@` is a
|
||
fetch, and it is inside the dictionary, so the dictionary hash either
|
||
covers it or is defined to skip it, as v3's canonical hash skips it.
|
||
|
||
**If heat is kept as the documents have it (A, the node's way).** The
|
||
call-target counts become part of the node, cover every address of it, and
|
||
are readable through `HEAT-CALL` as a memory-mapped register, which needs
|
||
D-4, the memory map, settled. This is not "as v3" in where heat lives; it
|
||
is in what is counted.
|
||
|
||
**B either way.** Three ways, and they are not equivalent:
|
||
|
||
1. In-line words are counted by opcode: `DUP`'s heat is `HEAT-OP[dup]`.
|
||
Words that are more than one opcode in line have no heat. Not as v3.
|
||
2. Nothing is compiled in line except what must be (`>R`, `R>`, `R@`, `I`,
|
||
`J`, `LEAVE`: a call would bury the return address). Every other word is
|
||
called and so counted. As v3 for those words; slower, and the six that
|
||
must stay in line are still uncounted.
|
||
3. The compiler lays down a marker the node counts and does not execute.
|
||
That is a new opcode or a new use of one, which is a change to the
|
||
instruction set.
|
||
|
||
**C.** For each of Loops #2 to #7 and L8: where its state lives, what
|
||
advances it, and what the heartbeat is on a node that has no timer of its
|
||
own (v3's is the kernel's timer interrupt; the documents' is "in the
|
||
fabric"). v3's code for each is the reference: `rolling_window_of_truth.c`,
|
||
`physics_pipelining_metrics.c`, `inference_engine.c`, `ssm_jacquard.c`,
|
||
`vm_runtime.c`.
|
||
|
||
### 2.6 What depends on this
|
||
|
||
- **Decomposition.** Moving a word from assembler to a colon definition
|
||
does not change how it is called, but it turns in-line opcodes into
|
||
calls, which changes what is counted under every answer to B. It should
|
||
wait for B.
|
||
- **ACL.** v3's TTL comes from heat (`ACL-TTL-COMPUTE`). With `ACL-HEAT@`
|
||
returning 0 every word has the same TTL. Row 8 waits for A.
|
||
- **POST's other 500 cases** (row 4) include the physics-freeze and
|
||
inference modules, which test words that read and write heat.
|
||
- **K.** Nothing computes K on v4. It is a figure over heat; it waits for A
|
||
and C.
|
||
|
||
### 2.7 Ruling (Captain Bob, 2026-10-05)
|
||
|
||
> One more time: v4 = v3 functionally. We will use [heat accumulation] on
|
||
> 32 opcodes rather than words. Before, a word was our smallest unit; now
|
||
> it is the opcode.
|
||
|
||
This settles section 2.4:
|
||
|
||
- **A.** Heat is kept per opcode: 32 accumulators in the node. Not in a
|
||
word's dictionary entry, and not per call target.
|
||
- **B.** The unit is the opcode. Whether a word is called or compiled in
|
||
line makes no difference to what is counted. `call` is one of the 32 and
|
||
is counted as itself.
|
||
- **C.** v4 = v3 functionally, so every loop v3 runs before its prompt
|
||
runs on v4, over opcodes where v3's runs over words.
|
||
|
||
What follows from it, and is not yet done:
|
||
|
||
- The per-call-target array (`v4/src/heat.c`, `call[]`, the freeze mask,
|
||
`v4_heat_on_call`) has no place and is to be removed, with `HEAT-CALL`
|
||
in `DECOMPOSITION.md` sections 1.4, 5.19, 5.23 and 7. D-6 is answered:
|
||
per-opcode.
|
||
- Sections 5.21 and 5.22 of `DECOMPOSITION.md` retire pipelining and the
|
||
hot-words cache. Under C they are not retired.
|
||
- Decomposition no longer waits on this: moving a word from assembler to a
|
||
colon definition changes which opcodes run, and those are counted
|
||
wherever the code is.
|
||
|
||
Still open, for the words v3 keys by word and v4 must key by something:
|
||
|
||
- **ACL.** Access control is per word, and v3 works a word's TTL out from
|
||
that word's heat (`ACL-TTL-COMPUTE`). A v4 word has no heat of its own.
|
||
- **Freeze and pin.** v3 freezes or pins a word's heat (`FREEZE-WORD`,
|
||
`WORD_PINNED`). In v4 what is frozen is an opcode, or nothing.
|
||
- **Hot-words cache.** v3 promotes a hot word so that it is found faster.
|
||
A v4 opcode is not looked up.
|
||
- **Heartbeat.** What ticks it on a node (v3: the kernel's timer
|
||
interrupt).
|
||
|
||
## 3. Stand-ins in v4, as found 2026-10-05
|
||
|
||
Each describes itself as one. None has been changed.
|
||
|
||
| What | Where | Says of itself |
|
||
|---|---|---|
|
||
| Per-call-target heat | `v4/src/heat.c`, `v4/include/v4/heat.h` | "in the meantime" (D-6) |
|
||
| `ACL-HEAT@` | `v4/capsule/acl.v4:80` | returns 0; "not readable from a programme yet" |
|
||
| Console | `v4/include/v4/node.h:136`, `:156` | "the model stands in for the console" until the mesh exists |
|
||
| Block storage | `v4/include/v4/node.h:248`, D-19 | "the model stands in" until the mesh carries the storage service |
|
||
| Memory map | `v4/tests/host_map.h`, D-4 deferred | a test header the product image is built from |
|
||
| CA public key | `v4/capsule/ACL.fth:40` | "placeholders, as in v3" |
|
||
| Address-dependent POST cases | `v4/tools/post79_rules.py`, `ADDRESS` | check how many values are left, not which |
|
||
|
||
`NUCLEUS.md` section 3 puts Q48, logging, ACL and the StarForth extensions
|
||
out of scope until FORTH-79 is accepted. Under the ruling at the head of
|
||
this file they are in scope, since v3 has them before its prompt. That
|
||
section is to be corrected once the rows above are ruled.
|