Turn-attractor rebuilt on real messaging: two live defects found and fixed before the full campaign (FABRIC-3.md §XXI)
Rewrote EXEC-STD79-DOE-CD's dispatch to coordinate via MSG-SEND/ MSG-TICK instead of blocking VM-EXEC, now that Hera can genuinely message (§XX). RUN-TEST/EXEC-STD79-DOE (the serialized baseline) are untouched, kept as a byte-for-byte-reproducible historical comparison point. A small 2-identity smoke test before any multi-architecture commitment caught two real defects the design alone didn't predict: 1. Absolute VM-HEAT can't produce fine-grained interleaving -- a fresh identity starts at heat=0 against Hera's ~62000+, a gap no 1..24 divisor closes, so priority locked onto whichever identity had executed least, for its entire campaign. Fixed with BASE-HEAT: each identity's heat is snapshotted once at campaign start, and priority is computed from heat gained *this campaign*, not lifetime heat. 2. Single-test-per-message granularity silently drops most of a campaign's data: MSG-SEND no-ops on MSG-ALLOC failure, and the turn bookkeeping advanced regardless, so rows looked complete while missing most of their tests. A live reservoir probe showed Hera's own STADIUM-RES@ draining ~725/cycle with no replenishment observed -- a 648-send full campaign would exhaust it almost immediately. Fixed by dispatching a whole rep (24 tests, one concatenated command, measured 442 bytes, well under VM-EXEC's 1025-byte cap) per message instead -- 27 sends for a full campaign, not 648. Re-verified after both fixes: 99/99 expected test outputs present, zero drops, zero faults, genuine rep-level interleaving instead of either the serialized baseline's fixed order or the first cut's 72-test lock-in. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7edccd2c35
commit
19916717b2
+76
@@ -2852,3 +2852,79 @@ via `mama_forth_words.c` -- turn cost falls on whichever VM sends, not a "winner
|
||||
then rerun the full 3×9×3 DoE campaign from the top per the standing rule that any defect
|
||||
repair requires a clean re-run before a result counts as closed.
|
||||
|
||||
## XXI. The turn-attractor rebuilt on real messaging -- two real defects found and fixed live
|
||||
before trusting it with a full campaign (2026-09-12)
|
||||
|
||||
**The rewrite itself.** `RUN-TEST`'s messaging sibling (`experiments/std79-doe/std79-doe.fth`)
|
||||
now queues each turn via `MSG-SEND` and drains it via `MSG-TICK` instead of calling `VM-EXEC`
|
||||
directly -- unblocked by §XX. `zuse` (doe-idx 0) still runs natively on Hera, unchanged, for the
|
||||
same self-targeting-`VM-EXEC`-reentrancy reason `RUN-TEST` always had. `PICK-COOLEST` became
|
||||
`PICK-NEXT-TURN`, `TIE-BREAK ( idx1 idx2 -- idx )` added as a seeded coin toss off the same
|
||||
`RANDOM` stream `SHUFFLE-MATRIX` already consumes (keeps the whole run reproducible). Confirmed
|
||||
before building anything further: `STADIUM-RES-PULL`/`STADIUM-RES-PUSH` (`mama_forth_words.c`)
|
||||
operate on the *calling* VM's own reservoir -- turn cost genuinely falls on Hera, the
|
||||
orchestrator, not on whichever identity receives the turn. "Sender pays," not "winner pays,"
|
||||
confirmed in the source rather than assumed from the earlier design conversation.
|
||||
|
||||
**Neither the priority formula nor the message granularity survived first contact with a real
|
||||
boot, and both were caught before committing to a 3-architecture campaign, not after.**
|
||||
Following the working-style rule that plan approval is not a start signal and a defect repair
|
||||
requires a clean re-run, not a quick patch: a smoke test (2 identities, zuse+rajames, amd64) was
|
||||
run before any multi-architecture commitment, and its own output was read closely rather than
|
||||
just checked for "did it finish."
|
||||
|
||||
**Defect 1: absolute `VM-HEAT` cannot produce fine-grained interleaving, only big block
|
||||
handoffs.** The first cut used `VM-HEAT / tests-remaining` exactly as scoped. The smoke test
|
||||
completed with zero faults, but its `DOE-RUN` rows read `zuse,0` then `rajames,0`, `rajames,1`,
|
||||
`rajames,2` back to back, then `zuse,1`/`zuse,2` -- one rep of alternation, then a full 72-test
|
||||
lock onto one identity. Root cause, confirmed by a direct live probe rather than inferred from
|
||||
the log: right after attach, before a single test ran, `S" Hera" VM-HEAT .` read `62672` and
|
||||
`S" rajames" VM-HEAT .` read `0` -- a ~63000x gap. `VM-HEAT` mostly encodes how long a VM has
|
||||
existed and how much boot/capsule-load work it already did (Hera's own dictionary alone --
|
||||
`fabric.4th`, `ACL.4th`, `messaging.4th`, etc. -- generates heat no identity VM ever will), not
|
||||
how recently it took a DoE turn. A 1..24 divisor cannot close 4-5 orders of magnitude. Fixed by
|
||||
adding `BASE-HEAT`: each active identity's `VM-HEAT` is snapshotted once at campaign start
|
||||
(`CAPTURE-BASE-HEAT`), and `TURN-PRIORITY` became `(heat - base-heat) / remaining` -- heat
|
||||
*gained this campaign*, zeroing the pre-existing lifetime disparity so every identity starts
|
||||
tied (a genuine N-way tie at turn 1, which is also what first exercised `TIE-BREAK` for real,
|
||||
rather than leaving it committed-but-unproven infrastructure in the `SPAWN-EVENT` pattern this
|
||||
whole investigation started by root-causing).
|
||||
|
||||
**Defect 2: single-test-per-message granularity silently drops most of a campaign's data, and
|
||||
the bookkeeping never notices.** With the priority formula fixed, a re-run showed real rep-level
|
||||
alternation (`zuse,0` / `rajames,0` / `zuse,1` / `rajames,1` / `zuse,2` / `rajames,2`). But
|
||||
counting `rajames`'s actual printed test outputs against the expected 33 tokens/rep × 3 reps =
|
||||
99 found only 45 -- roughly half, worsening to ~29% by the third rep. `MSG-SEND` silently no-ops
|
||||
when `MSG-ALLOC` fails to admit (`Q.SLOT MSG-ALLOC DUP 0= IF 2DROP 2DROP 2DROP DROP EXIT THEN`,
|
||||
`messaging.4th`) -- and `STEP-TURN`'s own bookkeeping (`TEST-IDX!`/`REP-IDX!`) advanced
|
||||
regardless of whether the send actually succeeded, so every row printed as if complete while
|
||||
silently missing most of its tests. Root cause confirmed by a second direct probe: repeated
|
||||
`MSG-SEND`+`MSG-TICK` cycles at Hera's own REPL, watching raw `STADIUM-RES@` (her own
|
||||
reservoir, the thing `MSG-ALLOC`'s `STADIUM-RES-PULL` draws from every send) -- it drained from
|
||||
`21760` to `13811` over just 11 cycles, with no observed replenishment during the run. At that
|
||||
rate a full 9-identity × 3-rep × 24-test campaign (648 sends at single-test granularity) would
|
||||
exhaust the budget almost immediately, which is exactly what the token-count shortfall showed
|
||||
happening in miniature with only 2 identities. Fixed by changing the turn granularity itself:
|
||||
`RUN-REP-CD` now builds one concatenated command string for a whole rep's 24 tests
|
||||
(`BUILD-REP-CMD`, a 1024-byte scratch buffer -- the real 24-test set measures 442 bytes,
|
||||
confirmed well under `mama_word_vm_exec`'s own `INPUT_BUFFER_SIZE` (1025) refusal threshold,
|
||||
checked in `mama_forth_words.c` rather than assumed) and sends it as a single message. A full
|
||||
campaign now costs 27 sends total instead of 648 -- comfortably inside the reservoir budget the
|
||||
probe measured -- while `PICK-NEXT-TURN` still re-evaluates priority between every rep, so which
|
||||
identity goes next is still heat-driven rather than shuffle-order-driven, just at rep granularity
|
||||
rather than single-test granularity. `TESTS-REMAINING@` became `REPS-REMAINING@` and the
|
||||
now-unused `TEST-IDX` per-test array was removed rather than left as dead state.
|
||||
|
||||
**Verification, re-run after both fixes, same 2-identity smoke test:** all 6 expected reps
|
||||
present, `rajames`'s printed test-output token count came to exactly 99/99 (3 reps × 33 tokens,
|
||||
zero drops), zero `UNKNOWN WORD`/fault lines, zero genuine `VM-EXEC: command too long` refusals
|
||||
(one grep hit was a false match against this very doc comment's own quoted text during
|
||||
compilation, not a runtime error), completed in 69s. No leaked `qemu` process after either run.
|
||||
|
||||
**Not yet done:** the actual full 3-architecture, 9-identity, 3×9×3 campaign this whole
|
||||
mechanism exists to support -- the smoke test deliberately stayed small (2 identities) so each
|
||||
iteration of finding and fixing a defect stayed cheap. That campaign, its analysis pipeline
|
||||
rebuild, and the LaTeX report comparing it against the §XV/§XVIII serialized baseline are the
|
||||
next step, now that the mechanism itself has been shown correct at small scale rather than
|
||||
assumed correct from a clean exit code.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user