All eight stages passed: the four boots (POST 539/539, word_count=377, dict_hash=0xa854ba15b437d288 on all
three architectures, Hera's words admitted to the Stadium after POST on each), test-32 (39 programs, 0
failures), the proofs, the images, the documents. logs/20261113-191247/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
ENGINE step 4 Phase 2 (plan docs/v4.0.0/plans/2026-11-13-engine-step4-phase2-word-accounts.md). Rulings,
Captain Bob 2026-11-13: "ID field in the header"; "Per heartbeat tick"; the ACL "All of it in Phase 4".
- The word ID, at xt-4 before the flags (ENGINE.md 3b). The system's words are numbered as they are
assembled, by a new directive, #id, (and #ids, the count), in the C assembler (text.c) and in the
machine ROM's (capsules/v4/rom), which counts in the system's own (NEXT-ID). (HEADER) numbers later
words; FORGET gives back the IDs it frees, always the newest; COLD resets to (BOOT-ID); (SEAL) records
it. All 313 system headers carry the cell.
- The kernel's records (v4/mesh.h): (TELL-DEFINED) and (TELL-FORGOTTEN), requests -19/-20 on port 0,
which the kernel puts in (WORD-DEFINED)/(WORD-FORGOTTEN) when it seals a node, and reads the system's
own words once. A bit per address marks a word's xt (calls into the ROM or headerless code are not
words); at call, the bit test and a count. v4_mesh_charge hands the owner the calls since.
- The Stadium: stadium_words_charge -- N calls as N of stadium_word_dispatch's dispatches, shared by calls
when the reservoir is short; sk_v4.c charges every node's words at the tick beside its opcodes, and
stadium_word_forget before an ID is used again.
- Tests first: test_text.c, test_host_dict.c, test_host_quit.c (numbering, FORGET, COLD),
test_mesh_boot.c (44 checks), kernel/tests/test_stadium_words.c; qemu_session.py: Hera's words
admitted after POST.
- amd64: Stadium words: promotions=141 after POST, CONSERVED; POST 539/539; word_count=377;
dict_hash 0xa854ba15b437d288 (the new cell); the boot 142 s against Phase 1's 153 s.
- v4 test, test-32: all pass; v4-checks: 80 programs under the sanitizers, 0 failures; the hosted
builds alike. docs/reference/v4-dictionary.tsv: the two new words; FABRIC-3 XLVIII.24.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
All eight stages passed: the four boots (POST 539/539, word_count=375, dict_hash=0xbbf72b1f752a1a51 on
all three architectures, the edge cases on amd64), test-32 (39 programs, 0 failures), the proofs, the
images, the documents. logs/20261113-170011/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
ENGINE step 4 Phase 1, Tasks 5b-5d, and the edge cases (Captain Bob, 2026-11-13: "Build it to proper
spec"; "Check for the edge cases"; "Yes, add it to v4-checks").
- v4/system/mesh.c, v4/include/v4/mesh.h: the nucleus assembled by the ROM and given to Hera as F18
cells; Hera born empty at place 0, the kernel on port 0, the console on port 1; told she is 10, in the
registry, the kernel's words, FORTH-79, sealed, POST, the kernel's capsules. NODE-BORN / NODE-KILL in
the owner's room.
- No scheduler: v4_mesh_tell returns once the node told says how its text ended, and
v4_mesh_step / v4_mesh_busy let the host step the fabric while it waits, so nodes run between
lines as during them. A text left "waiting" is owed its end: the next line ends it "Interrupted"
and is then run (MESH.md 7b.6).
- kernel: sk_v4.c boots through the mesh; its idle steps the fabric while a node can run, and halts
only when none can (#151 kept). stadium_return_quota and stadium_ops_forget on a kill.
- Tests: v4/tests/test_mesh_boot.c (32 checks: the boot, births, kills, rebirth, a live number, a
fault, no such node, Hera not killing herself, no room, a line too long, a node running for ever,
a wait broken by the next line), run by `make -C v4 test` and under ASan+UBSan by `sanitize`
(v4-checks); kernel/tests quota return; scripts/qemu_session.py births() and the edges on bare
metal.
- Docs: ENGINE.md 6 "who runs next" struck (settled: no scheduler); the Phase 1 plan; FABRIC-3
XLVIII.23; .claude/memory/rules.md: alpha.5 closed to new work.
- Evidence: v4-checks 80 programs under the sanitizers, 0 failures; the hosted builds alike; two
stopped v4-checks runs labelled STOPPED; three development amd64 boots labelled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#189 Phase 1 Task 5a: Hera in the kernel's fabric and registry. On the
four boots: NODE-ME . gives 0 ok, the physics lines as before, POST
539/539; word_count 375 and dict_hash 0x06531687cc075aee on all three
architectures (centre.4th and hera.4th loaded); test-32 39 programs 0
failures; proofs; images; documents, the dictionary covering all 375
live words. Every boot under timeout 570. logs/20261113-142432/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#189, ENGINE step 4 Phase 1, Task 5a. Captain Bob, 2026-11-13: "Full
births now"; "Hera as now, in a fabric".
- sk_v4.c: the kernel's fabric (v4/fabric.h), Hera's node at its one
place, entered in its registry (v4/manage.h) as node 10. The registry's
answers are real: a birth is "no room" -- the fabric has one place
until 5b; CAPSULE-OPEN/-LINE read the kernel's capsule directory,
checked as the boot checks (no capsule of F18 code is there until 5b);
a born node's parity line. She is not told her number: the boot's
console addresses node 0 (told 10, the boot stopped after POST -- kept,
labelled, logs/20261113-132712).
- boot.h/boot.c: v4_boot's `request` hook (the registry's requests) and
`capsules` (the kernel's own, loaded before the seal, so POST runs on
them). hosted.c sets neither: the hosted product's boot is as it was.
- kernel/Makefile: manage.c in the kernel's v4 engine.
- qemu_session.py: a v4 acceptance boot asks NODE-ME . and wants 0.
- v4-dictionary.tsv: the 55 words of centre.4th and hera.4th, written
from their source and manage.h; mkdictionary.py loads the kernel's
capsules into the hosted system before WORDS, so the live list is the
kernel's -- 375 words.
- .claude/memory/rules.md, rule 6: every boot command under timeout 570.
Seen to fail first (logs/20261113-132410): NODE-ME was an unknown word.
After: amd64 NODE-ME . gives 0 ok; POST 539/539; word_count 375. v4
suite: test, test-32 99 programs 0 failures; v4-checks 79 under the
sanitizers 0 failures, the hosted builds alike.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#189 Phase 1, Tasks 1-4: v4 in the kernel's boot. On the four boots: the
Stadium made ("Stadium: 83886 cells"), POST 539/539, "Stadium opcodes: 30
resident, hottest opcode 8", "Stadium conservation: CONSERVED", the quota
self-test and the heartbeat's ticks -- the new physics check passing;
word_count 320 and dict_hash 0x47570d4ced6ce255 on all three
architectures, unchanged; test-32 39 programs 0 failures; proofs; images;
documents. logs/20261113-125011/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#189, ENGINE step 4, Phase 1 (plan 2026-11-13-engine-step4-phase1), Tasks
1-4. Captain Bob, 2026-11-13: Q1 "A new node key", Q2 "Per heartbeat
tick", Q3 "All of v3's", Q4 "In Phase 1" / "Full births now", who runs
next "Hera by compudynamics now" (Task 5, to come).
- stadium.c/.h: stadium_node_key(node) ("NODE" | number),
stadium_boot_init_for(first), stadium_birth_node(key, name);
stadium_boot_init() and stadium_birth_hera() are them for Hera's key, so
v3's path is as it was (only an impossible panic's words changed).
- kernel_main.c: the system is chosen and said first, then the Stadium,
sessions, switch-signal and kernel-Hermes tables for both systems in
v3's order; v4: Hera, node 10, patron zero under her node key, the word,
block and opcode layers. The quota self-test and the heartbeat's line
are functions now, called by both systems.
- sk_v4.c/.h: sk_v4_run() goes -- sk_v4_boot() returns, the kernel's
checks after POST (opcodes, words, conservation, quota, heartbeat), then
sk_v4_prompt(). sk_v4_charge_opcodes() at the heartbeat's service points
(the key wait, after each line) and once after POST.
- stadium_ops.c/.h: a node's 32 opcodes as Stadium patrons (HEAT-OP's
feed, "Both"): retirements charged as the word layer's dispatches, a
quantum each, the reservoir's floor kept, shared by retirements when
short; cooling per tick as words. ~0.5 us a charge on the host: kept.
- qemu_session.py: a v4 acceptance boot fails without "Stadium: N cells",
"Stadium conservation: CONSERVED" and the heartbeat's ticks (#189).
Tests first (logs/20261113-122142): the physics check failed on the v4
boot; test_stadium_node, test_stadium_ops (and its share case, after a
real boot showed ";" taking all the heat) failed before. Now: kernel host
tests all pass; amd64 v4 boot passes, POST 539/539, dict_hash unchanged,
"Stadium opcodes: 30 resident, hottest opcode 8", CONSERVED; a system=v3
boot prints its Stadium lines as on 2026-11-06.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
A2 (#189): every word but the ten called. POST 539/539 on the four
boots; word_count 320 and dict_hash 0x47570d4ced6ce255 on all three
architectures; test-32 39 programs 0 failures; proofs; images; documents.
Boot times (stage, with its build) against be456d44's run: amd64 123 s ->
118 s, aarch64 208 -> 197, riscv64 96 -> 93 -- no slower under QEMU.
logs/20261113-053019/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Plan 2026-10-20 (ENGINE step 4), Task A2, for #189. Captain Bob,
2026-11-13: "The ten"; "Accept it".
- compile.f18 (COMPILE,): a word is copied in line only when it is flagged
in-line and compile-only (24) -- the ten that work on the return stack,
>R R> R@ I J LEAVE and the later UNLOOP 2>R 2R> 2R@. Every other word,
in-line ones too, is a call the hook at `call` sees.
- EXECUTE calls the xt: `call xt` (opcode 3, slot 0) and a ; in (EXEC),
run. INTERPRET runs a word by (GO): `call xt` and `jump (IL)` in
(RUNX), entered by a jump, at the old return-stack depth.
- host_map.h: (EXEC) BUF0_W-22, (RUNX) BUF0_W-115, from what was free.
- Its cost, accepted: one return entry at the bottom of a chain (30 deep
from the prompt, not 31) and one per explicit EXECUTE while its word
runs; the hosted boot +2.4% (2.917 s to 2.987 s), instructions +0.4%.
- Tests first (logs/20261113-045122/a2): inline_words_are_called,
residue_stays_inline, execute_passes_the_hook, rstack_kept_across_call,
abandoned_definition_not_called -- 3 of 1096 failed before. The depth
checks moved to the new figures; SEE shows the calls; two layout checks
use in-line test words; 2>R 2R@ 2R> checked in test_host_quit.
- DECOMPOSITION.md EXECUTE, the plan's A2 and rulings, FABRIC-3 XLVIII.22.
Suite: test, test-32 99 programs 0 failures; v4-checks 79 under the
sanitizers 0 failures, the hosted builds alike; hosted POST 539/539.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#190 (POST regenerated, 539 cases) and #16 (v4-checks nightly). POST
539/539 on the four boots, at the new floor; word_count 320 and dict_hash
0xcac4cf58ed493172 on all three architectures; test-32 39 programs 0
failures; proofs; images; documents, the dictionary covering all 320
live words. logs/20261113-031936/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-13: "Create the issues then fix them before the long
acceptance test runs"; #16: "Nightly".
#190 -- make -C v4 post79 did not reproduce POST:
- mkpost.py runs v3 with address randomisation off (setarch -R): its
printed addresses (>IN, FIND) are the same each run, so POST79.md is.
- v4/Makefile post79 builds hosted v3 from this tree's source first and
uses it, not the lfs/ copy, which can be older.
- post_cases.c and POST79.md regenerated: 539 cases -- LOAD.rest_of_line,
which v3 gets through since it changed after 2026-10-07. Two runs the
same. POST_FLOOR 538 -> 539 (#173).
- test_host_unit.c takes the table's count, not 538 typed in the test.
#16 -- scripts/nightly.sh v4-checks: make -C v4 sanitize hosted-check,
logged under logs/<TS>/v4-checks/, refused without qemu-user; nightly.yml
runs it after publishing, before the proofs, installing qemu-user if the
image lacks it.
Evidence (logs/20261113-014927/post79, -024314): before, regenerated with
nothing changed: 539 cases and addresses differing run to run; after: the
same twice, hosted POST 539/539; test, test-32 99 programs 0 failures;
v4-checks 79 programs under the sanitizers 0 failures, the hosted builds
alike. The first verification failed at test_host_unit.c:442 (kept); a
stray v4-checks run stopped at once is kept, labelled (-014453).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
A1 (the hook at call), the merge of master (the six runner.capacity
comments) and HEAT-OP/ANTICLOCK (#189). POST 538/538 on the four boots;
word_count 320 and dict_hash 0xd148437fb39a1afd on all three
architectures (318 and 0x8c92508f748f99cf before: the two new words);
test-32 39 programs 0 failures; proofs; images; documents, the
dictionary covering all 320 live words. logs/20261113-005100/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#189 -- Captain Bob, 2026-11-12: "Add HEAT-OP. If it's a huge performance
hit, we'll revert it. If not ... it stands"; a full 33-cell array, as
DECOMPOSITION.md section 7 draws it; the Stadium feed is Phase 1's.
- node.h/node.c: v4_node_heat_regs_attach; a data fetch from base+k gives
opcode k's count, base+32 the anti-clock (the low cell at 32 bits); a
store changes nothing. Reset detaches them.
- host_map.h: HEAT_REG at word 13824, in what was free between the
dictionary space and SEND_TEXT; the compile-time check covers it.
Nothing moved. map-*.f18: HEAT-OP 13824, ANTICLOCK 13856.
- image.h/image.c/mkmap.c: the image carries the address; v4_image_born
attaches the node's own counts.
- system.f18: HEAT-OP@ ( op -- n ), op mod 32; ANTICLOCK@ ( -- n ).
word_count 318 -> 320 (hosted 317 -> 319): dict_hash changes.
- v4-dictionary.tsv: both words; DECOMPOSITION.md 7 records the build.
Also in this batch:
- Makefile: make init installs qemu-user -- hosted-check needs it
(Captain Bob: "Add to make init now").
- .claude/memory/rules.md, rule 5: stop and ask when something comes up
(Captain Bob: "you are supposed to stop and ask").
Tests first (logs/20261113-005047/heat-op): test_node did not compile;
test_host_quit 3 of 1337 failed. Suite: 199 programs, 7448554 checks, 0
failures; hosted-check, the three alike. Timing: no measurable cost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-13: "I merge master in". PR 164 could not merge:
master's six comment-only commits of 2026-11-11 (751bfe26..268e5593,
"record runner.capacity: 1 decision ... (FABRIC-3, #140)") edit the
concurrency blocks the branch deletes for #140 ("It should be global").
Resolved in every workflow for the branch -- no concurrency group --
with master's fact kept as a line of the #140 comment: the capacity is
explicit in the runner's config.yaml, runner.capacity: 1. Each file
parses; scripts/test_acceptance_signing.sh passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Plan 2026-10-20 (ENGINE step 4), Task A1, for #189 -- Captain Bob,
2026-11-12: the physics blocks alpha.5; order A, 1, 2, then 7.
- exec.h/exec.c: v4_call_hook, es->on_call/on_call_ctx; called at `call`
once the return address is pushed, before P moves. NULL: as before.
- heat.h/heat.c: the per-call-target table (4096 slots, no capsule word
counted), its freeze mask and v4_heat_call_* go (ENGINE.md step 3: "The
per-call-target count goes"); the kernel will keep a word's accounts.
- tests: test_call_hook_sees_every_call, seen to fail first (no on_call);
test_heat's per-call tests go with the table.
- the plan records today's rulings (order; HEAT-OP: both, a full array).
Suite (logs/20261112-225951/v4-tests): test, test-32, sanitize, 0
failures; hosted-check, the three alike. amd64 boot: POST 538/538,
dict_hash 0x8c92508f748f99cf, unchanged -- nothing sets the hook yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
#188 (the Jacquard selector) and 7e0728e4 (a release refuses an unsigned
build). POST 538/538 on all four boots, dict_hash 0x8c92508f748f99cf on the
three, test-32 39 programs 0 failures, proofs, images, documents.
logs/20261112-210531/PROTOCOL.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "Wire L2, keep L7 on". The table held the 128
cards of the 7-bit L1-L7 space; nothing read L7, and the rolling window
recorded whatever the card said, so the 128 were 32 behaviours.
- compudynamics.c: cd_tuning_word() sizes the table to 64 (L1-L6).
- ssm_jacquard.c: card_bits() makes a card's 7-bit mask, L7 set, where a
card is read, seeded and started (C4: 17 -> card 8);
ssm_l8_force_config() still takes the 7-bit index, its L7 bit implied.
- physics_execution_hooks.c, kernel vm_core.c: the rolling window records
only while L2 is on (or before there is a config).
- ssm_jacquard.h says what is wired, bit by bit (it said L7 was);
v3/CLAUDE.md and the L8 reference corrected in place; FABRIC-3 XLVIII.21.
Tests first, seen to fail against HEAD (logs/20261112-210510/kernel-tests):
test_ssm_jacquard 4 of 7, test_physics_l2 1 of 4; all pass now. v4 reads
no rolling window: acceptance is unchanged; the protocol runs next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "release MUST refuse unsigned builds". release.yml's
"The capsule-signing key" step warned when CAPSULE_SIGN_KEY was missing and the
release went on, unsigned. Now it is an ::error:: and the step fails, as the
gate into master's does (#174). build.yml and nightly.yml still warn.
scripts/test_acceptance_signing.sh now takes the step from both acceptance.yml
and release.yml as CI runs them. Against release.yml as it was: the release's
unsigned case passed, no error -- 2 failures (acceptance's 3 checks passed).
Now 6 checks, all pass. logs/20261112-205446/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-185800/PROTOCOL.md, for #142, #173, #174 and the notes: the four
boots 538/538, word_count=318, dict_hash 0x8c92508f748f99cf on all three; the
new post-count stage (#173) on the real boots: all four at or above the floor,
all passed; test-32 39 programs, 1,869,223 checks, 0 failures; the proofs
(40 s); the images; the documents. The tree clean before and after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "Yes, reject unsigned builds". acceptance.yml's
"The capsule-signing key" step warned when CAPSULE_SIGN_KEY was missing and
the PR's acceptance went on, unsigned. Now it is an ::error:: and the step
fails, so the gate does too. A local or protocol build may still be unsigned
(kernel/Makefile, v4/Makefile): the refusal is the gate's. build.yml,
nightly.yml and release.yml still warn -- release.yml is Captain Bob's to rule.
scripts/test_acceptance_signing.sh takes the step from acceptance.yml as CI
runs it and runs it with and without a key. Against the workflow as it was:
the unsigned case passed, no error -- 2 failures. Now: no key fails with an
::error::, a key is handed to the build as SIGN_KEY. logs/20261112-185739/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
4738aee4's log has a placeholder where the run against the code before #173
belongs ("see the session") -- not evidence. Rerun against
scripts/nightly.sh as it was (4738aee4~1): every one of the 7 cases fails,
the stage not existing. post-count-before-rerun.log; the first log is kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "Yes". Acceptance checked POST: PASSED, so a POST
that lost cases still passed. Now scripts/nightly.sh post-count, which the
stick-high stage runs after dict-hash: each of the four boots must report
PARITY:V4_POST with every test passed and at least the floor's tests --
v4/system/POST_FLOOR, 538 today, raised when POST grows and never lowered
without Captain Bob. A boot with no POST line, not run, or no floor file is
refused, not skipped.
scripts/test_nightly_post_count.sh, written first and seen to fail (the stage
not existing), then 7 cases: 538 and 600 pass; fewer than the floor, a
failure, no POST line, a boot not run, no floor -- refused. Run on the boots
of the last protocol (d7b2f6bf): all four 538 of 538. logs/20261112-185620/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "correct deficiencies". heartbeat_capture_tick_snapshot
wrote cache_hits_delta and bucket_hits_delta as 0 ("TODO: wire ..."), though
physics_hotwords_cache.c counts both. Now each is read from the VM's hot-words
cache as a delta since the previous tick, the way word_executions_delta is
(and after the cache's stats are reset, the count since then); a VM with no
cache has 0. word_executions_delta was measured already: doe_log.c's "TODO: 0"
for it was stale, and its three column notes are corrected.
kernel/tests/test_heartbeat_export.c, 4 checks: a VM in memory with a cache
whose counters the test sets, captured tick by tick. Against the code as it
was: 3 failures (the hits 0 where the cache counted 5 and 3, then 7 and 7).
Now: 0. Built for amd64, aarch64, riscv64 and the hosted v3. Shared v3 code,
under the ruling. v3 is not part of acceptance; no DoE has run since 2026-09-16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-182015/PROTOCOL.md, for the kernel host-test chunk: the harness
and #170, #171, #176, #177, #178, #182. The four boots 538/538 -- a data stick
enumerating through the moved USB descriptor walk, genesis through the identity
code's new seed handling -- word_count=318, dict_hash 0x8c92508f748f99cf on all
three; test-32 39 programs, 1,869,223 checks, 0 failures; the proofs (37 s);
the images, no race; the documents. The tree clean before and after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
sk_v4_genesis never wiped its seed or its read-back; sk_v4_drive_arrived
never wiped the proxy's seed after her login; sk_v4_real_zuse_arrived wiped
the seed only on a match. (The logged-in Zuse's own key stays in g_zuse_seed,
by design.)
Option 1: the three use one buffer the identity module owns, g_seeds (seed,
then its read-back), and sk_v4_drive_arrived -- which every drive goes through,
and which alone calls the other two -- runs the drive's handling (now
handle_drive()) and then wipes it, whichever way it went.
sk_v4_identity_seeds() lets the host tests read it.
kernel/tests/test_sk_v4_identity.c, 10 checks, through the real drive-arrival
path: a fake xHCI controller marks a slot attach-pending, the identity code's
idle beat handles it, the real gpt.c reads the stick's table from the RAM disk;
the block layer, signatures, key mint, marker and console faked. Genesis; a
genesis not read back; the proxy logging in; a real Zuse named, then her stick
logging in. Against the code before the wipe: 5 failures (every case's seeds
left). Now: 0. The harness gains fake_disk_bind. Built for amd64, aarch64,
riscv64. #176 done with 2bac2ac8 (the mint).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
sk_v4_mint_zuse wiped seed and rseed only when the real Zuse was minted; its
refusals and every failure after YES left them in stack memory.
Option 1 (Captain Bob, 2026-11-12: "1 is great"): the seeds are in a 64-byte
buffer the caller owns. sk_v4_mint_zuse_with(seeds) runs the mint (now a
private mint()) and then wipes the buffer, whichever way it returned -- one
place, every exit; sk_v4_mint_zuse() gives it a buffer of its own.
kernel/tests/test_sk_v4_mint.c, 17 checks: the real gpt.c on the RAM disk, the
identity code, key mint, signature checks, marker and keyboard faked; each of
the mint's eight exits run with the buffer filled with 0xEE first -- no stick,
under 64 MiB, not YES, the key mint failing, the read-back not hers, no
marker, the marker write failing, and minted. Against the mint as it was: 7
failures (every exit but success). Now: 0. Both runs in logs/20261112-181719/. Built for
amd64, aarch64, riscv64. The identity code's two (sk_v4_genesis,
sk_v4_real_zuse_arrived) follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
sk_v4_grow.c's dev_rw4k computes 1 KiB block numbers as (uint32_t)devblock * 4,
which wraps past 4 TiB; Artemis is capped at 256 GiB (STICK_ARTEMIS_CAP_GIB,
kernel/Makefile), so it is latent -- but nothing said so where the cast is. Now
a compile-time check there (the C99 negative-array pattern the tree uses): a
cap past 4 TiB stops the build, and a cap not defined at all is an #error, not
a skipped check. gpt.c's casts are bounded by the disk's own size, itself a
32-bit count of 1 KiB blocks, checked before each: each now says so.
kernel/tests' check_cap, seen to fail first (a 4096 GiB cap built); now 3
checks, 0 failures -- 256 GiB builds, 4096 GiB and none refused. Built for
amd64, aarch64, riscv64. The plan's increments 2 and 3 marked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
sk_v4_idle allocated a controller's slot array again whenever max_slots + 1
was more than it held -- the old array dropped, neither copied nor freed --
while the identity code holds pointers into it (g_offered, g_spare,
g_pending_real, g_real_drive, g_zuse_dev). Its two slot loops then ran to
max_slots whatever the array held.
sk_v4_slots_get() (kernel/src/v4/sk_v4_slots.c): allocated once, zeroed, at the
size first asked for; never replaced; the slots that may be used are those it
has. sk_v4_idle uses it, and its loops stop at the array's end.
kernel/tests/test_sk_v4_slots.c, kmalloc_aligned faked, seen to fail first
against the allocation as it was (4 failures: replaced when more were asked
for, 17 said usable where 9 existed, a held pointer left behind, an allocation
for 0); now 6 checks, 0 failures. Built for amd64, aarch64, riscv64; latent
today (max_slots does not grow), so the boots show no change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
sk_v4_run's three stops -- "not started", "did not let go of POST's
blocks", "stopped on a fault" -- ended in for (;;) { }: a core spinning at
100%, the thing #151 removed from the prompt. Each now calls sk_v4_stop()
(kernel/src/v4/sk_v4_stop.c): interrupts off, then arch_halt() for ever. Each
still says why first. sk_v4_stop.c added to the loader's and the kernel's v4
sources.
kernel/tests/test_sk_v4_stop.c, with arch_halt and arch_disable_interrupts
faked (the halt jumps back out after three calls; an alarm fails a spin):
against the stop as it was -- "spun for 2 s without halting"; now -- 2
checks, 0 failures: halts in a loop, interrupts off before the first halt.
Built for amd64, aarch64 and riscv64. #177's "seen on the three
architectures": no boot reaches these stops, so it is shown on the host only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
a8824655's evidence log shows its "before" run failing to compile: the copy
of usb_config.c with the old decision was cut at the wrong brace by my script.
The failure the commit describes was real (seen in the session), but the log
did not show it. Rerun with a correct copy:
test_usb_config-before-rerun.log -- 20 checks, 10 failures (wTotalLength 1 to
9 asked for again; the cut unsaid). The first log is kept, as what it is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
After the configuration descriptor's first 9 bytes the event loop asked for
min(wTotalLength, 128) whatever it was. A wTotalLength of 9 or less was then
asked for again as "short" -- for ever, that slot never leaving enumeration
(#170); 0 also issued a zero-length data stage. A set longer than the 128-byte
buffer was cut without a word, its later interfaces never seen (#171).
The decision is usb_config_request_length() (moved out of the event loop,
then fixed): 9 or less is 0 -- "xhci: a configuration of N bytes has no
interface -- not used", and nothing more is asked; longer than the buffer is
cut and said -- "xhci: config of N bytes cut to 128 -- rest unseen" (at most
53 characters). The buffer stays 128 bytes; its size is #171's to rule.
kernel/tests/test_usb_config.c, seen to fail first against the decision as it
was (10 failures: wTotalLength 1 to 9 asked for again, the cut unsaid), now
20 checks, 0 failures. Both runs in logs/20261112-180140/kernel-tests/. Built for amd64,
aarch64 and riscv64; the boots come with the protocol. #171's other box, a
composite device on the SER5, is Captain Bob's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
xhci.c's XHCI_XFER_CONFIG_DESC_FULL case walked the descriptor set inline, in
the event loop, where nothing could test it. The walk is now
usb_config_parse() (kernel/src/usb/usb_config.c), returning what it found;
the case acts on it as before -- the same messages, the same decisions: the
first Interface descriptor only, a BOT interface's bulk endpoints (the last of
each direction), a boot keyboard's first interrupt IN endpoint, bLength 0
ending the walk, nothing read past len. One difference, in debug output only:
the bulk endpoints are logged IN then OUT, not in descriptor order.
kernel/tests/test_usb_config.c, 7 checks, pins the walk as moved: a BOT stick
as QEMU presents it, a boot keyboard with its HID descriptor, a mouse before a
drive (the first interface only), a drive with bulk IN only, bLength 0, an
endpoint cut by len, an interface cut before its protocol byte. All pass.
Built for amd64, aarch64, riscv64; the boots come with the protocol (a data
stick enumerates through this path). The fixes for #170 and #171 follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "Build an appropriate test harness! Love the idea."
The kernel had no tests below the boots, so defects QEMU cannot provoke could
not be tested first. Plan: docs/v4.0.0/plans/2026-11-12-kernel-host-tests.md.
kernel/tests/: one host program per kernel source, built with that source as
it is, the kernel's flags (-std=c99 -Wall -Wextra -Werror), and fakes --
the console captured line by line, a deterministic RNG that can fail, and a RAM
disk whose reads, writes or flushes fail at chosen 1 KiB blocks.
make -C kernel/tests test runs them; SRC_<test>= runs a test against other
code, which is how a test is seen to fail against the code before a fix.
test_gpt.c, 12 checks: a table written and read back; 16, 17 and 18 used
entries against max 16 and an entry out of range after the 16th (#180); the
RNG, the first write, a later write and a flush failing (#168). Against gpt.c
before #168 and #180: 4 failures, each defect caught. Now: 0. Both runs in
logs/.../kernel-tests/. Not yet a protocol stage: to rule (the plan, step 5).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-164108/PROTOCOL.md, for the batch #172, #169, #185, #144, #143,
#181, #180 and the #187 test: the four boots 538/538, word_count=318,
dict_hash 0x8c92508f748f99cf on all three -- the new dict-hash stage (#172)
naming each; test-32 39 programs, 1,869,223 checks, 0 failures (the manage
test's 78 among them, #169); the proofs (43 s); the images, no race (#185);
the documents. The tree clean before and after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
gpt_read() stopped at max used entries (16 for the identity code, 4 in the
mint): a disk whose StarshipOS partitions came after the first max read as
having none, and the entries after max were never range-checked.
Now every entry is checked and every used one counted; a good table with more
used entries than max is GPT_MANY (the first max in parts), and the identity
code says "GPT: a USB drive has more than 16 partitions -- not used". Other
callers treat anything but GPT_OK as before.
Tested first, seen to fail: qemu_session.py gpt_many -- a data stick with its
two partitions as entries 17 and 18 after 16 others, and the same with an entry
19 past the usable range: both "not this system's stick" before (silently cut,
entry 19 never checked; logs/20261112-162236). After: "more than 16
partitions" and "a damaged partition table" (logs/20261112-162921).
Regressions: gpt_bad_entries, gpt_foreign PASS. gpt_zuse FAILS, on a stale
expectation unrelated to this change -- an identity-only GPT drive with no
system stick has been held silently as a possible real Zuse since #92 Task 4;
its log is kept here. The gpt_many images are made before the boot: a first
version made them after, failed in sgdisk and left its QEMU running, stopped
by hand (logs/20261112-162003).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
A data stick hot-plugged with every read at its identity partition's first
sector (LBA 2048) failing, after a boot with no drive; it expects a message
naming the identity partition, Artemis let go (both partitions or neither,
#179), no prompt, and the same stick without the fault going on to genesis.
add_stick() takes fail_read_sector for it.
It FAILS today, and is kept so (Captain Bob, 2026-11-12: "keep the test"):
the partition attaches anyway and Zuse is minted onto it, because
blk_format_or_load_disk() ignores the header read's result and takes an
unreadable disk as blank -- filed as #187. #179 is parked: its half-attached
state cannot be reached from a disk fault. The run: logs/20261112-160050.
Not part of acceptance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
- heat.c call_index(): the comment read as an unfinished thought ("hash-mod or
just take low bits?", "ignore for now? Or clamp?"). It now states the rule
the code follows: indexed by the target, a target past the table not counted,
-1 telling the callers so; the table D-6's stand-in, which ENGINE step 4
Part A1 plans to remove.
- stack.h points 1 and 2 said there was no overflow detection "and there never
will be" and that a depth exceeded corrupted silently -- D-2, which D-16
revised. Now: guarded before every opcode, a mesh node 10 and 9, the host node
32 and 32 (D-17); C code that serves a node checks the depth itself.
- stack.c named an 8-ring and depths 10 and 9 only, and said D-2's rule still
held.
- DATASHEET-F18.md section 13 item 4 (this gap) struck, resolved in place.
Comments only: test_stack and test_heat unchanged at both widths (730,137 and
8,272 checks, 0 failures).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
The kernel build's only warnings were five -Wformat-truncation in mkcapsule's
--resolve: two snprintf copies of a capsule name into the claim registry, and
the capsule's path built from base_dir and its name.
- The names: both are char[CAPSULE_NAME_MAX], and names are checked to fit when
read (line 335) -- copied whole with memcpy, nothing to truncate.
- The path: base_dir may be up to 4095 bytes, so it can be cut, and a cut path
names another file -- now refused, the capsule left unchanged and counted
rejected, with the reason.
Seen to fail first: built with -Werror=format-truncation, 5 errors. After: 0,
and 0 warnings with the kernel's flags; the manifest it writes is
byte-identical, --lint passes. The too-long-path refusal is on --resolve's
interactive conflict path and was not driven by a test. CLAUDE.md's count of
open warnings corrected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
The header said "M6: Infrastructure present (validation deferred)" and "M7:
Not started (VM integration pending)", and "(LithosAnanke branch)" -- there
is no such branch since the split. .claude/CLAUDE.md had warned since
2026-08 not to propagate it instead of it being corrected. Now: M0-M6 and M7
complete, M7.1 in progress (as CLAUDE.md's Architecture section gives them),
v4 the system booted by default; the correction dated in place. The note in
CLAUDE.md's Gotchas goes, as #144 asks. Comments only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
kernel/Makefile gave capsules/v4/sys/map-64.f18 and map-32.f18 one rule with
two plain targets -- in GNU make, two rules sharing a recipe. Under -j both
ran at once: two make -C v4 sysmap built and ran the same v4/build/mkmap-<w>
side by side (Build run 255's RASPI job: "mkmap-32: Permission denied").
Now one grouped target (&:, GNU make 4.3+, as here and in the CI image).
Seen to fail first: the two targets with -j8, mkmap removed each time, 12
runs -- 6 failed ("Text file busy", "Permission denied"). After: 0 of 12.
Both sets of runs in logs/20261112-152711/race-185/. The map files are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
v4_manage_serve took its arguments with v4_dstack_pop and never checked the
stack's depth: a request with too few values acted on stale ring values, and
one whose results did not fit dropped the oldest silently -- around the D-16
guards. Now each request's arity (manage.h) is checked first: fewer values
than it takes, or no room for what it leaves, is error 12 with the stack as it
was -- as a block request is refused (blocks.c).
test_manage.c, written first and seen to fail (12 of 13 requests at both cell
widths; NODE-BORN passed only because the stale value read was below 1): every
request with one value fewer than it takes, and NODE-ME and CAPSULE-CELL on a
stack with no room -- refused, the stack unchanged. After: 78 checks, 0
failures at 32 and 64 bits; all v4 tests at 64 bits, 40 programs, 1,871,313
checks, 0 failures (logs/20261112-152602/v4-test).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
The stick-high stage passed when one distinct dict_hash appeared: an
architecture whose boot left no accept file, no LOG: line, no serial log or no
PARITY:V4_SYSTEM line gave nothing, and two that agreed passed for three.
It is now a stage of its own, scripts/nightly.sh dict-hash, which stick-high
runs: one hash from each of amd64, aarch64 and riscv64, all found and one value;
otherwise refused, naming the architectures with none or the values that
differ. NIGHTLY_OUT points the stages at another directory, for the tests.
scripts/test_nightly_dict_hash.sh, written first and seen to fail (6 of 6, the
stage not existing), then 7 cases: agree -- pass; differ, no PARITY line, no
LOG: line, not booted, no serial log, none at all -- refused. Two of them
caught lookups that ended the script silently under set -e; guarded.
Captain Bob, 2026-11-12: "172 then finish alpha.5".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-124144/PROTOCOL.md: the four boots 538/538, word_count=318,
dict_hash 0x8c92508f748f99cf on all three; test-32 39 programs, 1,869,197
checks, 0 failures; the proofs (StarForth, 37 s); the images; the documents.
The tree clean before and after.
Stage 3 (riscv64) was stopped while booting, when Captain Bob interrupted to
mean the build pipeline; its partial serial log and console output are kept,
labelled, in logs/20261112-124831/. It was rerun on the same commit and
passed (logs/20261112-130801).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
failed() printed "MINT-ZUSE: failed -- nothing changed" on every failure
after YES, though by then gpt_write_one() had rewritten the stick's partition
table and the identity partition's first blocks had been zeroed.
gpt_write_one() now tells the two apart: GPT_EIO when its first write failed
(nothing written), GPT_PART when a later write or flush failed (the disk is
changed). MINT-ZUSE keeps "failed -- nothing changed" for GPT_EIO only, and
says "failed -- the stick was erased; Zuse not minted" for every failure
after the table is written. The marker is still written last.
Tested first, seen to fail: qemu_session.py mint_part_fail (writes fail only
at the identity partition's first sector, LBA 2048) -- "nothing changed",
logs/20261112-122132. After: mint_part_fail PASS; mint_fail (every write
fails) still "nothing changed", PASS; replace (the success path) PASS. Their
logs here. FABRIC-3 XLVIII.20.
Captain Bob, 2026-11-12: "start #168".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-114545/PROTOCOL.md: one stage per foreground command (paused
between stages 2 and 3 for Captain Bob's emergency, then resumed on the same
commit): the four boots 538/538, word_count=318, dict_hash
0x8c92508f748f99cf on all three; test-32 39 programs, 1,869,197 checks, 0
failures; the proofs (StarForth, 44 s); the images; the documents. The tree
clean before and after.
The evidence for the held batch: plan section 8 (the FMEA in the PR review),
the notes, and scripts/ci_litter_check.sh (#129).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Each cleanup #129 set up (Captain Bob, 2026-11-07), and what proves it ran:
the Docker prune's and the package cleanup's logs written in the last 8 days;
no image older than 8 days that no container uses; at most KEEP (5)
lithosananke-runner tags; no artifact older than ARTIFACT_DAYS (30) + 1; no
Nexus snapshot asset older than 8 days (with NEXUS_USER/NEXUS_PASSWORD,
skipped and said so without); a dated disk line appended to HISTORY each run,
so "disk use flat" is a comparison of weeks. PASS:/FAIL:/SKIP:/INFO:,
RESULT:, exit 0 only if nothing fails.
Tested here against fixtures (a stale log, an old artifact, no docker -- each
FAIL; clean -- PASS) and a stand-in docker (one stale unused image of three --
FAIL, the in-use and the recent ones kept). The registry check ran against
the real registry: 2 tags. Not run here: the real Docker, Nexus.
Captain Bob, 2026-11-12: "Correct the issue text and write the check script".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-12: "Is it possible to include the FMEA in the pr
review? That way the items are forced into a manual review beforehand?" --
"Yes, add it to the plan". Each FMEA row names its paths; the PR carries a
review record with a decision for every row its diff touches; a
check_fmea_review.sh beside check_protocol.sh refuses the PR without one, or
with one for another diff. A sixth point to rule. Nothing built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261112-001304/PROTOCOL.md: scripts/nightly.sh protocol, one stage per
foreground command: accept amd64, aarch64, riscv64, stick-high -- 538/538,
word_count=318, dict_hash 0x8c92508f748f99cf on all three; test-32 39 programs,
1,869,197 checks, 0 failures; the proofs (StarForth, 36 s); the images (PC,
RASPI, MILKV); the documents (book, fabric, dictionary, vol1-3, api). The tree
clean before and after. Every stage's output in logs/20261112-001304/protocol/,
the boots' serial logs and DoE CSVs beside it.
The first protocol run: the evidence the PR's Acceptance check now asks for.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
scripts/nightly.sh protocol: every stage a PR, the nightly and a release run --
accept amd64, aarch64, riscv64, stick-high, test-32, proofs, images, docs --
in order, never publish; the first failure ends it. protocol <stage>... runs
those only, so each can be its own foreground command (the QEMU rule);
accept-amd64 begins a protocol, recording the commit and whether the tree is
clean. protocol-report writes logs/<TS>/PROTOCOL.md (the commit, the tree,
each stage's result and output, POST and dict_hash per architecture compared,
test-32's totals, the proofs' log, the images' and documents' SHA-256) and
keeps every stage's output in logs/<TS>/protocol/ -- nothing is left only in
build/nightly. PASS only if every stage passed on the commit it began on and
the tree is unchanged but for the evidence.
acceptance.yml: scripts/check_protocol.sh on the PR's head, first, before the
boots. The PR template asks for PROTOCOL.md; .claude/CLAUDE.md names the
protocol as the acceptance a developer runs.
Captain Bob, 2026-11-07 (#135); 2026-11-12: "Keep working on alpha.5".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
scripts/check_protocol.sh [<rev>]: refused (exit 1) unless <rev> carries a
logs/<TS>/PROTOCOL.md naming a commit whose protocol passed on a clean tree,
and that commit differs from <rev> only in the evidence (logs/ and
experiments/bare_metal/runs/, committed after the run). Any other change since
makes the evidence stale: the protocol is run again.
scripts/test_check_protocol.sh, written first and seen to fail (8 of 8, and
tightened so a missing script is not taken for a refusal): no protocol, stale,
failed, dirty, unknown commit -- refused; fresh, fresh among stale ones, other
files in logs/ -- passes. 8 of 8 pass.
Not yet wired into acceptance.yml: that comes with nightly.sh protocol.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Captain Bob, 2026-11-11: "I'm thinking about adding a CAPA & FMEA GATE to our
build pipelines", then yes to writing it up. A nightly.sh quality stage run in
the acceptance gate: every kind/escaped issue has a CAPA record whose
preventive control exists and runs in a stage; every FMEA row over the
threshold has a control in the gate. Seeded with five CAPAs from 2026-11-11.
Five points to rule (section 7).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Every workflow shared the concurrency group qemu. A group keeps one running
and one waiting run, and a run that joins cancels the one waiting: Build
runs 245 and 247 were cancelled at 0 s by PR 164's Acceptance runs.
Captain Bob, 2026-11-11: "It should be global"; the runner has capacity 1.
So the concurrency block is removed from all six workflows (a comment in
each says why): with one runner at capacity 1 every job waits its turn in
Gitea's queue and none is cancelled, and a runner-image rebuild still
blocks the rest. CLAUDE.md's CI section corrected; FABRIC-3 XLVIII.19.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
logs/20261111-193825/v4-test: make -C v4 test on feb740c5 -- 79 programs,
3,740,484 checks, 0 failures, at V4_CELL_BITS=32 and 64. CI's v4-tests job
(Build run 247) was cancelled at 0 s by the shared qemu concurrency group
(#140), so this is the run of record for that job.
logs/20261111-185352/nightly: what scripts/nightly.sh wrote only under
build/nightly for 9415d7ed's acceptance (d6846b34) -- the four accept
summaries, test-32 (39 programs, 0 failures) and the images stage (PC,
RASPI, MILKV). The test-32 output of the earlier 90c5c140 run was
overwritten in build/nightly before it was kept, and is not recoverable.
Captain Bob, 2026-11-11: all logs are evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
XLVIII.18 records 2026-11-11: the LFS trim (Captain Bob: "they can be
trimmed out"), version.h untracked and BLOCK_MAP.md without its timestamp
(#145), my put-back error and its fix, the acceptance rulings (never in the
background; all logs and CSVs are evidence), the acceptance of 9415d7ed,
and alpha.4's Gitea release marked final.
README: alpha.4's release is no longer a pre-release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Run one stage at a time in the foreground through scripts/nightly.sh:
20261111-185352 amd64 PASS
20261111-185600 aarch64 PASS
20261111-185950 riscv64 PASS
20261111-190128 stick-high PASS
PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, [zuse@Hera] ok>
on every boot; word_count=318 dict_hash=0x8c92508f748f99cf on all three;
test-32 39 programs, 0 failures.
scripts/nightly.sh images -- the stage the version.h put-back had broken --
built PC, RASPI and MILKV and left the tree as committed.
DoE CSVs for every boot (empty, as every v4 acceptance boot's: #141).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
90c5c140 untracked v3/include/version.h, but six places still put it back
with git checkout. Git refuses the whole checkout when one path is unknown:
- scripts/nightly.sh images (set -e): the stage ended there, so the nightly
(images, publish, proofs) and release.yml (images, docs, gitea-release)
would fail. Acceptance does not run images, so it passed.
- scripts/check_images.sh (no -e), demo/build-iso.sh, demo/mint-zuse.sh
(|| true): silently put nothing back, BLOCK_MAP.md and the SBOM included.
- scripts/qemu_session.py: an error after every boot, otherwise harmless.
- boards/BRINGUP.md: the step said to put it back.
BLOCK_MAP.md stays in every put-back: a signed build (CI's) still rewrites
its Signed column. Found while setting up alpha.5; Captain Bob: fix it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
amd64, aarch64, riscv64 (clean qemu), stick-high, test-32, run one at a
time in the foreground through scripts/nightly.sh:
PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, [zuse@Hera] ok>
on every boot; PARITY:V4_SYSTEM word_count=318
dict_hash=0x8c92508f748f99cf on all three; test-32 39 programs, 0 failures.
No tracked file changed across the five builds.
20261111-170703 amd64 PASS
20261111-170909 aarch64 PASS
20261111-171235 riscv64 PASS
20261111-171410 stick-high PASS
Also kept as evidence:
20261111-170134 amd64 on aec7ddb5 (before the clean-tree fix), PASS
20261111-170544 amd64 on 90c5c140, stopped by me during boot: it had been
started in the background, against the protocol, and was
rerun in the foreground as 20261111-170703
DoE CSVs for every completed boot (experiments/bare_metal/runs).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
v3/include/version.h is written by every build (kernel/Makefile and
v3/Makefile, both FORCE), with a timestamp and the last build's ARCH; the
committed copy was stale (LITHOS_VERSION 2.1.0). Untracked, and .gitignore's
entry corrected: it said include/version.h, the path before the move to v3/,
and matched nothing.
capsules/BLOCK_MAP.md differed on every build only in mkcapsule's
"Generated ... <timestamp>" header. The timestamp is dropped, so the manifest
changes only when the capsules do; two runs are byte-identical.
mkcapsule's warnings unchanged (5, #143).
Captain Bob, 2026-11-11: untrack version.h and fix the ignore; drop the
manifest timestamp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
Their pointers were committed in a5ed8c3d (2026-08-01) and the objects were
never uploaded: the server answers 404 for all of them, and no copy exists
(Captain Bob, 2026-11-11: "they can be trimmed out").
Removed: 3,827 phase-1 logs (docs/working/archive/legacy/phase-1), 3 in
docs/working/archive/historical, 106 DoE CSVs in experiments/bare_metal/runs,
QEMU_BASELINE.log, docs/SYSTEM_NARRATIVE.log, docs/ontology.log.
Kept: the 5 LaTeX build logs under docs/patent (legal hold) -- excluded from
fetch instead. .lfsconfig excludes every one of these paths, so older commits
check out and LFS fetches run without 404s.
Every LFS pointer left in the tree (1,195) has its object on the server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
These logs/ files were committed as plain text even though
.gitattributes routes logs/**/*.log through the LFS filter, so every
fresh clone showed them all as modified. Renormalize them so they are
stored as LFS pointers. File contents are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
PublicInquiry files the inquiry as before, then mails it through the wiki's mail service: plain text, the subject fixed but for the topic (line breaks removed), Reply-To the visitor's checked address, a link to the filed entry. If it is not sent the inquiry is filed all the same; a new class field, mailed (E-mailed to Captain Bob), says which, shown on the entry's sheet. Installed on the .org; a guest's test inquiry filed and thanked, mailed 0 -- the wiki has no SMTP account yet (Mail.MailConfig: no host), which Captain Bob sets in Administration > Email.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The design canvas (v17) gains the Documents artboard -- the Book of Fabric and
the Dictionary of v4 first, then the book, the three volumes and the API
reference, each with its SHA-256, and the SSRN paper -- and Downloads and
Documents in every .com nav; Downloads' reading list becomes a pointer to
Documents. site/com/canvas/ copied from it.
site/com/build.py --release TAG --sums SHA256SUMS builds Downloads and
Documents from the release ([TAG], [RELEASE]/<file>, [SHA:<file>]; a file the
release's SHA256SUMS lacks fails the build). Without a release it builds Home,
Try it and Inquiries exactly as before -- byte for byte -- with no link to the
two pages, so they go live only with alpha.4. install.sh installs them when
built.
scripts/nightly.sh gitea-release: the release's SHA256SUMS now covers every
file it attaches -- the images' sums, then the PDFs and the Root CA's
certificate -- so `sha256sum -c SHA256SUMS` checks all of it and Documents
finds each sum. The Nexus artifacts keep their own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
make dictionary -> build/docs/Dictionary.pdf (20 pages): mkdictionary.py checks docs/reference/v4-dictionary.tsv against the booted system's words first, so a stale dictionary fails the build; then Markdown, pandoc, docs/book/dictionary.tex (the books' preamble, its own title page: version and commit). Quoted FORTH tokens set as code, so their quotes print straight. The nightly's docs stage builds it; publish sends classifier dictionary; the Gitea release attaches it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The names from the system itself (the hosted v4's WORDS, plus the kernel's sk_v4_words[]); the stack notation and description in docs/reference/v4-dictionary.tsv, drafted from the source where it says (54 stacks, 105 descriptions), the rest to write. check refuses a missing, unfinished or stale entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
`make fabric` -> build/docs/BookOfFabric.pdf (722 pages): Part I the living
record (FABRIC-3), Part II the closed documents in the order written, Part
III the forward-looking notes; its title page carries the version (git
describe --tags: a release's tag) and the commit. Built from the same pandoc
fragments as the book; the book's preamble moved into docs/book/preamble.tex,
shared by both (the book builds as before, 821 pages).
scripts/nightly.sh: the docs stage builds it ($DOCS/fabric.pdf); publish
sends it as classifier `fabric`; gitea-release attaches every PDF in $DOCS,
so every release carries it. Progress for the rest of alpha.4's documents:
docs/v4.0.0/plans/2026-11-10-alpha4-documents.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Task 5 of plan 2026-10-29-stick-5, accepted in full, and with it #92:
- amd64, aarch64, riscv64: PARITY:V4_POST tests=538 pass=538 fail=0,
POST: PASSED; word_count=318 dict_hash=0x8c92508f748f99cf on the three
- the PC stick as built, loaded high: 538/538, the prompt
- make -C v4 test-32: 39 programs, 0 failures
Sessions: fallback, replace, mint_fail, system_pull_real; regressions:
every Task 4 session, genesis, stick_genesis, screen_dark_until_login,
screen_dark_after_logout, kbd_typeahead, emergency. Verdicts in
logs/20261110-075036/verdicts/. The plan's Task 5 ticked; STICK.md 11
increment 5a done; FABRIC-3 XLVIII.17; the SER5 bench steps in
boards/BRINGUP.md 4.2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
First boot (genesis, growth, the time to the prompt), the second boot, MINT-ZUSE onto a second stick, the system stick alone (the fixed screen), both sticks at power-on -- each rehearsed first in QEMU by the qemu_session.py mode named. 3.2's 'boots headless' corrected: the stick's first boot now mints its Zuse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The four lines on the screen and serial while the proxy is recognised and her stick is not here; R runs sk_v4_mint_zuse(), every other key is dropped. Her stick pulled: the screen again. The system stick pulled while hers is in: hers let go first (the block chain's tail), remembered for the system stick's return. Builds on three ISAs; fallback running.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Task 4 of plan 2026-10-29-stick-5, accepted in full:
- amd64, aarch64, riscv64: PARITY:V4_POST tests=538 pass=538 fail=0,
POST: PASSED; PARITY:V4_SYSTEM word_count=318 dict_hash=0x8c92508f748f99cf
on the three (MINT-ZUSE, the lone node's second word)
- the PC stick as built, loaded high: 538/538, the prompt
- make -C v4 test-32: 39 programs, 0 failures
Sessions: mint_zuse on the three; mint_zuse_refuse, mint_small,
mint_zuse_used, mint_pull_system, zuse_stick_first; regressions genesis,
two_sticks, hotplug, midpull, typeahead. Verdicts in
logs/20261110-051726/verdicts/. The plan's Task 4 ticked; FABRIC-3 XLVIII.16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
A GPT stick with an identity partition and no Artemis, the system stick in and its marker naming a real Zuse: checked against the real key; a match attached and logged in (a running session moves to her); no match: 'not this system's Zuse stick -- not used'. Arriving first, it is remembered and checked when the marker is read. Builds on three ISAs; mint_zuse running.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The header scan (Captain Bob, 2026-11-10): 788 source files -- 351 with the
SL-1.0 header, 12 with the old name (docs/working/experiments, kept by
ruling), 31 under someone else's licence (tools/kconfig, Linux's, GPL-2.0:
kept), and 394 with none. Ruled: the SPDX form; capsules (.4th, .f18) and
proofs (.thy) left for a ruling of their own (mkcapsule's 64x16 block format,
content-addressed capsules).
253 files now begin
SPDX-License-Identifier: LicenseRef-Starship-1.0
Copyright (c) 2023-2026 Robert A. James
as a /* */ block (C, headers, assembly, linker scripts) or # lines (scripts,
Makefiles, Kconfig; below a shebang or a coding line); tools/mkcapsule.c,
which had the copyright line, gets the SPDX line only.
Not touched: docs/working/ (archive and old campaign material, as the
ruling kept the experiments); v4/system/post_cases.c (generated by
v4/tools/mkpost.py, "do not edit" -- the generator has the header).
Comments only: the kernel builds on amd64, aarch64, riscv64; make -C v4
test-32: 39 programs, 0 failures; every changed script parses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Asks for a stick, shows its size, writes nothing until YES; then gpt_write_one, the partition's first devblocks zeroed, a fresh Zuse minted, read back, and only then the marker's real key. Any failure before the marker: 'failed -- nothing changed'. The gate remembers the last stick it turned away as a spare, offered first by the next mint. Builds on three ISAs; not yet called.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
sk_v4_identity_offer_wait() beats until a stick that is not this system's arrives (offered), a key is pressed, or the system stick leaves; sk_v4_identity_recheck_offered() runs the arrival check again once the mint has written it. Builds on three ISAs; not yet called.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The old MBR zeroed first, the backup header and entries, the primary, the protective MBR last: a write torn anywhere leaves no table. Builds clean on amd64, aarch64, riscv64; checked on the host against blank 600 MiB and 32 MiB images and a used Zuse stick (sfdisk --verify clean, gpt_read reads it back). Not yet called.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
347 headers said "Licensed under the StarForth License, Version 1.0" -- a
shortening (Captain Bob, 2026-11-08: "License file SL I think I shortened
accidently"); LICENSE is, and has been since the first commit, the
Starship License 1.0 (SL-1.0, SPDX LicenseRef-Starship-1.0). 349 files,
566 occurrences, now "Starship License, Version 1.0 (SL-1.0)".
Left as they are, pending a ruling: docs/patent/ (the patent figures),
docs/formal/ (the citable volumes) and the generated reports under
docs/working/experiments/ (32 files). Comments and license text only:
the amd64 kernel builds, every changed script parses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The README still named v2.1.0 and an old dict_hash. Now: the version
(kernel 4.0.0-alpha.3, engine 3.2.0) and the release; Try it on the .com;
the stick (plug and play, the proxy Zuse, growth -- #92 Tasks 1-3), M9 on
the stick's GPT partitions; how a change reaches master (the acceptance
gate, every run a first boot); signed capsules and the Root CA; v3's
retirement (#156); `make write_stick`, `qemu-stick-high`; the stick and the
Book of Fabric in the documentation table. v4's dict_hash 0xfec8c47cfc6f437f.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Accepted in full:
- amd64, aarch64, riscv64: PARITY:V4_POST tests=538 pass=538 fail=0,
POST: PASSED, [zuse@Hera] ok> on a fresh data stick; dict_hash
0xfec8c47cfc6f437f on the three
- the PC stick as built, loaded high: 538/538, the prompt
- make -C v4 test-32: 39 programs, 0 failures
- regressions: v3_keys, genesis on the three, stick_grow, midpull, hotplug
SAVE-BUFFERS on the 16 GiB stick: 5.1-6.1 s before, 1.1 s after; the BAM's
bytes the same (verdicts in logs/20261108-145611/verdicts/). FABRIC-3
XLVIII.14.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Not yet accepted. bam_flush_to_disk() and bam_sync_from_disk() read and
wrote every page of the BAM; with the stick's BAM sized for 256 GiB (6144
devblocks, 24 MiB) every flush of a dirty block moved 24 MiB each way.
They now touch only the pages that hold the slot's bits -- its reserved
bits and one per user block (bam_pages_used()) -- the pages past them are
never set, so the bytes on disk are the same.
Test (qemu_session.py bam_flush, --target qemu-stick --stick-gib 16):
three SAVE-BUFFERS of an Artemis block, each timed, then the BAM hashed.
Before: 5.1 / 5.6 / 6.1 s (the 2 s limit fails; it was set after seeing
this baseline). After: 1.1 / 1.1 / 1.1 s. The BAM's bytes the same either
way: sha256 79197a40...b9e44b50, 5 non-zero bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Task 3 of plan 2026-10-29-stick-5, accepted in full:
- amd64, aarch64, riscv64: the proxy Zuse minted on a fresh data stick,
PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, [zuse@Hera] ok>;
dict_hash 0xfec8c47cfc6f437f on the three
- the PC stick as built, loaded high (stick_genesis): 538/538, the prompt
- make -C v4 test-32: 39 programs, 0 failures
Regressions pass. v3_keys failed once (a virtio_blk request never completed,
logs/20261108-132844) and passed on its rerun (logs/20261108-141539).
The plan's Task 3 steps ticked; FABRIC-3 XLVIII.13.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
system=v3: Hestia logged 'virtio_blk: request never completed'; Hera reached the Zuse drive's attach and no further. Task 1's v3_keys (logs/20261108-043612) has no such line and passed. The drives were the same three, passed explicitly. To be rerun; bisected against Task 1 if it fails again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Not yet accepted (plan 2026-10-29-stick-5, Task 3).
- kernel/Makefile: a v4 `qemu` boot attaches a fresh data stick
(DATASTICK=1) and nothing else; ARTDISK/ZUSEDISK keep the minted pair only
for system=v3 (QEMU_V3_BOOT, from KERNEL_ARGS).
- qemu_session.py: the Makefile's defaults for every mode but those that ask
for the pair by name (stick_artemis, two_sticks, artemis_unsigned,
raw_ident, v3_keys) or for no drive; `zuse` now expects the genesis line.
- nightly.sh: accept stick-high runs stick_genesis (the stick as built).
- .claude/CLAUDE.md "The disks", the stick-high line; disk/README.md (the
pair: tests and v3 only); STICK.md 11, increments 3 and 5 done.
Before the change: zuse on amd64 FAIL -- the pair's "identity confirmed",
no genesis line (logs/20261108-130732).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Task 2 of plan 2026-10-29-stick-5, accepted in full:
- amd64, aarch64, riscv64: PARITY:V4_POST tests=538 pass=538 fail=0,
POST: PASSED, [zuse@Hera] ok>; dict_hash 0xfec8c47cfc6f437f on the three
- the PC stick loaded high: 538/538, POST: PASSED, the prompt
- make -C v4 test-32: 39 programs, 0 failures
The acceptance boots' logs, the accept-*.txt verdicts and test-32's output
(logs/20261108-123847/verdicts/). The plan's Task 2 steps ticked; FABRIC-3
XLVIII.9, with one item for a ruling: blk_flush rewrites the whole BAM, now
sized for 256 GiB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Not yet accepted (plan 2026-10-29-stick-5, Task 2, step 3).
- gpt.c: the writer, gpt_grow_last() -- the backup entry array and header to
the disk's end, the last partition to the last usable sector (whole MiB,
capped), both headers' CRCs, the backup before the primary, the
protective MBR's size; gpt_alternate_lba().
- sk_v4_grow.c: the volume grown to its partition -- its fence (the Artemis
signature, Zuse's genesis marker) moved to the new top, the header last;
the partition grown no further than the BAM tracks (the block subsystem
places the fence by the device's size, so a volume must fill it).
- sk_v4_identity.c: a stick of 8 GB or more whose GPT ends short of the disk
is grown before its partitions are opened; "Artemis: grown to fill the
stick" / "under 8 GB -- not grown" / "past 256 GiB ... left unused".
- block_subsystem: blk_volume_compute_totals() (compute_totals_from_B,
public) and blk_subsys_set_format_bam_for(); v3's behaviour unchanged.
- mkartemis --bam-for, mkdiskimage.sh --bam-for, kernel/Makefile
STICK_GROW_MIN_BYTES / STICK_ARTEMIS_CAP_GIB: the stick's and data stick's
Artemis BAM sized for 256 GiB (6144 devblocks). STICK.md 5a: 256 GiB (R1).
After: stick_grow PASS (16 GiB: 12129370 user blocks, 8 s POST to prompt;
second boot not grown, recognised; sfdisk --verify: no errors), stick_small
PASS, check_images.sh PASS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Plan 2026-10-29-stick-5, Task 2, steps 1-2:
- qemu_session.py: --stick-gib N (the session's copy of the stick extended,
sparse); modes stick_grow (16 GiB: grown, over 12000000 user blocks, the
prompt, the first boot's time; the second boot of the same copy not grown
again; sfdisk --verify clean) and stick_small (4 GiB: under 8 GB, not grown,
said so).
- kernel/Makefile: STICK_GIB and STICK_FRESH on qemu-stick, for those.
- check_images.sh: the PC stick's and data stick's Artemis BAM sized for the
256 GiB cap (6144 devblocks).
Before the change: stick_grow FAIL (no growth line, 1137649 user blocks,
sfdisk: the backup GPT not at the end); stick_small FAIL (no line);
check_images.sh FAIL on the two BAM checks only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Task 1 of plan 2026-10-29-stick-5, accepted in full:
- amd64, aarch64, riscv64: PARITY:V4_POST tests=538 pass=538 fail=0,
POST: PASSED, [zuse@Hera] ok>; dict_hash 0xfec8c47cfc6f437f on the three
- the PC stick loaded high: 538/538, POST: PASSED, the prompt
- make -C v4 test-32: 39 programs, 0 failures
The logs of the acceptance boots (aarch64 044253, riscv64 044558, the stick
high 044725; amd64 044115 is already in), the four accept-*.txt verdicts and
test-32's output. The plan's Task 1 steps ticked; FABRIC-3 XLVIII.8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Work in progress on StarForth-v4.0.0; not yet accepted (plan
2026-10-29-stick-5, Task 1).
- zuse_genesis_marker.h: the marker's version 2 -- the proxy's key and the
real Zuse's -- beside version 1.
- capsule_zuse_boot.c: capsule_zuse_boot_check_key() (the identity-record
half of the check) and capsule_zuse_boot_genesis_mint() (the mint half of
v3's genesis) split out; v3's two callers unchanged in behaviour.
- sk_v4_marker.c: the v4 boot reads version 1 as a proxy with no real Zuse,
and writes version 2.
- sk_v4_identity.c: no marker and a blank identity partition -> genesis:
mint, read back, then the marker; the proxy logs in. A marker with a real
key: no session for the proxy (the fixed screen is Task 5).
- qemu_session.py: boot()/shutdown(), so a mode can boot twice; modes
genesis and stick_genesis; stick_boot now expects genesis and the prompt.
Logs: genesis on amd64 before the change (both boots: "no genesis on this
disk", FAIL) and after (minted, then recognised: PASS). The DoE CSV of
032532 is from a run whose QEMU never started (no display; its empty log
directory was removed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
ci/pki/starshipos-root-ca.pem, made on the CI box by make-ca.sh
(2026-11-07, Ed25519, to 2046-11-07; Captain Bob), and its SHA-256
DA:A7:40:56:65:41:1A:FE:E6:08:85:3F:6E:AD:83:3A:38:30:83:E6:F0:6D:69:A6:A8:9E:92:BD:85:93:39:81
in starshipos-root-ca.sha256. Verified: self-signed, CA:TRUE, and it issued
capsules/pki/starshipos-intermediate.der (openssl verify: OK). Every
release attaches it (gitea-release), and the Downloads page shows its
fingerprint; it is also the anchor #139 would build into the kernel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
- scripts/nightly.sh images builds the PC's USB stick too (make boot_image
TARGET=PC -> pc-stick.img.xz, in SHA256SUMS); publish sends it to Nexus
as classifier pc-stick. pc stays the ISO QEMU boots.
- scripts/nightly.sh gitea-release <tag>: the tag as a Gitea release -- a
pre-release for -alpha.N and the like -- notes from the tag's message with
the checksums, the images, SHA256SUMS, the documents and the StarshipOS
Root CA's certificate attached; run again, it adds only what is missing.
release.yml runs it after the Nexus publish, with the secret RELEASE_TOKEN.
Tested here: images builds pc-stick.img.xz (785 KB); gitea-release against
a stand-in Gitea API made a pre-release with the notes and ten files, and a
second run added nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Since #151 an idle guest halts (1% of a core at the prompt), so the cap no
longer has to hold back spinning sessions. Captain Bob set 1.5 cores for
all sessions together on the server (2026-11-08): one busy visitor a full
core, half a core always left to the wikis and Gitea. Confirmed on the
server with a live session idle for 3 minutes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
An idle StarshipOS kept a CPU core 100% busy: sk_v4_readline(), with
nothing typed, and sk_v4_identity_wait(), headless until Zuse, waited in
arch_relax(). Both now halt until the next interrupt (hlt; wfi on aarch64
and riscv64): the heartbeat's timer, ISR-driven on all three, wakes them at
100 Hz, so a key is still seen within a tick.
Idle at the prompt, QEMU's CPU: 100% -> 1% of a core on amd64, 1% on
aarch64 and riscv64. Acceptance passes: amd64 logs/20261108-005539, aarch64
-005753, riscv64 -010136 (POST 538/538, one dict_hash, 7 ok), the stick
loaded high, test-32 (39 programs, 0 failures). FABRIC-3 XLVIII.5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The canvas's Home and Inquiries artboards gain a 'Try it' link (canvas
versions 12, 13); canvas/ copies them, build.py rebuilds the pages, and
install.sh put them on the wiki. Checked as a visitor: the home page, the
link, the Try it page in 1.1 s, its framed console Ready. FABRIC-3 XLVIII.4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
An idle StarshipOS guest keeps a host core 100% busy (measured 2026-11-08:
QEMU at 100% of a core, 148 MiB, the guest idle at its prompt; #151).
starshipos-demo.service: CPUQuota=100% and Nice=19 for all sessions
together, MemoryMax=1G -- sized for this server, where the old 300% and 4G
let two visitors starve both wikis and Gitea. DEPLOY.md says how to apply
it. FABRIC-3 XLVIII.4: Try it deployed and checked from outside; the ttyd
package's own login service; #151, #152.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Ubuntu's ttyd package starts ttyd.service, which runs login on port 7681;
installed by step 1, it took the port, and try.starshipos-f18.com served
the server's login prompt until it was disabled (2026-11-08). Step 4 now
disables it first and checks what listens on 7681. And the check from
outside, done: ready in 1.5 s, 7 ok, 49 ok, the third visitor busy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Five steps on the server after #148: the checkout and amd64 build tools,
the demo's own Zuse, the image and the saved machine at 384 MiB, the
service, TLS and Apache for try.starshipos-f18.com; then the check from
outside and the .com's navigation link (#115, #116, #117).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Today's rulings and work since XLVII.6, kept at the pace of the work
(Captain Bob, 2026-11-07: 'the book of fabric needs to keep pace'): the
alpha.4 list (#147) and what is in it, the developer protocol (#135), the
Book of Fabric (#138), the SDK milestone with the capsule repository (#149)
and the latency DoE (#150), #136 and the demo's guests and busy message,
with what was measured.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: 'Limit guests and have a Busy, try back in a few
minutes.' start-session.sh takes one of DEMO_MAX_GUESTS slots (default 2),
a lock it holds for the session's life (flock -n: two visitors cannot both
take the last one; QEMU and the bridge are started without its descriptor);
with every slot taken, the visitor's terminal says every machine is busy and
to try back in a few minutes, and the session ends without a machine. The
service: DEMO_MAX_GUESTS=2, RuntimeDirectory for the locks, ttyd's
--max-clients 6 so a visitor over the limit reaches the message. The guest:
384 MiB (v4 boots from 256 MiB, refuses at 128; measured, #116). Tested
here: every slot held -> the busy message; slot 1 held -> slot 2 taken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Run 197's riscv64 failure (#131) could only be read from the run's logs
artifact, which Gitea's API does not list. qemu_session.py's check() now
prints, on a FAIL, the serial lines after the first match of an anchor the
check names, or the log's last lines; control characters as escapes, so a
stray byte or terminal sequence in a line shows instead of only failing a
match. The boot-disk checks anchor on 'Boot successful!'. A passing run
prints as before (riscv64 here, logs/ committed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
On 50d2bc98 (LithosAnanke v4.0.0-alpha.3), in this session, one QEMU at a
time in the foreground: amd64 logs/20261107-195526, aarch64 -195725,
riscv64 -200055 (POST 538/538, dict_hash=0xfec8c47cfc6f437f on all three),
the stick loaded high, test-32 (39 programs, 0 failures); the proofs
through the capped stage, logs/20261107-195341 (47 s, ~1.8 GiB).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
v4.0.0-alpha.2's release run (200) was killed in the StarForth session:
Isabelle's defaults (Java 4 GiB, a thread per CPU). scripts/nightly.sh
proofs now runs one thread, Java 512 MiB, Poly/ML 900 MiB, through a
settings file of a home made for the run (heaps linked to the user's):
47 s, ~1.8 GiB, logs/20261107-195341. Nothing was published from alpha.2;
its tag stays. LITHOS_VERSION 4.0.0-alpha.3. FABRIC-3.md XLVII.6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Acceptance run 197 (#130) failed one riscv64 check: no 'Boot disk: not a
StarshipOS stick' line, with POST, the identity and the prompt all passing.
Booted three more times here on the same tree: each printed the line and
passed (4 of 4 with logs/20261107-184616). The Zuse stick has no ESP
(--esp-mib 0), so the firmware cannot have booted from it; the serial
capture losing or garbling the line is what is left to check, against run
197's own log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The protocol on 04006bff (LithosAnanke v4.0.0-alpha.2), in this session,
one QEMU at a time in the foreground: amd64 logs/20261107-184040, aarch64
-184241, riscv64 -184616 (POST 538/538, dict_hash=0xfec8c47cfc6f437f on all
three), the stick loaded high -184753, test-32 (39 programs, 0 failures),
the Isabelle/HOL proofs (logs/20261107-185450/).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
v4.0.0-alpha.1's release run (196) was killed in the proofs: release.yml's
full `make init` fetched Isabelle into the workspace and pointed isabelle
at it, without the image's prebuilt HOL-Library, so the proofs built it
from scratch. Nothing was published. Ruled: the tag stays; release.yml runs
`init INIT_PROOFS=0`; LITHOS_VERSION 4.0.0-alpha.2, the first published
alpha. FABRIC-3.md XLVII.5, CHANGELOG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The image runner-image.yml built from master 4f675c8b (run 193): what init
installs, Maven, and the HOL-Library heap fetched prebuilt (checksum OK, 4.8
s), so the proofs build only the StarForth session. Its acceptance run is
this PR's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: "I also want that rebuilds block other jobs
always." acceptance, nightly and release shared the group qemu; now
runner-image, build and nightly-docs do too, so a rebuild of the runner
image (on the host's Docker daemon) never overlaps another job, whatever
the runner's capacity (#121). On this server every CI run is then one at a
time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The server cannot build it (5.3 GiB from scratch; capped, still 2.6-3.3
GiB against ~2.3 GiB free). The heap built here by the same Isabelle2025-2
is a generic package in this repository's registry (45 MB, SHA-256
bb247846...e999cb339e); the Dockerfile fetches it into Isabelle's system
heaps with the checksum pinned, the token a build secret. Portable: a
fresh Isabelle home with only this heap checks StarForth without
rebuilding HOL-Library. FABRIC-3.md XLVII.4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The protocol on 4ca935d8: three boots (POST 538/538, one dict_hash), the
stick loaded high, test-32 (39 programs, 0 failures), the proofs. Every
capsule logs 'missing (unsigned)': the kernel reads the new certificate;
CI signs with CAPSULE_SIGN_KEY. FABRIC-3.md XLVII.3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Made on the CI box by ci/pki/make-ca.sh (2026-11-07 16:50 UTC): subject
O=StarshipOS, CN=StarshipOS Capsule Signing; issuer O=StarshipOS,
CN=StarshipOS Root CA; 2026-11-07 to 2036-11-06; CA:TRUE, pathlen:0;
Ed25519. SHA-256 of the DER
13a28dda4098ef4f11cba42823a30a9898fdaffdf0c15130126fd2fe029b9a6c. Its key
is the repository secret CAPSULE_SIGN_KEY; the root's stays on the box.
The snakeoil intermediate leaves the tree (its history is in git).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The acceptance protocol on b7534107 (LithosAnanke v4.0.0-alpha.1), in this
session, one QEMU at a time in the foreground:
- amd64 logs/20261107-150809, aarch64 -151023, riscv64 -151359: [zuse@Hera]
ok>, PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED,
dict_hash=0xfec8c47cfc6f437f on all three
- the PC stick loaded high, logs/20261107-151539: the same, no fault
- make -C v4 test-32: 39 programs, 0 failures
- Isabelle/HOL proofs, logs/20261107-152312/isabelle: Finished StarForth
CHANGELOG and FABRIC-3.md XLVII: the ruling, what was verified, and what
an alpha leaves open (the v4.0.0 milestone; unsigned capsules until the
StarshipOS CA).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: "Kernel is 4.0.0. This is our first alpha
release." LITHOS_VERSION 2.1.0 -> 4.0.0-alpha.1; the engine (VERSION)
stays 3.2.0. The 4.x line is a working line (even major); v3.0.0 is no
longer the next number, and an LTS line takes the next odd major when
FABRIC-3.5.md XXX.5's criteria are met. Recorded in kernel/Makefile's
versioning policy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: "The banner XWiki should not say that." Both
wikis now have a colour theme of their own, FlamingoThemes.StarshipOS (the
stock Iceberg, copied, with the starshipOS wordmark as its logo; Iceberg
untouched), and the browser tab's title ends "- StarshipOS". Installed on
both; checked as a guest on each (logo and title), and the .org's top bar
seen logged in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Five website commits queued five Build runs (183-187), ~17 minutes of image
builds each on the server both wikis run on; the .org stopped answering.
build.yml now ignores pushes whose changes are all under site/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: "Menu bar". For guests only, the .com pages and
the .org landing page hide XWiki's top bar, breadcrumb, title block, page
menu, panels, footer and tour, and the design runs the full width (a
velocity check on $isGuest; the stylesheet in a literal block). Logged in,
the wiki is all there. Checked on a phone and a desktop: the chrome is
hidden on Main, Inquiries and TryIt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
- site/colorlock.py: both XWikis force black and white with !important (a
HIGH CONTRAST DARK THEME block in the skin's cssVariablesInit.css). On our
pages only, the design's colours win: each inline colour made !important,
and a stylesheet scoped to the page root (.ssos) for the rest. Used by
site/com/build.py and site/org/build.py; the .com reinstalled with it.
- site/org/inquiries (Captain Bob, 2026-11-07): the .com's inquiries go to an
admin-only master/detail on the .org -- Inquiries.WebHome (Live Data
table), one page per inquiry under Inquiries.Entries with a sheet and a
status, PublicInquiry (public) filing them with its author's rights and
echoing nothing a visitor sends; a hidden trap field for robots. The .com
form posts there. Installed and tested: a guest's inquiry filed and
deleted; one whose name and message were script macros was stored as
text, nothing ran.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The first run on starshipos-f18.org created the dashboards, then XWiki
refused the group and rights objects: a form-encoded POST needs XWiki's
form token (CSRF), an XML one does not. For about two minutes Admin.WebHome
and Contributors.WebHome were readable by guests (links and the names of
secrets, no values). Objects now go as XML, and the spaces' rights are made
before the pages, so a failed run cannot leave a dashboard open. Installed:
Main 200, Admin and Contributors 401 as a guest, 200 as rajames; a second
run changes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Captain Bob, 2026-11-07: build the .com from the StarshipOS.com canvas.
canvas/ holds the artboards as drawn; build.py makes Main, Inquiries and
TryIt as {{html}} pages (the wiki's links and domains, the images as
attachments, the real console in Try it, the forms by e-mail); install.sh
puts them on the wiki and checks a guest's view. Installed on
starshipos-f18.com: every page and image reads 200 as a guest, and renders
without a macro error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Nightly 174 passed acceptance, then Isabelle was killed building HOL-Library
(exit 137, out of memory on the runner), and the images were never built or
published. The proofs check the theories, not the images: they now run after
the publish, whatever happened before them, and a failure still turns the run
red. Their log stays in the run's logs artifact. A release still runs them
before it publishes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-07 11:21:59 +00:00
5461 changed files with 18512 additions and 14116 deletions
# Nightly snapshot of the kernel images: the acceptance protocol, the board images, Nexus, then
# the proofs. Each stage is a step of scripts/nightly.sh (its header says what each does); any
# v4 under the sanitizers with the hosted builds (#16), and the proofs. Each stage is a step of scripts/nightly.sh (its header says what each does); any
# failure stops the run, and nothing is published unless every stage before it passed. The proofs
# come last and run whatever happened before them: they check the theories, not the images, so a
# failed proof does not hold back images that passed acceptance -- it turns the run red.
# failed proof does not hold back images that passed acceptance -- it turns the run red. The v4
# checks (#16; Captain Bob, 2026-11-13: "Nightly") are the same: the engine on the host, not the images.
## 2026-11-10 — LithosAnanke v4.0.0-alpha.4: the plug-and-play stick
The plug-and-play stick (#92), the BAM flush (#155), the Book of Fabric (#138), the Dictionary of v4 (#157), and the .com’s Downloads and Documents pages (#126, #161).
## 2026-11-07 — LithosAnanke v4.0.0-alpha.3: the first published alpha
`v4.0.0-alpha.2` (`2d43db25`) used the image's HOL-Library as intended, but its release run (200) ran
the proofs with Isabelle's defaults -- Java's heap up to 4 GiB, a thread per CPU -- and they were
killed in the StarForth session. Nothing was published; the tag stays where it is. The proofs now run
capped (`scripts/nightly.sh proofs`: one thread, Java 512 MiB, Poly/ML 900 MiB; 47 s, ~1.8 GiB), and
`v4.0.0-alpha.3` is the first alpha published. `docs/fabric/FABRIC-3.md` XLVII.6.
## 2026-11-07 — LithosAnanke v4.0.0-alpha.2: not published
`v4.0.0-alpha.1` (`233025da`) was accepted and tagged, but its release run (196) built HOL-Library
from scratch in the proofs step and was killed: `release.yml`'s full `make init` replaced the
image's Isabelle, the one with HOL-Library prebuilt. Nothing was published; the tag stays where it is
(Captain Bob, 2026-11-07). `release.yml` now runs `init INIT_PROOFS=0`, and `v4.0.0-alpha.2` is the
first alpha published -- the same system as below. `docs/fabric/FABRIC-3.md` XLVII.5.
## 2026-11-07 — LithosAnanke v4.0.0-alpha.1: the first alpha release
The first alpha of the kernel, `v4.0.0-alpha.1`: v4, StarForth's F18 engine, is the system every
board boots by default, with v3 a boot argument away. The kernel's version goes from 2.1.0 to the
4.x working line (Captain Bob, 2026-11-07); the engine stays 3.2.0. Accepted in full before the tag:
amd64, aarch64 and riscv64 to `[zuse@Hera] ok>` with POST 538/538 and one `dict_hash`
(`0xfec8c47cfc6f437f`), the PC stick loaded high, `test-32` (39 programs, 0 failures), and the
Isabelle/HOL proofs. An alpha: the v4.0.0 milestone's own definition -- parity with v3's vocabulary,
K=1.0 measured on v4, the hosted mesh, Verilator -- is still open, and the capsules are unsigned until
the StarshipOS CA is made (FABRIC-3.md XLVI). Also today: CI in a prebuilt runner image, the
nightly's proofs no longer able to hold back its images, and the .com and .org websites. Full record:
`docs/fabric/FABRIC-3.md` XLVII.
## 2026-11-07 — CI jobs start ready: the runner image
The CI jobs now run in `lithosananke-runner` (`ci/runner-image`, #120), an image with everything
| M7.1 | Capsule birth · Mama FORTH vocabulary · the Tripod fleet · kernel-Hermes · word-level ACL | ✅ Live |
| M8 | Keyboard input to the REPL — PS/2, virtio and **USB** keyboards (a full keyboard: Caps/Num Lock, keypad) | ✅ In QEMU, all three ISAs |
| M9 | Block storage — Artemis's disk on virtio-blk; identity thumbdrives on USB mass storage | ✅ In QEMU · real disks: no driver yet (`boards/BRINGUP.md` A4) |
| M9 | Block storage — on v4, Artemis and Zuse's identity on the StarshipOS stick (GPT partitions, over USB mass storage); v3's Artemis on virtio-blk | ✅ In QEMU · real disks: no driver yet (`boards/BRINGUP.md` A4) |
| The stick | One USB stick is the whole OS: plug it in, boot, `[zuse@Hera] ok>` — its first boot mints its own Zuse and grows Artemis to fill it (`docs/v4.0.0/STICK.md`, #92) | ✅ Tasks 1–3 of 5 in QEMU · the real Zuse on a second stick next |
| Bare metal | a generic PC (amd64; first on the bench: a Beelink SER5), Raspberry Pi 5 (aarch64), Milk-V Mars (riscv64); Zynq-7020 (ARMv7) not yet ported | Images build; first boots on the bench — `boards/BRINGUP.md` |
**v4 is the default build, and v3 is being retired**: every kernel boots v4 unless its boot
arguments say `system=v3`. POST at boot, on all three ISAs: v4 — **538 tests**,
DEVICE=/dev/sdX`, plug it in, boot: the stick's first boot mints its own Zuse (no two sticks share
one) and grows its Artemis partition to fill the stick, up to 256 GiB, writing metadata only.
- **Identities on thumbdrives** — Zuse, the superuser, and every user is a minted USB
thumbdrive (Ed25519, Zuse-signed); plugging one in births that user's VMs, pulling it out
ends them. There is only the drive: no password, no PIN.
- **Signed capsules** — the capsules the kernel boots from are signed under the StarshipOS Root CA
(`ci/pki/starshipos-root-ca.pem`, published with every release) and checked at boot.
- **Word-level ACL** — every dictionary entry carries a TTL/allow/mode/pin access-control
record; strict, TTL and pinned modes; two console layers (emergency `ok>` and superuser
`zuse)ok>`). Measured overhead of the live ACL-TTL mechanism: **+0.0603%**, CV 0.000%,
@@ -84,10 +103,16 @@ make # every board with a kernel port + hosted v3 +
make docs # build/docs/LithosAnanke.pdf (LaTeX master: docs/book/main.tex)
make clean TARGET=RASPI # that board's outputs and build/aarch64/kernel
# The kernel in QEMU (OVMF / AAVMF / EDK2), one architecture at a time -- boots v4
# The PC stick, written to a real USB stick (checks the device, asks you to type its name back,
# verifies the write); then boot it from the PC's firmware boot menu
make write_stick DEVICE=/dev/sdX
# The kernel in QEMU (OVMF / AAVMF / EDK2), one architecture at a time -- boots v4 from a fresh
# data stick, so every boot is a stick's first boot
make -f kernel/Makefile ARCH=amd64 clean qemu
make -f kernel/Makefile ARCH=aarch64 clean qemu
make -f kernel/Makefile ARCH=riscv64 clean qemu
make -f kernel/Makefile ARCH=amd64 clean qemu-stick-high # the PC stick itself, loaded high
make -f kernel/Makefile ARCH=amd64 KERNEL_ARGS=system=v3 clean qemu # v3, while it remains
# The Pi 5's native boot path, rehearsed on QEMU's virt machine at EL2
@@ -123,7 +148,8 @@ which to believe. Among them:
| | |
|---|---|
| [The FABRIC record](docs/fabric/) | Every design decision and the work as it happened (`FABRIC-3.md` is the living one) |
| [The FABRIC record](docs/fabric/) | Every design decision and the work as it happened (`FABRIC-3.md` is the living one) — published as *The Book of Fabric* from alpha.4 |
| [The stick](docs/v4.0.0/STICK.md) | The x86-64 StarshipOS stick: plug and play, the proxy Zuse, growth |
| [StarForth v4](docs/v4.0.0/) | The F18-derived engine |
| [Board bring-up](boards/BRINGUP.md) | Getting onto a PC, the Pi 5 and the Mars |
| [Roadmap and versioning](docs/reference/ROADMAP.md) | Milestone plan and release-versioning policy |
# boards/raspi/board.mk -- Raspberry Pi 5 (BCM2712, Cortex-A76, aarch64).
#
# Native firmware boot, no UEFI (FABRIC-3.md §IV): the Pi 5 bootloader
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.