Commit Graph
100 Commits
Author SHA1 Message Date
Robert Allan JamesandClaude Sonnet 5 3e0966095c Stadium: real VM-patron admission + real COOL dispatch at KILL (FABRIC-3.md §B)
capsule_vm_kill() had zero Stadium involvement (vm_cleanup()/sf_free()
only), and child-VM birth only ever called stadium_grant_quota() -- a
resource pool for the VM's own future word/block patrons, never
stadium_admit() for the VM itself. stadium_birth_hera() looked like a
precedent but admits Hera into her own quota as a permanently pinned
cell 0, which can never reach stadium_evict() -- not a working example
of COOL firing for a VM.

Adds size_t stadium_patron_cell to VMRegistryEntry. At birth, right
after the existing stadium_grant_quota() call, admits a candidate into
the new VM's own quota mirroring stadium_birth_hera()'s shape
(identity=0, mass=1, behaviour=COOL) but deliberately unpinned --
pinning would need a new "unpin" primitive (none exists) to ever evict
it later, and unpinned costs nothing since nothing wires COOL's
dispatch body to kill anything; the worst case of an unrelated natural
eviction is stale bookkeeping, tolerated the same way
stadium_word_forget() already tolerates staleness elsewhere. At
capsule_vm_kill() and capsule_vm_kill_all_nonmama(): stadium_evict()
the tracked cell if still resident, silently tolerating refusal
(already gone). stadium_dispatch()'s COOL case needed no new payload
body -- same as it already is for words, where COOL has no defined
extra action beyond stadium_evict()'s own universal reservoir credit.

On investigation this turned out not to be entangled with the
still-iterating Tripod/Zuse/messaging vision after all -- birth and
kill already funnel through two single choke points, so the earlier
deferral (previous commit) was overcautious.

Verified live: a second, new "Stadium: dispatch cell=... behaviour=
COOL" now fires immediately before every PARITY:KILL line, for both
Hermes and Artemis, distinct from the pre-existing COMMON-CH
word-eviction self-test's own COOL print. Conservation
(resident_sum + reservoir == Q48_ONE) intact throughout. Clean
zero-warning compile and clean boot on all three architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-26 02:53:56 -04:00
Robert Allan JamesandClaude Sonnet 5 af1eb0ca2d Fix USE/RUN dictionary shadowing: remove dead lib.4th aliases
capsules/lib.4th:13-14 defined ": USE ( addr u -- ) EXEC ;" and the
same for RUN, shadowing the C-registered mama_word_use()/RUN primitives
(CLAUDE.md names both, with BIRTH, as untouchable C primitives) with an
unrelated "load/exec a capsule" meaning. This broke the interactive
USE-based VM-redirect (S" Artemis" USE printed "EXEC: failed: Artemis"
instead of redirecting), discovered while chasing FABRIC-3.md's
live-MIGRATE verification.

Traced every real caller before touching anything: RUN's alias was
dead code, never called anywhere as bare RUN. USE's alias had exactly
one real caller -- capsules/hermes/init.4th:397, intentionally
exploiting the shadow to load common:msg.4th right after lib.4th
itself loaded. Both aliases were pure EXEC wrappers with zero added
behavior, so this deletes both definitions outright and switches the
one real call site (plus its matching doc comment in
capsules/common/msg.4th) to call EXEC directly. No new names invented,
the C primitives untouched.

Verified live: Hermes still births and her COMMON-CH-eviction
self-test (depends on common:msg.4th having loaded) still passes;
interactively, S" Artemis" USE now correctly redirects the REPL and
prints "USE: now using Artemis". mkcapsule --lint clean (31/31).
Clean compile and clean boot with Stadium conservation intact
(resident_sum + reservoir == Q48_ONE) on all three architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-26 01:01:26 -04:00
Robert Allan JamesandClaude Sonnet 5 0f683c15fd FABRIC-3.md: close the live-MIGRATE verification gap; report a USE/RUN shadowing bug
Confirmed the real MIGRATE dispatch fires live: a temporary boot probe
(STADIUM-ADMIT + STADIUM-EVICT against the live Artemis VM, inserted
into the existing 4.6 self-test and reverted immediately after capture)
produced "Stadium: dispatch cell=63257 behaviour=MIGRATE lbn=100" with
blk_flush(100) firing and zero error -- closes the honest gap left open
in the previous commit. Interactive flooding alone couldn't reach this:
Hera's reservoir sits at the Q48_ONE/3 floor from boot self-tests, so
block-touch candidates pull 0 heat and can never out-density an
existing resident, a pre-existing reservoir-floor/eviction interaction
unrelated to this pass.

Also reports (not fixes, per CLAUDE.md) a real dictionary-shadowing bug
found while chasing this: capsules/lib.4th:13 redefines USE as EXEC,
shadowing the C primitive mama_word_use() (REPL VM-redirect) with an
unrelated capsule-loading meaning -- same for RUN at lib.4th:14. Same
bug class as the K-PUSH dictionary-shadowing issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-26 00:52:36 -04:00
Robert Allan JamesandClaude Sonnet 5 c7c9332321 Stadium: real block-patron admission + MIGRATE dispatch (FABRIC-3.md §B)
stadium_admit()'s mass==1 refusal looked like a hard blocker for 1024-byte
blocks, but stadium_word_dispatch()'s real candidate construction proves
Stadium cells carry pure identity/heat/bookkeeping, never the resident's
actual content -- a block patron follows the same shape (identity=LBN,
payload unused), so this was real, scoped work, not a case for stubbing.

New stadium_blocks.h/.c mirror stadium_words.c's admission/cooling shape,
keyed by (quota_slot, lbn) in a fixed-capacity open-addressing hash table
(tombstone deletion) instead of a dense array, since LBN space isn't
densely bounded like word_id. Wired into block_word_block()/buffer()/
update() (block_words.c), __STARKERNEL__-guarded. stadium_dispatch()'s
MIGRATE case now calls blk_flush(lbn) for real instead of printing
"(stub)". Three new Kconfig constants (STADIUM_BLOCK_HEAT_QUANTUM/
STADIUM_BLOCK_COOL_RATE_Q48/STADIUM_BLOCK_TRACK_CAP_MULT) mirror the
word-patron ones, same three-layer wiring.

VM-COOL/DELIVER/EXPIRE stay explicit punch-list items -- VM-COOL
deferred pending the still-iterating Tripod/Zuse/messaging vision,
DELIVER/EXPIRE are their own future subsystem integrations per
FABRIC.md's own "open, not resolved" notes.

Verified clean compile (zero warnings) and clean boot to REPL with
conservation intact (resident_sum + reservoir == Q48_ONE) on all three
architectures (amd64/aarch64/riscv64); BLOCK/BUFFER touches exercised
live from the REPL with no crash; a 22,000-distinct-block flood loop
against an artificially shrunk Stadium ran clean under heavy admission
load. A live MIGRATE console fire was not directly observed this
session (root-caused to a pre-existing reservoir-floor/density-eviction
interaction unrelated to this change, documented in FABRIC-3.md) --
flagged as an honest follow-up, not silently claimed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 23:28:59 -04:00
Robert Allan JamesandClaude Sonnet 5 ecdb547786 FABRIC-3.md: block-patron admission investigation + Tripod final-shape vision
Investigated whether stadium_admit()'s mass==1 refusal blocks block-patron
Stadium admission -- it doesn't: stadium_word_dispatch()'s real candidate
construction confirms Stadium cells carry identity/heat/bookkeeping only,
never the resident's actual content, so a block patron (identity=LBN,
payload unused) fits the same pattern words already use. The real gap is
just that no LBN->cell_index residency map or touch-on-access hook exists
yet -- real, scoped, buildable work, not a blocker.

Deferred VM-COOL pending the Tripod final-shape vision Captain Bob laid
out (thumbdrive minting, one-time Zuse fuse-blow, messaging-only inter-VM
interaction, polymorphic block-boundary behavior) -- recorded in a new
§D so near-term Stadium work doesn't ignore it, without treating a
one-sentence vision as a ready-to-implement spec.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 23:04:19 -04:00
Robert Allan James 912cc8ea4b Claude
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
2026-08-25 20:41:50 -04:00
Robert Allan JamesandClaude Sonnet 5 d68223d43f Close FABRIC-2.md, open FABRIC-3.md; audit Stadium dispatch stubs; new no-stubs rule
FABRIC-2.md closed archival at ~4,400 lines / 51 open items, same reasoning
FABRIC.md itself was closed for at 7,595 lines -- continuing to append made
still-open work hard to find. All 51 open items carried forward into
FABRIC-3.md's new Section A, verified complete via programmatic diff against
the source (49 unique + 2 confirmed pure duplicates from FABRIC-2.md's own
F.3 cross-reference section, not dropped content). .claude/CLAUDE.md's
pointer note updated to name FABRIC-3.md as current.

New Section B: full audit of stadium_dispatch()'s four behaviour stubs
(MIGRATE/DELIVER/EXPIRE/COOL), triggered by investigating "words/VMs/blocks/
messages should all be on the same engine". Found the picture is more
nuanced than "everything's a stub" -- words are already fully live via a
separate bespoke mechanism (stadium_word_dispatch(), wired into vm_core.c's
real word-execution path, item 4.1), contradicting ONTOLOGY.md's stale
"not yet migrated" claim (flagged for a follow-up fix). MIGRATE (blocks)
and VM-COOL are genuinely stub with zero consumers; DELIVER (Hermes) and
EXPIRE (ACL) are substantial, undecided subsystem integrations FABRIC.md
itself already flagged as open, not touched here.

New standing rule, saved as memory feedback_no_stubs_or_todos.md: stub
implementations and TODO placeholders are never acceptable in this
workflow, in any language, ever -- triggered by finding stadium_dispatch()'s
stub handlers during this investigation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 19:43:28 -04:00
Robert Allan JamesandClaude Sonnet 5 36d832ff47 Single-block relocation: RELOCATE-BLOCK, resolve_lbn(), persisted exception table
Implements the full design from the prior commit in one pass. resolve_lbn()
is the single choke point threaded through the ten public LBN-consuming
entry points (blk_get_buffer, blk_update, blk_flush, blk_is_allocated,
blk_mark_allocated, blk_mark_free, blk_is_valid, blk_get_meta, blk_set_meta,
plus blk_get_empty_buffer covered via delegation) -- an LBN->LBN redirect,
not a new storage allocator, since the LBN space is already unified across
every attached blkio_dev backend. VM window cache staleness across a
relocation reuses the existing blk_vm_check_epoch() mechanism from
Milestone 2h's hot-detach fix for free -- g.epoch bumps on relocation too.

Persistence lands in the same pass: two new uint32_t fields
(reloc_start/reloc_devblocks) appended after hdr_crc in blk_volume_meta_t,
carved from existing padding without moving any earlier field's byte
offset -- an old formatted volume's zeroed padding reads back as
reloc_devblocks=0 ("no reloc capacity"), gracefully, not a format-breaking
change. compute_totals_from_B() generalized to account for the new
reserved region. reloc_flush_to_disk()/reloc_load_from_disk() mirror the
BAM I/O functions' own absolute-devblock-addressing shape; the persisted
copy's owner is first_disk_slot() (already existed, already used for this
exact "which device is canonical" question by blk_get_volume_meta()).
blk_subsys_relocate_block() is a mechanical primitive only -- copies
content (staged through a local buffer, since obtaining the target's
blk_get_buffer() result can evict and invalidate the source's cache
pointer if they share a device), frees the source BAM entry, appends the
exception entry, bumps the epoch, flushes to disk. RELOCATE-BLOCK exposes
it to FORTH, no policy of its own (ACL's job, per this session's direction).

A first live-test attempt gave a false negative against disk/artemis.img
(predates reloc capacity, so relocation only ever existed in memory that
boot) -- traced to the test's own setup before being mistaken for a bug,
then re-verified correctly against a fresh volume (new fixture,
disk/artemis-reloc-test.img): relocated a RAMDRIVE block to the fresh
disk, confirmed live resolution through the redirect, then confirmed both
the redirect and the relocated content survived an abrupt QEMU kill and
full reboot. Also fixed three lingering "glibc" doc-comment
misattributions from Milestone 2h (the actual allocator is this kernel's
own kmalloc) that survived an earlier FABRIC-2.md-only correction. All
three architectures re-verified clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 19:14:01 -04:00
Robert Allan JamesandClaude Sonnet 5 073dae4f56 FABRIC-2.md: full design for single-block relocation, persistence included
Complete design, not just the earlier flag: resolve_lbn() as the single
choke point threaded through ten public entry points, LBN->LBN redirect
mechanism (no new storage allocator needed, the LBN space is already
unified across all backend-agnostic blkio_dev devices), VM window
staleness solved for free by reusing the existing epoch mechanism from
Milestone 2h's hot-detach fix, in-memory table shape, and on-disk
persistence via two new fields carved from blk_volume_meta_t's existing
padding (byte-compatible with old formatted volumes) using the same
absolute-devblock I/O pattern the BAM already uses. Ownership of the
persisted copy assigned to first_disk_slot() (already exists, already
used for this exact "which device is canonical" question), with the
multi-primary-device question for a future multi-SSD/cloud world
explicitly punted rather than hand-waved. Noted the known, separate
limitation: USB relocation targets aren't exercisable until WRITE(10)
exists in the xHCI driver -- verification will use two already-writable
devices instead. Policy (when to relocate, whether a target is validly
owned) stays ACL's job, not this primitive's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 18:49:51 -04:00
Robert Allan JamesandClaude Sonnet 5 aea7f85d34 FABRIC-2.md: flag block_subsystem.c routing revision needed for single-block relocation
Milestone 3 direction from this session: ACL decides when to relocate
(capacity pressure or a compudynamics heat/cold signal), migration
expected rare not routine. Flagging only, not designing yet: current
lbn_to_slot() is pure contiguous-range routing, one device owns one
unbroken range -- incompatible with relocating an individual block to a
different device while its LBN stays fixed. Direction sketched (a sparse
LBN-to-actual-device exception table, consulted before the range walk,
zero cost for the common never-relocated case) but the actual structure
is still open. Block-migration implementation now explicitly depends on
this revision landing first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 18:39:40 -04:00
Robert Allan JamesandClaude Sonnet 5 306ee70468 FABRIC-2.md: identity-range allocation is first-touch, not a hash formula; identity is a CA-signed cert
Dropped the hash-modulo-MAX_IDENTITIES approach: there is no way to bound
how many identities might ever exist, so no population size can be
pre-divided into slots regardless of hash function. Resolution: first
time an identity is seen, claim a range at the SSD's existing free-space
frontier (g.total_user_lbn, already used by every device attach) sized
to whatever it needs, write the assignment into the drive's own map;
every later visit just reads it back. No central directory, no quota,
matches Section U's existing requirements exactly.

