Commit Graph
100 Commits
Author SHA1 Message Date
Robert Allan James be598af65c ONTOLOGY.md: add Stadium/Fabric vocabulary section, close taxonomy/glossary debt
Extends the existing lexicon (which already covered heat/decay/inference vocabulary but predated Stadium work entirely) with patron, mass, density, K, cell, code field, Stadium, warehouse, utility -- all cited to their FABRIC.md DECIDED sections. Adds a Kconfig-knob-to-concept table with verified wiring status, flagging STADIUM_CAPACITY_TICK as dead (matches this session's §12 Q5 finding). Bumped to v1.1.
2026-08-13 10:26:22 -04:00
Robert Allan James c9710093ae FABRIC-2.md: §17.4 framebuffer physics -- confirm still not ripe, correct its real prerequisite
Live console/framebuffer stack has zero dirty-region or heat/decay instrumentation (grepped framebuffer.c/vt100.c/console.c). True prerequisite is item 1.11 (dirty-event granularity), still unstarted, not 'the framebuffer work' generally, which has since shipped. Left open.
2026-08-13 10:22:55 -04:00
Robert Allan James bb39012e55 FABRIC-2.md: §12 Q5 eight-loop interference analysis -- found a real §22.4 violation
Traced every loop's actual firing cadence from source. Headline finding: the fleet-capacity loop (vm_physics_heartbeat_tick, the exact mechanism §22.4 cites as precedent) shares a global counter fed by every live VM, so with Tripod's real multi-VM topology it can fire faster in wall-clock terms than any single VM's own heat-inference loop -- the opposite of §22.4's required ordering. STADIUM_CAPACITY_TICK, the Kconfig symbol §22.4 specified as the fix, exists but is never read anywhere. Reported, not fixed; left open for Captain Bob's call.
2026-08-13 10:20:53 -04:00
Robert Allan James bdb85bc7c0 FABRIC-2.md: close section D §23.4 #2 -- settled by divergence, not by measurement
Hermes v1's real message struct (init.4th blocks 4100/4105/4143) is 72 bytes with an out-of-line pointer+length payload, not the speculative 64-byte-cell/32-byte-inline-payload scheme from FABRIC.md §23.3. The design question is moot: the implementation went a different direction.
2026-08-13 10:16:25 -04:00
Robert Allan James a0033a2052 FABRIC-2.md: close Kconfig/menuconfig end-to-end item
Verified via tools/kconfig/conf + kernel_amd64_defconfig: a .config edit to CONFIG_SK_PARITY_DEBUG genuinely flows through to the parity.c compile line's -D flag in both directions. Required installing bison/flex, which were missing.
2026-08-13 10:14:05 -04:00
Robert Allan James b381578cb3 FABRIC-2.md: confirm fbtest.c/ttftest.c doc discrepancy, leave open
fbtest.c never existed in git history; ttftest.c exists but is undocumented. Not fixed pending instruction.
2026-08-13 10:05:08 -04:00
Robert Allan James e83a881b75 FABRIC-2.md: confirm and close m5_time_trust/m5_variance dead-field item
Repo-wide grep: no reader or writer anywhere besides the vm.h declarations. Leave as-is.
2026-08-13 10:04:22 -04:00
Robert Allan James 13fffa12ce FABRIC-2.md: close heartbeat_trust() item -- claim was stale, has a caller
kernel_main.c:913 prints it in the M5 heartbeat diagnostic line.
2026-08-13 10:03:18 -04:00
Robert Allan James 845f3d4e3b FABRIC-2.md: confirm and close hotwords_cache_promote() NULL-write item
Ruling recorded: real defect, unreachable under all four call sites' existing NULL guards, leave as-is.
2026-08-13 10:02:51 -04:00
Robert Allan JamesandClaude Sonnet 5 b42993322c FABRIC-2.md: close block_subsystem encoding-field item, wider scope found
Investigated 2026-08-13: not just the encoding field -- blk_get_meta()/
blk_set_meta() and the whole blk_meta_t on-disk layout have zero callers.
Captain Bob's ruling: flag and leave as-is, expected to be consumed once
Artemis's design (content-typed/owned/ACL'd blocks) is completed. No
code changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:32:16 -04:00
Robert Allan JamesandClaude Sonnet 5 d38b3103b8 FABRIC-2.md: check off arch_mmu_init() item -- ruling recorded
No code change; closed as investigated and ruled not-a-bug (deliberate
future-milestone scaffolding) rather than left open as a loose TODO.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:49:27 -04:00
Robert Allan JamesandClaude Sonnet 5 a813a147fa FABRIC-2.md: arch_mmu_init() is a deliberate TODO, not dead code
Investigated 2026-08-13: confirmed unreachable by repo-wide grep, but
each of the three stubs is a real doc-commented placeholder for a future
per-arch MMU milestone, not leftover cruft. Captain Bob's call: leave in
place, keep tracked as a TODO rather than delete or wire in a no-op call
site. No code changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:46:45 -04:00
Robert Allan JamesandClaude Sonnet 5 307f0e4ecc FABRIC.md/FABRIC-2.md: close vm_physics_retire() Hera-drop item
Punch list §C item complete. Corrects this morning's "structurally
excluded" framing -- the Hera-is-root case was reachable via
S" Hera" KILL, fixed in db66406. Broken-parent-chain half remains
genuinely unreachable and is no longer tracked as open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:39:53 -04:00
Robert Allan JamesandClaude Sonnet 5 db6640682b mama_forth_words: KILL must not physics-retire Hera before refusing her
S" Hera" KILL called vm_physics_retire(hera_id) before capsule_vm_kill()'s
own Hera guard ever ran. Hera's self-referential parent_vm_id makes
vm_physics_find_root_id() return her own id immediately, so
vm_physics_retire() treated her as an unreachable root and zeroed the
fleet's entire execution_heat_q48 sum -- silently, with only the
harmless-looking "cannot kill Hera" message as output. Guard the retire
call the same way capsule_vm_kill() already guards the actual kill.

Three-arch acceptance boot, all clean to ok>:
logs/20260813-083429/amd64, logs/20260813-083551/aarch64,
logs/20260813-083738/riscv64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:38:33 -04:00
Robert Allan JamesandClaude Sonnet 5 b929a59f3d FABRIC.md §20.2: correct the truncation-leak claim in place
The touch()-fan-out truncation was wrongly blamed for monotonic
conservation drift. Corrected in place per this document's own rule for
bookkeeping errors (§25 discipline, same treatment as the four fixes
made during the 2026-08-12 closure audit) rather than left standing.
Full investigation and worked example live in FABRIC-2.md §B/§C.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:26:45 -04:00
Robert Allan JamesandClaude Sonnet 5 05c8462f2f FABRIC-2.md: close Fleet heat leak item -- truncation claim doesn't hold
Punch list §B item complete. Full read of capsule_vm_physics.c plus a
worked example show the touch()-fan-out truncation FABRIC.md §20.2
blamed cannot cause conservation drift -- vm_physics_transfer() moves
matched amounts on both sides of every call. Git history rules out a
since-fixed bug: the code predates §20.2's correction unchanged.

