Build DOE-PERSIST-TRIAL: block-backed DoE campaign persistence, live-verified

FABRIC-3.md §XXXV.3/.4 designed this and it was never built -- two live
campaigns got launched relying entirely on a live serial-log tail before
this was caught. doe_region.c/.h mirrors log_region.c's own growable-ring
pattern (own devblock_from_top fence at 98, past log_region's ceiling at
97) to persist one trial-summary record per completed trial straight to
disk/artemis.img, surviving past QEMU exit with no host required.

Verified end to end: booted amd64, called DOE-PERSIST-TRIAL at the
console, clean BYE, then read the raw disk bytes back with QEMU fully
dead -- confirmed the exact values passed in. Wired into both
multiuser-doe.4th and per-isa-doe.4th's trial markers. Clean build, zero
new warnings, all 3 ISAs; mkcapsule --lint passes both edited capsules.

FABRIC-3.md §XXXV.10 documents the fix and the root-cause correction: two
campaigns were launched on an unbuilt persistence design before this was
caught and fixed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-17 16:43:46 -04:00
co-authored by Claude Sonnet 5
parent 8b8e8e1405
commit 2da746c01c
8 changed files with 471 additions and 22 deletions
+64
View File
@@ -5578,3 +5578,67 @@ even one real trial. Launching the first live ~24.8h run is a separate, later st
their baseline identity/auth works (confirmed live), but elevation eligibility, if any of them
had it before, was not restored. Left open; re-add via `ZUSE-ELIGIBILITY-ADD` later if needed.
### XXXV.10 -- §XXXV.3/.4's persistence writer BUILT and live-verified end to end
(2026-09-17)
**Root-cause correction first:** two live campaigns (the original single-ISA 180-trial run and
this section's own per-ISA amd64 leg) were launched between §XXXV.8 and this entry on the
mistaken assumption that the campaign was ready, without re-checking that §XXXV.9 explicitly
flagged the persistence writer as design-only. Both runs depended entirely on a live serial-log
tail and were killed mid-flight (one by a colliding peer session, one deliberately, by request)
with no durable record beyond the raw serial logs already committed. Flagged directly by Captain
Bob ("Just plain dropped the ball and ignored all previous instructions") -- correct. Saved as
`feedback_verify_design_implemented_before_launching_campaign.md`: grep the actual source for a
named primitive before treating a design section as launch-ready, don't infer readiness from a
nearby "ratified"/"executed" header.
**Built, mirroring `log_region.c`/`log_region.h`'s exact pattern per §XXXV.3:**
- `include/starkernel/doe_region.h` / `src/starkernel/doe_region.c` -- new, separate growable
ring (own control header, own `devblock_from_top` base at 98, immediately past
`log_region.c`'s own ceiling at 97 -- confirmed by direct arithmetic, not the `log_region.h`
doc comment's slightly-off "97+" framing, which actually meant "97 is log_region's last used
devblock," so 98 is the first genuinely free one). 64-byte slots (`doe_trial_slot_t`: two
`uint64_t` aggregates -- `fleet_k_q48`, `switch_count_cumulative` -- six `uint32_t` trial
fields matching `MU-EMIT-TRIAL-MARKER` exactly -- `run_id`/`cfg`/`rep`/`nw`/`mode`/
`fail_count` -- plus `fleet_conserved` and an 8-byte ISA tag), 64 slots/devblock, growable
1->4 devblocks (256 slots ceiling, well over one full 3-ISA campaign's 54 trials). Plain FIFO
eviction at the ceiling (no priority-level concept for a trial summary, unlike
`log_region.c`'s `LOG_REGION_PROTECTED_MAX_LEVEL`).
- `DOE-PERSIST-TRIAL ( run cfg rep nw mode fail isa-addr isa-u -- )`, registered in
`src/word_source/log_words.c` (same file as `(LOG-APPEND-RAW)`, same kernel-only pattern).
`fleet_k_q48`/`fleet_conserved`/`switch_count_cumulative` are read directly inside the C word
(`vm_physics_fleet_heat_sum()`, `vm_physics_conserved()`, `sk_vm_switch_signal_switch_count()`)
-- not caller-supplied, same non-spoofable-attribution discipline `(LOG-APPEND-RAW)` already
established for its own source field.
- `Makefile.starkernel`: `doe_region.c` added to both `LOADER_SRCS_BASE` and `KERNEL_SRCS_BASE`
alongside `log_region.c`.
- Wired into both `multiuser-doe.4th`'s own `MU-EMIT-TRIAL-MARKER` (Block 5051, empty ISA tag --
the base campaign driver has no ISA concept of its own) and `per-isa-doe.4th`'s redefinition
(Block 5118, real `PER-ISA-TAG-BUF`/`PER-ISA-TAG-LEN` passed through) -- both fit within the
existing block allocation with no new blocks needed (`per-isa-doe.4th` had zero spare blocks
per §XXXV.8's own note; fit entirely inside the 4 lines of headroom Block 5118 already had).
`mkcapsule --lint` PASS on both files after editing.
**Verified live, full round trip, not just "it compiles":**
1. Clean build, zero new warnings, all 3 ISAs (amd64/aarch64/riscv64) -- confirmed `doe_region.o`
present in both loader and kernel object trees.
2. Booted amd64, loaded `multiuser-doe.4th` then `per-isa-doe.4th`, called
`111 22 3 4 5 0 S" testisa" DOE-PERSIST-TRIAL` directly at the console -- `ok`, no error;
`VM-ERROR? .` printed `0`. Clean `BYE`, zero leaked `qemu-system-x86_64` processes.
3. **With QEMU fully exited**, read `disk/artemis.img` directly off disk with an independent
host-side script (no live process, no serial socket involved) -- confirmed the control header
at `devblock_from_top=98` (magic `'DOED'`, `devblocks=1 head_slot=0 tail_slot=1
record_count=1`) and the first slot at `devblock_from_top=99` contain exactly
`run_id=111 cfg=22 rep=3 nw=4 mode=5 fail=0 conserved=1 isa="testisa"` -- the literal values
passed at the console, byte-for-byte, persisted with no host in the loop. This is the actual
property §XXXV.1 identified as missing and required.
4. Reverted the synthetic test write from `disk/artemis.img` (`git checkout --`) before
committing, per this repo's own established convention (§XXXV.8's `mounted_time` precedent)
-- the region's first real record should be an actual campaign trial, not test data.
**Still open, unchanged from §XXXV.9:** the host-side extraction/reader tool (reading the ring
back into a CSV, mirroring `scripts/extract_doe.sh`'s role for serial logs) is not built -- v1
scope per §XXXV.3 was the writer only, verified here by a one-off Python script reading the raw
bytes directly, not a maintained tool. Launching the first live multi-hour campaign is still a
separate, later, explicit decision -- this entry closes the persistence-writer gap, nothing more.