Identity itself is a certificate signed by this project's own (not yet
created) CA root, extending Milestone 6's PKI design to users instead of
inventing a separate mechanism. Derivation-relevant value is the cert's
embedded pubkey, not its raw bytes -- a renewal shouldn't relocate an
already-allocated range.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 18:32:30 -04:00
Robert Allan JamesandClaude Sonnet 5 4891fd0067 FABRIC-2.md: drop GPT partitioning for home-blocks USB drive, whole-device layout instead
Checked the math with Captain Bob: a PBAM for ~15GB of user blocks needs
only ~1.92MB (15M blocks / 32768 per 4KB page), fitting easily alongside
identity/credential/PKI material in a 1GB reserved region. No partition
table needed -- same whole-device pattern artemis.img already uses today,
just with a generously fixed ~1GB reserved region instead of tight
bam_start+bam_devblocks packing. Eliminates the GPT-parser work item
entirely (no GPT code exists in src/starkernel/ today). Confirmed no
conflict with Milestone 8's USB boot drive, which is a separate physical
drive (flashed starkernel.iso) with its own independent GPT/ESP need.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 15:00:49 -04:00
Robert Allan JamesandClaude Sonnet 5 8eaefeb9ee sk_repl_idle() auto-flush: implement Section V's "anything dirty? no? done" check
Makes blk_vm_flush_all() (block_words.c) non-static and declares it in
block_words.h -- it's already the entire implementation behind
SAVE-BUFFERS (block_word_save_buffers() is a one-line wrapper), so
sk_repl_idle() can call the exact same flush path outside word dispatch
without duplicating any logic. Cheap every idle tick regardless of dirty
state: every check inside is a small fixed-size scan, so no separate
pre-check was needed on top of it.

Caught a real bug via a live persistence test before trusting the
feature: the first version gated the flush on sk_repl_get_active_vm()
returning non-NULL, but NULL is that accessor's documented default
(Tripod's own USE-redirect override, "restore default dispatch") --
without an active USE redirect, the flush silently no-op'd for the
entire session. Confirmed live: wrote a byte via BUFFER (no
UPDATE/SAVE-BUFFERS), waited past the idle cadence, killed QEMU abruptly,
rebooted with the same disk image, read back 0 instead of the written
65. Fixed by threading the VM sk_repl_run()'s own loop already resolves
each iteration (g_repl_active_vm ? g_repl_active_vm : vm) down as a
parameter through sk_readline() into sk_repl_idle(), rather than trying
to re-derive it from an accessor with the wrong default. Re-ran the same
test after the fix: read back 65, matching the written byte -- the write
survived an abrupt kill with no explicit flush call anywhere in the
test, proving the idle-tick auto-flush genuinely ran.

All three architectures re-verified clean. FABRIC-2.md Section V item 6
and the corresponding Milestone 3 punch-list item marked done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 14:51:02 -04:00
Robert Allan JamesandClaude Sonnet 5 1b80609cb0 FABRIC-2.md: correct glibc misattribution in 2h hot-detach writeup
block_subsystem.c is shared/vendored source -- its calloc()/free() calls
resolve to real glibc in the hosted build, but to this kernel's own
freestanding shims (src/starkernel/vm/host/shim.c, backed by kmalloc()/
kfree() in src/starkernel/memory/kmalloc.c) in the kernel build, which is
where the address-reuse bug was actually diagnosed live. The previous
writeup said "glibc's allocator" -- wrong environment entirely. Verified
kmalloc_aligned() is a plain first-fit walk from heap_head with no
coalescing, confirming the same free-then-immediate-same-size-alloc reuse
behavior originally observed, just attributed to the right allocator.
Caught by the user asking directly whether this project has any glibc
dependency, given .claude/CLAUDE.md's strict ANSI C99/no-GNU-extensions
requirement (confirmed -std=c99 throughout both Makefiles). Documentation
correction only -- no code changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 14:16:12 -04:00
Robert Allan JamesandClaude Sonnet 5 af267a52a6 Artemis Milestone 2h: hot-detach -- 2h complete
blk_subsys_detach_device() (block_subsystem.c) walks the device chain,
refuses removal of anything but the current tail (a mid-chain removal
would corrupt every later slot's start_lbn -- this architecture's own doc
already argues USB stays last specifically to avoid that), unlinks,
shrinks total_user_lbn, closes and frees the slot. Discards rather than
flushes dirty state -- the device is physically gone by the time this
runs (PORTSC disconnect only). Trigger wiring mirrors the attach path:
bot_msc_attached (set only once attach actually succeeds) gates a new
bot_msc_detach_pending flag set at PORTSC disconnect (not Disable Slot
completion, which is conditionally skipped and would miss concurrent
connect/disconnect pairs), consumed in sk_repl_idle().

Advisor flagged the real hazard ahead of time: block_words.c's VM block
window (blk_vm_lbn[]/blk_vm_cbuf[]) can go stale across a detach then a
same-LBN re-attach, and suggested a pointer-identity re-check in
blk_vm_load() as a minimal fix. That fix was implemented, then directly
falsified by its own designed-for-this test: attach a blank device, read
a block (populating the cache), detach, re-attach a device with distinct
content at the identical LBN, read again -- served stale content from
the first device. Root cause, confirmed live: glibc's allocator hands
free(slot) straight back to the very next same-size calloc(), so the
"fresh" and stale pointers were bitwise identical despite being two
different devices. Fixed properly with a monotonic blk_subsys_epoch()
counter (bumped on every attach/detach) checked by a new
blk_vm_check_epoch() helper at the one choke point (blk_vm_find(), plus
blk_vm_flush_all() which reads the same arrays directly) that covers
every path touching the window cache -- unfooled by address reuse.

Verified live with a new disk/usb-thumbdrive-test2.img fixture (distinct
content from the existing blank test image): attach A, read (cache hit
populated), detach, re-attach B at the same LBN, read again -- correctly
ran a fresh device read and returned B's real content, not A's stale
cached zeros. The failing pointer-comparison attempt's own capture log
kept as evidence, not deleted. All three architectures re-verified clean.
FABRIC-2.md Section X 2h marked complete -- enumeration through
hot-detach all live and verified; only WRITE(10) (2g's own still-open
item) remains unimplemented in the driver, not blocking anything here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 14:10:05 -04:00
Robert Allan JamesandClaude Sonnet 5 3b085dd875 Artemis Milestone 2h: blkio_usb.c backend -- USB thumb drive is now a real block device
Wires a hot-plugged USB Mass Storage device into the block subsystem's
unified LBN chain. blkio_usb.c/blkio_usb.h mirror virtio_blk.c/
virtio_blk.h's established shape exactly (singleton state, blkio_vtable_t,
a blkio_usb_open_msc() "find" function playing virtio_blk_find_artemis()'s
role): read() translates a Forth block into a SCSI LBA/count pair and
calls xhci_bot_read_block() + xhci_bot_wait_for_idle(); write() returns
BLKIO_ENOSUP (no SCSI WRITE(10) exists yet, and blk_format_or_load_disk()
never writes at attach time, so read-only is sufficient -- confirmed by
reading that function first, not assumed). Refuses (-2) if the reported
SCSI block size doesn't evenly divide the 1024-byte Forth block size.

Connect-time wiring reuses the bot_msc_attach_pending/consume-in-
sk_repl_idle() shape the prior increment's temp probe already validated,
now made permanent: SET_CONFIGURATION sets the flag, sk_repl_idle()
(strictly after its own xhci_poll_events() call returns) calls
blkio_usb_open_msc() then blk_subsys_attach_device().

Verified live via hot-attach: full chain from USB connect through
'blkio_usb: MSC device ready' to 'blk: disk 'StarForth Volume' v2 LBN
26074..75184 (49111 user blocks)' -- real attachment, disk image confirmed
byte-for-byte untouched after. Chased a real debugging detour along the
way: the attach initially appeared silent (no blk: log line) -- traced to
LOG_INFO filtering at the default LOG_WARN boot level, not a functional
bug (settled via a temporary log-level bump, reverted after capture; also
found and reported, but did not fix, a pre-existing unrelated
Makefile.starkernel bug where --log-level=info via KERNEL_ARGS breaks
printf parsing). All three architectures re-verified clean. FABRIC-2.md
Section X 2h updated -- only hot-detach remains for 2h.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 12:55:53 -04:00
Robert Allan JamesandClaude Sonnet 5 d686f28853 Artemis Milestone 2h (foundational): sync wait bridge + SCSI READ CAPACITY(10)
Closes the gap block_subsystem.c needs before any of 2h's real work
(blkio_usb.c, attach wiring, hot-detach) can start: this driver is fully
async/polled with no way for a synchronous caller (blkio_read()/
blkio_info() etc.) to get a result back. xhci_bot_wait_for_idle() is a
bounded busy-wait over xhci_poll_events() -- MUST be called only from
outside xhci_poll_events()'s own call frame, never from within it or a
next_action dispatch (recursion into live Event Ring/ERDP processing,
same class of hazard already documented for doorbell rings in this
driver). xhci_get_dev() exposes the module-static device handle to
outside callers that didn't observe the original hotplug event.

SCSI READ CAPACITY(10) (opcode 0x25) is the other half -- nothing could
learn a device's block size/capacity before this. First attempt sent it
bare and hit the classic first-command UNIT ATTENTION (CSW FAILED); fixed
with the same TUR-guard pattern READ(10) already used, generalized via a
new bot_tur_chain_target field so TEST UNIT READY's PASS handling can
chain into either command. bot_data_buf grown 512->1024 bytes (one Forth
block = two 512-byte SCSI blocks, per block_subsystem.c's own 1KiB-unit
convention).

Verified live via a temporary probe (hot-attached disk/usb-thumbdrive-
test.img via QMP, reverted after capture): TUR-guarded READ CAPACITY10
correctly reported last LBA=0x1ffff, block size=0x200 -- exactly 64MiB,
matching the test image byte for byte -- followed by a TUR-guarded
1024-byte/2-block READ10, both PASS. All three architectures re-verified
clean, probe-free boot to ok> on the reverted tree. FABRIC-2.md Section X
2h updated with the writeup; the blkio_usb.c backend itself is next.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 12:27:57 -04:00
Robert Allan JamesandClaude Sonnet 5 65effbd1ba Artemis Milestone 2g: TEST UNIT READY unit-init sequence -- READ(10) now PASSes
Roots out the CSW status FAILED left unexplained in the prior increment: a
freshly attached SCSI target's standing UNIT ATTENTION condition, which a
bare READ(10) with no retry can never clear. xhci_bot_send_test_unit_ready()
sends SCSI TEST UNIT READY (SPC-4 6.33) ahead of the real command; the CSW
handler now tags command kind (bot_cmd_kind) to distinguish a TUR completion
from a READ10 completion, chains TUR PASS into the real READ(10), and
bounded-retries TUR on FAILED/PHASE ERROR (bot_tur_retries, capped at
XHCI_BOT_TUR_MAX_RETRIES). xhci_bot_read_block() is the new intended entry
point tying lba/num_blocks/block_size + the TUR-first sequencing together.