The one path that can genuinely drop heat is vm_physics_retire()'s
guarded no-valid-root case, structurally unreachable today (Hera can't
be killed, parent chains can't corrupt). Tracked as its own item in §C.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:21:32 -04:00
Robert Allan JamesandClaude Sonnet 5 389ca74d9f FABRIC-2.md: close Multi-VM heartbeat ownership item
Punch list §B item complete. Documents the Hera-sole-owner ruling and
points to the vm_runtime.c fix (bcc72d0) and its three-arch acceptance
logs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:15:44 -04:00
Robert Allan JamesandClaude Sonnet 5 bcc72d00bb FABRIC-2.md Category B: single-owner heartbeat physical-timer re-arm
Only Hera writes the shared physical timer period now, gated by
vm_uuid_is_hera(vm->stadium_vm_id) in vm_tick_inference_engine(). Every
other VM's Loop #7 still adapts its own tick_target_ns as before, it just
no longer races to re-arm the one physical timer.

Includes 3-arch acceptance run (amd64/aarch64/riscv64, all booted clean
to ok>) and regenerated capsule/DoE artifacts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:13:04 -04:00
Robert Allan JamesandClaude Sonnet 5 f75228dda5 Add docs/lithosananke/DICTIONARY.md: full core word dictionary reference
No document like this existed. Covers every core C-primitive FORTH word
(~470 registrations, 435 unique names after collapsing double-registered
ones) across all 36 src/word_source/*.c files plus
src/starkernel/capsule/mama_forth_words.c, organized into 34 category
sections matching the module order in register_forth79_words().

Each entry has word name, stack effect, and a one-sentence description
pulled from the doc comment above its implementation (or inferred where
none existed). Explicitly scoped to core primitives, not the ~330
FORTH-defined words inside .4th capsules -- those track individual
experiments/policies rather than the language itself and would need
their own document with a different update cadence.

Resolved, not just noted, the two real name collisions in the live
dictionary: [ ] STATE (dictionary_manipulation_words.c vs.
defining_words.c) and MOD /MOD */ */MOD (arithmetic_words.c vs.
mixed_arithmetic_words.c) -- checked actual registration order in
word_registry.c against the newest-first FIND search to determine which
implementation is actually reachable by name, rather than guessing.

Includes a "keeping this current" section documenting how to extend it
when words are added/removed/re-registered.

Also includes BLOCK_MAP.md/artemis.img/amd64.csv regenerated by builds
during this session, and a qemu boot log/DoE run that weren't from any
command in this session -- kept per repo convention, logs are audit
artifacts, not deleted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:09:18 -04:00
Robert Allan JamesandClaude Sonnet 5 aba0b01a08 Close FABRIC.md, open FABRIC-2.md as the living document
FABRIC.md did its job: §1-24's design argument is settled and every
implementation item through 4.5/4.4ac either landed or was explicitly
deferred with a reason. At 7,595 lines it was no longer a good place
to find what's actually still open, so it's now archival -- header
rewritten to say so, pointing to FABRIC-2.md.

Before closing it, read the entire document end to end (not sampled)
looking for anything unresolved: punch-list checkboxes, the nine
"### N.N Open" architectural subsections in §1-24, the §25.7
"reported, not scheduled" list, and any other "not yet"/"deferred"
language. Found and fixed four stale bookkeeping spots where later
work had actually resolved something but the note was never updated:
§19.6 #3 (resolved by item 2.1), §21.5 #4 (resolved by §20.5 #4), the
§25.7 stadium_owner[idx] bullet (resolved by item 4.2), and item 4.5's
own parent checkbox (all six sub-items 4.5a-4.5f were already [x]).

FABRIC-2.md carries forward everything genuinely still open: the
blocked/scoped punch-list items (1.11, 4.3, 4.4s, 4.6, 5.1-5.3, plus a
specific pending TRIPOD.md edit found within 5.3), two regressions
that were invisible with Tripod pruned to Hera-alone and are now live
since item 4.2 restored Hermes (the fleet heat leak in
vm_physics_touch(), and multi-VM heartbeat ownership), nine dead-code/
cruft reports, three open design questions (§12 Q5, §17.4, §23.4 #2),
and two documentation-debt items (the taxonomy/glossary Captain Bob
flagged 2026-08-04, and re-measuring ACL-RWT DoE overhead now that
real compiler optimization is enabled).

Also includes BLOCK_MAP.md/artemis.img/amd64.csv regenerated by builds
during this session, and a qemu boot log/DoE run that weren't from any
command in this session -- kept per repo convention, logs are audit
artifacts, not deleted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 18:45:13 -04:00
Robert Allan JamesandClaude Sonnet 5 b6872d28ae FABRIC.md item 4.4ac: screendump-verify boot scrollback on aarch64/riscv64 too
Extends the amd64 headless screendump verification (99999 SCROLL-BACK
injected over the serial chardev socket, captured via QEMU's HMP
screendump over its monitor socket) to aarch64 (-device ramfb) and
riscv64 (-device ramfb) -- same script shape, no GUI or physical
typing needed on either. Both show the same deep-POST recovery
(Init: Mama birth..., HADES DoE rows 58-73, boot banner) and the same
pre-existing 4.4q live-cursor-draw glitch already confirmed on amd64,
present identically -- boot-mode scrollback is real and reachable on
every architecture, not just amd64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 18:29:37 -04:00
Robert Allan JamesandClaude Sonnet 5 31a86ee50d FABRIC.md item 4.4ac: screendump-verify boot scrollback, mark done
Confirms 4.4ac's boot-mode scrollback ring actually works: injected
'99999 SCROLL-BACK' over the serial chardev socket (same mechanism the
old DOE_INJECT automation used to drive EXEC-DOE -- SCROLL-BACK is a
plain FORTH word, and sk_repl_step()'s input comes from console_getc()
polling the UART), then captured the framebuffer with QEMU's own HMP
screendump command over its monitor socket. No GTK session or physical
typing needed, correcting this item's own earlier assumption that it
would.

Result (logs/screendump-4.4ac/amd64-scrollback.png) shows PARITY:
MAMA_INIT, Init: Mama birth OK, ACL: CAPSULE-BIRTH pinned STRICT,
Starting heartbeat..., and HADES DoE rows from steps 58-73 all on
screen at once -- genuinely early POST content, not just the pre-TTF
tail. Also confirms a small pre-existing 4.4q limitation (live cursor
draw corrupting a scrolled-back view) is unaffected by this item, not
a new regression.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 18:25:52 -04:00
Robert Allan JamesandClaude Sonnet 5 3396e9a7b4 FABRIC.md item 4.4ac: scrollback during boot/POST, not just from REPL
vt100.c: font_8x16/bitmap-mode boot output previously had no scrollback
at all -- g_shadow/g_ring were only allocated in vt100_enable_ttf(), so
POST/self-test/heartbeat text was gone the instant it scrolled off,
recoverable only from the serial log. Gives boot mode its own ring/
shadow pair (bitmap cell geometry, 4096-line capacity), frozen as a
snapshot the moment vt100_enable_ttf() switches to the TTF-geometry
pair, per the two-independent-rings design scoped with Captain Bob.
scrollback_line_at()/scrollback_redraw()/vt100_scroll_back() now walk
all four segments (boot ring, boot shadow, TTF ring, TTF shadow) as one
continuous history, so PgUp from the REPL reaches back through POST.

Three-arch QEMU boot + logs clean (amd64/aarch64/riscv64, no faults, no
dictionary/parity regressions). Visual verification that PgUp actually
recalls POST text still needs an interactive GTK screendump -- noted as
open in FABRIC.md, same pattern as 4.4ab's screendump.

Also includes BLOCK_MAP.md/artemis.img regenerated by these builds, and
the acceptance-boot logs (plus stray logs from an earlier QEMU-instance
collision during testing -- kept per repo convention, logs are audit
artifacts, not deleted).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 18:21:31 -04:00
Robert Allan James 149dbc4c73 Merge branch 'stadium-step-one' 2026-08-12 16:57:05 -04:00
Robert Allan JamesandClaude Sonnet 5 2822e52ea8 make qemu: drop auto-kill/DOE-inject wait loop, run interactively
The qemu target used to poll the serial log for ok>/zuse)ok>, then
unconditionally kill the VM (optionally injecting EXEC-DOE first) — a
DoE-campaign automation shape that also fired during plain interactive
use, cutting the session out from under you the moment the prompt
appeared. All three arch branches (amd64/aarch64/riscv64) now just run
qemu-system-* in the foreground and block until it's closed manually;
serial logging to logs/ and DoE CSV extraction on exit are unchanged.

Also includes BLOCK_MAP.md/artemis.img/amd64.csv regenerated by the
qemu-esp test run, and that run's log/CSV artifacts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 16:56:35 -04:00
Robert Allan James 099db4f428 Merge branch 'stadium-step-one' into master
Brings in the cursor indicator + HB-ON/HB-OFF runtime DoE toggle work.
Diverged from master's own three-arch verification commit (0d8fff3,
logs only, no code overlap) since that verification was made directly
on master rather than merged back to stadium-step-one first.
2026-08-12 16:28:43 -04:00
Robert Allan JamesandClaude Sonnet 5 59458a0a16 Cursor indicator + HB-ON/HB-OFF runtime DoE instrumentation toggle
Cursor (Captain Bob: "the only thing we need is a cursor"):
vt100_draw_cursor() draws a solid block at the terminal's current
position, called from repl.c after the prompt prints and after every
keystroke/backspace. vt100_erase_cursor() cleans up the one gap a static
cursor has -- Enter/newline moves away from the cursor cell without a
character draw ever overwriting it, which left a stray block behind
until this fix.

HB-ON/HB-OFF (Captain Bob: run a program with or without instrumentation
without rebuilding):
Converted per-tick DoE logging from a build-time flag (HEARTBEAT_DOE_LOG)
to a runtime one. doe_log_tick_row() now self-gates on g_doe_log_enabled
(default 1, matching the old default) instead of being compiled out
entirely; the call site in vm_runtime.c is unconditional. Two new FORTH
words, HB-ON and HB-OFF, flip the flag live. Removed the now-dead
HEARTBEAT_DOE_LOG plumbing: the Kconfig symbol, and the -D forwarding in
both LOADER_CFLAGS and KERNEL_CFLAGS.

Verified: three-arch clean QEMU boot + logs; dictionary word count 466
(463 baseline + ALT+TAB + HB-ON + HB-OFF, exactly the three words added
across this session); amd64 screendump confirms the cursor renders
correctly after real interactive typing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 16:22:09 -04:00
Robert Allan JamesandClaude Sonnet 5 0d8fff3cc0 Three-arch acceptance verification: master matches stadium-step-one
Confirms all three architectures boot clean on master after the
fast-forward merge from stadium-step-one (af20efa), identical to the
behavior verified on that branch: UEFI -> POST -> Mama birth -> Hermes
self-test -> heartbeat -> ok>, no DoE/ECW noise.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 15:50:23 -04:00
Robert Allan JamesandClaude Sonnet 5 af20efaa15 FABRIC.md items 4.4v/4.4r/4.4ab: keyboard bridge, and simplify to a
full-screen vt100 terminal

4.4v -- keyboard-to-REPL bridge, real and tested:
Refactored KEY-EVENT's per-arch translation logic (keyboard_words.c) into
a shared C function, sk_key_event_poll(), so the REPL bridge reuses item
4.3.5f's already-converged Linux-keycode-namespace event stream instead
of building separate amd64/aarch64/riscv64 tables. repl.c's sk_kbd_getc()
decodes the standard US-QWERTY printable range plus Enter/Backspace/Shift
against that stream; sk_readline() polls it as a second source alongside
console_getc(). Verified via QEMU monitor sendkey injection, and by
Captain Bob typing directly into the live QEMU window over real emulated
PS/2 hardware mid-session (1 1 + . -> 2 ok, then a clean BYE shutdown).

4.4ab -- simplify to a full-screen terminal:
Captain Bob's call, reverting the 640x480 CANVAS box + independent REPL
strip (4.4o/4.4t/4.4x/4.4z) in favor of the simplest shape: the entire
framebuffer is one vt100 terminal, g_vt.cols/rows = fb_width()/fb_height()
divided by cell size, no origin offset, no box, no strip, no border
drawing. The REPL prompt is just the terminal's last scrolling line.
Scrollback, TTF rendering, and SGR color are all box-agnostic and keep
working unmodified.

4.4r -- reframed as a text/graphics mode toggle:
"Hide/show the scroll box" stopped meaning anything once the box was
removed; the underlying need survives as a whole-screen mode switch.
vt100_toggle_graphics() is a two-state machine (VISIBLE/HIDDEN) -- hidden
mode stops the terminal from touching the framebuffer while its logical
state keeps advancing, so direct framebuffer/TTF-TEXT drawing can use the
whole screen; showing again wipes and reuses scrollback_redraw() to
restore the terminal exactly. Reachable two ways, one transition function:
physically via Alt+TAB (4.4y revised from Ctrl+TAB) and programmatically
via the new ALT+TAB FORTH word.

Verified: three-arch clean QEMU boot + logs; amd64 screendump confirms
full-width text with no box/strip artifacts.

