Stage G: SEND, and two workers interleave; decision compares work heat (FABRIC-3.8 §3.8, §3.13.7)

SEND ( paddr plen name-c name-u -- ok? ): general kernel-Hermes send to a
named VM, from = calling VM, one block max (refused, not truncated), every
VM. New SK_HERMES_MSG_TYPE_SEND (30).

Ruling C-4 (beta), Captain Bob: the switch decision compares work heat --
the heat each VM pulled in by its own per-beat charges -- not absolute
heat, so Hera's structural endowment no longer makes her hottest. Before
it, the two-worker test ran serial (AAAA...BBBB); after it, byte-identical
on amd64/aarch64/riscv64:
AAABBBBBBBBAAAAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAABB
(40 A, 40 B, 16 runs; ordinary words only, nothing yields). Acceptance:
relay 3, idle growth 0; dict_hash set changed by the new word
(word_count 533) and identical across ISAs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-23 21:01:44 -04:00
co-authored by Claude Opus 5.5
parent c7185facf0
commit 81def7b4a5
18 changed files with 46044 additions and 7 deletions
+125 -2
View File
@@ -666,6 +666,55 @@ without §3.7's idle point** (Stage F):
the idle point she is eligible when input is pending (the REPL's own input poll), exactly as a
worker is eligible when its kernel-Hermes queue is non-empty. **Ruling C-5**, below.
#### 3.13.7 Finding at Stage G: under C-4 (α), a sender can't dispatch a batch (2026-09-23)
`SEND` is built (§3.8). The naive interleave test, typed at `[zuse@Hera] ok>` with ordinary
words only (`logs/20260923-201602/amd64/`):
```
S" workload-1-lite.4th" S" wa" WORKER-BIRTH . → 1
S" workload-1-lite.4th" S" wb" WORKER-BIRTH . → 1
S" : LA 40 0 DO 65 EMIT 300 0 DO LOOP LOOP ; LA" S" wa" SEND . S" : LB 40 0 DO 66 EMIT 300 0 DO LOOP LOOP ; LB" S" wb" SEND .
→ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB1 ok
```
`SEND` works: each payload is delivered by a switch and runs on the worker's own stack. But the
run is **serial**, and the mechanism is exactly C-4 (α):
- The first `SEND` makes `wa` eligible at heat 0.
- Hera (heat ≈ `Q48_ONE`) is displaced at her next owned checkpoint, before she even prints that
`SEND`'s `1`.
- She is eligible only as "parked mid-task" and is the hottest VM, so she gets the CPU back only
once `wa` has no work left. Then she sends to `wb`.
The rebuilt DoE driver (Stage H) would serialize the same way: it is Hera sending to N workers in
a loop. So would the console under load (already recorded under C-b).
**Needs Captain Bob's ruling (C-4 reopened):**
- **(β) compare work heat, not absolute heat.** Work heat is each VM's cumulative heat pulled in
by its own per-beat charges (Stage C-a). It is conserved-transfer bookkeeping already happening,
so no new physics, but it is a different quantity than the one "coolest" has meant so far.
Hera's structural endowment doesn't count.
- Predicted: Hera keeps the CPU while she has work, because on a tie the incumbent stays and the
workers' heat is still 0. She sends both messages, and the workers then alternate by work
heat.
- Hera with pending console input is cooler than busy workers, so the console gets turns under
load.
- **(δ) mail arrival stops triggering a decision for the running sender.** Decisions happen only
at beats, the trampoline and idle points.
- Batches sent within one beat all land before anyone runs.
- Where the beat boundary falls decides whether a given batch lands intact. It's deterministic,
not guaranteed.
- It doesn't address the console starvation.
- **(ε) keep (α)** and prove interleaving with a chain instead: worker A's payload `SEND`s B's.
That satisfies Stage G's evidence, but leaves the DoE driver and the console serialized.
**RULED 2026-09-23, Captain Bob: (β) work heat.** The decision compares
`vm_physics_work_heat_of()`, not `vm_physics_heat_of()`. Absolute heat still moves, is still
conserved, and still appears in the DoE heat columns; it just no longer decides turns. The
prediction held on all three ISAs: see the Stage G entry in §6.
#### 3.13.6 Stage C, split
This splits the single C row in §4 in two:
@@ -715,7 +764,7 @@ QMP `send-key` computing a value, per `FABRIC-3.6.md` task 1.5).
phase is the concurrent one). If the latter: new `-def` capsule variants, or strip the tail
call from the existing `workload-N.4th` files (check their other users first, per `FABRIC-3.5.md`
§XXII.2's three reachability routes)?
3. **The send word's name** (§3.8): `SEND`, `HERMES-SEND`, `KH-SEND`, something else.
3. **The send word's name** (§3.8) — **RULED 2026-09-23: `SEND`.**
4. **The multiuser factor.** The DoE as built varies concurrency × workload mode and runs once
per ISA. `FABRIC-3.md` §XXXIII.2 planned identity origin as a fixed arm, never built. Should
identities (`UNATTENDED-BIRTH` capsule identities, or WIREBIND thumbdrives) become a crossed
@@ -733,7 +782,8 @@ QMP `send-key` computing a value, per `FABRIC-3.6.md` task 1.5).
8. **C-3 (§3.13.3):** ties. The incumbent stays on a tie with itself. Among several candidates:
whether "waiting longest," by a single-writer arrival stamp, is acceptable under *"no scheduler
allowed,"* or whether Bob wants something else. Slot, UUID and registry order are rejected.
9. **C-4 (§3.13.2):** Hera's reservoir mass means the console gets no turn under worker load.
9. **C-4 (§3.13.2) — RULED 2026-09-23: (β) work heat** (§3.13.7; first taken as (α) at C-b,
reopened at Stage G). Hera's reservoir mass means the console gets no turn under worker load.
Options are (α) accept it, (β) compare charged heat instead of absolute heat, or (γ) something
else. No recommendation.
10. **C-5 (§3.13.5):** fold the idle point (Stage F's §3.7) into C-b, since the relay can't be
@@ -1103,3 +1153,76 @@ explicit instruction.
**What this makes possible (not exercised yet):** every `WORKER-BIRTH`ed DoE worker is now
a participant. Mail sent to a worker is delivered by a switch onto its own stack, and it
competes by heat. Stage G's `SEND` word and interleave test are next.
- [x] **Stage G — `SEND`, and two workers interleave (§3.8, §3.13.7).** 2026-09-23. Captain
Bob: *"SEND, go ahead with stage G"*, then ruling C-4 (β), work heat, when the first run
came out serial.
Changes:
- `repl.c`: new `SEND ( paddr plen name-c name-u -- ok? )`, registered for every VM
through the standard word set (`sk_repl_register_words`).
- It resolves the target by registry name, copies the payload (at most 1023 chars plus
the NUL; oversized payloads are **refused, not truncated**), and calls
`sk_hermes_send_one()`. That stamps the message and sets decision-due (C-b).
- `from` is the calling VM, derived in C, never taken from the stack.
- It returns 1 if admitted, 0 if refused.
- No C-side restriction; ACL is `ACL.4th`'s job.
- `kernel_hermes.h`: new `SK_HERMES_MSG_TYPE_SEND` (30), clear of every older type space.
- **C-4 (β):**
- `capsule_vm_physics.c/.h`: a per-VM `work_heat_q48` accumulates what each of the VM's
own per-beat charges actually moved in. Read with `vm_physics_work_heat_of()`.
- `sk_vm_switch_decide()` compares work heat for candidates and for the incumbent.
**First run, before (β):** `logs/20260923-201602/amd64/`, the §3.13.7 finding. It came
out `AAAA…A1 BBBB…B1`, serial.
**Evidence, as named in §4.** Only ordinary words, typed at `[zuse@Hera] ok>`, no probe:
```
S" workload-1-lite.4th" S" wa" WORKER-BIRTH .
S" workload-1-lite.4th" S" wb" WORKER-BIRTH .
S" : LA 40 0 DO 65 EMIT 300 0 DO LOOP LOOP ; LA" S" wa" SEND . S" : LB 40 0 DO 66 EMIT 300 0 DO LOOP LOOP ; LB" S" wb" SEND .
```
Result, **byte-identical on all three ISAs** (`logs/20260923-202403/amd64/`,
`-204054/aarch64/`, `-205150/riscv64/`):
```
[zuse@Hera] 1 1 ok
[zuse@Hera] ok> AAABBBBBBBBAAAAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAAABBBBBAAAABB
```
- **A = 40, B = 40, in 16 alternating runs.**
- Hera kept the CPU while she had work (work heat tied at ~0, so the incumbent stays), and
both sends landed.
- From her idle point, `wa` and `wb` took turns. Each switch came from the per-beat charge
making the runner strictly hotter by work heat.
- Nothing in either payload asks to yield.
- The sequence is deterministic across ISAs, as the execution-paced beat implies.
**Acceptance,** in the same three boots, after the interleave test with both workers still
alive:
- All reach `[zuse@Hera] ok>` with zero `UNKNOWN WORD`, failures and faults.
- Mint → WIREBIND → `USE` → `1 2 + .` → `3`, with `stadium_conserved(self)=true`.
- Idle log growth: 0 bytes.
- **The `dict_hash` set changes, as expected, because `SEND` is a new word in every VM's
dictionary, and is identical across all three ISAs.**
| | New | Stages A–E |
|---|---|---|
| `word_count` | 533 | 532 |
| M7.1a | `0x330b28ce0f4e1c75` | `0x3933d76939ef66c6` |
| Hera | `0x0bf15066a73f6e32` | `0x27ba08011349842b` |
| Hestia | `0x9116e19b34d2cb0b` | `0xdd1aa879b3a6c5df` |
| Artemis | `0x165a9a66eafce131` | `0xe9d0408b1119d51f` |
- Clean build on all three plus hosted, no new warnings.
**Harness note (not a kernel change):** the first aarch64 attempt
(`logs/20260923-203226/aarch64/`, kept) typed the next line while Hera was still birthing
`wa`. Serial input received while Hera isn't polling is dropped, so the line arrived
truncated (`S" workload-1-li…`) and gave `UNKNOWN WORD`. My test script now waits for each
prompt before typing. Serial input is lost while the console isn't reading, which is the
pre-existing behaviour.
**Consequences of (β) to know:**
- Work heat only grows. A long-lived VM that has done a lot of work loses ties to newer
ones until they catch up.
- Hera's work heat grows only when other VMs hold absolute heat for her charges to pull
from. She runs cheaply while they hold ~0.
- Both are properties of the ruled quantity, recorded here, not changed.