Verified live via a temporary probe (hot-attached disk/usb-thumbdrive-test.img
through the running instance's QMP socket), captured on amd64: full chain
CBW(TUR) -> FAILED -> retry -> PASS -> CBW(READ10) -> Data-In -> CSW PASS.
Probe reverted after capture; all three architectures re-verified clean,
probe-free boot to ok>. FABRIC-2.md Section X 2g updated with the writeup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
2026-08-25 11:46:55 -04:00
Robert Allan JamesandClaude Sonnet 5 c54ea24aaf Artemis Milestone 2g: Data-In stage read and CSW receive/validation
Completes the CBW -> Data-In -> CSW chain for READ(10) started last
commit. xhci_bot_read_data_in() and xhci_bot_receive_csw(), each a
single Normal TRB on the bulk IN Transfer Ring via a new
xhci_bulk_in_enqueue_and_ring() helper (mirrors the OUT-side helper
from CBW send). All three stages now chain automatically via the
existing deferred next_action pattern: CBW completion defers into
Data-In, Data-In completion defers into CSW receive, CSW completion is
where signature/tag/status validation happens.

Data-In reads into a new fixed 512-byte bot_data_buf -- single-block
scope for this increment, matches QEMU's usb-storage reported block
size; xhci_bot_send_read10() now refuses rather than overflow/truncate
if a request exceeds it. CSW validation (BOT spec section 5.2) checks
dCSWSignature and dCSWTag (a new bot_last_tag field, latched from the
CBW) before trusting bCSWStatus at all, so a garbled/misaligned CSW
read can't be misread as a clean pass. usb_bot_csw_t follows the same
struct-with-explicit-length-not-sizeof discipline as usb_bot_cbw_t.

Verified live via a temporary probe (written, run once, log captured,
reverted per this project's own probe convention), all three
architectures, byte-identical: the full CBW -> Data-In -> CSW exchange
completes cleanly, well-formed CSW with correct signature and echoed
tag, no wedge, clean disconnect immediately after. The SCSI command
itself reports CSW status FAILED against the current test fixture --
expected at this stage (no TEST UNIT READY / UNIT ATTENTION handling
implemented yet, consistent with a fresh-attach unit-attention
condition, not a transport-layer defect) and not root-caused further
here; the BOT mechanism itself is confirmed correct end to end.
Probe-free re-verification afterward on all three architectures.

FABRIC-2.md Section X Milestone 2g's CSW checklist item marked done;
"get one real READ(10) working end to end" stays explicitly open,
distinguishing "the mechanism works" from "the SCSI command succeeds."

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
2026-08-25 09:33:17 -04:00
Robert Allan JamesandClaude Sonnet 5 a88c004ecb Artemis Milestone 2g: CBW construction and send for SCSI READ(10)
First real use of the bulk Transfer Rings Configure Endpoint wired up.
xhci_bot_send_read10() builds a 31-byte Command Block Wrapper (USB Mass
Storage Class Bulk-Only Transport spec section 5.1) and submits it as a
single Normal TRB on the bulk OUT ring via a new
xhci_bulk_out_enqueue_and_ring() helper -- a CBW is always exactly one
TRB, so unlike the EP0 helper this one rings its own doorbell rather
than leaving that to a caller assembling a group.

usb_bot_cbw_t is a real struct (every field up to the CDB array is
naturally aligned, and this driver's targets are all little-endian
already assumed everywhere else), but its DMA length is the explicit
USB_BOT_CBW_LENGTH (31) constant, never sizeof(*cbw), since the
compiler may pad the struct to 32 bytes. The SCSI READ(10) CDB itself
is written byte-by-byte since its LBA/Transfer Length fields are
big-endian on the wire, unlike everything else in this driver -- the
one place two byte orders are both live in the same function.

Completion is correlated via the existing pending_transfer_slot_id/
transfer_purpose gate (new XHCI_XFER_CBW_SENT purpose) -- no
ring-specific dispatch needed, since this driver's single-outstanding-
transfer scope already implies which ring produced an event.

This covers construction and send only (one third of a full READ(10):
CBW -> Data-In stage -> CSW) -- reading the Data-In stage and CSW
receive/validation are separate, explicitly not-yet-implemented items.

Verified live via a temporary probe (written, run once, log captured,
reverted per this project's own probe convention) -- all three
architectures, byte-identical: CBW submitted -> CBW send completed,
then a clean disconnect even with the Data-In stage never drained
(confirms no wedge on a dangling BOT transaction). Probe-free
re-verification afterward on all three architectures.

FABRIC-2.md Section X Milestone 2g's CBW checklist item marked done.
Also records a monitoring gotcha hit three times this session: `ls -t`
over the logs/ tree can return a stale leftover log from an earlier
run in the same session -- fixed going forward by reading the log path
off the actual running QEMU process's own command line instead, and a
memory note added so it doesn't recur next session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
2026-08-25 09:07:33 -04:00
Robert Allan JamesandClaude Sonnet 5 92ce1f85dd Artemis Milestone 2g: Configure Endpoint command
Adds the xHCI Configure Endpoint command for the two bulk endpoints
identified by the previous increment, and fixes control-transfer
sequencing to match the spec: xHCI 1.2 section 4.3.5 requires Configure
Endpoint before SET_CONFIGURATION is sent to the device, the reverse of
the order this driver used through 2f (which happened to work against
QEMU's lenient qemu-xhci emulation but wasn't spec-correct).

New XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD, EP Context type constants for
Bulk IN/OUT, and an XHCI_EP_ADDR_TO_DCI() macro (DCI = 2*EndpointNumber
+ Direction) in xhci.h. xhci_cmd_configure_endpoint() builds the Input
Context (Slot + one EP Context per DCI up to the highest bulk endpoint
in use) and submits the command via the existing next_action deferral
mechanism, correlated on completion via a new
XHCI_CONN_AWAIT_CONFIGURE_ENDPOINT connect_state, then chains into the
existing SET_CONFIGURATION path.

Two allocations had to grow beyond what Address Device sized them for:
the Input Context (previously room for one EP Context only) and, less
obviously, the Device Context that DCBAA[slot_id] itself points at --
the controller only touches DCIs named in a command's own Add/Drop
flags, so growing that buffer required copying its existing Slot+EP0
content forward rather than zeroing it, to avoid handing the controller
a blank EP0 out from under an endpoint this command isn't touching.
Bulk Transfer Rings (bulk_in_ring/bulk_out_ring) are allocated and
wired into the new EP Contexts but not yet exercised by an actual
transfer -- CBW/CSW submission is next.

Verified live via QMP hotplug, all three architectures, byte-identical:
bulk endpoint identification -> configure endpoint command submitted ->
configure endpoint succeeded -> the existing set configuration ->
device configured chain, then a clean disconnect/disable-slot teardown
afterward with the larger Device Context installed.

FABRIC-2.md Section X Milestone 2g's endpoint identify+configure
checklist item marked fully done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
2026-08-25 08:40:35 -04:00
Robert Allan JamesandClaude Sonnet 5 96d55fcd87 Artemis Milestone 2g (partial): bulk endpoint discovery + 2e disconnect teardown
Picked up from a crashed session: xhci_driver.h/xhci.h already had the
bulk_in/out_ep_addr/max_packet fields and Endpoint-descriptor offset
macros scaffolded, but the actual walk that populates them was never
written. Added it: after 2f confirms a Mass Storage/SCSI/BOT interface,
a nested walk continues through the Endpoint descriptors that follow it
(bDescriptorType==5, stopping at the next Interface descriptor or end
of stream), keeping only Bulk-type endpoints and splitting IN/OUT by
bEndpointAddress bit 7. Also reset the four new fields in
xhci_bringup(), which the scaffolding had missed.

Also completed 2e's disconnect teardown, which was fully implemented
this session (not scaffolded): a Disable Slot command is now submitted
on a real disconnect, with the port's tracked slot ID captured and
cleared from port_slot_id[] immediately (before the command completes)
so a fresh connect on the same port isn't confused for one already in
progress, and DCBAA[slot_id] cleared only on a successful completion.

Verified live via QMP hotplug (deliberate device_add/device_del against
freshly launched, individually-tracked instances -- not whatever
happened to be attached at boot), all three architectures,
byte-identical: bulk IN endpoint=0x81, bulk OUT endpoint=0x02, then a
clean disconnect -> disable slot succeeded, no wedge. Caught and fixed
a documentation near-miss in the same pass: an initial draft cited the
probe-free three-arch acceptance boots as this feature's verification
evidence, but a stale leftover log directory from a pre-crash orphaned
QEMU process had been picked up by an `ls -dt | head -1` glob during
monitoring and mistaken for this session's own result -- the real
acceptance logs never had a device attached at all. Re-verified against
real PIDs and real log paths before writing FABRIC-2.md's final
writeup.

FABRIC-2.md Section X Milestone 2 updated: 2e's disconnect-teardown
checklist item marked done, 2g's endpoint-identification item marked
partially done (identification only -- Configure Endpoint / EP Context
wiring is still open).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
2026-08-25 08:17:50 -04:00
Robert Allan JamesandClaude Sonnet 5 b4bbd043d0 Artemis Milestone 2f: SET_CONFIGURATION -- 2f complete
Chains off a confirmed Mass Storage/SCSI/BOT interface match via the
existing next_action deferral mechanism: device descriptor -> config
descriptor -> SET_CONFIGURATION is now a single automatic sequence.
bConfigurationValue is read directly out of the already-fetched
config_descriptor buffer, no extra transfer needed.

First write control transfer this driver has issued (every prior one was
a read), so it needed its own submission helper,
xhci_ep0_control_write_nodata() -- SET_CONFIGURATION has no Data Stage
(wLength=0), and per USB 2.0 spec 8.5.3 a no-data control transfer's
Status Stage is always IN, the reverse of an OUT-data request's status
stage. XHCI_SETUP_TRT_NO_DATA already existed in xhci.h, unused until now.

Verified live via QMP hotplug, all three architectures, worked first try,
byte-identical: "set configuration submitted" -> "device configured",
guest stays running throughout (checked via QMP query-status). Disconnect
confirmed clean on every arch afterward, no wedge. FABRIC-2.md Section X
Milestone 2f updated -- 2f is now fully complete, 2g (Bulk-Only Transport)
can start.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPfdtaXs9ay1nbwuMnrscu
2026-08-25 07:40:16 -04:00
Robert Allan JamesandClaude Sonnet 5 b9c540a78b Artemis Milestone 2f: Configuration descriptor read + Mass Storage/BOT class confirmation
Chains off the device descriptor request via a new deferred-action mechanism
on xhci_dev_t (next_action/next_action_slot_id/next_action_length): a short
9-byte Configuration descriptor read learns wTotalLength, then a full read
retrieves Config+Interface+Endpoint descriptors, walked for the Interface
descriptor to confirm bInterfaceClass/SubClass/Protocol == Mass Storage/
SCSI/Bulk-Only Transport.

The deferral exists because ringing the next doorbell synchronously inside
xhci_poll_events()'s event-processing loop -- before the current event's
ERDP write -- hung the guest outright (confirmed live via checkpoint
logging, amd64). Fixed by moving the actual control-transfer submission to
a small dispatch at the end of xhci_poll_events(), after ERDP is updated.

A debug hack that shipped mid-session (forcing a repeated 9-byte read
instead of chaining into the real 44-byte length, to isolate whether the
hang was doorbell-ordering or length-specific) has been reverted: restored
the real length and re-verified live. The doorbell-ordering fix was the
whole story -- the 44-byte read completes cleanly.

Verified live via QMP hotplug, all three architectures, byte-identical
results: wTotalLength=0x2c, bInterfaceClass=0x08, bInterfaceSubClass=0x06,
bInterfaceProtocol=0x50 -- confirmed Mass Storage/SCSI/BOT. Disconnect
confirmed clean on every arch, no wedge. FABRIC-2.md Section X Milestone 2f
updated with the full writeup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPfdtaXs9ay1nbwuMnrscu
2026-08-25 07:27:07 -04:00
Robert Allan JamesandClaude Sonnet 5 2c34e45d05 Artemis Milestone 2f: EP0 control transfer, device descriptor request
Adds Setup/Data/Status stage TRB types and control bits (IDT, TRT, DIR)
to xhci.h, and xhci_ep0_enqueue_trb()/xhci_ep0_get_device_descriptor() to
xhci.c -- the first real control transfer this driver has issued.
Follows the same enqueue-then-doorbell-once pattern as the Command Ring,
operating on the EP0 Transfer Ring built during 2e's Address Device work.
Setup Stage uses Immediate Data (parameter IS the 8-byte setup packet);
Data Stage reads into a reused 18-byte device_descriptor buffer; Status
Stage alone carries IOC, so exactly one Transfer Event signals transfer
completion, correlated via a new pending_transfer_slot_id (same
single-outstanding-operation pattern as connect/Enable Slot/Address
Device).

Automatically triggered once Address Device succeeds. Verified live via
QMP hotplug, all three architectures, worked first try with identical
results everywhere: idVendor=0x46f4, idProduct=0x0001, bDeviceClass=0x00
-- the class=0 confirms Mass Storage class detection needs the
Configuration/Interface descriptor (2f's next item), not the device
descriptor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 12:59:49 -04:00
Robert Allan JamesandClaude Sonnet 5 2e7e957680 Milestone 6 (ACL/PKI): Ed25519 verify + SHA-512, built from scratch
New freestanding, verify-only Ed25519 (RFC 8032) implementation:
include/starkernel/{sha512,fe25519,scalar25519,ed25519}.h +
src/starkernel/crypto/{sha512,fe25519,scalar25519,ed25519}.c, wired into
Makefile.starkernel. Kernel never signs or generates keys -- only
ed25519_verify() is needed; signing happens in the host-side mkcapsule
build tool via libsodium/OpenSSL.

Confirmed __int128 multiply/add/shift-by-constant compile with zero
undefined symbols on all three target toolchains (only division needs
libgcc's __udivti3, per timer.c's existing documented finding -- that
file's comment updated to narrow the claim, since it had been read as
"avoid __int128 entirely"). This enabled the standard 5-limb radix-2^51
field arithmetic representation.

An abandoned first attempt (10-limb radix-2^26, avoiding __int128 out of
premature caution) hit two real bugs, both invisible on inspection and
found only by property-based testing against Python's own bignum
arithmetic: a non-uniform-radix limb misalignment in multiplication, and
a double-counted carry. Verification chain: SHA-512 against known +
boundary vectors (7/7); field arithmetic property-tested 25,045 cases;
scalar-mod-L arithmetic 300 cases (L confirmed prime via Miller-Rabin
first); full verify() end-to-end against 110 real signatures from
Python's cryptography library, including tampered inputs and the RFC
8032 S>=L malleability attack -- all correctly accepted/rejected.

Compiles clean (zero warnings) and links on all three architectures,
confirmed via the mandatory three-arch QEMU boot. The code is linked but
not yet called from anywhere -- wiring into capsule_birth.c needs a
from-scratch X.509/DER parser first (Captain Bob chose real X.509 over a
raw-blob cert format this session), which is the next open item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 12:41:26 -04:00
Robert Allan JamesandClaude Sonnet 5 2b7743027c Artemis Milestone 2e: Address Device implemented, worked first try, 3-arch
Adds Slot/Endpoint/Input Control Context structs (32-byte layout only --
HCCPARAMS1.CSZ checked live and confirmed 0 against this driver's QEMU
target; 64-byte contexts refuse rather than silently mis-laying-out),
xhci_cmd_address_device(), and a new dev->connect_state
(idle/await-enable-slot/await-address-device) sequencing Enable Slot and
Address Device per connect. Input Context (what the command TRB's
parameter points at) and Device Context (what DCBAA[slot_id] points at)
are separate 64-byte-aligned allocations, lazily created once and reused
across every connect -- single-device driver scope, no free path needed.
A new EP0 Transfer Ring uses the same fixed-ring-plus-Link-TRB pattern as
the Command Ring.

Two facts checked live before writing any context code, not assumed:
HCCPARAMS1.CSZ (32-byte, confirmed) and PORTSC.PED at connect time
(already set -- PORTSC=0x00021203, SuperSpeed -- the test device
self-enables via USB3 link training, so no port-reset state machine was
needed this increment; USB2 would need one, untested). Both diagnostics
also added console_puts/println-based hex logging (xhci_log_hex32()) --
console_println() only takes string literals, no formatted print existed
on this driver's console path before now.

Verified live via QMP hotplug, all three architectures, succeeded on the
first attempt with no debugging needed: "enable slot succeeded" ->
"address device command submitted" -> "address device succeeded" on
every boot.

Also fixes a FABRIC-2.md dependency-direction error from the previous
commit (Address Device is 2f's prerequisite, not the reverse).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 11:44:15 -04:00
Robert Allan JamesandClaude Sonnet 5 6d330efdd8 Artemis Milestone 2e: real connect drives Enable Slot, slot ID correlated
xhci_poll_events()'s Port Status Change connect branch now calls
xhci_cmd_enable_slot() directly (the earlier boot-time smoke test call is
gone), tracked via a new dev->pending_connect_port_id -- since this
driver only ever has one command outstanding at a time, that alone
identifies which port a later Command Completion Event answers, without
needing to match the Command TRB Pointer yet. On success the returned
Slot ID is recorded in a new dev->port_slot_id[], a fixed
uint32_t[XHCI_MAX_TRACKED_PORTS] (32) indexed by port. Disconnect clears
the port's tracked slot (real teardown -- Disable Slot, DCBAA clear,
Section U callback -- is still a later increment).

Fixed array, not heap-allocated: a first attempt sized port_slot_id
dynamically via kmalloc_aligned(dev->max_ports * sizeof(uint32_t), 64)
inside xhci_bringup() and it crashed amd64 with a page fault (IFETCH at
RIP=CR2=0xA0000, the legacy VGA hole) during the unrelated Mama-VM-birth
phase afterward -- a heap-corruption signature, not chased to root cause.
Switching to a fixed array (matching this driver's existing preference
for fixed over dynamic allocation) made the crash go away; the crashing
boot's log is kept (logs/20260822-102516/) as the evidence trail.

Verified live via QMP hotplug, all three architectures: connect ->
"enable slot command submitted" -> "enable slot succeeded", with a
disconnect/reconnect cycle repeating cleanly and no port wedge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 10:33:37 -04:00
Robert Allan JamesandClaude Sonnet 5 dd043bbfeb Artemis Milestone 2e: PORTSC connect/disconnect detection, verified live
xhci_poll_events()'s Port Status Change branch now decodes the Port ID
from the event TRB (XHCI_PSC_EVT_PORT_ID, new in xhci.h), reads that
port's PORTSC.CCS via a new xhci_port_regs() helper, and logs connect vs.
disconnect. Acknowledges by writing back only PP (preserved) and CSC (the
bit being cleared) -- PED/PR/other _C bits written 0 so nothing is
accidentally disabled, reset, or silently cleared, matching the RW1C
discipline already used for ERDP.EHB in 2d.

Verified with the real target scenario via QMP hotplug on all three
architectures: boot with the xHCI controller present but no USB device
attached (confirmed zero port activity at ok>), then live
attach/detach/re-attach of a virtual USB thumb drive
(disk/usb-thumbdrive-test.img via usb-storage on xhci0.0). Full
connect->disconnect->connect cycle confirmed clean (no port wedge) on
amd64; single connect confirmed on aarch64 and riscv64.

Still open: correlating Command Completion Events back to their issuing
command, driving Enable Slot/Address Device from this connect path
(currently only a boot-time smoke test), and the callback surface into
Section U's higher-level code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 10:11:47 -04:00
Robert Allan JamesandClaude Sonnet 5 bb84eba7e3 Artemis Milestone 2e: virtual USB thumb-drive hotplug test + block-layout decisions
Verified live on amd64: booted with the xHCI controller present but no USB
device attached (no Port Status Change at ok>), then hotplug-attached a
virtual USB thumb drive via QMP (usb-storage on xhci0.0, backed by
disk/usb-thumbdrive-test.img) and got an immediate port status change
event -- the real connect trigger Milestone 2e's PORTSC handling will
consume next.

Confirmed blk_subsys_attach_device() (src/block_subsystem.c) is already
the correct integration point for USB -- it already appends a new device
to the end of the existing LBN chain, matching the intended design.
Documented the remaining gaps: no blkio_usb.c backend yet, no hot-detach
path in the device chain yet.

Decided the on-drive layout for USB thumb drives: GPT-partitioned (unlike
artemis.img's whole-device StarForth header), ~1GB metadata partition +
remainder for blocks, 16GB reference drive size, sizing tentative. No GPT
parser exists in kernel code yet -- new prerequisite work for Milestone
2h/3, not blocking current 2e work.

disk/usb-thumbdrive-test.img added as a tracked test fixture, per this
repo's standing convention that virtual disk/thumb-drive images used for
testing are committed, not left in scratchpad.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 09:49:15 -04:00
Robert Allan JamesandClaude Sonnet 5 9c8ad8f6ff Artemis Milestone 2e (in progress): xHCI Command Ring write path proven live
Enable Slot command TRB submitted via a new xhci_submit_command()/
xhci_cmd_enable_slot(), ring doorbell 0, confirmed by a real Command
Completion Event on all three architectures -- the first time this driver
has written a TRB rather than only reading the Event Ring (2d). Added the
Command Ring's previously-missing Link TRB (xHCI 1.2 spec sec 4.9.2) for
wraparound correctness.

Port Register connect/disconnect handling, slot-ID/context bookkeeping,
Address Device, and the callback surface into Section U's code are still
open -- this is the discriminating first step, not full 2e.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 09:37:55 -04:00
Robert Allan JamesandClaude Sonnet 5 2b16daba16 Artemis Milestone 2d: xHCI Event Ring servicing, polled not interrupt-driven
Implements Event Ring TRB parsing and ERDP dequeue-pointer update
(xhci_poll_events(), src/starkernel/usb/xhci.c), called from
sk_repl_idle()'s existing ~1s idle cadence rather than a per-arch
interrupt handler.

A first attempt wired real interrupt delivery (PCI->IOAPIC GSI routing,
a dedicated isr_stub34/vector 0x22, GIC/PLIC routing mirroring
virtio_input.c). Checked live via QMP query-pci before trusting it: the
amd64 PIRQ swizzle formula predicted GSI 16 for the xHCI controller at
PCI slot 4; the real QEMU-assigned IRQ was 10, and embedded ICH9
functions contradicted the same formula too. Reverted all of it back to
the exact committed baseline rather than chasing chipset PIRQ routing
further, and reframed around Section U item 6's own design intent
("interrupt-driven, coarse cadence, cheap early-exit... quick check
blocks... done") via sk_repl_idle() instead -- USB insertion is a
human-timescale event, not a hot path.

Added -device qemu-xhci to all three QEMU launch targets (required for
any of this to be testable). Verified end to end via genuine post-boot
hotplug (QMP device_add/device_del usb-storage): all three architectures
detect a live attach within seconds. A false-alarm heartbeat "freeze"
found mid-verification traced to querying the wrong counter
(vm->heartbeat.tick_count, which only advances during word execution,
not the kernel's real ISR-driven heartbeat_ticks()) -- confirmed via a
temporary diagnostic word, captured and reverted.

Full writeup, including the discarded interrupt-routing attempt and the
false-alarm investigation, in FABRIC-2.md's Milestone 2c/2d entries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 09:25:25 -04:00
Robert Allan JamesandClaude Sonnet 5 c2f1d94c97 Artemis Milestone 2c: xHCI controller bring-up wired, DoE CSV export off by default
xhci_bringup() (HC reset, DCBAA, Command/Event rings, RUN/STOP) was
uncommitted and referenced an XHCI_WAIT_FOR macro that was never defined,
breaking the build. Wired all four wait sites to the existing
xhci_wait_bit() helper instead, matching each register/bit/polarity
needed (halt-before-reset waits for HCH set; HCRST, CNR, and post-RUN
HCH waits all wait for their bit to clear).

Also flipped g_doe_log_enabled's default from 1 to 0 -- the per-tick
[HADES][DOE] CSV export was flooding every boot log and slowing
interactive verification for no reason during ordinary acceptance runs;
HB-ON still re-enables it at the REPL for anyone running an actual DoE
campaign.

Three-arch acceptance: amd64/aarch64/riscv64 all boot clean to ok>,
zero DoE rows in any log. aarch64 and riscv64 both exited cleanly via
BYE with no exception, confirming the earlier SMC->HVC PSCI fix still
holds. Logs and DoE CSV artifacts from this run included.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
2026-08-22 08:33:35 -04:00
Robert Allan JamesandClaude Sonnet 5 5970c54912 Artemis Milestone 2b complete: xHCI PCI discovery and BAR0 mapping
New src/starkernel/usb/ subsystem directory (added to both
LOADER_SRCS_BASE and KERNEL_SRCS_BASE wildcards in Makefile.starkernel,
matching the existing virtio/*.c pattern). xhci_find_and_map() locates
the controller via the already-generic pci_find_first(), enables it,
maps BAR0 via the already-generic pci_map_bar(), and fills in all four
register-region pointers (cap/op/runtime/doorbell) plus max_slots/
max_ports/max_intrs from HCSPARAMS1 -- ready for controller bring-up
(2c) to consume directly.

No pci.c extension needed, per 2a's finding that PCI discovery here is
ID-based lookup (already generic), not class-code scanning. Verified:
clean standalone syntax check, full amd64 kernel build with zero
warnings, live boot still reaches POST 1012/0/0 unaffected (nothing
calls xhci_find_and_map() yet, so this is purely additive).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:58:27 -04:00
Robert Allan JamesandClaude Sonnet 5 94345c24b7 Artemis Milestone 2a complete: xHCI register header, PCI ID confirmed
live via QMP, ring sizing decided

include/starkernel/xhci.h: Capability/Operational/Runtime register
layouts, Port Register Set, Interrupter Register Set, Doorbell Array,
16-byte TRB struct -- all from the xHCI 1.2 spec, no existing
reference in this tree to build from (unlike virtio-blk). volatile
fields, no packed attribute, matching virtio_blk.c's documented
riscv64/QEMU-MMIO precedent. Compile-checked clean, sizeof(xhci_trb_t)
verified == 16.

QEMU qemu-xhci's PCI vendor:device ID (0x1B36:0x000D) confirmed live
via QMP query-pci against a real running instance -- not assumed from
memory, matches the Milestone 1 QMP infrastructure just built.

Ring sizing decided: fixed 256-TRB (one page) Command Ring and Event
Ring, single interrupter -- documented rationale in the header.

Bonus finding: src/starkernel/pci/pci.c already has more reusable
infrastructure than Milestone 2b assumed (pci_find_first is ID-based
lookup already existing; pci_bar/pci_map_bar/pci_enable are already
generic) -- 2b is smaller than originally scoped, noted in the punch
list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:53:16 -04:00
Robert Allan JamesandClaude Sonnet 5 7c6bdb6849 FABRIC-2.md Section X: fix Milestone 2's sub-item labels 3a-3h -> 2a-2h
Leftover from the milestone renumbering -- cross-references elsewhere
already said "Milestone 2e" etc., but the bare sub-item labels inside
Milestone 2's own section still said "3a."-"3h.". Now consistent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:49:54 -04:00
Robert Allan JamesandClaude Sonnet 5 3d91015659 Artemis Milestone 1 complete: QMP socket added to all three QEMU
launch targets, three-arch verified

Makefile.starkernel: added -qmp unix:$QMP_SOCK,server=on,wait=off to
the amd64/aarch64/riscv64 qemu targets, matching the existing serial
chardev socket pattern exactly (same discoverability, same cleanup on
exit). Verified on all three architectures: QMP greeting arrives on
connect, qmp_capabilities handshake succeeds, device_add/device_del
round-trip correctly.

Real finding surfaced during device_add testing (recorded in
FABRIC-2.md's punch list for Milestone 2): the q35 machine's pcie.0
root bus doesn't support runtime PCI hotplug without a bridge --
Milestone 2's qemu-xhci USB controller needs to be present in the
static launch command, with USB devices hot-attached to its bus at
runtime, not the controller itself hot-added.

Also noted: g_doe_log_enabled's default-on per-tick heartbeat CSV
export was briefly mistaken for a hang during aarch64 verification --
it isn't one, just a large volume of routine diagnostic output before
reaching ok>. Not changing the source default; adopting HB-OFF
immediately after boot as the working pattern for the rest of this
punch list's dev work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:48:52 -04:00
Robert Allan JamesandClaude Sonnet 5 0008f19bbb FABRIC-2.md Sections U/W/X: renumber milestones to match actual
execution order, physically reordered in the file

Previously kept stable IDs with a separate "read this note for the
real order" translation layer. Renumbered so the milestone numbers
themselves read top-to-bottom in execution order and physically
reordered the ### Milestone blocks in Section X to match -- no
translation needed anymore. New order: 1=QEMU monitor/QMP socket,
2=USB hardware stack, 3=block subsystem extensions, 4=drive/credential
security, 5=console/VM key-match binding, 6=PKI signing chain,
7=contributor capsules/trust tiers, 8=bare-metal USB boot (still
second-to-last, not first -- QEMU-first per Captain Bob's explicit
reinforcement), 9=networking (unchanged, still last). All cross-
references between milestones (including Milestone 2's internal
sub-item labels 2a-2h) updated to match throughout Sections U, W, and
X.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:32:57 -04:00
Robert Allan JamesandClaude Sonnet 5 ef83ba46c8 FABRIC-2.md Sections U/X: correct the snakeoil-cert chain -- one
continuous chain, not two parallel paths; resolves Milestone 7's
bootstrapping question precisely, not just for dev/test

Captain Bob's precise correction: "my own real root CA -> snakeoil
embedded cert -> blob & capsule + MANIFEST.md" is one chain. The
snakeoil intermediate is CA-signed, not self-signed/untrusted --
"snakeoil" names its informal/private-project status, not that it
lacks a real trust root. This means Milestone 7's CA-bootstrapping
question (how does the CA public key get into the kernel without
being just another unverifiable capsule) is resolved outright, not
just worked around for dev/test builds as the previous draft of
Section U's fourth addendum implied: trust is established once, at
build time, by whoever holds the real root CA and produces the build.
No kernel-boot-time verification against a hardcoded CA public key is
needed at all. Corrected both Section U item 20 and Milestone 7's
punch list in Section X to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:25:31 -04:00
Robert Allan JamesandClaude Sonnet 5 d42a81961c FABRIC-2.md Section U fourth addendum: user-role tiers, and snakeoil
cert resolves Milestone 7's bootstrapping question for dev/test builds

Three distinct user-role tiers clarified (builder+dev, SDK-only dev,
no-SDK user) -- refines the trust-tier question beyond a simple core/
contrib boundary. More importantly: a snakeoil cert embedded directly
into each build (not loaded as a capsule, not verified against an
external CA at boot) is the actual answer to the CA-bootstrapping
problem Section X's Milestone 7 punch-list surfaced, at least for dev/
test builds -- trust is established at build time, sidestepping the
runtime chicken-and-egg entirely for that case. Two paths into a build
confirmed: snakeoil-signed, or code review + inclusion in the source
repo -- the latter likely makes at least one of Milestone 8's four
spitballed trust-tier directions (signature-authority tiers)
redundant, worth revisiting before picking one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:21:42 -04:00
Robert Allan JamesandClaude Sonnet 5 d33b68b2d5 FABRIC-2.md Sections W/X: correct execution order -- validate Artemis
in QEMU first, defer real-hardware USB boot to last; add UEFI-only
boot-path constraint

Captain Bob's explicit correction: real-hardware boot is "difficult
and lots of blind guesswork" (no serial log, unknown firmware quirks)
and isn't worth attempting until there's a working Artemis subsystem
to actually demonstrate, not just an empty kernel proving UEFI boot
works. QEMU's own USB hotplug emulation is sufficient to build and
validate the entire home-blocks subsystem without touching real
hardware at all.

Milestone IDs in Section X kept stable (not renumbered, to avoid
breaking cross-references between milestones) with an explicit
execution-order note instead: 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 1,
networking (9) still deferred past all of them.

New scope constraint captured for whenever Milestone 1 resumes: UEFI-
only boot path, no legacy BIOS/MBR, no GRUB2 -- starkernel_loader.efi
is meant to be the entire boot path, not one stage in a longer chain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:15:05 -04:00
Robert Allan JamesandClaude Sonnet 5 1a6b164fdc FABRIC-2.md Section X: Artemis punch list -- deep, function-level task
breakdown across all 9 milestones, no code written

Nine milestones, in Section W's sequencing order, each broken down to
single-function granularity per Captain Bob's explicit request:

1. Bare-metal USB boot (demo mode) -- the actual near-term milestone,
   ~9 concrete steps from ISO build through real-hardware validation.
2. QEMU monitor/QMP socket -- small dev-workflow unblock.
3. USB hardware stack -- the hard prerequisite, broken into 8 sub-areas
   (spec groundwork, PCI discovery, controller bring-up, interrupt/
   event handling, hotplug detection, device enumeration, Bulk-Only
   Transport read/write, block-subsystem integration) since nothing
   in this tree has ever touched USB before.
4. Block subsystem extensions (identity-derived ranges, drive map,
   migration state machine, sk_repl_idle() body, unclean-removal
   handling).
5. Drive/credential security (foreign-drive signature, zuse one-way
   burn extending the existing acl_pinned mechanism).
6. Console/VM key-match binding.
7. Kernel/capsule PKI signing chain, including a real open
   bootstrapping question (how the CA public key itself gets into the
   kernel without being just another capsule) not previously
   surfaced in Sections U/V/W.
8. Contributor capsules/trust tiers.
9. Networking -- deliberately left unexpanded, deferred per Captain
   Bob's own sequencing, not premature-detailed.

Every item cross-references back to the specific Section U requirement
and Section V verified-status finding it comes from. Still direction
only -- no code, no capsule work started.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:09:36 -04:00
Robert Allan JamesandClaude Sonnet 5 ec78b28f11 FABRIC-2.md Section W: Artemis concept board -- consolidated vision in
one place, pulling together Sections U and V

Single-read consolidation of the whole Artemis thumbdrive/home-blocks/
PKI vision: one-paragraph statement of intent, a component table
cross-referencing each piece to its detail (Section U) and verified
status (Section V), and explicit sequencing with the actual near-term
milestone first -- bare-metal boot from a physical USB stick in demo/
"try it" mode, confirmed NOT gated on the USB hardware driver gap
since booting from USB is a UEFI firmware responsibility, not a kernel
one. The existing starkernel.iso/raw-disk-image build artifacts (built
on every QEMU launch already) are, mechanically, what gets dd'd onto a
physical drive for this. Two 64GB SanDisk drives confirmed on hand and
available now. Everything else in the concept board explicitly waits
on the USB hardware driver as the singular hard prerequisite.

Still direction only -- nothing implemented, no hardware testing done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 07:05:57 -04:00
Robert Allan JamesandClaude Sonnet 5 15640988f7 FABRIC-2.md Section V: complete gap analysis of the Artemis home-
blocks/thumbdrive/PKI subsystem against the actual codebase

Systematic pass over every requirement gathered in Section U, each
verified directly against the tree rather than recalled. Organized by
area (physical block layout, USB hardware, drive/credential security,
console/VM binding, capsule signing/PKI, contributor trust tiers,
networking, dev workflow).

Found more than expected already exists and is reusable as-is: the
block address space and device-chain abstraction, sk_repl_idle()'s
empty trigger hook, capsule_birth_baby()'s on-demand VM spin-up,
acl_pinned's one-way-ratchet mechanism (a direct precedent for the
zuse one-way-burn requirement), arbitrary binary payload capsule
embedding (proven by the font capsule), the manifest's already-
documented Ed25519 anchor point, and the live-boot ISO pipeline.

Confirmed real, clearly-scoped gaps with nothing partially started:
identity-to-block-range derivation, the block migration state machine,
drive-map format, console/VM key binding, all signature/cert
verification code, magic-number content-type/foreign-drive detection,
the contributor trust-tier flag, QEMU monitor socket exposure, and the
install path.

Identifies the USB stack itself as the one hard, load-bearing
prerequisite gating almost every other gap from being testable at all,
even in QEMU -- the honest first-cut recommendation if a concrete next
milestone gets picked from this analysis.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 06:58:42 -04:00
Robert Allan JamesandClaude Sonnet 5 e3df22a5af FABRIC-2.md Section U third addendum: contributor capsule directory,
sequencing, and spitballed trust-tier ideas -- still brainstorming,
nothing implemented

Captures the QEMU-dev-environment assumption, confirms capsules/contrib/
would fit the existing subdirectory convention (artemis/, common/,
fonts/, hermes/ already exist), and confirms via mkcapsule.c that no
provenance/trust-tier distinction exists today -- every non-Mama-init
capsule gets identical FLAG_PRODUCTION|FLAG_EXPERIMENT unconditionally.
Explicit sequencing: ACL/PKI work closes first, then contrib-directory/
trust-tier work, then networking (downloadable capsules named but not
scoped). Closes with four explicitly-unvetted spitballed directions on
the trust-tier question, requested as free brainstorm: a new
FLAG_CONTRIB bit, signature-authority tiers hanging off the cert chain,
block-namespace sandboxing for contrib capsules, and QEMU-vs-real-
hardware conditional signature enforcement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 06:43:11 -04:00
Robert Allan JamesandClaude Sonnet 5 7b263f3872 FABRIC-2.md Section U second addendum: kernel/capsule signing design,
extending items 7-8 -- still brainstorming, nothing implemented

Five more points captured: (10) intermediate cert embedded as a capsule
blob (CA stays external/unrevocable), reusing the capsule system's
already-proven arbitrary-binary-payload capability (the font capsule is
existing precedent); (11) two-stage validation chain, both stages net
new code; (12) confirmed via tools/mkcapsule.c's own header comment
that Ed25519 signing hanging off the xxHash64 manifest column was
already the documented Phase 8 plan, independent of this conversation
-- strong validation of the whole direction; (13) signing granularity
is per-capsule, matching the existing hash column's 1:1 file
granularity exactly; (14) content-type detection via magic numbers
rather than a new MIME-type field, and confirmed to be the same
mechanism as item 7's foreign-drive detection -- one shared
byte-sniffing primitive plausibly serves both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 06:38:16 -04:00
Robert Allan JamesandClaude Sonnet 5 21168f99da FABRIC-2.md Section U addendum: foreign-drive protection, zuse one-way
burn, console/VM key-match attachment -- still brainstorming, nothing
implemented

Three more requirements captured while fresh, same design session:
(7) home-blocks write path must check for a home-blocks signature
before ever writing to an inserted drive, warn and refuse on foreign/
unrecognized/blank media instead of silently claiming it; (8) zuse
credential minting is one-way, asymmetric with an operator drive's
presumed re-provisioning path; (9) console/VM split -- console is
generic and shared, drive insertion spins up a per-identity VM (a
Tripod-birth-mechanism consumer), and console-to-VM attachment is a
key/lock match, structurally similar to ACL-PIN's existing key model
but not yet confirmed to reuse it directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 06:30:43 -04:00
Robert Allan JamesandClaude Sonnet 5 afe64ba537 FABRIC-2.md Section U: Artemis USB thumb-drive / home-blocks design
direction notes -- brainstorming only, nothing implemented

Captures the direction from a design conversation immediately following
the ACL-TTL campaign close (Section T): Phase 8 PKI/thumbdrive context,
confirmation that zero USB code exists anywhere in the kernel today,
verification that the block-address-space layout the conversation
converged on independently already matches block_subsystem.h's own
documented (unimplemented) chained-device design almost exactly, and
six requirements gathered in order (no quota for now, re-insertion
consistency, identity-derived not attach-order-derived block ranges,
drive-carries-its-own-map, bidirectional transparent block migration
as a state machine, and sk_repl_idle() as the likely trigger hook --
already an empty coarse-cadence placeholder found during Section R).

Explicitly not a spec or plan of record -- written up so the next
session starts from an accurate baseline instead of re-deriving the
shape from scratch. No code, no design doc, no capsule work started.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 06:20:35 -04:00
Robert Allan JamesandClaude Sonnet 5 f2e3bb1a90 ACL-TTL overhead: full 36-cell campaign complete (6 seeds), FABRIC-2.md
Section T -- +0.0603%, final accepted figure

Extended Section S's 3-seed/9-pair campaign to 6 seeds/18 pairs (36
cells) per Captain Bob's request for a fuller campaign before moving
on. All 36 cells: 480/480 rows, 0 errors, 17,280/17,280 rows total.

Every one of 18 disabled cells reads exactly 261063 ticks -- CV=0.000%
across all 3 architectures and 6 seeds, zero exceptions. Every enabled
cell's tick count is fully determined by seed alone, identical across
all 3 architectures, zero exceptions. Pooled overhead across all 18
pairs: +0.0603% (mean +0.0603%, stdev 0.0008%, range +0.0598%-
+0.0617%) -- statistically indistinguishable from Section S's 9-pair
figure, now confirmed over double the data with 3 entirely new seeds.

This closes the ACL-TTL overhead measurement line of investigation
(Sections P, Q, R, S, T). +0.0603% is the final accepted figure.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 23:46:02 -04:00
Robert Allan JamesandClaude Sonnet 5 392561e7de ACL-TTL tick campaign extension checkpoint: 34/36 cells
riscv64/99999/disabled, aarch64/11111/disabled added. All 480/480
rows, 0 errors. 2 cells remain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 23:35:50 -04:00
Robert Allan JamesandClaude Sonnet 5 a52fcf0367 ACL-TTL tick campaign extension checkpoint: 32/36 cells
riscv64/11111/enabled, aarch64/24680/enabled added. All 480/480 rows,
0 errors. 4 cells remain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 23:24:13 -04:00
Robert Allan JamesandClaude Sonnet 5 db05f29e49 ACL-TTL tick campaign extension checkpoint: 30/36 cells (5/6)
aarch64/99999/enabled, amd64/99999/disabled added. All 480/480 rows,
0 errors. 6 cells remain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 23:12:27 -04:00
Robert Allan JamesandClaude Sonnet 5 ef74e45a3b ACL-TTL tick campaign extension checkpoint: 28/36 cells
aarch64/99999/disabled, riscv64/99999/enabled added. All 480/480 rows,
0 errors. 8 cells remain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 23:00:02 -04:00
Robert Allan JamesandClaude Sonnet 5 2be3c8c68e ACL-TTL tick campaign extension checkpoint: 26/36 cells
amd64/99999/enabled, aarch64/24680/disabled added (cell 26 needed a
retry after an unexplained external SIGTERM killed the qemu process
mid-boot -- matches a previously-noted, still-unexplained SIGTERM
recurrence from a process named "claude", first seen 2026-08-18;
1-line stub log from the killed attempt kept as audit trail). All
successful cells: 480/480 rows, 0 errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 22:48:14 -04:00
Robert Allan JamesandClaude Sonnet 5 a5cd1b76c8 ACL-TTL tick campaign extension checkpoint: 24/36 cells (2/3 done)
amd64/24680/disabled, amd64/24680/enabled, aarch64/11111/enabled
added. All 480/480 rows, 0 errors. Cross-arch consistency continues
holding: seed 24680 gives 261219 on both riscv64 and amd64; seed 11111
gives 261222 on both amd64 and aarch64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 22:35:17 -04:00
Robert Allan JamesandClaude Sonnet 5 f8693d50be ACL-TTL tick campaign extension checkpoint: 21/36 cells (3 new seeds)
Extended from 3 to 6 seeds (added 24680/11111/99999) per Captain Bob's
request for a fuller campaign before moving on. amd64/11111/enabled,
riscv64/24680/enabled, riscv64/24680/disabled added. All 480/480 rows,
0 errors. Disabled-arm determinism (261063) holding across new seeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 22:18:19 -04:00
Robert Allan JamesandClaude Sonnet 5 e9d5353b6e ACL-TTL overhead: full 18-cell campaign complete, FABRIC-2.md Section S
-- +0.0604% mean, architecture-independent, fully deterministic

All 18 cells (9 arch/seed pairs x disabled/enabled, zuse-authenticated
throughout) complete: 8,640/8,640 rows, 0 errors. Every disabled cell
reads exactly 261063 ticks -- CV=0.000% across all 3 architectures and
3 seeds. Every enabled cell's tick count depends only on seed, identical
across all 3 architectures for a given seed. Pooled overhead: +0.0604%
(mean +0.0604%, stdev 0.0010%, range +0.0598%-+0.0617%).

This is now the accepted ACL-TTL overhead figure for this workload,
superseding Section P's invalidated wall-clock numbers (ACL never
actually armed) and refining Section R's single-pair pilot (+0.0448%,
n=1) to a tight, fully-reproducible, architecture-independent result
across 9 independent pairs.

One tooling bug fixed mid-campaign (cells 1-3): tick-extraction regex
missed the "[Hera] " console-tagger line prefix; underlying VM runs
were unaffected, affected cells' values recovered by hand from their
serial logs before the fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 15:06:36 -04:00
Robert Allan JamesandClaude Sonnet 5 0f0f28e784 ACL-TTL tick campaign checkpoint: 17/18 cells
aarch64/13579/disabled, riscv64/13579/disabled added. All 480/480
rows, 0 errors. 1 cell remains.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 15:00:32 -04:00
Robert Allan JamesandClaude Sonnet 5 e12705983c ACL-TTL tick campaign checkpoint: 15/18 cells
aarch64/12345/enabled, riscv64/67890/disabled added. All 480/480 rows,
0 errors. 3 cells remain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:48:46 -04:00
Robert Allan JamesandClaude Sonnet 5 436633a731 ACL-TTL tick campaign checkpoint: 13/18 cells
amd64/67890/disabled, riscv64/13579/enabled added. All 480/480 rows,
0 errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:37:05 -04:00
Robert Allan JamesandClaude Sonnet 5 9c6f6ec57c ACL-TTL tick campaign checkpoint: 11/18 cells
riscv64/67890/enabled, aarch64/67890/enabled added. All 480/480 rows,
0 errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:27:44 -04:00
Robert Allan JamesandClaude Sonnet 5 3b16c48ff9 ACL-TTL tick campaign checkpoint: 9/18 cells (halfway)
aarch64/12345/disabled, aarch64/67890/disabled added. All 480/480
rows, 0 errors. Pattern holding: disabled delta=261063 identical
across every arch/seed so far; enabled clusters at 261219/261224
depending on seed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:15:57 -04:00
Robert Allan JamesandClaude Sonnet 5 c1622aaba8 ACL-TTL tick campaign checkpoint: 7/18 cells
amd64/12345/enabled, aarch64/13579/enabled, amd64/67890/enabled added.
All 480/480 rows, 0 errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:01:11 -04:00
Robert Allan JamesandClaude Sonnet 5 d90f28b9da ACL-TTL tick campaign checkpoint: 4/18 cells (zuse-authenticated, real
enforcement)

Automated driver (scratchpad run_cell.sh) replicating Section R's
validated pilot procedure per cell: independent clean build, boot,
load doe.4th, load ACL.4th + ZUSE-AUTHENTICATE for enabled cells,
HB-OFF/HB-ON bracketed HEARTBEAT-TICKS@ before/after a seed/30-rep
EXEC-DOE run. Randomized 18-cell order (9 arch/seed pairs x 2 ACL
states), same discipline as Section P/Q.

4/18: amd64/13579/enabled, riscv64/12345/enabled,
riscv64/12345/disabled, amd64/12345/disabled -- all 480/480 rows, 0
errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 13:44:04 -04:00
Robert Allan JamesandClaude Sonnet 5 70c259dad0 Revert HEARTBEAT-TICKS@ to vm->heartbeat.tick_count; FABRIC-2.md Section R:
find and fix the real ACL-TTL measurement bug (zuse session never
authenticated, ACL enforcement never active)

Two mistakes corrected in sequence, both documented in full in
FABRIC-2.md Section R:

1. HEARTBEAT-TICKS@ was swapped to read heartbeat_ticks() -- a newer,
   kernel-only ISR hardware-timer counter (src/starkernel/heartbeat.c,
   the M5 TIME-TRUST engine) -- based on a misreading of which counter
   "the one clock" law refers to. Reverted to vm->heartbeat.tick_count,
   Loop #7 "Adaptive Heartrate", the actual year-plus-old counter the
   whole physics runtime is built on. Removed the now-irrelevant
   HEARTBEAT-PERIOD-NS@ accessor added to diagnose the wrong counter's
   adaptive re-arm period. Three-arch QEMU re-acceptance: POST 1012/0/0
   on amd64/aarch64/riscv64, HEARTBEAT-TICKS@ confirmed returning 77
   (matching the original pre-heartbeat_ticks() acceptance) on all three.

2. The real bug, found after the revert: every "ACL enabled" measurement
   in this investigation (Section P's 18-cell campaign, Section Q's
   pilot) loaded ACL.4th and ran EXEC-DOE from the bare `ok>` prompt
   without ever authenticating a zuse session. repl.c:303 keeps
   emergency_console=1 until zuse_session=1; vm_core.c:755 skips the
   entire ACL check block (TTL decrement and acl_recheck()) whenever
   emergency_console is set. ACL was configured but never armed.
   capsules/zuse.4th's pre-existing self-pin bug means the documented
   automatic zuse activation doesn't work either (still flagged, not
   fixed) -- worked around by invoking the directly-registered
   ZUSE-AUTHENTICATE word explicitly.

Validated pilot (amd64, seed 12345, 30 reps, same build, disabled vs.
genuinely zuse-authenticated-enabled): +117 ticks, +0.0448% overhead.
Disabled-arm determinism double-confirmed (261064 ticks, exact repeat
on a fresh boot) -- the 117-tick difference is real signal, not noise.
Reconciles with the original ACL-RWT campaign's own heartbeat-tick
result (+0.0054%-0.0088%, same order of magnitude). Section P's
wall-clock numbers and Section Q's "instrument blind" conclusion are
both marked invalidated/corrected in place, not deleted.

n=1 per arm, one architecture -- not yet a full campaign. Scoped as
next step, not undertaken in this pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 11:22:56 -04:00
Robert Allan JamesandClaude Sonnet 5 4076a01c35 Fix HEARTBEAT-TICKS@: read heartbeat_ticks() (ISR hardware timer), not
vm->heartbeat.tick_count (FORTH-dispatch counter)

Captain Bob's law is unambiguous: the adaptive heartbeat is the one and
only clock, full stop. The first cut of this word read the wrong
counter under that name -- vm->heartbeat.tick_count is a colon-word-
dispatch counter gated at a fixed cadence (frozen during idle, blind to
per-dispatch CPU cost, see FABRIC-2.md Section Q). The real adaptive
heartbeat is heartbeat_ticks() in src/starkernel/heartbeat.c, driven
directly by the ISR-latched 100Hz hardware timer -- genuinely
time-based, confirmed advancing during idle wall-clock time on all
three architectures (amd64 4039->5510, aarch64 6126->7607, riscv64
2965->4466, each over ~15s idle). Kernel build only (__STARKERNEL__);
hosted build has no ISR timer and keeps the old fallback.

Three-arch QEMU acceptance: POST 1012/0/0 on each, word live-tested.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 09:33:17 -04:00
Robert Allan JamesandClaude Sonnet 5 3998ce6aaf FABRIC-2.md Section Q: heartbeat-tick ACL-TTL remeasurement finds the
instrument blind to the effect, not a corrected number

Per Captain Bob's correction (heartbeat tick counter is the sole
canonical clock, not wall-clock), added HEARTBEAT-TICKS@ and re-ran the
ACL-TTL overhead measurement using tick deltas. Diagnostics confirmed
the counter is a FORTH-level colon-word-dispatch counter (frozen at
idle, jumps with real work) -- not a wall-clock proxy. A pilot pair
(amd64, seed 12345, 30 reps, ACL disabled vs enabled) produced
byte-identical deltas (261064 ticks both runs): acl_recheck() runs at
the C dispatch level and doesn't change which/how many colon words
execute, so it's invisible to a counter gated on colon-word-entry
count. Root-caused, not proceeding to the full 18-cell campaign --
every cell would read +0.00% by construction. Section P's wall-clock
numbers stand as the best estimate on record pending a instrument that
can see per-dispatch cost rather than control-flow shape.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 23:28:05 -04:00
Robert Allan JamesandClaude Sonnet 5 a7a837e136 Add three-arch acceptance boot logs for HEARTBEAT-TICKS@
amd64/aarch64/riscv64 QEMU serial logs from the acceptance run for
commit 0b11f92 -- POST 1012/0/0 and HEARTBEAT-TICKS@ live-tested on
each architecture.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 23:10:46 -04:00
Robert Allan JamesandClaude Sonnet 5 0b11f92102 Add HEARTBEAT-TICKS@: read-only heartbeat tick counter accessor
The adaptive heartbeat tick counter (vm->heartbeat.tick_count) is the
project's sole canonical clock for timing measurements -- host wall-clock
is not a valid substitute. Exposes it read-only so DoE/overhead campaigns
can measure elapsed ticks instead of wall-clock deltas.

Verified: three-arch QEMU acceptance (amd64/aarch64/riscv64), POST
1012/0/0 on each, HEARTBEAT-TICKS@ live-tested returning a real non-zero
count on all three.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 23:10:38 -04:00
Robert Allan JamesandClaude Sonnet 5 6e7323b3b8 ACL-TTL overhead: paired 18-cell measurement complete, FABRIC-2.md Section P
Full 18-cell paired campaign (9 arch/seed pairs x ACL disabled/enabled)
complete: 8,640/8,640 rows, all 16 cfg values x 30 each in every cell,
zero errors. Confirmed capsules/zuse.4th's ACL-ZUSE-BOOT self-pin bug
(self-pin placed inside its own colon definition, causing a genuine
forward-reference failure) is isolated from the core ACL enforcement
mechanism -- verified via live VM state query on multiple cells that
ACL-INIT-PRIMITIVES and EXEC/BYE pinning both complete correctly
regardless.

Result: +5.30% pooled overhead, +4.42% unweighted mean across the 9
pairs (sd 6.77%), paired t=2.043 (df=8) -- not significant at p<0.05.
Documented honestly as a real positive trend that doesn't establish a
precise percentage with confidence, given wall-clock timing's noise
floor is comparable to the effect size -- unlike the original ACL-RWT
campaign's VM-internal tick-counter methodology. A tighter measurement
(more replications, or reading a VM-internal counter directly) is
scoped as a next step, not attempted here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 19:41:55 -04:00
Robert Allan JamesandClaude Sonnet 5 6a71f503a4 Checkpoint: paired ACL-TTL overhead measurement, 15/18 cells
Cells 13-15 complete and verified (480/480 rows, 16/16 cfg coverage,
zero errors each): amd64/13579 enabled, riscv64/67890 enabled,
aarch64/67890 disabled. 3 cells remaining.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 19:21:35 -04:00
Robert Allan JamesandClaude Sonnet 5 becae2a763 Checkpoint: paired ACL-TTL overhead measurement, 12/18 cells (2/3)
Cells 10-12 complete and verified (480/480 rows, 16/16 cfg coverage,
zero errors each): amd64/67890 enabled, riscv64/13579 enabled,
riscv64/67890 disabled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 19:03:37 -04:00
Robert Allan JamesandClaude Sonnet 5 1880e78a1a Checkpoint: paired ACL-TTL overhead measurement, 9/18 cells (halfway)
Cells 7-9 complete and verified (480/480 rows, 16/16 cfg coverage, zero
errors each): aarch64/13579 enabled, amd64/13579 disabled,
amd64/12345 disabled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 18:48:25 -04:00
Robert Allan JamesandClaude Sonnet 5 e7b7f45d60 Checkpoint: paired ACL-TTL overhead measurement, 6/18 cells
Cells 4-6 complete and verified (480/480 rows, 16/16 cfg coverage, zero
errors each): aarch64/12345 enabled+disabled (a real pair: 310.5s vs
283.0s, +9.7% in the expected direction), riscv64/13579 disabled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 18:27:01 -04:00
Robert Allan JamesandClaude Sonnet 5 f0b0c6d683 Checkpoint: paired ACL-TTL overhead measurement, 3/18 cells
In-progress paired ACL-enabled/disabled campaign (18 cells: 3 seeds x 3
ISAs x 2 ACL states, randomized order, one continuous sitting per
Section O's naming/scoping ruling -- calling this "ACL-TTL overhead",
not "ACL-RWT", since the RWT mechanism no longer exists in the codebase).

Real finding along the way, not blocking: capsules/zuse.4th's
ACL-ZUSE-BOOT places its own self-pin inside its own colon-definition
body instead of after the closing ";", causing a genuine forward-
reference failure at capsule-load time. Confirmed via live VM state
query (EXEC's ACL-MODE@/ACL-PINNED? and DOE-WORK's ACL-MODE@) that this
does NOT affect the core ACL enforcement mechanism itself --
ACL-INIT-PRIMITIVES correctly stamps the whole dictionary, ACL-BOOT
correctly pins EXEC/BYE to STRICT -- so it doesn't invalidate this
measurement. Not fixed, flagged only.

3 cells complete and verified (480/480 rows, 16/16 cfg coverage, zero
errors each): riscv64/12345 disabled+enabled, aarch64/13579 disabled.
Cell 3's timing is mtime-based/approximate rather than precise
wall-clock -- a multi-hour session gap landed inside its measurement
window, contaminating the direct stopwatch reading; the log file's own
last-write mtime is used as a corrected proxy instead, noted as such in
timing.csv.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 18:02:59 -04:00
Robert Allan JamesandClaude Sonnet 5 900fa71d3a FABRIC-2.md: record the corrected-shuffle campaign/report, and a real
ACL-RWT naming/dead-code finding found while scoping the next step

Section O: points to the 127-page deep-dive report and corrected
dataset already committed (dbe4b67, cf5b08f), records the headline
determinism findings, and documents a real finding surfaced while
looking at ACL's current state before implementing a paired
ACL-enabled/disabled measurement -- the "ACL-RWT" name traces to a
Rolling Window of Truth TTL mechanism that ACL.4th's own comments
record as dead code from the day it was written (removed 2026-07-08,
never reachable by the C hot path). The original June 2026 campaign
predates that removal by three weeks, raising a real historical-
accuracy question about what its own overhead numbers measured -- not
settled here, just flagged. Ruled: future paired measurements use an
accurate name ("ACL-TTL overhead") since RWT no longer exists in the
codebase at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:24:51 -04:00
Robert Allan JamesandClaude Sonnet 5 cf5b08fb65 Stadium relaunch: full 127-page deep-dive report -- per-cell, per-ISA,
every factor interaction, and a raw-data appendix

Expanded the campaign-mechanism validation report from a condensed
6-page summary into the full depth Captain Bob asked for: analyze all 9
cells as a conglomerate Latin square, then dive into each cell's own
data, then cover every within-ISA and cross-factor interaction
explicitly rather than averaging it away.

Report structure (127 pages, compiled clean, no undefined references):
- Front matter: context, methodology, the SWAP-MTX bug narrative
  (console-interleaving fix + the Fisher-Yates correctness bug and its
  fix, both already committed separately)
- Layer 1: aggregate 3x3 Latin square (heatmap, invariant-metrics table)
- Per-Cell Deep Dive (9 sections): cfg-level distribution, summary
  table, and a rep-order execution-trajectory chart per cell -- the
  trajectory charts are what actually visualize the order-dependence
  finding rather than just stating it
- Per-ISA Deep Dive (3 sections): within-architecture seed comparison
  (violin plots, Kruskal-Wallis, per-factor main effects)
- Factor Interactions (6 sections, every pairwise combination of the 4
  L8 binary factors): both infer_dec_q and early_exit interaction plots
  faceted by architecture, plus the three-way
  factor x factor x architecture significance test
- Per-Factor Response (4 sections): linear response by architecture,
  with an explicit note that a true quadratic term isn't identifiable
  from this 2-level factorial design
- Appendix: full run_id-ordered raw data, all 4,320 rows across all 9
  cells, as the primary-source backing for every statistic above

Generated programmatically (analyse_stadium_relaunch_fixed.R for the
aggregate layer, generate_stadium_deepdive.R for the per-cell/per-ISA/
interaction/appendix layers) rather than hand-authored, since content at
this scale needs to be data-driven to stay honest.

Also includes analyse_stadium_relaunch.R, the earlier script built
against the pre-fix (buggy-shuffle) dataset -- superseded but kept for
the record, matching how the underlying data commits were handled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 13:10:01 -04:00
Robert Allan JamesandClaude Sonnet 5 dbe4b671a1 Re-run ACL-RWT relaunch campaign against the fixed SWAP-MTX shuffle
Full 9-cell campaign re-run from scratch (fresh clean build per cell,
fully randomized order, one continuous sitting) using the corrected
Fisher-Yates shuffle. All 9 cells now produce a genuinely valid uniform
permutation: 480/480 rows, all 16 cfg values represented exactly 30 times
each, zero errors -- across all three architectures and all three seeds.

The previous relaunch campaign (experiments/bare_metal/runs/
acl-rwt-20260820/, committed 79d160c) ran against the buggy shuffle and
is superseded by this one for any analysis; kept as-is per policy
(audit artifacts, not deleted), not treated as the canonical dataset.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 12:08:48 -04:00
Robert Allan JamesandClaude Sonnet 5 7e2fd9f044 Fix SWAP-MTX: Fisher-Yates shuffle was never actually shuffling correctly
Found while building the analysis report for the ACL-RWT relaunch
campaign: cfg=0 was missing from run coverage for 2 of 3 seeds, reproduced
identically across all three architectures. Root-caused rather than
worked around, per Captain Bob's "this is worrisome."

SWAP-MTX (capsules/doe.4th Block 2104) never actually swapped two
RUN-MATRIX cells -- it performed a lossy one-way copy (second MATRIX!
call mis-targeted mat[i] again instead of mat[j]). Confirmed by direct
empirical test on the hosted build: INIT-MATRIX gives mat[0]=0, mat[5]=5;
after 0 5 SWAP-MTX, mat[0]=0 (unchanged, should be 5) and mat[5]=0
(correct), with the original value 5 permanently destroyed. Every
Fisher-Yates shuffle this mechanism has ever run silently duplicated some
values and dropped others -- not a true permutation. Not new, not
introduced by item 4.6/Stadium work; predates this session.

Fixed with explicit temp variables (SW-I/SW-J/SW-VI/SW-VJ), trivially
verifiable by inspection over clever stack juggling. Verified on the
hosted build for all three seeds used by the relaunch campaign: each now
produces all 16 cfg values exactly 30 times, run_id 0-479 fully distinct.
Three-arch QEMU acceptance clean: 1012/0/0 POST on all three, identical
dict_hash (expected -- doe.4th isn't C-registered or auto-loaded at
boot). BLOCK_MAP.md correctly shows only doe.4th's own hash changed.

Also includes the R analysis/chart pipeline (analyse_stadium_relaunch.R)
built for the relaunch campaign report, and the three acceptance boot
logs.

Retroactive caveat: the relaunch campaign's own run-matrix coverage
(experiments/bare_metal/runs/acl-rwt-20260820/) is not a valid uniform
permutation, having run against the buggy shuffle. Whether to re-run it
against the fix is a separate call, not made here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 10:56:12 -04:00
Robert Allan JamesandClaude Sonnet 5 79d160c1ca FABRIC-2.md: ACL-RWT-style 3x3 Latin square re-run on Stadium substrate (item 5.1/F.3)
Found and fixed a real bug before any campaign work could start: EXEC-DOE's
own CSV output was almost entirely lost to console interleaving with the
routine per-tick heartbeat export -- same bug class as Section L's PLOT
case. Fix: HB-OFF immediately before EXEC-DOE, HB-ON after DOE: complete.
Confirmed HB-ON-first (the reverse order) does NOT fix it -- tested
directly, row loss recurred identically.

Also found: L8-DOE/WL-HI/WL-LO (the mechanism bare_metal/README.md
describes as auto-run) don't exist anywhere in capsules/, and Makefile.
starkernel's DOE_SEED variable is declared but never referenced -- both
vestigial, matching Section K's earlier staleness finding.

Built QEMU-serial-socket injection tooling (socat) to drive EXEC-DOE
interactively after boot, since it requires live REPL input, not just
observation. Two real defects found and fixed in that tooling itself: a
log-discovery race (self-excluding the very log it needed to find,
causing two separate stuck-injector incidents, one overnight) and an
unredirected background launch that deadlocked socat on a full stdout
pipe. Both fixed by having the orchestrator pass exact log/socket paths
directly and always launching through the harness's tracked-background
mechanism.

First full campaign attempt ran all 9 cells as three ISA-blocked loops,
reusing one build per architecture -- caught mid-run: this confounds ISA
with time/session-order, invalidating the Latin square design. Discarded
(logs kept as audit artifacts, not treated as valid data) and re-run
clean: all 9 (arch, seed) cells in fully randomized order, fresh clean
rebuild before every single cell, one continuous sitting. Result:
4,320/4,320 rows captured, zero VM errors anywhere.

This validates the campaign mechanism runs cleanly and reproducibly under
the post-4.6 Stadium substrate -- satisfies item 5.1's own concern that a
green POST suite isn't evidence determinism holds post-migration. It does
NOT produce an ACL-RWT overhead number: ACL.4th is not self-activated in
this repo's default init.4th, so these 9 cells ran with ACL inactive.
Reproducing the original +0.0054%-+0.0088% measurement needs a paired
ACL-enabled/disabled run using this now-validated mechanism -- scoped,
not attempted here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 09:16:18 -04:00
Robert Allan JamesandClaude Sonnet 5 ea5d2c7ceb FABRIC-2.md: riscv64 re-verified 30/30 PASS for item 4.6's Artemis stress campaign
Closes the last open item in Section H. amd64 and aarch64 were already
confirmed post-quota-grant-fix; riscv64 was pending. Temporarily re-enabled
ART-STRESS-CAMPAIGN (block 4170, disabled since Section L) for this one
headless run, confirmed 30/30 reps / 1500/1500 trials passed with a clean
CAMPAIGN-DONE, then reverted the capsule back to its committed disabled
state (byte-identical to HEAD, mkcapsule --lint clean).

Two SUMMARY lines (reps 4, 15) printed visually garbled from concurrent
[HADES][DOE] console writes -- confirmed cosmetic only by grepping the full
log for refused (result=0) trials: zero matches across all 1500.

Also includes: the two DoE CSV exports and serial logs from this session's
riscv64 runs (audit artifacts per repo convention), and the resulting
Artemis disk image state from real block writes during the stress test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 11:26:23 -04:00
Robert Allan JamesandClaude Sonnet 5 eaf3f8c9ae FABRIC-2.md: F.3 punch list -- rule to wait for Artemis before DoE/ACL-RWT re-measurement
Captain Bob went with the recommended path rather than measuring now: item
5.1 + ACL-RWT overhead re-measurement stays deferred until Artemis lands,
since Artemis's own storage/timing work would immediately perturb whatever
baseline gets captured today. The other F.3 item (4.4s -> 1.11 -> 4.3 ->
S17.4 chain) is unchanged -- still genuinely blocked on ACL Phase 8, no
ruling needed there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 09:39:17 -04:00
Robert Allan JamesandClaude Sonnet 5 413b5a9bbf Verify turtle.4th rendering live, revert overdue ART-STRESS-CAMPAIGN disable
Disabled capsules/artemis/init.4th block 4170's ART-STRESS-CAMPAIGN -- its
own comment already said to revert to disabled once the K-invariant/
heartbeat verification run (item 4.6, closed earlier this session) was
done. This was the actual ~25-30 minute wall blocking interactive REPL
access, unrelated to any DoE mechanism.

Verified capsules/turtle.4th and capsules/sdk.4th live in a gtk-display
QEMU session: a red hexagon (6 100 POLYGON) and a green self-intersecting
star (100 STAR) both render with correct geometry and color. Screenshot in
evidence/amd64/.

Two real obstacles found and worked around along the way: CS's full-
framebuffer PLOT loop is far slower under TCG than previously documented
(closer to 20+ minutes than "slow"), and the kernel's heartbeat CSV logging
draws to the same console surface PLOT writes pixels to, overwriting
drawings within a fraction of a second unless silenced first with the
existing HB-OFF word. Both HOWTOs updated to record this.

Re-verified full three-arch acceptance boot (POST, DoE, parity) with the
ART-STRESS-CAMPAIGN change: 1012/0/0 and matching dict_hash on all three,
identical to the pre-change baseline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 07:57:43 -04:00
Robert Allan JamesandClaude Sonnet 5 d1547ecdae Add capsules/sdk.4th: SDK v1.9.0 vocabulary + FENCE over the cookbook capsules
Loads turtle.4th and doe.4th, defines SDK-VERSION/SDK-HELP into an SDK
vocabulary, then calls FENCE once everything is loaded -- protecting the
base wordset and both cookbook capsules from FORGET. Kernel-only (EXEC
doesn't exist hosted), REPL-invoked via S" sdk.4th" EXEC, not part of
init.4th's boot sequence.

Verified before writing the capsule, not assumed: VOCABULARY/DEFINITIONS
does not actually scope word visibility in this interpreter -- vm_find_word
is a flat dictionary scan that never consults CONTEXT/CURRENT. Documented
plainly in the HOWTO so this isn't mistaken for namespace isolation later.

Block range 5109-5115 -- discovered along the way that user-block space is
capped at [2048, 5120) by mkcapsule, tighter than expected.

Verified: mkcapsule --lint clean, hosted-build trace runs SDK-HELP with
zero attributable VM errors, zero build warnings and identical 1012/0/0
POST results with matching dict_hash on all three kernel architectures.

HOWTO: docs/working/architecture/SDK-HOWTO-20260819.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 06:10:51 -04:00
Robert Allan JamesandClaude Sonnet 5 4e7dcdf889 Add FENCE word (SDK v1.9.0 scoping); fix severe pre-existing FORGET use-after-free
FENCE ( -- ) exposes the dict_fence_latest/dict_fence_here state FORGET
already honored internally, letting callers (e.g. a future SDK capsule)
raise the boundary after loading their own content -- no new VM fields,
no policy logic beyond exposing existing state.

Writing a direct test for it surfaced a real, severe, pre-existing bug in
FORGET's relink logic, unrelated to FENCE itself and reproducible with the
original boot-time fence alone:

- Forgetting the single newest word incorrectly destroyed every other word
  back to the fence too, not just the target.
- Forgetting an older word (correctly cascading to remove newer words too,
  per FORTH-79 semantics) crashed with SIGSEGV.

Root cause: the relink code's target_prev pointer was, by construction,
always inside the range the preceding loop had just freed whenever target
wasn't vm->latest -- so writing through it was a use-after-free every time
that branch executed. Fixed by removing the target_prev tracking and both
branches entirely; vm->latest unconditionally becomes target_next (target's
own captured, still-valid link) after the free loop, correct in every case.

Added a FENCE test suite to dictionary_manipulation_words_test.c (Module 14)
including the exact regression case (forgetting the newest word must not
disturb an older one). Verified zero warnings and identical POST/dict_hash
results across all three kernel architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 05:57:18 -04:00
Robert Allan JamesandClaude Sonnet 5 6d8b48f100 FABRIC-2.md: SDK v1.9.0 scoping ruling -- FENCE already exists, VOCABULARY already exists
No code in this commit. Two findings that reframe the scope: dict_fence_latest/
dict_fence_here already exist on VM and FORGET already honors them correctly --
set once at bootstrap, right after the base wordset registers, never exposed to
FORTH. "A proper FENCE" is exposing existing state via one new word (FENCE ( -- )),
not designing a new mechanism. VOCABULARY/DEFINITIONS/CONTEXT/ORDER are already
registered and POST-tested but have never been used in any real capsule content --
an SDK capsule would be the first production use.

Five open questions named but not decided: SDK word inventory, load model
(autoload/opt-in/REPL-only), kernel-only-vs-portable (EXEC is kernel-only, so a
capsule that EXECs the cookbook capsules can't claim hosted portability), the
1.5.4 -> 1.9.0 version jump, and turtle.4th's still-unconfirmed rendering if it
ships as an SDK demo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 05:26:48 -04:00
Robert Allan JamesandClaude Sonnet 5 d0a76420a5 Add DoE library HOWTO (cookbook entry 2), flag stale L8-DOE claims in bare_metal/README.md
Documents capsules/doe.4th's word-level DOE/EXEC-DOE entry points, CSV
format, and a verified-not-fixed caveat: the rep column doesn't track
actual repetition count when n-reps differs from the file's fixed N-REPS=30
constant (cfg is unaffected, only rep is misleading -- use run_id instead).

Also surfaces, but does not fix, a real staleness finding in
experiments/bare_metal/README.md: its documented L8-DOE/WL-HI/WL-LO
entry point and workload-dispatch mechanism does not exist anywhere in the
current capsule set. What "DoE" actually names today is three separate
mechanisms (doe.4th's word-level DOE, doe-campaign.4th's fleet-touch
campaigns, and artemis/init.4th's auto-run ART-STRESS-CAMPAIGN) -- this
HOWTO documents only the first, per explicit scope decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 05:11:12 -04:00
Robert Allan JamesandClaude Sonnet 5 e40134da0d Add capsules/turtle.4th, a limited LOGO-style turtle graphics demo capsule
First entry in the "cookbook" track: a demo capsule plus HOWTO, per the
sequencing laid out after the POST-coverage sweep. Built entirely in FORTH
on top of existing primitives -- fabric.4th's LINE (raster Bresenham) and
Q.SIN/Q.COS (Q48.16 trig), plus PLOT/FB-WIDTH/FB-HEIGHT -- no new C words.

FORWARD/BACK/LEFT/RIGHT/PENUP/PENDOWN/HOME/SETXY/SETHEADING/SETCOLOR give
the classic turtle model; POLYGON and STAR compose FORWARD+turn into simple
demo shapes; TURTLE-DEMO is a one-call visual smoke test. Not wired into
init.4th -- REPL-invoked only, matching the original idea's own scope.

Verified: mkcapsule --lint clean, hosted-build logic trace shows zero VM
errors and correct stack balance through the whole vocabulary, zero build
warnings and capsule loads cleanly on all three kernel architectures.
Visual pixel-level confirmation not yet done (needs an interactive
gtk-display session or driving past the ~25-30 min DoE-before-REPL wall),
documented as an open item in the HOWTO.

HOWTO: docs/working/architecture/TURTLE-GRAPHICS-HOWTO-20260819.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 01:50:54 -04:00
Robert Allan JamesandClaude Sonnet 5 abb858a300 Add POST coverage for physics-freeze words (Module 27), fix two real bugs found in the process
Cluster 4 of the POST-coverage sweep: physics_freeze_words_test.c covers the 6
words proof/StarForth_Physics_Freeze_Words.thy actually gives real lemmas for
(FREEZE-WORD, UNFREEZE-WORD, FROZEN?, HEAT!, HEAT@, DECAY-RATE@), correcting
an earlier fork summary's wrong "5 words" scope.

Writing the tests surfaced two independent, pre-existing bugs in
physics_freeze_words.c, both now fixed:

- Every address-taking word cast the VM's caddr directly to a host pointer
  instead of resolving it through vm_ptr() -- caddr is an offset into
  vm->memory, not a host pointer. Fixed in all 9 call sites (the 5 in-scope
  words plus SHOW-HEAT, which shares the identical pattern).
- Every underflow check used dsp < N (item count) instead of dsp < N-1, since
  this VM's dsp is a 0-indexed top-of-stack pointer. Fixed in all 6 checks.

Together these meant every word in this file taking a stack-supplied name has
been broken for any real caller since the file was written. Verified zero
build warnings and a clean three-arch QEMU boot (amd64/aarch64/riscv64), 1009
passed / 0 failed / 0 errors identically on all three, dict_hash matching
across arches.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 00:12:09 -04:00
Robert Allan JamesandClaude Sonnet 5 825ab078f1 POST coverage cluster 3/4: inference-engine accessors (proof-covered, previously untested)
New module (inference_words_test.c, Module 26) covers exactly the 8
words proof/COVERAGE.md marks proof-covered in inference_words.c (out
of 20 registered): the 5 output accessors (INFER-WINDOW@/DECAY@/
VARIANCE@/FIT@/EARLY-EXIT@), INFER-RUN (populates what they read), and
Q.VARIANCE/INFER-DECAY-SLOPE/INFER-WINDOW-WIDTH (array-based
primitives, using HERE as multi-cell scratch memory). Deliberately not
the L8 Jacquard or Bayesian-posterior words in the same file -- not
proof-covered, out of this cluster's scope.

Caught and fixed a contract-selection mistake before booting: copied
CONTRACT_PHYSICS_TRANSPARENT from the Q48.16 cluster without checking
whether it fit. It doesn't -- these words are specifically about
reading physics state (dictionary heat, rolling window), so asserting
A4' transparency on them would test an invariant they deliberately
don't have. Switched to CONTRACT_NONE with an explanatory comment.

Boot-verified: zero warnings, all 9 suite entries pass, FINAL TEST
SUMMARY 1031->1040 total / 993->1002 passed (+9 exactly), 0 failed,
contract checks (A4'/A1) still report "all passed" -- confirms the
CONTRACT_NONE fix actually avoided the violation, not just silenced it.

Cluster 4 of 4 (final one) left: physics freeze/diagnostic, 5 words.
Full writeup in FABRIC-2.md Section J.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 23:34:59 -04:00
Robert Allan JamesandClaude Sonnet 5 7100523656 POST coverage cluster 2/4: Q48.16 math primitives (proof-covered, previously untested)
New module (q48_words_test.c, Module 25 -- matches word_registry.c's own
existing numbering for this file's registration) covers all 23 words in
q48_words.c: no test file existed for this file at all before. Standard
WordTestSuite/TestCase tabular format, unlike ACL's hand-rolled style --
these are pure stateless functions, a natural fit. 28 TestCase entries;
values built via Q.FROM-INT/Q.1/Q.0, read back via Q.TO-INT for readable
log output.

Verified q48_16.h's q48_to_u64() sign-extends through a signed int64_t
intermediate before writing the Q.NEG/Q.ABS tests, rather than assuming
negative round-trip works.

Boot-verified: zero build warnings, all 23 words pass individually,
FINAL TEST SUMMARY 1003->1031 total / 965->993 passed (+28 exactly),
0 failed, 0 errors. Noted (pre-existing, not fixed): print_module_summary()
is called with hardcoded (name,0,0,0,0) across every WordTestSuite module
in the tree, including this new one -- decorative, always zero; the real
counts live in each word's own per-suite line and the global summary.

Cluster 3 of 4 in the POST-coverage sequence (code sweeps -> HOL green ->
POST coverage, one proof-covered cluster at a time). Two clusters left:
inference-engine accessors, physics freeze/diagnostic. Full writeup in
FABRIC-2.md Section J.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 23:30:46 -04:00
Robert Allan JamesandClaude Sonnet 5 b2918fd0b2 POST coverage cluster 1/4: ACL accessors (proof-covered, previously untested)
Adds interpreter-level POST coverage for six ACL read accessors
(ACL-MODE@/PINNED?/TTL@/ALLOW@/HEAT@/WORD-ID), ACL-INHERIT as an
interpreted word (not just its underlying C function, already tested),
and ACL-INIT-PRIMITIVES -- all proof-covered per proof/COVERAGE.md but
never exercised via vm_interpret() before. Follows acl_words_test.c's
existing hand-rolled ACL_ASSERT style, not the WordTestSuite table
format the rest of the tree uses.

First boot caught a real bug in the new test itself (2/29 assertions
failed): ACL-INHERIT's C implementation pops dst before src, the test
pushed them backwards. Fixed the test, not the word -- ACL-INHERIT's
own dispatch was correct throughout. Re-verified: 29/29 pass, zero
build warnings. Both the failing and fixed boot logs kept as evidence.

Part of the agreed sequence (code sweeps -> HOL green -> POST coverage,
one proof-covered cluster at a time). Three more clusters queued:
Q48.16 math primitives, inference-engine accessors, physics
freeze/diagnostic words. Full writeup in FABRIC-2.md Section J.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 23:15:32 -04:00
Robert Allan JamesandClaude Sonnet 5 e535346504 FABRIC-2.md: record verified clean Isabelle/HOL rebuild (52 theories, genuinely green)
Ran isabelle build -c (clean, forces fresh rebuild bypassing any cached
heap) for real, per the agreed sequencing (code sweeps -> HOL green ->
POST coverage). All 52 theories rebuilt from scratch in 42s, zero
errors/failures/sorry/oops anywhere in the log -- upgrades the earlier
entry's static-inspection-only inference to an actual verified result.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 22:50:03 -04:00
Robert Allan JamesandClaude Sonnet 5 1a2ec565e8 Zero C-compiler warnings on all three architectures; fix real restore_vm_state() bug
Maintainability sweep (prompted by "this is getting hard to maintain"):
fixed the remaining three warning classes after the missing-field-
initializers commit -- 2x -Wsign-compare (control_words.c, cast at the
comparison site rather than changing cf_last_mode's type, which
deliberately holds a -999 sentinel outside vm_mode_t's valid range),
2x -Wstringop-truncation (mkcapsule.c, strncpy+manual-null-terminate
replaced with the idiomatic snprintf equivalent), and 26x
-Wunused-parameter (mostly documented stubs, silenced with the repo's
existing (void)param; idiom).

One of the unused-parameter warnings was not a deliberate stub -- a
real bug. restore_vm_state() (test_common.c) is named, documented, and
called by nine real call sites (acl_words_test.c x8 plus its own
internal use) as "restore saved VM state", but ignored all four of its
parameters and hard-reset to a fixed baseline instead, silently not
restoring what any caller actually saved. Fixed to actually assign the
passed-in dsp/rsp/error/mode. Found while fixing warnings, reported
before touching it, fixed/tested/documented/committed on explicit
instruction.

Verified: all three architectures build with zero C-compiler warnings
(amd64: 3040 -> 0; aarch64's one remaining note is lld-link's own
unrelated linker warning, not a C warning). Full amd64 acceptance boot
post-fix: POST 1003/965/0/0/38 (total/passed/failed/errors/stubs),
"ALL IMPLEMENTED TESTS PASSED!", contract checks (A4'/A1) all passed,
dict_hash=0x24b4279f0670aa3a -- an exact match to this document's own
previously-recorded baseline hash.

.claude/CLAUDE.md corrected to describe the real -Wno-error= exemption
list instead of the "-Wall -Werror" oversimplification. FABRIC-2.md
Section J records the full sweep, including doc-tree staleness findings
flagged but not fixed this pass (docs/lithosananke/ROADMAP.md branch
topology, docs/03-architecture/word-acl/DESIGN.md's Phase 7 claim
contradicting CLAUDE.md, top-level ROADMAP.md's stale StarForth-era
status, the Isabelle pipeline-metrics model mismatch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 22:31:57 -04:00
Robert Allan JamesandClaude Sonnet 5 bf59c4916e Fix systemic -Wmissing-field-initializers across src/test_runner/modules/ (3010 -> 0)
TestCase gained a trailing `contract` field (WordContract) at some point
after all 20 test-module files' compound literals were written -- every
single TestCase/WordTestSuite initializer in the tree (sentinels, real
entries, and per-suite entries) omitted it, producing ~3010 warnings on
every build. CLAUDE.md's own documentation claimed this was isolated to
one file (vocabulary_words_test.c); a full audit found it systemic
across all 20 files.

Fixed mechanically: added the missing `{0}` trailing initializer
everywhere. Semantically a no-op -- C99 already zero-fills unlisted
trailing struct fields, so this only silences the diagnostic, changes
no behavior. Verified: all three architectures (amd64/aarch64/riscv64)
build clean, remaining warning count unchanged (30, matching the other
three known -Wno-error-exempted classes: unused-parameter, sign-compare,
plus mkcapsule.c's stringop-truncation which was never actually gated
by this policy -- it's a separate host tool with no -Werror at all).

.claude/CLAUDE.md corrected to describe the actual -Wno-error= exemption
list (four classes, not "build with -Wall -Werror" unconditionally) and
the real current warning inventory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 21:43:30 -04:00
Robert Allan JamesandClaude Sonnet 5 4270cf23f1 docs: fix stale proof-suite claims in FABRIC-2.md; correct docs/CLAUDE.md's Makefile pointer
FABRIC-2.md item 5.2: both lemmas described as deliberately oops-flagged
(ROLL semantics, pipeline pm_wf invariant) were actually resolved
2026-08-13, same day, but FABRIC-2.md was never updated to match --
found during a docs-tree maintainability sweep. Corrected both, and
flagged a real untracked finding the pipeline fix surfaced: the Isabelle
model's accuracy num/den fraction pair doesn't correspond to the real
PipelineGlobalMetrics C struct at all. Also reconciled the theory-count
drift (53/54 mid-sweep numbers vs. the actual current 52, matching
proof/COVERAGE.md; proof/FINDINGS.md's own stale "53" flagged but not
fixed, out of this pass's scope).

docs/CLAUDE.md described a docs/Makefile with docs-formal/docs-working/
docs-index/docs-audit targets that doesn't exist anywhere in the tree.
The real build is docs/formal/Makefile with a completely different
target set (vol1/vol2/vol3/books/standalone/doxygen/clean) -- corrected
to match, and noted docs/INDEX.md has no automation and goes stale
between manual triage passes.

doxygen installed on this machine (was missing entirely, blocking the
API-reference build target).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 21:05:21 -04:00
Robert Allan JamesandClaude Sonnet 5 5b248343b0 FABRIC-2.md: record item 4.6's effort number, per §10
Recorded in item 4.6's own closure entry in FABRIC-2.md, not literally
under FABRIC.md's §10 -- matches how item 4.2's effort number actually
lived (inside that item's own punch-list entry), and respects
FABRIC.md's own closed/no-further-edits rule. Same format as item 4.2's
report: session time, lines changed split FORTH vs. C surface, file
count.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 20:42:21 -04:00
Robert Allan JamesandClaude Sonnet 5 719cf811f4 FABRIC-2.md: close item 4.6, pointing to Section H's full writeup
Item 4.6 (Artemis Stadium migration) was still marked open despite its
own "Done when" criteria all being met by today's work: Stadium-admission
boundary shipped, FM-* untouched, ART-STRESS-CAMPAIGN 30/30 on all three
arches, POST clean, three-arch boot logs, ARTEMIS-K conservation holding.
Marked closed with a pointer to Section H; noted the one unverified
criterion (the §10 effort-number bookkeeping step) rather than silently
claiming it was done.

Found during a full sweep of FABRIC-2.md for the same tracking-drift
class that forced FABRIC.md's closure (§12 Q5, fixed in the prior
commit) -- this was the other real instance found.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 20:36:00 -04:00
Robert Allan JamesandClaude Sonnet 5 316fa93842 FABRIC-2.md: fix stale §12 Q5 tracking — checkbox and punch-list drift
Found while checking for the same scattered-punch-list problem that
forced FABRIC.md's closure: §12 Q5 was actually closed 2026-08-15 (the
STADIUM_CAPACITY_TICK flat-4000-divisor fix), but Section D's checkbox
was never flipped to [x], and Section F.3's punch list still re-listed
it as an open question. Fixed both; corrected the F.2/F.3 "net result"
summary to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 20:31:53 -04:00
Robert Allan JamesandClaude Sonnet 5 60907503f9 docs: record item 4.6 fix, aarch64 BYE crash fix, and DoE campaign in CHANGELOG/ROADMAP
CHANGELOG.md: new 2026-08-18 entry for today's work, plus a post-split
note explaining the branch-tag convention no longer applies (this repo
is now LithosAnanke-only, master as sole production line).

docs/lithosananke/ROADMAP.md: M7.1 section predates all the real
Tripod/Stadium/ACL work and was silently stale -- added a dated
redirect to FABRIC.md/FABRIC-2.md (matching the doc's own existing
pattern for the M8 section) rather than rewriting the whole section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 20:27:05 -04:00