Punch list §25 items 4.4v/4.4r/4.4ab complete; 4.4y revised.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 15:41:26 -04:00
Robert Allan JamesandClaude Sonnet 5 b21aa50a14 FABRIC.md item 4.4z: draw the scroll box's visible border
draw_box_border() (vt100.c) strokes four 1px edges around the 640x480
CANVAS box, reusing the same border-gray constant the REPL strip's
border lines use (renamed VT100_STRIP_BORDER_GRAY -> VT100_BORDER_GRAY
since it's now shared -- one pinned color decision, 4.4w, not two).
Called from erase_display()'s box-scoped branch so the border survives
every box clear (the initial one and any later ESC[2J), not just the
first.

Verified: three-arch clean QEMU boot + logs, amd64 screendump showing a
full rectangle outline around the box, visually distinct from the strip
below it.

Punch list §25 item 4.4z complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 15:07:04 -04:00
Robert Allan JamesandClaude Sonnet 5 91742e02f4 FABRIC.md item 4.4x: split the REPL prompt into its own bottom strip
Scope expanded from pure CANVAS-rectangle arithmetic (as originally
scoped) to also splitting the REPL prompt/input line out of the
scrollback box into an independent single-line strip, per Captain Bob's
explicit fold-in after the gap was reported (§25.0 rule 3) rather than
silently expanded.

vt100.c: VT100_BOX_ORIGIN_X/Y are no longer hardcoded per-arch literals --
both are now derived from fb_width()/fb_height() at vt100_enable_ttf()
time. New vt100_strip_draw() renders the bottom strip (gray border lines,
bright-white text) directly via the existing ttf_draw_glyph_cell()
rasterizer, independent of the box's own grid/cursor state. Border lines
are drawn after the glyph loop so an oversized cell can only be clipped
by them, never erase them.

console.c/console.h: console_fb_strip_draw() thin wrapper, matching the
existing console_fb_enable_ttf()/console_fb_scroll_*() pattern.

repl.c: builds a plain-text "[VMName] ok> <input>" mirror in
g_strip_prompt/strip_refresh(), refreshed on every keystroke (including
backspace) from sk_readline() -- already wired for item 4.4v, since
keyboard-typed characters will flow through the same console_getc() path
once that lands. Also widened sk_repl_step()/sk_repl_run()'s local input
buffer from a second, smaller 256-byte buffer to INPUT_BUFFER_SIZE
(1025), per 4.4w's decision.

Verified: three-arch clean QEMU boot + logs, amd64 screendump showing
the box and strip as two visually distinct regions with no visible
glyph/border clipping.

Punch list §25 item 4.4x complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 14:59:07 -04:00
Robert Allan JamesandClaude Sonnet 5 763c6f2cd5 FABRIC.md items 4.4u/4.4w/4.4y: pin console layout numbers with Bob
4.4w resolved: border gray = FB_ANSI_PALETTE[7] (0xAAAAAA); REPL input
line uses the full INPUT_BUFFER_SIZE=1025 buffer with left/right
horizontal scroll on a single line, not a smaller practical limit; the
15px/15px REPL-strip gaps and 8px box-to-strip gap from the second
mockup pass confirmed as-is. 4.4y resolved: toggle meta-key is Ctrl+TAB.
4.4u's own done-when (three open gaps resolved with Bob) is satisfied by
4.4w's resolution, so it's checked off too. Design-only, no code changes
in this commit -- 4.4x/4.4z pick up the drawing work these numbers
unblock.

Punch list §25 items 4.4u/4.4w/4.4y complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 14:08:43 -04:00
Robert Allan JamesandClaude Sonnet 5 39838b604f Quiet the POST ECW dispatch trace; three-arch clean-boot verification
vm_core.c: demote the per-word "ECW: w=... func=... 'NAME'" dispatch trace
from LOG_INFO to LOG_DEBUG. POST forces the logger to LOG_TEST for the
duration of the self-test run, and LOG_TEST includes LOG_INFO, so every
single word execution during POST was echoing this trace -- hundreds of
lines burying the actual module summaries and pass/fail tally. Still
available via --log-level=debug.

Combined with HEARTBEAT_DOE_LOG=0 (command-line Kconfig override, no
default change -- experiments/bare_metal/'s own DoE tooling still gets
HEARTBEAT_DOE_LOG=1 by default), all three architectures now boot clean:
UEFI -> POST summary -> Mama birth -> Hermes self-test -> heartbeat ->
ok>, with no [HADES][DOE] rows and no ECW flood. Verified by three-arch
QEMU boot; logs attached.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 13:08:49 -04:00
Robert Allan JamesandClaude Sonnet 5 a02e14915f WIP checkpoint: quiet default log level, QEMU_DISPLAY control, tee'd serial log
Default log level dropped from info to warn so the per-word ECW dispatch
trace doesn't flood REPL output after POST (--log-level=info/debug still
re-enables it). qemu target gains QEMU_DISPLAY (default gtk) so the
framebuffer window shows by default; serial log is tee'd live via
`tail -f` instead of dumped with `cat` at the end. Includes regenerated
BLOCK_MAP.md/amd64.csv/artemis.img and this morning's boot logs/DoE runs
from the sessions that produced this WIP.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 12:55:08 -04:00
Robert Allan JamesandClaude Sonnet 5 64a3ff58cc FABRIC.md: note first task for next session -- collect punch-list items at document end
Captain Bob flagged the document (7,300+ lines) has grown cluttered,
with punch-list items scattered throughout rather than collected in one
place. Recorded as the explicit first task for next session, before any
4.4-series work resumes: a full reorg pass collecting all punch-list
items to the end of the document, preserving every item's content
(including Done blockquote history) exactly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:52:40 -04:00
Robert Allan JamesandClaude Sonnet 5 3723640d69 FABRIC.md: ROADMAP.md is superseded entirely, not just M8
Captain Bob was explicit: don't consult docs/lithosananke/ROADMAP.md at
all anymore, for anything, not just the REPL/M8 section already marked
obsolete inside it. Added an explicit statement to the preamble so this
isn't scoped too narrowly by a future reader.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:51:14 -04:00
Robert Allan JamesandClaude Sonnet 5 098b437180 FABRIC.md: break the morning resume note into proper punch-list items
The prior commit's resume note was a single blockquote blob with a
numbered list buried inside item 4.4v -- not the document's own
established format. Replaced with four real standalone items matching
every other entry in this section (own checkbox, description, Done
when, Refs): 4.4w (pin 4.4u's open numbers), 4.4x (redo 4.4n's CANVAS
math for the real strip height), 4.4y (decide the toggle meta-key),
4.4z (draw the scroll box's visible border). Updated 4.4r's dependency
list to include 4.4v and 4.4z.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:49:25 -04:00
Robert Allan JamesandClaude Sonnet 5 074466f271 FABRIC.md: defer toggle meta-key choice, add morning resume punch list
TAB was recorded too specifically in 4.4u/4.4v -- Bob deferred the exact
toggle key (TAB/Ctrl+TAB/other) to decide later; both items now say so
and 4.4v's interception scope is keyed off "whatever key gets chosen"
instead of hardcoded to TAB.

Added an explicit six-step breakpoint/punch list after 4.4v recording
the dependency-ordered resume sequence for tomorrow: pin 4.4u's open
numbers, redo 4.4n's CANVAS math, decide the toggle key, build 4.4v,
draw the scroll box's border, then build 4.4r.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:44:30 -04:00
Robert Allan JamesandClaude Sonnet 5 fa8d7ab7dd FABRIC.md items 4.4u/4.4v: locked console layout design + M8 keyboard-bridge scope
4.4u records the full bottom-up console layout Captain Bob walked through
tonight (REPL strip geometry, single-line horizontal-scroll input, drawn
scroll box, TAB-toggle, colors), including a mockup review round that
grew the REPL-strip gaps by 3px and added scroll-box content soft-wrap.
Flags that it revises 4.4m/4.4n's REPL-strip sizing without editing those
items in place. 4.4v scopes the keyboard-to-REPL bridge precisely: the
i8042/virtio_input interrupt-driven keyboard layer is real and working,
but nothing connects it to sk_readline() yet -- that gap is what's left,
not a from-scratch keyboard subsystem.

Neither item has code yet -- design/scope documentation only, per this
document's own discipline of capturing design before implementation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:29:35 -04:00
Robert Allan JamesandClaude Sonnet 5 c92be2768f FABRIC.md item 4.4t: confine REPL text rendering to the CANVAS box
vt100's TTF-mode text grid now operates within the per-arch 640x480 box
(computed in 4.4o, pixel-verified in 4.4p) instead of the full framebuffer:
box-origin offset in px_of()/py_of(), box-derived cols/rows (53x20) set
before the 4.4q scrollback allocation depends on them, mode-aware
erase_display()/reverse-index fill, and a new box-scoped fb_scroll_rect()
alongside the existing whole-framebuffer fb_scroll_rows() (bitmap/boot mode
unaffected either way). Also clears the full framebuffer once at the
bitmap-to-TTF switch so leftover boot debris doesn't sit frozen outside the
box now that erase_display(2) is box-scoped afterward.

Three-arch QEMU boot + pixel-scanned screendumps confirm zero non-background
pixels land outside the box on amd64, aarch64, and riscv64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 23:07:04 -04:00
Robert Allan JamesandClaude Sonnet 5 1f3ec3554e starkernel: REPL scrollback, ~1000 lines (FABRIC.md item 4.4q)
Scope decided with Captain Bob before implementation: ring buffer +
recall on today's full-screen vt100 grid, not also confining REPL text
to the 4.4o 640x480 box (that confinement stays open as its own future
item, not a third silent deferral). No keyboard input path exists yet
(M8 unstarted), so the trigger is two new FORTH words, SCROLL-BACK
( n -- ) / SCROLL-FWD ( n -- ), exercised via serial injection.

vt100.c gains a text-only 1000-line ring buffer (kmalloc'd, tens of KB
-- not pixel snapshots, which would be ~1000x larger for no benefit)
plus a shadow buffer mirroring the current screen. scroll_up() now
pushes evicted rows into the ring before the pixel scroll. History is
one continuous sequence (ring then shadow); scrolling always redraws
from that sequence -- no separate pixel-scroll path for scrollback,
decided up front to avoid retrofitting later.

New src/word_source/scroll_words.c (Module 31), thin wrappers over
console_fb_scroll_back()/_fwd() -> vt100_scroll_back()/_fwd(). Bug
caught during live testing: both words initially used an off-by-one
underflow check (dsp < 1) copied from a different, older dsp
convention elsewhere in this codebase; vm_pop() (which these words
actually call) uses dsp as a 0-based top-of-stack index, so the check
rejected every legitimate single-argument call. Fixed by removing the
separate precheck and relying on vm_pop()'s own guard.

Live-verified on all three architectures (exceeds this item's
amd64-minimum bar): generated 50+ lines via a FORTH loop, confirmed
SCROLL-BACK recovers correctly older content, and on amd64 confirmed
SCROLL-FWD returns to genuinely live state (not a frozen snapshot) by
showing the injected commands' own echo. Known limitation confirmed by
direct pixel measurement: redrawn lines lose their original SGR color
(not stored per-cell) -- text recovers exactly, color does not.

Three-arch verified: Failed: 0, dict-hashes identical across all
three (values changed correctly from prior items -- two new words
were added).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 21:23:25 -04:00
Robert Allan JamesandClaude Sonnet 5 277845e3bf FABRIC.md: item 4.4p -- CANVAS geometry verified via one-shot probe, all three architectures
Verification only, no permanent code (matches this item's own title
and 4.4i's same-shape precedent -- 4.4l-4.4o were geometry decisions,
not drawing code). One-shot diagnostic probe in sk_repl() drew 4.4o's
box outline plus a strip-top marker, then was reverted after capture
per this document's write/run-once/capture/revert discipline.

Measured pixel bounds directly from each screendump (not eyeballed)
and confirmed exact matches against 4.4o's computed coordinates on
all three architectures: amd64 box x:[320,959] y:[104,583], strip
marker y:704; aarch64/riscv64 box x:[80,719] y:[4,483], strip marker
y:504.

Observed, not fixed here: on the small architectures the REPL banner
text visibly overlaps the box's top edge, because vt100's cursor grid
still spans the whole screen rather than being confined to the 96px
strip -- a real gap between the landed REPL path and the mockup,
belongs to 4.4q/4.4r's wiring work, not this item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:34:14 -04:00
Robert Allan JamesandClaude Sonnet 5 68840bed0c FABRIC.md: item 4.4o -- 640x480 scroll-box centering math computed
Pure geometry, no code change. Blocking question checked first: both
4.4n CANVAS heights (688px amd64, 488px aarch64/riscv64) clear the
480px minimum, so no architecture fails the fit.

amd64: box raster top-left (320,104), 320px side margins, 104px
top/bottom margins.
aarch64/riscv64: box raster top-left (80,4), 80px side margins, 4px
top/bottom margins (confirms 4.4n's 16px gap choice lands exactly
where predicted).

Also translated both into TTF-TEXT's Cartesian bottom-left-origin
convention for whatever later item issues the actual TTF-TEXT calls:
amd64 bottom-left (320,216), aarch64/riscv64 bottom-left (80,116).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:20:59 -04:00
Robert Allan JamesandClaude Sonnet 5 2b4d426e37 FABRIC.md: item 4.4n -- CANVAS rectangle computed, per architecture
Pure geometry, no code change. Gap chosen at 16px, within 4.4m's
flagged <=24px ceiling for the 600px-tall architectures, leaving 8px
of margin rather than cutting to the exact limit.

amd64 (1280x800): CANVAS top-left (0,0), 1280x688, strip at (0,704)
96px tall.
aarch64/riscv64 (800x600): CANVAS top-left (0,0), 800x488, strip at
(0,504) 96px tall.

Checked against 4.4o's 480px scroll-box requirement: 488px clears it
with exactly the 8px margin the gap choice was picked to preserve.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:19:21 -04:00
Robert Allan JamesandClaude Sonnet 5 a4afecb656 FABRIC.md: item 4.4m -- REPL text size and strip height decided
Design decision, no code change (4.4j's constants are already the
final values). Text size 20px (unchanged from 4.4j), 4 visible lines,
strip height 96px (4 x the existing 24px cell height, no extra
padding -- leading is already baked into that cell height).

Flagged the constraint this feeds into before deciding: 4.4o needs a
640x480 scroll-box to fit inside CANVAS on the 600px-tall
aarch64/riscv64 screens, which only leaves 24px of slack over the
480px minimum once the 96px strip is subtracted. 4.4n's gap choice
must stay <=24px on those architectures or 4.4o's fit check fails --
recorded now so it's not a surprise two items later.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:17:33 -04:00
Robert Allan JamesandClaude Sonnet 5 9caebabd17 FABRIC.md: item 4.4l -- framebuffer resolution confirmed, all three architectures
Investigation only, no code change. Answered incidentally by 4.4k's
screendumps rather than requiring a separate run: amd64 1280x800
(QEMU/OVMF GOP default), aarch64 and riscv64 both 800x600 (-device
ramfb's default). Two different resolutions across the fleet, not
three uniform ones -- flagged for 4.4n/4.4o's CANVAS geometry work,
which needs to branch per architecture rather than assume one shared
screen size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:12:53 -04:00
Robert Allan JamesandClaude Sonnet 5 418f040997 FABRIC.md: item 4.4k -- live SGR color verification, all three architectures
No code changes -- investigation/verification only. Injected a raw SGR
escape sequence over the serial socket at the ok> prompt (composed from
EMIT + ." since no FORTH word emits a literal ESC byte + text
directly): 27 EMIT ." [95mCOLOR-TEST" 27 EMIT ." [39m", bright magenta
(the p>=90&&p<=97 branch in apply_sgr()), a third SGR code path
distinct from 4.4h's already-verified truecolor prompt.

Screendump on all three architectures confirms COLOR-TEST renders in
bright magenta via the 4.4j-retargeted TTF draw call, proving the SGR
parser and the new glyph backend work together end-to-end, not just
independently. First screendump evidence ever captured for
aarch64/riscv64 in this document -- every prior screendump item was
amd64-only with that gap explicitly accepted; incidentally closed here
via the QEMU monitor screendump command against each arch's own
display device (ramfb for aarch64/riscv64). Both confirmed booting at
800x600.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:10:12 -04:00
Robert Allan JamesandClaude Sonnet 5 f729b91a09 starkernel: retarget REPL glyph rendering to TTF-TEXT's rasterizer (4.4j)
font_8x16.c keeps rendering everything through and including POST;
TTF-TEXT's rasterizer takes over at the interactive REPL boundary
(sk_repl()) via a new runtime mode switch, vt100_enable_ttf()
(console_fb_enable_ttf() wrapper), not a compile-time swap -- both
backends coexist in the same binary since boot/POST must stay
font_8x16.c per this item's own done-when.

TTF-TEXT (the FORTH word) isn't directly callable from vt100.c -- VM
stack arguments, different call shape than a one-glyph cell draw. Used
hal/ttf.c's VM-independent primitives directly instead (same rasterizer
TTF-TEXT itself calls underneath), added as a native C helper in
vt100.c. Lazily loads fonts:JetBrainsMono-Regular.ttf and kmallocs a
96-slot raster cache (covers all 95 printable ASCII, no eviction
thrash) on first switch.

Cell geometry changes at the switch (mode-aware cell_w()/cell_h()):
provisional 12x24 TTF cell (600/1000em * 20px = 12px exactly, using
4.4i's confirmed-uniform hmtx advance width) vs font_8x16's fixed 8x16
-- cols/rows re-derived and screen cleared at the switch point, same as
vt100_init() itself does. Final REPL text size is 4.4m's decision, not
this item's.

Also fixes the second call site 4.4i flagged: erase_line_range() now
uses one fb_fill_rect() instead of a per-cell font_8x16-specific blank
glyph draw, consistent with erase_display(2)'s full-screen case.

Three-arch verified: amd64/aarch64/riscv64 all reach ok>, POST
Failed: 0, identical dict-hashes. amd64 screendump shows real
proportional JetBrains Mono letterforms on the REPL tail, visibly
distinct from every prior font_8x16 screenshot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 19:56:50 -04:00
Robert Allan JamesandClaude Sonnet 5 64c20c78eb FABRIC.md: item 4.4i -- glyph-draw call-site audit, not cleanly separable
Investigation only, no code change. draw_cursor_glyph() itself is
single-call-site as claimed, but found two things the item's original
framing missed:

1. A second, independent fb_draw_glyph() call site in
   erase_line_range() (partial-line/partial-screen erase), inconsistent
   with full-screen erase which already uses a pixel fb_fill_rect().
2. fb_cell_w()/fb_cell_h() are hardcoded 8*scale/16*scale literals
   matching font_8x16.c specifically, not derived from any generic
   font-metric abstraction; UNDERLINE_ROW hardcodes "row 14 of 16" of
   that same fixed grid.

So 4.4j has three things to retarget/generalize, not one. Font data
verified directly from JetBrainsMono-Regular.ttf's hmtx table (parsed
by hand, no fontTools available): all 95 printable ASCII glyphs share
one advance width (600/1000 em units) -- genuinely monospace for the
glyphs in use, not just by filename.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 19:39:54 -04:00
Robert Allan JamesandClaude Sonnet 5 ae7c9429b4 starkernel: color the console prompt (FABRIC.md item 4.4h)
console.c's emit_prefix() now wraps [VMName] (brackets included) in
FABRIC.md 4.4's locked orange (0xFFA500), and repl.c's two "ok> "
call sites send FABRIC.md 4.4's locked cyan (0x55FFFF), both as real
SGR escape sequences through the existing font_8x16.c/vt100.c pipeline
-- 4.4b already established this needs no dependency on TTF-TEXT/4.4j.
Sent through both raw_putc() (serial) and vt100_putc() (framebuffer),
matching the existing dual-path pattern, so an ANSI-aware serial
terminal renders the same colors as the framebuffer.

Three-arch verified: amd64/aarch64/riscv64 all reach ok>, POST
Failed: 0, identical dict-hashes. Color applies correctly to any VM
name (confirmed via the [Hermes]-prefixed PARITY:BIRTH line in all
three logs, not just [Hera]). amd64 screendump confirms the rendered
colors directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 19:35:32 -04:00
Robert Allan JamesandClaude Sonnet 5 f33353430f starkernel: land console_fb_init() reorder (FABRIC.md 4.4g decided)
Moves the console_fb_init() call in kernel_main.c from after
capsule_birth_mama() to before it, so the fleet-birth/self-test
transcript (Hermes x2, Artemis births, Stadium self-tests -- currently
serial-only) is also framebuffer-visible, not just the small post-birth
tail.

4.5f's -O2 experiment already showed this doesn't hang under
optimization, just costs roughly 12x more boot-time heartbeat ticks
(one-shot, paid only during fleet birth, never repeated at runtime).
Captain Bob's call: worth it, since the serial log was never the
problem -- this is about the same transcript also reaching a real
screen.

Three-arch verified: amd64/aarch64/riscv64 all reach ok>, POST
Failed: 0, identical dict-hashes across all three. amd64 screendump
confirms the framebuffer now carries the full transcript.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 17:18:58 -04:00
Robert Allan JamesandClaude Sonnet 5 9b117c787f FABRIC.md: item 4.5f -- reorder experiment confirms -O2 fixes the stall
Uncommitted experiment (code reverted after capture, per Captain Bob):
moved console_fb_init() before capsule_birth_mama() in kernel_main.c,
amd64 only. At -O2 the boot completes cleanly and reaches ok> well
inside a 300s bound, versus the indefinite stall previously seen at
-O0. Real cost: ~12x more heartbeat ticks during boot from the extra
framebuffer scroll volume -- not free, but not a hang.

Screendump confirms the actual point of 4.4g: the framebuffer now
carries the full HADES/ECW/Stadium/self-test transcript, not just the
small post-birth tail.

This informs 4.4g's open reorder decision, it doesn't make it -- 4.5f
stays unchecked (single-arch feasibility check only, not the three-arch
acceptance pass its own done-when requires).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 17:06:09 -04:00
Robert Allan JamesandClaude Sonnet 5 a1c9fc7330 starkernel: fix lidt() inline-asm constraint hazard, land -O2
FABRIC.md item 4.5d Finding 4: lidt()'s inline asm used a register-only
("r") constraint on the idtr pointer, never telling GCC the asm
dereferences the pointee. At -O2 this let the compiler treat the
256-entry idt[] population loop and idtr_desc's field writes as dead
stores and eliminate them entirely, loading IDTR from uninitialized
stack instead of the real table -- a #GP on the first APIC timer tick
that happened to land on garbage. Same bug class as the earlier
muldiv64 fix (b43e51a): an inline-asm constraint too weak for what the
asm actually touches, invisible at -O0, live at -O2.

Fixed by switching to a memory operand ("m"(*idtr_desc)), matching how
Linux's own load_idt() is written. aarch64/riscv64 checked for the same
pattern -- neither has it, both install their vector/trap tables
entirely in hand-written .S.

Verified: all three architectures boot clean to ok>, POST Failed: 0,
identical dict-hashes across all three under -O2, zero new warnings
vs an -O0 baseline (amd64 3040/3040, aarch64 3041/3041 serial,
riscv64 3037/3037). -O2/-U_FORTIFY_SOURCE landed permanently in
COMMON_CFLAGS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:57:20 -04:00
Robert Allan JamesandClaude Sonnet 5 065ab50240 FABRIC.md: item 4.5d Finding 4 -- deep-traced, not yet root-caused
Computed the loader's true runtime relocation delta to correctly correlate
fault addresses (the running image is starkernel_loader.efi, a relocated
PE, not the separately-linked starkernel_kernel.elf assumed at first).
Fault RIP decodes to log_message()'s entry -- coincidental, not causal,
since it's called on nearly every HADES dispatch during word registration.

Used QEMU's monitor for -d exec,int tracing. Late-start tracing (stop right
before the danger zone to keep trace size down) failed twice -- the window
between a detectable checkpoint and the crash is shorter than host-side
reaction latency. Fell back to full-boot tracing from -S (~2.7GB per
attempt, not committed). That trace shows an unremarkable, normal-looking
repeating three-block loop immediately before the fault, then "Servicing
hardware INT=0x20" (APIC_TIMER_VECTOR) with IDT already showing limit=0 at
that instant.

Ruled out a second illegitimate lidt call (only one call site exists
anywhere, one-time M4 boot setup; searched the trace for any later
execution of that address range and found none). Not yet established: the
actual corrupting write. Documented two remaining explanations (earlier
silent corruption vs. a genuine TCG artifact) and that pinpointing the
exact instruction needs GDB-level single-stepping, a bigger tooling step
than attempted this session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 12:40:30 -04:00
Robert Allan JamesandClaude Sonnet 5 1c5e926c3f FABRIC.md: item 4.5d -- Finding 3 (muldiv64) root-caused and fixed via QEMU tracing, Finding 4 blocks
Used QEMU-side instrumentation (-d int tracing, plus a working chardev-based
monitor -- the older bareword -monitor syntax silently fails on QEMU
10.2.1) as directed. The PM Timer "stall" was never a hang: it was a #DE
divide error cascading to a triple fault, which -no-reboot converts into a
silent clean QEMU exit -- indistinguishable from a hang without tracing,
and why arch_relax() (solving a hang that didn't exist) had no effect.
Root cause and fix documented in full (also see commit b43e51a).

With the fix, amd64 boot at -O2 now proceeds far past the original stall --
through capsule birth and into Hermes's word registration -- before hitting
a second, different fault (Finding 4): a direct #GP at IDT index 32
(APIC_TIMER_VECTOR), not yet root-caused. Same silent-triple-fault-exit
shape, so this was very likely bundled into "the hang" before tracing
distinguished the two separate bugs.

-O2 reverted again (uncommitted); muldiv64's fix is kept, real and
independently verified at unchanged -O0 on all three architectures.
Routine three-arch artifacts from this session's verification runs
included.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 12:17:23 -04:00
Robert Allan JamesandClaude Sonnet 5 b43e51a95d starkernel: fix muldiv64() inline-asm register-allocation hazard
FABRIC.md item 4.5d: root-caused the -O2 boot stall via QEMU '-d int'
tracing -- not a hang. It's a genuine divide-error (#DE) cascading through
a double fault into a triple fault, which -no-reboot converts into a
silent, clean QEMU exit (indistinguishable from a hang without tracing).

muldiv64()'s inline asm declared RDX as a plain output ("=d"(hi)), which
only tells GCC "I want RDX's value after this block" -- nothing told it
that mulq writes RDX *before* divq needs to read a *different* value (the
divisor c) out of it. Nothing stopped the register allocator from placing
c itself in RDX, which mulq then overwrites with the product's high 64
bits before divq ever reads it. Confirmed via the fault's register state:
RAX=0xe8d4a51000 (=1000*1e9 exactly, product fits in the low 64 bits, so
mulq's high-word output is 0) -- if c got allocated to RDX, divq then
divides by that corrupted 0, exactly matching #DE. Worked by accident at
-O0 (different, more conservative allocation); -O2 actually hit it.

A unsigned __int128 rewrite was tried first but needs libgcc's __udivti3
for the general 128-bit case, undefined in this freestanding build -- not
viable, same class of problem as the earlier putc/getc finding. Fixed
instead by declaring rdx a pure clobber rather than an output, the same
pattern the Linux kernel's own mul_u64_u64_div_u64 uses -- a clobber tells
GCC the register is used internally for the whole block and must never be
allocated to any operand, which is the guarantee the previous constraint
list was missing.

Also added a defensive end_tsc<start_tsc guard in the caller
(calibrate_tsc_with_pmtimer): this file's own comments already flag TSC
non-monotonicity as a real risk under TCG hypervisor mode, and an
underflowed delta_tsc would hit the same class of quotient-overflow #DE.
Not the bug that was found, but a real latent risk given what this
function's own documentation already says about the environment.

Verified: with -O2 (uncommitted, not yet reintroduced) this specific stall
is gone -- boot now proceeds far past this point, through capsule birth
and into Hermes's word registration, before hitting a second, different,
not-yet-root-caused fault (write-up follows). Three-arch acceptance boot
clean at unchanged -O0 (this fix doesn't change -O0 behavior, only
prevents UB that only manifested under optimization).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 12:16:21 -04:00
Robert Allan JamesandClaude Sonnet 5 dd09de65f5 FABRIC.md: item 4.5d -- arch_relax() tested against the PM Timer stall, disproven
Follow-up probing narrowed Finding 3's behavior (inconsistent stall point
run-to-run: sometimes reaches iters=1000/delta=951 before stopping,
sometimes never gets past iters=0 even after a 400-second bounded wait) but
didn't pin the mechanism.

Tested the strongest available hypothesis: single-threaded TCG scheduling
starvation from an -O2-tightened spin loop, based on a real precedent --
calibrate_apic_timer() (apic.c) already calls arch_relax() every iteration
of its own spin-wait; calibrate_tsc_with_pmtimer() never had it. Added the
same call, matching that precedent exactly. Result: no change, same exact
stall point on a fresh 60-second bounded wait. Reverted.

Stopping here per this document's own §25.0 rule 5 -- root-causing further
needs either deeper TCG/QEMU internals knowledge or a different diagnostic
approach (host-side instrumentation) than another guess-and-check pass.
Makefile.starkernel and timer.c both back to committed -O0 state, confirmed
booting clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 11:35:09 -04:00
Robert Allan JamesandClaude Sonnet 5 7df2e1bae3 FABRIC.md: item 4.5d -- fortification and putc/getc fixed, PM Timer stall now blocks
Finding 2 (putc/getc) fixed via shim.c backfill (previous commit). With
both Finding 1 (-U_FORTIFY_SOURCE) and Finding 2 fixed, amd64 links clean
at -O2 -- rigorously confirmed zero new warnings by diffing normalized
warning text between -O0 and -O2 builds (empty diff, ~3040 pre-existing
warnings in vendored code unchanged).

New Finding 3, not fixed, now blocking: amd64 boot stalls for minutes
inside calibrate_tsc_with_pmtimer() (timer.c:560-589) at -O2 -- a
mainline busy-wait loop reading the ACPI PM Timer via genuinely-volatile
inl() until 1000 real ticks elapse, bounded by a 5M-iteration timeout. A
one-shot diagnostic probe (reverted after capture) caught exactly one
checkpoint in 55 seconds of observation, then nothing -- not yet
root-caused whether this is the 5M-iteration timeout itself taking several
minutes to exhaust under -O2, or a genuine non-terminating condition.

Makefile.starkernel reverted to -O0 again; nothing broken landed in
history. Routine artifacts from this session's boot attempts included.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 11:14:52 -04:00
Robert Allan JamesandClaude Sonnet 5 37eec5aaa1 starkernel: shim.c -- backfill freestanding putc()/getc()
FABRIC.md item 4.5d: GCC's -O2 folds putchar(c)/fputc(c,stdout) call sites
into putc(c,stdout), and getchar() into getc(stdin) -- neither symbol was
ever needed at -O0 because that fold pass is inactive there. Both are thin
wrappers reusing the existing putchar()/getchar() implementations exactly
(putc -> console_putc via putchar; getc -> the existing "no stdin in
kernel" -1/EOF stub via getchar), not new behavior.

Harmless at the current -O0 build (nothing calls these symbols directly at
-O0); this is prep for enabling optimization, verified against a clean
amd64 boot at unchanged -O0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 11:14:05 -04:00
Robert Allan JamesandClaude Sonnet 5 96ff2f6ae5 FABRIC.md: item 4.5d in progress -- fortification fixed, putc/getc blocks completion
Attempting -O2 on amd64 surfaced two link-time findings, neither of which
was warnings the way 4.5d's own text anticipated:

1. Fixed: -O2 broke the link with __printf_chk/__memset_chk/__fread_chk/
   __snprintf_chk undefined references across five vendored word_source
   files. Root cause: those files unconditionally #include real glibc
   headers (no __STARKERNEL__ guard), which under Ubuntu's default
   _FORTIFY_SOURCE and -O2's __OPTIMIZE__ rewrite printf/etc. call sites to
   _chk variants that shim.c's freestanding backfill never provided --
   worked by accident at -O0 where the macros stay dormant. Fixed by adding
   -U_FORTIFY_SOURCE, the standard fix for this exact situation in
   freestanding/kernel builds.

2. Not fixed, blocking: with fortification disabled, plain putc/getc turned
   up as genuinely undefined -- shim.c never backfilled those, only printf/
   snprintf. -O0 doesn't need these symbols for reasons not fully
   established (GCC's -O2 function-splitting visibly clones at least one
   call site); this needs a real design decision (backfill shim.c vs. guard
   the call sites out of __STARKERNEL__ builds), not a mechanical flag.

Makefile.starkernel reverted to the committed -O0 state (the -O2 change was
uncommitted, so a plain git restore -- nothing broken landed in history).
4.5d stays open pending Finding 2's resolution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 10:58:33 -04:00
Robert Allan JamesandClaude Sonnet 5 c5d46858fb FABRIC.md: item 4.5c complete -- decided -O2, no LTO, no -DNDEBUG
-O2 over -O1/-Og: no optimization level has a verified track record here,
so pick the one that actually solves the motivating problem (4.4g's
fb_scroll_rows() stall needs real loop batching -Og doesn't reliably do)
and matches what both sibling Makefiles already default to.

No LTO yet: deliberately deferred, not rejected -- stacking a second risky
change (LTO, which CLAUDE.md already documents has broken this exact
codebase before) on top of a first-ever optimization pass would make any
4.5e failure ambiguous between two causes. Isolate them.

No -DNDEBUG: checked, not assumed. Zero runtime assert() calls exist
anywhere in the kernel build -- the two "assert(" hits found are a
_Static_assert pair (compile-time, ungated regardless) and a comment. The
freestanding assert.h shim is itself unconditional and ignores NDEBUG too.
Nothing for the flag to affect; copying it by habit would have been exactly
the cargo-culting this item warned against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 10:12:36 -04:00
Robert Allan JamesandClaude Sonnet 5 bc126c5a91 FABRIC.md: item 4.5b complete -- TimeTrustState.ticks fixed, three-arch verified
Marks 4.5b done with the verification record (three log dirs, all reaching
[Hera] ok> at unchanged -O0). Routine artifacts from this session's
three-arch runs: capsules/BLOCK_MAP.md, disk/artemis.img, DOE CSVs, QEMU
serial logs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 10:09:56 -04:00
Robert Allan JamesandClaude Sonnet 5 5cbb04c60a starkernel: TimeTrustState.ticks -- mark volatile, fixing the one hazard 4.5a found
Written directly in ISR context on all three architectures
(heartbeat_tick(), heartbeat.c:163) and read directly by mainline
(heartbeat_ticks(), including the busy-wait at kernel_main.c:880) without
being volatile -- worked by accident at -O0, would be a real bug once the
kernel builds with optimization (item 4.5). Every other field in this
struct is mainline-only (heartbeat_service()'s deferred window/variance/
trust processing), so only this one field needed the qualifier.

Punch list item 4.5b complete.
Three-arch acceptance boot clean at unchanged -O0 (no behavior change
intended yet -- this is prep for enabling optimization, not the switch
itself).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 10:09:47 -04:00
Robert Allan JamesandClaude Sonnet 5 8f4348ec18 FABRIC.md: item 4.5a complete -- full ISR-shared global audit, all three architectures
Read every interrupt/exception vector handler on amd64, aarch64, and
riscv64, and every global or static variable each one touches directly or
through a called function, checked against its volatile declaration.

One confirmed hazard, matching what 4.5 already reported: TimeTrustState.
ticks is written in ISR context on all three architectures and read by
mainline (including a busy-wait) without being volatile.

Everything else checked out for one of three reasons, each verified by
reading the actual read/write sites rather than assumed: already correctly
volatile (g_sk_fault_word, g_spurious_count, g_plic_claim_count, the
heartbeat.c top/bottom-half handoff, i8042.c's ring buffer, virtio_input.c's
diagnostic counters); write-once during init then single-context for the
rest of boot, so never actually concurrent (each arch's timer-calibration
state, virtio_input.c's device-routing globals); or ISR-reachable only on
the fatal exception path, which halts the core permanently afterward so
there's no return to mainline to race with (console/framebuffer state).

Full findings recorded in FABRIC.md as 4.5a's inventory. No code changed --
investigation only, per the item's own scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 10:04:31 -04:00
Robert Allan JamesandClaude Sonnet 5 de69b3827d FABRIC.md: mark 4.5 as blocking priority over all other punch-list work
Captain Bob 2026-08-11: no other item gets worked until 4.5a-4.5f (the
-O0-kernel fix) are done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:56:26 -04:00
Robert Allan JamesandClaude Sonnet 5 e5b4f4b814 FABRIC.md: swap 4.5/4.6 -- -O0 finding moves to 4.5, Artemis last moves to 4.6
Captain Bob: the -O0-kernel finding (with its 4.5a-4.5f scoping) takes
priority over Artemis-last, so it moves up to 4.5 and Artemis moves down
to 4.6. Updated the three other places in this document that referenced
"the 4.5 Artemis boundary" by number to point at 4.6 instead, with a note
on the renumbering history for anyone reading those passages later.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:54:35 -04:00
Robert Allan JamesandClaude Sonnet 5 2e22303ef1 FABRIC.md: scope item 4.6 into 4.6a-4.6f -- audit, fix, decide flags, build, verify, retry 4.4g
Scoping only, per Captain Bob's explicit instruction -- nothing implemented.
Breaks the -O0-kernel finding into six sequential, individually-committable
items matching this document's §25.0 rule-1 discipline (same treatment 4.4
itself got before 4.4a onward):

4.6a full ISR-global volatile audit (investigation only), 4.6b fix whatever
4.6a finds (starting from the one already-confirmed TimeTrustState.ticks
hazard), 4.6c decide the actual -O flags and record the reasoning before
touching the Makefile, 4.6d apply them and get a clean three-arch build,
4.6e the real three-arch acceptance boot (a kernel that has only ever run
at -O0 has no track record at any other level), 4.6f retry 4.4g's reorder
now that optimization exists to make it viable.

Also flagged, not scoped: the ACL-RWT DoE campaign's overhead numbers were
all measured at -O0; nobody has asked whether they still hold once the
kernel builds differently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:48:20 -04:00
Robert Allan JamesandClaude Sonnet 5 b42308762b FABRIC.md: 4.4g stays open (reorder not viable), add urgent item 4.6 (-O0 kernel build)
Attempted 4.4g's console_fb_init() reorder twice this session: once bare,
once with the fb_scroll_rows() volatile fix applied. Both stalled boot
indefinitely (12,000+ lines logged, still running after 3 minutes vs. a
normal few-second boot) instead of completing. Root cause traced past the
scroll fix to Makefile.starkernel building the kernel at -O0 -- no
optimization flag has ever been configured there, verified against the
file's full git history (17 commits, only ever one unrelated host-tool -O2
line). Both the kernel's own vendored hosted Makefile and the standalone
StarForth repo's Makefile default to -O2 (up to -O3/-flto on faster
targets); Makefile.starkernel was written fresh for the bare-metal target
and never got that ladder.

Documented as new item 4.6: enabling optimization is not a safe drop-in
change on its own. Found one confirmed, isolated correctness hazard first --
TimeTrustState.ticks (timer.h:90) is written directly in ISR context on all
three architectures (heartbeat.c:163) and read directly by mainline
(heartbeat.c:200-202, including a busy-wait in kernel_main.c:880) without
being volatile, unlike every other ISR-shared global checked
(g_spurious_count, g_plic_claim_count, g_pending_counter/g_pending_valid/
g_adaptive_period_ns are all correctly volatile already). Reverted the
console_fb_init() reorder itself (uncommitted, so a plain git restore) --
4.4g stays open pending 4.6.

Both the reorder attempts' logs (stalled, never reached ok>) and this
session's routine three-arch artifacts (capsules/BLOCK_MAP.md, disk/
artemis.img, DOE CSV) are committed as audit trail per CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:42:35 -04:00
Robert Allan JamesandClaude Sonnet 5 e211707e2d starkernel: fb_scroll_rows() -- drop unnecessary volatile from the bulk copy/fill
Found while investigating item 4.4g's boot stall (moving console_fb_init()
earlier caused a >3-minute hang scrolling the fleet-birth transcript). The
GOP framebuffer is mapped write-back RAM (vmm.c:350-363), not
cache-disabled MMIO with side effects, so there's no correctness reason for
the scroll/fill loops to force one un-batchable volatile access per pixel.
g_fb.base stays volatile for other call sites; this function now casts to a
plain pointer for its bulk copy only.

