Files
LithosAnanake/logs/hermes-tripod-integration-design.md

236 lines
7.3 KiB
Markdown

# Hermes Tripod Integration Test — Executive Summary
**Date:** 2026-06-27
**Author:** Claude Code / Captain Bob (Robert Allan James)
**Branch:** `lithosananke`
**Status:** Design — not yet implemented
---
## What This Addresses
The Hermes smoke test confirms the messaging substrate in isolation. What it does
not exercise is the inter-VM dispatch path: `MSG-DELIVER → VM-EXEC → recipient handler`.
In the hosted build `VM-EXEC` is a no-op stub (`2DROP 2DROP`). This design replaces
that stub for the duration of the test with a working dispatcher, then drives all six
directional message paths through the Tripod and confirms each one with a stdout line.
No logs are kept. No persistent state changes. The test script patches `init.4th`,
runs, and restores — same pattern as `tools/hermes_smoke.sh`.
---
## Architectural Basis
From `TRIPOD.md` — dispatch is **capability-based**, never heat-based:
| Work type | Correct recipient |
|-----------------|-------------------|
| VM lifecycle | Hera |
| Event emit/drain| Hermes |
| Block I/O | Artemis |
`VM-EXEC` signature (from `MSG-DELIVER`, block 4107):
```
( paddr plen name-addr name-len -- )
```
`IDX>NAME` maps VM index → string:
- `0``"Hera"` (len 4)
- `1``"Hermes"` (len 6)
- `2``"Artemis"` (len 7)
All three names have unique lengths. The hosted test dispatcher uses name length as
its discriminator — no `COMPARE` word is needed.
---
## The Six Message Paths
| # | Sender | Recipient | Type | Rationale (capability-based) |
|---|---------|-----------|---------------|----------------------------------------|
| 1 | Hera | Hermes | SPAWN-EVENT | Hera notifies Hermes: child was spawned |
| 2 | Hera | Artemis | 10 (arbitrary)| Hera requests persistence of boot record|
| 3 | Hermes | Hera | SPAWN-EVENT | Hermes confirms delivery back to Hera |
| 4 | Hermes | Artemis | 11 (arbitrary)| Hermes stores message log to Artemis |
| 5 | Artemis | Hera | 12 (arbitrary)| Artemis ACKs Hera boot record stored |
| 6 | Artemis | Hermes | 13 (arbitrary)| Artemis asks Hermes to route a result |
After all six sends, `HERMES-TICK` runs once. All six messages cool one step
(heat: Q.1 → Q-DECAY). Then `0 FILL` heat on each and a second `HERMES-TICK`
reaps them. Final check: `MSG-ARENA MSG-TYPE@` must be 0 (arena clean).
---
## Exemplar: VM-EXEC Dispatcher Shim
This block replaces the no-op `VM-EXEC` for the duration of the test.
Name-length dispatch: 4=Hera, 6=Hermes, 7=Artemis.
```forth
( test VM-EXEC dispatcher — hosted only )
: VM-EXEC ( paddr plen name-addr name-len -- )
>R >R 2DROP R> R> ( drop payload, keep name )
DUP 4 = IF DROP ." [Hera recv]" CR EXIT THEN
DUP 6 = IF DROP ." [Hermes recv]" CR EXIT THEN
DROP ." [Artemis recv]" CR ;
```
Stack trace for the `4 =` branch:
- Entry: `( name-addr name-len )`
- `DUP 4 =``( name-addr name-len flag )`
- `IF DROP``( name-addr )` — then `." ..."` and `EXIT`, name-addr is dead on stack
Wait — name-addr leaks. The handler must also drop it:
```forth
: VM-EXEC ( paddr plen name-addr name-len -- )
>R >R 2DROP R> R>
DUP 4 = IF 2DROP ." [Hera recv]" CR EXIT THEN
DUP 6 = IF 2DROP ." [Hermes recv]" CR EXIT THEN
2DROP ." [Artemis recv]" CR ;
```
`2DROP` consumes `( name-addr name-len )` after `DUP` copies len for the test.
Actually with `DUP 4 = IF`:
```
( name-addr name-len )
DUP → ( name-addr name-len name-len )
4 = → ( name-addr name-len flag )
IF → ( name-addr name-len ) ← both still on stack inside IF
2DROP ( -- )
." [Hera recv]" CR EXIT
```
That is correct. Remainder branch falls through with `( name-addr name-len )` still
on stack after the failed IF, so `2DROP` at the end of each branch is correct.
---
## Exemplar: Six-Path Test Sequence
```forth
( Hermes Tripod Integration Test )
CD-INIT
." >>> Tripod integration test" CR
( Path 1: Hera → Hermes )
." >>> [1] Hera->Hermes SPAWN-EVENT" CR
SPAWN-EVENT 0 1 S" boot" MSG-SEND
( Path 2: Hera → Artemis )
." >>> [2] Hera->Artemis store request" CR
10 0 2 S" boot-rec" MSG-SEND
( Path 3: Hermes → Hera )
." >>> [3] Hermes->Hera delivery confirm" CR
SPAWN-EVENT 1 0 S" ok" MSG-SEND
( Path 4: Hermes → Artemis )
." >>> [4] Hermes->Artemis log store" CR
11 1 2 S" msglog" MSG-SEND
( Path 5: Artemis → Hera )
." >>> [5] Artemis->Hera ACK" CR
12 2 0 S" stored" MSG-SEND
( Path 6: Artemis → Hermes )
." >>> [6] Artemis->Hermes route result" CR
13 2 1 S" result" MSG-SEND
." >>> HERMES-TICK (cool all 6)" CR
HERMES-TICK
." >>> HERMES-TICK ok" CR
( Zero heat on all 6 and reap )
MSG-ARENA MSG-SCAN !
6 0 DO
0 MSG-SCAN @ MSG-HEAT!
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP
MSG-REAP
." >>> MSG-ARENA clean (expect 0): " MSG-ARENA MSG-TYPE@ . CR
." >>> === Tripod integration complete ===" CR
BYE
```
`MSG-SEND` calls `MSG-DELIVER` which calls `VM-EXEC`. With the test shim in place,
each send prints `[Hera recv]`, `[Hermes recv]`, or `[Artemis recv]` to stdout
immediately at send time — no async; hosted FORTH is synchronous.
---
## Expected Output
```
>>> Tripod integration test
>>> [1] Hera->Hermes SPAWN-EVENT
[Hermes recv]
>>> [2] Hera->Artemis store request
[Artemis recv]
>>> [3] Hermes->Hera delivery confirm
[Hera recv]
>>> [4] Hermes->Artemis log store
[Artemis recv]
>>> [5] Artemis->Hera ACK
[Hera recv]
>>> [6] Artemis->Hermes route result
[Hermes recv]
>>> HERMES-TICK (cool all 6)
>>> HERMES-TICK ok
>>> MSG-ARENA clean (expect 0): 0
>>> === Tripod integration complete ===
```
The test script greps for `>>>` lines to confirm the sequence completed.
The `[VM recv]` lines confirm dispatch fired on the correct path.
---
## Pass / Fail Criteria
| Check | Pass condition |
|-------|---------------|
| 6 `[VM recv]` lines appear in the right order | Hermes, Artemis, Hera, Artemis, Hera, Hermes |
| `HERMES-TICK` completes without error | Line `>>> HERMES-TICK ok` present |
| Arena clean after reap | `>>> MSG-ARENA clean (expect 0): 0` |
| Script exit code 0 | grep matched at least one `>>>` line |
---
## Block Size Note
The test shim + 6-path sequence shown above totals approximately 580 bytes combined.
Split into two smoke blocks as with the existing test (Block 9996 = shim + CD-INIT,
Block 9997 = 6 sends + tick + reap + BYE). Each well under 1024 bytes.
---
## What This Does NOT Test
- True async inter-process delivery (hosted FORTH is single-threaded; `VM-EXEC`
fires synchronously inside `MSG-DELIVER`)
- K≡1.0 fleet accounting across VM boundaries (that requires the kernel Tripod
with real separate VM instances and a fleet K observer)
- Channel negotiation (CH-REQUEST → CH-ACCEPT → ephemeral channel lifecycle)
- Hera lifecycle decisions driven by fleet K telemetry
Those belong to the kernel integration test (three-arch QEMU boot). This test
validates the Hermes dispatch substrate — that messages reach the named VM and the
thermal machinery cleans up correctly.
---
## Implementation Vehicle
`tools/hermes_tripod_smoke.sh` — same structure as `tools/hermes_smoke.sh`:
1. Back up `capsules/core/init.4th`
2. Concatenate: core stubs + VM-EXEC shim block + Hermes capsule + 6-path test blocks
3. Run `./build/amd64/standard/starforth --log-none 2>&1 | grep '^>>>'`
4. Restore `capsules/core/init.4th` on EXIT/INT/TERM
Say the word and this gets built.