Captain Bob, 2026-10-26: sized for an off-the-shelf thumb drive, "a minimum
and then ... no max or reasonable max size"; "all to Artemis, identity stays
at 500 MiB". The image is 2 GiB (ESP 64 MiB, identity 500 MiB, Artemis the
rest); the minimum stick 8 GB; at first boot Artemis grows to fill the stick,
up to 2 TiB, writing metadata only (GPT, volume header, free map, fence); a
stick under 8 GB is not grown. With genesis, increment 5; the GPT writer is
INSTALL's too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captain Bob, 2026-10-26: "64 megabytes does not need to be an engraved in
stone size ... start maybe 500 megabytes." Sizes are set in kernel/Makefile
and are not fixed by the formats.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approved by Captain Bob 2026-10-26, with his ruling on review: a GPT disk is
never attached whole -- the identity partition is attached in the raw
identity drive's place; a GPT disk with no StarshipOS partition, or a damaged
one, is not attached.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the fresh review of the stick's increment 1 (With fixes):
- Critical: after logout Zuse's last screen, her prompt included, could be
drawn back on a headless machine. The logout clear (ESC[2J) blanked the
pixels only: Alt+TAB, still read while headless, redrew the terminal
from its saved text; and if she had Alt+TABbed to the graphics view
before the pull, the clear did nothing and her session stayed on screen
(and the console did not draw at her next login). Now vt100_reset()
forgets everything the terminal has shown -- the on-screen text, the
scrollback and their boot snapshots -- makes it visible again and fills
the screen; and Alt+TAB does nothing while the screen is off (v3's never
is, so v3 is unchanged).
- Important: an EMERGENCY_CONSOLE_ENABLED build no longer clears the screen
when Zuse's drive is pulled: its console goes on running.
Red: alttab_after_logout 183308 (4515 lit), alttab_before_pull 183529
(4539 lit; the console not redrawn), emergency_pull 183759 (0 lit).
Green: 184115, 184328, 184552; regression 184805-185956 (screens,
keyboard, hotplug, emergency, v3 typed by keyboard) all pass.
Accepted: 190111, 190312, 190710, POST 538/538, dict_hash
0xfec8c47cfc6f437f; test-32, 39 modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stick, increment 1, task 2 (plan 2026-10-26-stick-1-screen-and-keyboard;
docs/v4.0.0/STICK.md 2, 5.3, 5.4). On the v4 path:
- the framebuffer is brought up after POST, cleared and dark: console text
goes to serial only ("splash only, log on serial") until Zuse logs in;
then the screen is the console (TTF, a blinking cursor, as v3's), and
when she logs out it is cleared and dark again (console_fb_mirror(),
console_fb_clear(); the mirror is on by default, so v3 is unchanged);
- the line editor and the node's KEY read every keyboard -- PS/2, USB, the
virtio keyboard -- through the shared bridge (sk_input_getc()); the
headless wait drops keyboard input as well as serial bytes;
- an EMERGENCY_CONSOLE_ENABLED build has the screen from the start.
The framebuffer setup is one helper both paths call (kernel_main.c).
Red (before): screen_dark_until_login 153051 (10835 lit), console/keys
153309, logout 153609, kbd_typeahead 153918, virtio_kbd aarch64 154245
and riscv64 154718; no_framebuffer 155546 passed before and after.
Green: 155926 (0 lit), 160156, 160409 (0 lit after logout), 160630,
virtio_kbd 161414 and 161820, no_framebuffer 161206; usb_kbd with the USB
keyboard the only one (-machine i8042=off) 164548, v3 control 164757;
the identity gate's sessions 162245-163802 all pass; v3 typed by keyboard
164009, 164115. (usb_kbd 160857 and 164313 failed in the harness:
input-send-event's device names a display, not a keyboard.)
Accepted: suite EXIT 0; three clean qemu boots, POST 538/538, dict_hash
0xfec8c47cfc6f437f unchanged (174704, 174911, 175315); test-32, 39
modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On riscv64 a system=v3 boot never reached its prompt: Artemis's writes
"timed out" and Zuse was never confirmed (logs/20261026-134850). vblk_io()
bounded its wait by ~1M polling iterations, which on riscv64 under TCG is
about one heartbeat tick of real time -- shorter than a write that allocates
space in a sparse host image. Instrumented, the request was seen completing
just after the give-up ("used idx=409 last=408"), and every later request
then took its predecessor's completion for its own and returned before its
own I/O was done (a stale used index at each later request), reusing the
descriptor chain while the device still owned it: silent read and write
corruption from that point on. FABRIC-3.md's 2026-09-09 "request that never
gets a used-ring completion" is this same early give-up.
Now: the wait is for this request's own completion (the used index
reaching the avail index it was given), bounded by 5 s of real time on the
CPU's counter (timer_now_ns(), which needs no interrupts); a request that
truly never completes takes the disk out of service instead of letting a
later request reuse the chain.
Red (riscv64 system=v3, with temporary instrumentation): 151003, 151100 --
a timeout then dozens of stale completions each. Green: 151238, 151332 --
none; Zuse confirmed; the keyboard line answered. system=v3 with the fix:
riscv64 151438, amd64 151528, aarch64 151610, no timeouts. Accepted (v4):
151722, 151916, 152247, POST 538/538, dict_hash 0xfec8c47cfc6f437f;
test-32, 39 modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stick, increment 1, task 1 (plan 2026-10-26-stick-1-screen-and-keyboard).
repl.c's keyboard bridge -- the key tables, Shift/Alt/Caps Lock/Num Lock and
their lights, the keypad, Alt+TAB, and the per-tick USB keyboard servicing --
moves unchanged to kernel/src/hal/kbd_input.c as sk_input_getc() (and
sk_input_drop()), so that the v4 boot's console reads the same keyboards
(docs/v4.0.0/STICK.md 5.4). v3's behaviour is unchanged.
scripts/qemu_session.py: the typed-QEMU-session harness, kept in the repo
from here on (the identity gate's sessions, and v3_keys: system=v3 typed on
QEMU's keyboard with send-key).
Yardstick, system=v3 typed by keyboard: before, amd64 PS/2 134805 PASS,
aarch64 virtio keyboard 135549 PASS; after, 135746 and 135835 PASS.
(riscv64 134850: v3 never reached its prompt -- Artemis virtio_blk writes
time out; v3's block path, before this change; being investigated.)
Accepted: suite EXIT 0; three clean qemu boots to [zuse@Hera] ok>, POST
538/538, dict_hash 0xfec8c47cfc6f437f (145722, 145859, 150231); test-32,
39 modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One GPT stick that is the whole OS: ESP, a StarshipOS identity partition and
a StarshipOS Artemis partition; a splash until Zuse logs in, automatically;
each stick mints its own Zuse on first boot; try-it writes persist on the
stick until INSTALL; pulling it goes headless. GPT comes back for boot media
and installed disks (overturns FABRIC-2.md F.8 for those); system=v3 is
refused on a stick; every clean qemu boot uses a GPT data stick over USB,
virtio Artemis leaves v4. Approved by Captain Bob 2026-10-26. First of three
designs (then INSTALL, then DOE/SDK/demos); ahead of ENGINE step 4 Part A.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the fresh whole-branch review of the identity gate (With fixes; no
Critical, four Important):
1. A drive pulled while a line ran: the drives are looked at before every
prompt (sk_v4_identity_check_now), so no prompt is shown once she is
gone and what was typed after the pull does not run as Zuse.
2. Pulled while a line WAITS: the wait is ended at logout, by an empty
line, and not carried into her next session (Captain Bob, 2026-10-26:
"end the waiting line at logout"); re-attaching brings the prompt back.
3. EMERGENCY_CONSOLE_ENABLED: v4 honours it as v3 does -- a bring-up build
has a prompt with no drive (boards/BRINGUP.md A2).
4. Keys typed at a headless machine are read and dropped, not run as
whoever logs in next. (v3 has the same gap, sk_repl_headless_wait;
reported, not changed.)
Each a QEMU session red then green (amd64): midpull 111650 -> 112953,
waitpull 111907 -> 113154, emergency 112524 -> 113609, typeahead
112248 -> 113359; headless 113800 and hotplug 114043 still pass.
Accepted: three clean qemu boots to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f on all three; hotplug on aarch64 and
riscv64; make -C v4 test test-32 sanitize hosted-check EXIT 0;
make -C v4 test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The identity gate on the v4 boot (plan 2026-10-26-engine-step4-identity-gate,
task G2; ENGINE.md 2, ruled 2026-10-20). As v3, by the kernel with no v3 VM:
after POST and the block chain, Zuse's public key from the genesis marker,
every xHCI controller brought up, the heartbeat started; then headless until
her drive is attached and checked (capsule_zuse_boot_check, G1). A drive that
arrives is given to the block subsystem by the kernel (Artemis is the
kernel's); her session is kept in the kernel for Hera, never in a node's
memory. The prompt is v3's, [zuse@Hera] ok>; pulling her drive ends the
session and the system goes headless; putting it back brings the prompt.
A blank pair stays headless: genesis writes Artemis's disk, Phase 5 (D2).
kernel/Makefile: ARTDISK and ZUSEDISK default to the minted pair,
disk/zuse-scratch/ (D4); .claude/CLAUDE.md's acceptance says so.
Fixed with it, at Captain Bob's word:
- kernel/Makefile: the ROM-and-map rule is a grouped target (&:). As two
targets of one plain rule its recipe ran twice at once under -j and the
copies met ("cp: cannot create regular file ... File exists"): 3 of 20
parallel builds failed, now 0 of 20.
- The v4 boot drops the logger to --log-level after POST, as v3 does
(sk_log_level_after_post, shared by both paths); INFO lines after POST,
3 before, 0 now.
Accepted: three clean qemu boots as built to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f on all three (unchanged), 0 INFO after POST;
the hot-plug session (attach, line, detach, headless, re-attach) on amd64,
aarch64 and riscv64; headless with no drive; make -C v4 test test-32
sanitize hosted-check EXIT 0; make -C v4 test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
capsule_zuse_boot_check() makes the check capsule_zuse_boot_try_attach()
made -- the genesis marker, the drive's identity record (magic, version,
CRC-64, public key) -- and says HERS, GENESIS or NOT_HERS, with no VM;
capsule_zuse_boot_root_pubkey() reads the marker's key. try_attach and
load_root_pubkey call them; their behaviour and messages are unchanged.
The v4 boot will make the same check (identity gate plan, D1).
Shown on v3 (system=v3, amd64): the minted pair, "Zuse: identity
confirmed" and [zuse@Hera] ok> (logs/20261026-083603); a blank pair,
"Zuse: genesis minted onto attached thumbdrive" (logs/20261026-084729).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captain Bob, 2026-10-26: "Gate first." Its own plan, with D1-D4 ruled as
recommended: the Zuse check split from the v3 VM; v4 recognises a minted
Zuse only (genesis with Artemis's writes, Phase 5); [zuse@Hera] ok> now;
the minted pair is QEMU's default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
disk/zuse-scratch/artemis.img and zuse-thumb-ident.img, minted from blank
by a system=v3 amd64 boot (genesis minted) and confirmed by a second
(identity confirmed); both logs included. The genesis marker is on the
Artemis disk, so the two are a pair. The committed artemis.img and
thumbdrives/zuse-thumb-ident.img are not touched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MACHINE.md stands: v3 goes after parity; Hera, Hermes, Artemis (and
Hestia) are kernel functions. ENGINE.md section 2 amended with the rulings,
section 6's step-3 rows struck (R2). The step 4 plan rewritten: Part A
(hook at call, called in-line words) and Phases 1-8 to parity. No identity
thumbdrive, headless; work goes ahead only with Zuse attached.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three boots through the top-level Makefile: POST 538/538, dict_hash
0xfec8c47cfc6f437f on amd64, aarch64, riscv64; '3 4 + .' answers 7.
make -C v4 test-32: 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Top-level 'qemu' fell through to v3/Makefile, which has no such rule.
qemu, qemu-esp and qemu-gdb now go to kernel/Makefile; with ARCH given on
the command line and no TARGET, 'clean' is the kernel's for that ISA.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three clean qemu boots to v4 ok>: POST 538/538, PARITY:OK,
word_count=317 dict_hash=0xfec8c47cfc6f437f on amd64, aarch64 and
riscv64; a typed line answered on each. make -C v4 test-32: 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruling 7 as amended: the kernel tells a node's going, so the system's
hand-on is not used. (GONE-HOOK), (DOWN) and (RUN) go from quit.f18, and
COLD's hook-clearing from system.f18; the cell is free again. The tests of
the hand-on go with it (mesh: the hand-on checks and the fourth disturbed
exchange; depth sweep: path 10, as before 529ba0fc). A believed GONE going
no further is still checked. test_host_unit.c's message for GONE down the
graph now says the kernel tells. MESH.md: 9a.6 items 5 and 7, and step 7's
record of both increments.
Suite EXIT 0; depth sweep 230 runs, 0 failures; mkcapsule lint 0
violations. Hosted and bare metal, all three ISAs: word_count=317
dict_hash=0xfec8c47cfc6f437f.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Suite (test test-32 sanitize hosted-check) EXIT 0. Three clean qemu boots
to v4 ok>: POST 538/538, PARITY:OK, dict_hash=0x248b4edc47f4357e on
amd64, aarch64 and riscv64. make -C v4 test-32: 0 failures. Also the
amd64 boot of 2026-10-19.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the final review of MESH step 7. NODE-KILL left children whose parent
was the dead number, so a node born later under it inherited authority over
them; they are re-parented to Hera. After UNIT-KILL Hera no longer lists the
removed centre, and a later KILL completes (shown to fail with GONE-DOWN's
unlisting taken out). test_manage 45/45 both widths; test_host_unit 127/127.
Acceptance: amd64, aarch64, riscv64 clean qemu: ok>, POST 538/538,
dict_hash=0x248b4edc47f4357e on all three; test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MESH.md step 7: what was built, the tests, the (DOWN) mend, the traced
(LOST) finding; 9a.5: a centre killed mid-birth, and birth authority not
yet tied to identity. v4/README.md: births follow v3.
Acceptance at this commit's code: amd64, aarch64, riscv64 clean qemu, v4:
ok>, POST 538/538, dict_hash=0x248b4edc47f4357e on all three; test-32 0
failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
amd64, aarch64, riscv64, clean qemu, v4 as built: ok>, POST 538/538,
PARITY:V4_SYSTEM word_count=318 dict_hash=0x248b4edc47f4357e on all three
(the same as the hosted build); Q./ answers 0 21845. make -C v4 test-32:
0 failures. BLOCK_MAP.md regenerated: centre.4th, hera.4th's new blocks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found by the depth sweep: a hook that sent a message about another node
overwrote (ONE), which AWAIT reads after believing a GONE, so the wait went
on. (DOWN) now calls the hook through (RUN) and restores (ONE).
AWAIT ended by a GONE that is handed on: works to 26 values and 21 calls
deep, then a stack error and nothing else, at both widths. Removal sweep:
node 11 or 12 removed, or the wire cut, at every step: 0 wrong. hosted
dict_hash=0x248b4edc47f4357e on all three ISAs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_host_unit: 125 checks. Shown to fail with the GONE hook taken out of
centre.4th, and with the Hera-only check taken out of manage.c.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What a birthing node needs is centre.4th; KILL, PAUSE, RESUME, UNIT-KILL and
CENTRE are Hera's. An outer node births, as a v3 VM may, and may not kill.
A capsule is read by the node that opened it. test_host_unit: 93 checks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
COLD takes out a hook it forgets. The system changed, so dict_hash did:
hosted, all three ISAs, word_count=318 dict_hash=0x1b5c633fd6bdd143.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Any node may birth and wire its own; only Hera sleeps, wakes and kills, by
number. Requests have fixed numbers, -6 to -18. NODE-BORN takes the
number; NODE-KILL a number. test_manage.c: 41 checks at both widths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixed request numbers; NODE-BORN takes the number; GONE handed on through
the system's (GONE-HOOK), so dict_hash changes; a reader per asker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruled 2026-10-16: Hera births the second centre and it births its own unit;
hera.4th split into centre.4th (BIRTH-AS, BIRTH, UNIT) and Hera's own
(KILL, PAUSE, RESUME, UNIT-KILL, CENTRE); the kernel keeps the registry and
checks who may ask; centres face each other on port 6; GONE goes down the
birth graph.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MESH.md ruling 7 and section 9 said only Hera's requests are honoured.
Ruled 2026-10-16: v4 births behave as v3's (any VM may BIRTH, the child's
parent is its birther, its ACLs are copied from the parent's at birth,
KILL is Hera's alone).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DOE only types its name for now, as asked 2026-10-15; the runner is still to be
built. Not yet a system capsule (MACHINE.md 6, step 3). With it, the two board
boots, amd64-pc and aarch64-rpi5, that tried it: DOE is unknown until
STARSHIPOS is in the search order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
amd64, aarch64, riscv64: ok>, POST 538/538, dict_hash=0xfec8c47cfc6f437f,
rom_hash=0x87b23d3ae2643c8d (2372 words) on all three; Q./ answers 0 21845.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DATASHEET-F18.md lists all 19 entries of the host ROM, the six shared ones
with the registers they use. MACHINE.md 2.2: built; 277 words, not the
estimated 150-200; the system's words are address, push and ;.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MACHINE.md 2.2. Hera carries the host's ROM; the four outer nodes the
shared math only, and compute UM*, U/MOD and Q./ with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MACHINE.md 2.2. Each is its entry's address, push and ;. Every node the
tests make carries the host ROM (host_load, Hera's births, the depth and
mesh tests' own nodes), and a division by zero inside the ROM returns to
the prompt (hosted-check). test_host_quit's fetch outside memory moves
past the ROM's range: 16384 is the ROM's first word now the tests' system
has its ROM, as the product's always had. dict_hash 0xfec8c47cfc6f437f.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MACHINE.md 2.2. UM*, UM/MOD, D+, DNEGATE, Q.* and Q./ are entries 0-5
of the host ROM and of a mesh node's ROM, from one source (rom/math.f18)
and one entry list (v4/rom_entries.h). The host ROM starts at entry 18.
The mesh ROM is 277 words; the host ROM 2372.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>