Confirmed this alone does not fix the 4.4g stall -- the kernel builds at
-O0 (no optimization flag anywhere in Makefile.starkernel), so nothing
here gets vectorized regardless of the qualifier. That's now documented as
its own item, FABRIC.md 4.6. Keeping this fix regardless: it's correct on
its own terms independent of 4.4g's outcome.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:42:19 -04:00
Robert Allan JamesandClaude Sonnet 5 7ee498705e FABRIC.md: check off 4.4c/4.4d/4.4e/4.4f, root-cause and reframe 4.4g
Three-arch acceptance boot (amd64/aarch64/riscv64) clean, all reaching
[Hera] ok>, plus amd64 screendump evidence for each item -- checking off
4.4c (console_fb_init wiring), 4.4d ([VMName] prefix reaching the
framebuffer), 4.4e (\r/\n fix), and 4.4f (glyph-flip fix, previous commit).
Screendump verification itself stays amd64-only pending future
aarch64/riscv64 screendump tooling; Captain Bob accepted that gap as
non-blocking for these checkboxes.

4.4g reframed from "anomaly, not root-caused" to a design decision: traced
the missing hundreds of lines of boot output to console_fb_init() running
after capsule_birth_mama() (which births the whole Tripod fleet and their
self-tests) rather than before it, so that output is serial-only by
construction -- not a scroll/CSI-parser bug. Left unchecked pending a call
on whether to reorder console_fb_init() earlier in boot.

Also commits routine artifacts from this session's three-arch runs:
capsules/BLOCK_MAP.md (regenerated manifest), disk/artemis.img (Artemis
writes on every boot), DOE CSVs, and the corresponding QEMU serial logs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:03:31 -04:00
Robert Allan JamesandClaude Sonnet 5 da88a9a546 starkernel: item 4.4f -- fix vertically-flipped glyph rendering on the framebuffer
font_8x16_data stores each glyph's 16 scanline bytes bottom-to-top, not
top-to-bottom -- confirmed by hand-decoding 'A' (0x41) and 'T' (0x54): both
only produce their correct letterform when the row order is reversed.
fb_draw_glyph() mapped glyph row 0 to the cell's top pixel row, which was
wrong for this table. Flip the row-to-pixel mapping instead of touching the
4096-byte font data; every glyph now renders right-side up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 09:03:17 -04:00
Robert Allan JamesandClaude Sonnet 5 099605d399 starkernel: remove item 4.3.1's orientation-test corner blocks from boot
fb_draw_orientation_test() was a one-time diagnostic for 4.3.1 (raw GOP
framebuffer wiring), already [x] done. With 4.4c's vt100 console now live,
the corner blocks just obscure real console output in every screendump.
Function definition left in framebuffer.c/framebuffer.h for future reuse;
only the boot-time call site is removed.

Also commits routine log/manifest housekeeping: capsules/BLOCK_MAP.md
(regenerated by mkcapsule on each build), the amd64 probe logs from before
today's outage, and the screendump logs + evidence screenshot from this
session's 4.4c/4.4d/4.4e verification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 08:38:12 -04:00
Robert Allan JamesandClaude Sonnet 5 859381640b FABRIC.md: insert 4.4e/4.4f/4.4g (found verifying 4.4c/4.4d), renumber 4.4e-4.4p to 4.4h-4.4s
4.4c/4.4d's fix was screendump-verified on amd64: the framebuffer console
mechanism works and [VMName] genuinely reaches the screen for the first
time. Verifying that screendump surfaced three more issues, each given its
own item per SS25.0 rule 3 rather than folded in silently:

- 4.4e (fixed this session, see prior commit): console_putc() forwarded raw
  '\n' to vt100_putc() without '\r', corrupting line-start columns.
- 4.4f (open, not root-caused): character glyphs render vertically flipped.
- 4.4g (open, not root-caused): most of the framebuffer stays blank despite
  hundreds of lines of boot output that should have scrolled through it.

Confirmed via a second screendump after the 4.4e fix that 4.4f and 4.4g are
both independent of the \r/\n bug -- unchanged before and after.

Added evidence/ as a new tracked location for durable proof screenshots,
distinct from the existing gitignored fb/ (disposable local eyeballing,
per the 2026-08-07 decision to stop tracking it). Linked from the relevant
4.4c/4.4d/4.4e/4.4f/4.4g entries.

4.4c and 4.4d remain unchecked -- their Done-when criteria require a
three-arch screendump match against the serial log, not yet attempted on
aarch64/riscv64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 08:35:58 -04:00
Robert Allan JamesandClaude Sonnet 5 eefe765f00 starkernel: item 4.4e -- fix console_putc() forwarding \n to vt100_putc() without \r
console_putc() mirrored raw '\n' to vt100_putc() while raw_putc() (serial
path) auto-injects '\r' before '\n'. vt100_putc()'s '\n' handler only
increments the row, never resets the column, so every line after the first
started at whatever column the previous line ended on instead of column 0 --
confirmed by screendump as diagonal text scatter across the framebuffer.
Latent since this code was written; invisible until 4.4c turned the
framebuffer console on for the first time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 08:35:48 -04:00
Robert Allan JamesandClaude Sonnet 5 becaea7def starkernel: item 4.4c/4.4d -- wire console_fb_init into boot, route emit_prefix to framebuffer
console_fb_init() (which calls vt100_init()) was never called anywhere in the
boot sequence -- only raw fb_init() ran, so vt100_putc() no-op'd on every
call and no console output (REPL, POST, boot logs) ever reached the
framebuffer, only the corner orientation-test blocks. Replace the raw
fb_init() call in kernel_main_deep() with console_fb_init() so the
framebuffer console actually comes up (4.4c).

emit_prefix() also wrote the "[VMName] " bracket text via raw_putc() only
(serial), never vt100_putc(), so the bracketed VM name never reached the
screen even once the framebuffer console was live. Mirror console_putc()'s
existing serial/framebuffer split there too (4.4d).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 08:13:10 -04:00
Robert Allan JamesandClaude Sonnet 5 bf89b8239f FABRIC.md: insert 4.4c (wire console_fb_init into boot), renumber 4.4c-4.4o to 4.4d-4.4p
Found while screendump-verifying the prefix fix (now 4.4d): kernel_main.c
deliberately never calls console_fb_init(), so vt100_init() never runs and
vt100_putc() no-ops on every call -- no console output has ever reached the
framebuffer, only fb_init()'s own corner self-test blocks. ROADMAP.md's
obsolete M8 section claimed this path was already live; that was never
actually screendump-verified.

Records Captain Bob's stated end goal (2026-08-11): framebuffer console and
serial console must be functional identically. 4.4c wires that in.

Only uncommitted items were renumbered; 4.4/4.4a/4.4b keep their IDs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:56:07 -04:00
Robert Allan JamesandClaude Sonnet 5 d187c87671 FABRIC.md: insert 4.4c (framebuffer prefix bug), renumber 4.4c-4.4n to 4.4d-4.4o
Found while scoping color application (now 4.4d): console.c's emit_prefix()
writes [VMName] directly via raw_putc(), serial-only -- it never calls
vt100_putc(), so the bracketed VM name has never actually reached the
framebuffer despite 4.4a's serial-verified "regression: clean" note. Given
its own item (4.4c) per §25.0 rule 3 rather than folded in silently.

Only uncommitted items (old 4.4c-4.4n, none yet [x]) were renumbered;
4.4/4.4a/4.4b keep their IDs since they're already committed. Also fixed one
stale reference in §27.8's narrative that still pointed at the old
CANVAS-geometry item by its pre-breakdown ID (4.4b -> 4.4k).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:50:57 -04:00
Robert Allan JamesandClaude Sonnet 5 a34273579d FABRIC.md: 4.4b -- prompt color does not depend on the TTF retarget
Punch list §25 item 4.4b complete.
Investigation only, no code. draw_cursor_glyph() (vt100.c:125) already
draws through g_vt.fg/g_vt.bg via fb_draw_glyph(), and apply_sgr() already
parses true 24-bit-color SGR (ESC[38;2;R;G;Bm) -- color reaches the screen
today independent of which font renders the glyph. 4.4c can proceed without
waiting on 4.4d/4.4e.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:41:04 -04:00
Robert Allan JamesandClaude Sonnet 5 f1d29e975e repl.c: unify REPL prompt to "[VM name] ok>"
Punch list §25 item 4.4a complete.
Removed the manually-built <Name>)ok>/zuse)ok> prompt suffix from
sk_repl_step()/sk_repl_run() -- console.c's console_putc() already emits a
"[VMName] " prefix at line-start, so the old code was double-printing the
name for non-Hera VMs ("[Hermes] Hermes)ok> "). Now prints only "ok> " and
lets the existing prefix supply the bracket. emergency_console/zuse_session
security semantics unchanged, display-only. Verified: all three
architectures boot live to "[Hera] ok>" (logs/20260811-073408 amd64,
logs/20260811-073448 aarch64, logs/20260811-073542 riscv64).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:37:13 -04:00
Robert Allan JamesandClaude Sonnet 5 838dcab5d2 FABRIC.md: lock REPL prompt format and colors
Punch list §25 item 4.4 complete.
Design-only, no code. Format [VM name] ok>; ok> reuses existing
FB_ANSI_PALETTE[14] bright cyan (0x55FFFF); [VM name] gets a fresh literal
orange (0xFFA500), since no orange exists in the ANSI palette. Verified: no
implementation, just literal values checked against the existing codebase
constants and written into FABRIC.md for 4.4a/4.4c to consume.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:31:15 -04:00
Robert Allan JamesandClaude Sonnet 5 a079028b40 FABRIC.md: break 4.4 REPL into 14 sub-items (4.4-4.4n), correct POST boundary
Expands the single 4.4 REPL item into a granular punch list matching the
4.3.5/4.3.6-series style: prompt format+color (4.4-4.4c), VT100 ANSI/SGR
engine retargeted onto TrueType (4.4d-4.4f), CANVAS geometry (4.4g-4.4k),
scrollback+toggle (4.4l-4.4m), and the blocked (user) prompt segment (4.4n).

Corrects the font_8x16/TTF handoff boundary: the embedded VT100 path renders
everything through and including POST (which runs after the capsule/VM
bootstrap, per CLAUDE.md), not just pre-bootstrap M1-M6 messages as
originally scoped -- TTF-TEXT takes over only once POST completes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:28:29 -04:00
Robert Allan JamesandClaude Sonnet 5 20801ded72 FABRIC.md/ROADMAP.md/ttf_words.c: scope console REPL (4.4), obsolete M8, flip TTF to Cartesian y
FABRIC.md: renumber Artemis-last boundary 4.4 -> 4.5, add new 4.4 REPL item
(console visual design scoped this session -- CANVAS is one shared region
above the REPL strip, 640x480 scroll box centered within it, stroke font,
ANSI color, VM-identity + ACL-identity prompt segments, ~1000-line
scrollback), linked to repl-mockup.png.

ROADMAP.md: mark M8 section OBSOLETE -- replaced by FABRIC.md 4.4, kept for
history only.

ttf_words.c: TTF-TEXT's y argument now Cartesian (origin bottom-left of the
physical framebuffer, y increasing upward) instead of raw framebuffer
coordinates, translated once via fb_height() - y. Verified via amd64
screendump (logs/20260811-070418/), text renders right-side-up with
increasing y moving up the screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 07:08:32 -04:00
Robert Allan JamesandClaude Sonnet 5 8e2c5dae5f ROADMAP.md: scope M8 REPL keyboard wiring, design decisions resolved
Not implementation -- documentation-only. M8 is tracked outside Stadium
(FABRIC.md §27.5), so this scoping lives in docs/lithosananke/ROADMAP.md
rather than as new FABRIC.md 4.3.x items.

Read the code before scoping, not assumed: the REPL already works
interactively over serial (sk_repl_run(), repl.c) with working
backspace/echo, and its on-screen text already renders via the existing
VT100 console (vt100_init()/font_8x16.c) independent of both the stroke
font and TrueType work -- neither was ever a REPL-strip prerequisite.
What's actually missing: sk_readline()'s console_getc() is
serial-UART-only, never touches KEY-EVENT (4.3.5f); KEY/?TERMINAL
(io_words.c) are dead stubs (KEY calls a getchar() hardcoded to EOF in
shim.c, ?TERMINAL always returns false).

Resolved design decisions: minimal US-QWERTY scancode->ASCII layout
with shift-state tracking (KEY-EVENT carries no modifier state today);
merge keyboard into console_getc()'s poll with serial staying a
co-equal source, not replaced (the entire acceptance/DoE harness
injects over the serial socket -- breaking that breaks make qemu,
DOE_INJECT, and every screendump technique used throughout 4.3.x); wire
KEY/?TERMINAL to the same merged source for FORTH-79 compliance;
CANVAS viewport sizing last, since it's presentation not input
plumbing. Extended scancodes, autorepeat-as-character-repeat, arrow-key
history explicitly out of scope for the "minimal" bar.

FABRIC.md's existing "not yet scoped" notes (4.3.5f's landing-point
note, 4.3.7f's closing note) updated to point here rather than
duplicating the design content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 00:52:40 -04:00
Robert Allan JamesandClaude Sonnet 5 ed8bf5460b FABRIC.md: checkpoint -- TTF rendering verified, 3 arches (4.3.7f)
Punch list §25 item 4.3.7f complete. No code changes -- ttf.c/ttf.h/
ttf_words.c unchanged since 4.3.7e; this is verification only, same
posture as 4.3.6g.

Three-arch acceptance boot clean (standard make ARCH=<arch> clean qemu,
run in order, one at a time): all three reached [Hera] ok> cleanly,
logs committed under logs/20260810-231553(amd64)/231640(aarch64)/
231739(riscv64).

One screendump per architecture, identical TTF-TEXT command sequence
(S" Hi 4.3.7e!" 200 200 28 16777215 TTF-TEXT) via monitor-socket +
serial-injection, same pattern as 4.3.7c/e. All three show the string
rendered legibly with correct mixed-case/digit/punctuation glyphs and
identical monospace spacing.

TrueType rendering (4.3.7-4.3.7f) is now complete, adjunct to the
stroke font per §27.7 decision #4. Stopping here before scoping REPL
wiring (M8), per this item's own posture matching 4.3.6g.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 00:45:11 -04:00
Robert Allan JamesandClaude Sonnet 5 715ebcc57e ttf_words.c: TTF-TEXT entry point, hmtx advance widths (item 4.3.7e)
Punch list §25 item 4.3.7e complete. New src/word_source/ttf_words.c
registers TTF-TEXT ( c-addr u x y size color -- ): lazily loads the v1
default font capsule + raster cache once, decodes UTF-8 (C
reimplementation mirroring capsules/fabric.4th's DECODE-UTF8 exactly),
looks up each glyph's cached bitmap, blits via fb_put_pixel, advances
the pen by the glyph's real hmtx advance width scaled to pixels.

Necessary plumbing: ttf_parse() now also locates hhea/hmtx, and
ttf_glyph_advance_width() reads a glyph's advance width -- required for
this item's own "proportional spacing correct" acceptance clause, no
advance-width data existed anywhere else in the parser. Verified in
tools/ttftest.c: A/a/0/space all read advance_width=600, correctly
uniform since JetBrainsMono-Regular.ttf is monospace.

(x,y) is raster pixel space (top-left origin, Y-down), deliberately not
the stroke font TEXT's Cartesian Y-up convention -- recorded explicitly
in ttf_words.h, not conflated.

Verified live, amd64, screendump: injected
S" Hi 4.3.7e!" 200 200 28 16777215 TTF-TEXT over a serial socket after
boot, no error, captured a screendump showing the string rendered
legibly with correct mixed-case/digit/punctuation glyphs and even
spacing. TTF-TEXT is this item's permanent deliverable, not a
throwaway probe. Compile-checked clean on all three architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 23:11:40 -04:00
Robert Allan JamesandClaude Sonnet 5 2db4603d04 ttf.c: glyph raster cache, fixed slots, no allocation (item 4.3.7d)
Punch list §25 item 4.3.7d complete. ttf_raster_cache_get() looks up
(font, codepoint, size_px) in a caller-owned fixed slot array, evicting
round-robin once full, rasterizing into a slot on a miss.

Verified live in tools/ttftest.c: an identical (font, 'A', 24px) call
made twice returns was_hit=0 then was_hit=1, and the slot's own hits
counter reads exactly 1 afterward -- checked programmatically. A
different-codepoint call misses again, proving the key actually
discriminates. Wall-clock timing (miss 0.040ms vs hit 0.001ms) is
printed as informational corroboration only, not the load-bearing
check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 22:31:56 -04:00
Robert Allan JamesandClaude Sonnet 5 095860251a ttf.c: rasterization -- Bezier flattening + even-odd scanline fill
Punch list §25 item 4.3.7c complete. ttf_rasterize_glyph() flattens
quadratic-Bezier contours (fixed 8-segment subdivision, matching
CIRCLE/ELLIPSE's fixed-segment precedent) and fills them into a
caller-supplied bitmap via even-odd scanline fill, no AA. A local
signed Q48.16 multiply (q48_smul) handles negative outline coordinates,
since the shared q48_mul/q48_div are unsigned-only.

Verified two ways: tools/ttftest.c's ASCII-art dump + structural checks
for 'A'/'.'/'a', all recognizable and passing; and a live amd64
screendump via a throwaway TTF-PROBE word (loaded the font capsule,
rasterized 'A', blit via fb_put_pixel), showing a clearly legible 'A'
on the CANVAS -- probe reverted immediately after capture, only the
permanent ttf.c/ttf.h rasterizer remains. Compile-checked clean on all
three architectures (hal/*.c wildcard); this item's own acceptance is
the amd64 screendump, not a three-arch boot (that's 4.3.7f).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 22:24:47 -04:00
Robert Allan JamesandClaude Sonnet 5 2ef8d26c6f capsules/fonts: JetBrainsMono-Regular.ttf as a raw-blob capsule (item 4.3.7b)
mkcapsule.c already ingests arbitrary non-.4th files as raw byte blobs
(validate_forth_blocks only applies to .4th filenames), so no hex/base64
text-encoding or tool changes are needed -- corrects the design premise
in FABRIC.md's 4.3.7b item text (see the FABRIC.md correction note this
commit carries). ttf_load_from_capsule() resolves the font capsule by
name, validates its content hash, and points ttf_font_t at the capsule
arena bytes directly, zero-copy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 21:50:35 -04:00
Robert Allan JamesandClaude Sonnet 5 70b6918279 ttf.c: glyph outline extraction, simple and composite (item 4.3.7a)
ttf_glyph_outline() decodes simple-glyph flag/coordinate runs and
recursively resolves composite components into a caller-supplied point/
contour-end buffer, in Q48.16. Composite scale/rotation/skew transforms
are rejected with TTF_ERR_UNSUPPORTED rather than mis-rendered, since the
shared q48_mul/q48_div are unsigned-only; translation-only composites
(the only kind the v1 glyph repertoire uses) apply cleanly via q48_add.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 21:45:04 -04:00
Robert Allan JamesandClaude Sonnet 5 5f6cc054d4 ttf.c/ttf.h/ttftest.c: TrueType parser core -- sfnt/head/maxp/loca/glyf/cmap (item 4.3.7)
Freestanding C module resolving a Unicode codepoint (cmap format 4) to a
glyph index and its outline header (contour count, bounding box), verified
against an independent from-scratch Python reference reader via
tools/ttftest.c. Not yet wired into the boot path or capsule system.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 21:41:42 -04:00
Robert Allan JamesandClaude Sonnet 5 b9b7cb2c6a FABRIC.md: checkpoint -- all 113 v1 glyphs verified, 3 arches (4.3.6g)
Punch list §25 item 4.3.6g complete. Fixed the cross-arch bug found
while first attempting this checkpoint: aarch64 and riscv64 both boot
an 800x600 ramfb device (confirmed empirically for both, not assumed),
against amd64's 1280x800 GOP framebuffer -- the original verification
grid's Y coordinates ran off the top of the smaller screens. Rebuilt
the grid to fit 800x600, safe on amd64's larger screen too.

All 113 glyphs confirmed legible and correctly positioned on all three
architectures, one screendump each, from the identical FORTH command
sequence. No code changes -- font.4th/fabric.4th are unchanged since
4.3.6f; this is verification only.

Three-arch acceptance boot clean, Stadium conservation unchanged.

Stroke font (4.3.6-4.3.6g) is now complete. Per this item's own
posture, stopping here before scoping REPL wiring (M8) -- 4.3.7
(TrueType, adjunct) is the scoped-but-not-started next work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 21:35:07 -04:00
Robert Allan JamesandClaude Sonnet 5 28731b8536 FABRIC.md: scope TrueType rendering as adjunct to stroke font (4.3.7)
Not implementation -- documentation-only. Reviewing the 4.3.6 stroke
font's full 113-glyph repertoire (mid-4.3.6g checkpoint) prompted the
decision to add TrueType rendering as an adjunct path rather than
continue refining strokes alone. Stroke font stays; nothing reverted.

Adds 4.3.7-4.3.7f (parser core, outline extraction, font data
ingestion, rasterization, glyph cache, TTF-TEXT entry point,
three-arch checkpoint) plus §27.7 documenting four resolved design
decisions: C implementation layer, Q48.16 fixed-point (not float --
confirmed real via Makefile.starkernel grep that GAP-B2's hypothesized
FP-register-clobber-on-interrupt risk is real on all three
architectures, not just hypothetical), capsule-block-encoded font
data, and TrueType as the primary text path once built.

4.3.6g itself stays open -- paused mid-verification when a real
cross-arch framebuffer-resolution difference (aarch64 800x600 ramfb
vs amd64 1280x800 GOP) surfaced; not yet re-run with corrected
coordinates.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 21:10:23 -04:00
Robert Allan JamesandClaude Sonnet 5 2960989100 font.4th: TEXT entry point, UTF-8 string rendering (item 4.3.6f)
Punch list §25 item 4.3.6f complete. TEXT ( c-addr u x y size color -- )
walks a UTF-8 byte string, decoding one codepoint at a time via
DECODE-UTF8, drawing each via DRAW-GLYPH, and accumulating the cursor
X by the glyph's em-advance scaled to pixels. Uses 2>R/2R> to stash
the DECODE-UTF8 remainder off the data stack while DRAW-GLYPH's args
are pushed.

Defined in font.4th, not fabric.4th, so its compiled DRAW-GLYPH call
binds to the real definition, not fabric.4th's 4.3.6b placeholder --
same early-binding constraint as DISPATCH-GLYPH itself.

Verified live: a string mixing ASCII, Latin-1 (degree sign), and
General Punctuation (em dash) renders correctly in one TEXT call with
proportional spacing, no overlap.

Three-arch acceptance boot clean, Stadium conservation unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:46:55 -04:00
Robert Allan JamesandClaude Sonnet 5 aee09cac0a user-font-demo.4th: prove the override mechanism (item 4.3.6e)
Punch list §25 item 4.3.6e complete. Optional capsule, not wired into
the boot chain, overriding DISPATCH-UPPER's codepoint 65 (G-A) with a
marked alternate glyph while every other letter falls through to
font.4th's originals unchanged.

Corrects §27.6.5: redefining the DISPATCH-* bucket word alone is not
enough, since DISPATCH-GLYPH/DRAW-GLYPH are themselves compiled early
against font.4th's own dispatch words (same early-binding finding as
4.3.6c, one layer up). Verified both ways: the partial override (bucket
word only) left DRAW-GLYPH still drawing the original glyph; redefining
DISPATCH-GLYPH/DRAW-GLYPH too made the override take effect.

Three-arch acceptance boot clean, Stadium conservation unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:41:04 -04:00
Robert Allan JamesandClaude Sonnet 5 ef930ce04e init.4th: wire fabric.4th/font.4th into the boot chain (item 4.3.6d)
Punch list §25 item 4.3.6d complete. Both capsules now EXEC via
Hera's Mama IDENTITY capsule (init.4th block 2049), loading on every
normal boot instead of manual serial injection. Verified by booting
with zero injected commands and calling DRAW-GLYPH directly.

Three-arch acceptance boot clean, Stadium conservation unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:33:01 -04:00
Robert Allan JamesandClaude Sonnet 5 5d2e1c2184 font.4th: default system font-set capsule, 113 glyphs (item 4.3.6c)
Punch list §25 item 4.3.6c complete. Digits, upper/lowercase, ASCII
punctuation, Latin-1 Supplement, and General Punctuation, each a
stroke-drawing word in the 4.3.6 em-square convention.

Corrected mid-build: the first pass used G-LINE only, missing that
CIRCLE/ARC/ELLIPSE already existed (4.3.3b). Reworked all round shapes
to use them via new em-square-aware wrappers (G-CIRCLE/G-ARC/G-ELLIPSE/
EM-R, fabric.4th 5000-5002), bounded to quarter/half/three-quarter/
full sweeps to avoid unbounded per-glyph angle tuning. font.4th also
redefines DISPATCH-GLYPH/DRAW-GLYPH themselves, not just the six
DISPATCH-* bucket words, since fabric.4th's originals were compiled
early against the 4.3.6b placeholders (CASE early-binding, §27.6.5).

Three-arch acceptance boot clean, Stadium conservation unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:26:14 -04:00
Robert Allan JamesandClaude Sonnet 5 4427986c96 fabric: codepoint -> glyph dispatch (DISPATCH-GLYPH, TOFU)
Punch list §25 item 4.3.6b complete.
capsules/fabric.4th blocks 4921-4924: DISPATCH-GLYPH routing via
WITHIN to six bucket words (DISPATCH-DIGIT/-UPPER/-LOWER/
-ASCII-PUNCT/-LATIN1/-GENPUNCT), TOFU fallback, DRAW-GLYPH. Buckets
carry one placeholder stroke word each (G-TEST-*), not the real
113-glyph set -- that's item 4.3.6c's scope, deliberately deferred.

Also: merged two lines in block 4920 (DECODE-UTF8) to fit mkcapsule's
real 64-char x 16-line block limit once a trailing blank separator
line is counted against it -- mechanical reformat, re-verified via a
DECODE-UTF8 regression check (65/176/8212, unchanged).

Verified live on amd64: one representative codepoint per bucket plus
one out-of-range codepoint, all seven DRAW-GLYPH results matched
expected exactly (400/600/450/250/550/700/500-TOFU). Three-arch
acceptance boot clean, Stadium conservation unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 19:15:05 -04:00
Robert Allan JamesandClaude Sonnet 5 24d6b9e20e fabric: UTF-8 decoder (DECODE-UTF8)
Punch list §25 item 4.3.6a complete.
capsules/fabric.4th blocks 4918-4920: UTF8-SEQ-LEN/UTF8-CONT? verbatim
from §27.6.2, DECODE-UTF8 dispatching to four UTF8-ASSEMBLE-N helpers
(1/2/3/4-byte). Factored into helpers after the single-word draft hit
mkcapsule's real 64-char x 16-line block limit. Verified live on
amd64: a 6-byte test buffer (ASCII + deg-sign + em-dash) decoded to
65/176/8212 across three sequential calls, exact match against
hand-computed codepoints, buffer fully consumed. Three-arch acceptance
boot clean, Stadium conservation unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 19:00:36 -04:00
Robert Allan JamesandClaude Sonnet 5 82e948afe9 fabric: em-square glyph coordinate convention (EM-X/EM-Y/G-LINE)
Punch list §25 item 4.3.6 complete.
capsules/fabric.4th blocks 4916-4917: EM-UNITS, GOX/GOY/GSIZE/GCOLOR,
EM-X/EM-Y/G-LINE per §27.6.1, scaling/translating em-square strokes
into CART-PLOT screen coordinates via */. Verified live on amd64 via
a temporary probe (built, run once, reverted): two G-LINE test shapes
at GSIZE 100 and GSIZE 50, one leg each exercising a negative em-y
value chosen to hit */'s truncate-toward-zero behaviour, not a
multiple of EM-UNITS. Screendump pixel-bbox extraction matched
hand-calculated raster coordinates exactly on both shapes. Three-arch
acceptance boot clean, Stadium conservation unaffected
(resident_sum=43691 reservoir=21845 sum=65536 on all three).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 18:53:02 -04:00
Robert Allan JamesandClaude Sonnet 5 980f902c7b chore: commit stray CaptainBob.png and an uncited riscv64 boot log
CaptainBob.png: untracked repo-root image, added per Captain Bob's
direction.

logs/20260808-002843/riscv64/: a riscv64 boot log from ~00:28, minutes
after the committed 4.3.5 acceptance boots. Not cited anywhere in
FABRIC.md. It ends in the scause=0xF store-page-fault at 0x0c201000
that item 4.3.5a later formally traced to riscv64 having no
software-controlled paging -- an earlier, informal hit of the same
bug, predating 4.3.5a's own cited diagnostic logs (10:19am+).
Committed for the audit record per this repo's "logs are committed
artifacts" convention, superseded by but not duplicating 4.3.5a's
own logs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 18:35:24 -04:00