Compare commits

...
55 Commits
Author SHA1 Message Date
Robert Allan JamesandClaude Sonnet 5 ff2941dfb9 FABRIC-3.md §I.7: close Milestone 9 deferral now that its precondition is met
The item only ever tracked whether the deferral itself was still
correctly in force, not the networking work. Milestone 7 (§I.5) closed
this session, satisfying the precondition, so the deferral resolves --
Milestone 9's actual networking design stays a separate, still-unscoped
effort, correctly out of scope on its own terms (FABRIC-2.md's own
sequencing: after ACL/PKI/contrib, not concurrent with it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 11:05:51 -04:00
Robert Allan JamesandClaude Sonnet 5 eeceec21a5 FABRIC-3.md §I.5: Milestone 7 trust tiers (QEMU-vs-real-hardware), closing it
Closes the contributor-capsule/trust-tier punch-list item. Decided
direction: QEMU-vs-real-hardware conditional enforcement.

Found before building on that decision: the obvious mechanism (expose
TimerInfo.vm_mode) only works on amd64 -- aarch64 and riscv64 both had
vm_mode hardcoded to 1 unconditionally, meaning they'd always report
"running under QEMU" even on real hardware. Built real detection for
both instead of shipping that: aarch64 checks the ACPI RSDP's OEM ID
for QEMU's "BOCHS " SeaBIOS-heritage signature; riscv64 checks the
devicetree root compatible property for "qemu". Confirmed vm_mode was
otherwise unread anywhere else in either file first -- zero risk to
existing timing behavior.

CAPSULE_FLAG_CONTRIB (mkcapsule.c: FLAG_CONTRIB) path-matches on
capsules/contrib/, mirroring FLAG_MAMA_INIT's exact-match pattern.
contrib_capsule_refused() (capsule_birth.c) enforces: no additional
check under QEMU (same WARN-only as everything else); on real hardware,
a contrib capsule additionally requires CAPSULE_SIG_OK, since it has no
other provenance to fall back on. Wired into capsule_birth_baby() and
capsule_run_experiment().

Also updates §I.7 (Milestone 9): its stated precondition (Milestone 7
closing) is now met, flagged as stale rather than treated as a green
light to design networking from nothing.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground) -- compile/boot verification only; the real-hardware
enforcement branch is unverifiable from this environment, same as all
of §I.6. logs and DoE CSVs from this session's verification runs
included per this repo's own audit-artifact convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 11:04:25 -04:00
Robert Allan JamesandClaude Sonnet 5 5567d03c12 FABRIC-3.md §I.4: magic-number content-type detection, closing Milestone 6
Closes both remaining Milestone 6 (PKI) punch-list items.

Signature-status column: doc-only closure -- the underlying need was
already redirected to capsules/BLOCK_MAP.md's real Signed column
(2026-08-26); checking the box off as moot-as-worded rather than
leaving an accurate-but-permanently-unchecked marker.

Magic-number content-type detection (Section U item 14): built in
tools/mkcapsule.c. detect_content_type() classifies a file's actual
leading bytes (TTF/OpenType sfnt tags, DER's 0x30 SEQUENCE tag, or a
printable-ASCII/TAB/CR/LF heuristic for text) against
expected_type_from_ext()'s .4th/.md/.der/.ttf mapping; process_file()
warns on mismatch, never refuses -- same WARN-first rollout this
project already used for capsule signing. Verified against every real
capsule in the repo (38 files) with zero false positives. This is the
shared primitive Milestone 7's contrib-capsule validation can reuse
next.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground); logs and DoE CSVs from this session's verification runs
included per this repo's own audit-artifact convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 10:45:57 -04:00
Robert Allan JamesandClaude Sonnet 5 4018fe8b04 FABRIC-3.md §I.2: FIRSTTOUCH + migration state machine (blk_meta_relocate_devblock)
Closes the block-subsystem punch-list item -- built exactly to §F.11's
already-decided algorithm after re-verifying it against current
blk_meta_t (a 2026-09-03 re-scoping note had wrongly claimed the chain
fields no longer existed; they do, untouched by BMAPFMT).

blk_firsttouch_claim(): one linear scan of Artemis's own device
(new blk_get_first_disk_range(), correctly bounding the scan instead of
the global multi-device LBN space), scattered-chain claim via
prev_block/next_block/chain_length, owner_fp stamped on every member
devblock, fails outright with no partial claim.

blk_meta_relocate_devblock(): the real migration primitive -- bridges
the existing FORTH-block-granularity blk_subsys_relocate_block() up to
devblock granularity (BLK_PACK_RATIO=3, corrected mid-design), running
it 3x and transferring blk_meta_t ownership fields. The "migration
state machine" turned out to be just the 2 states BLK_FLAG_MIGRATING
already reserved; the real design work was the trigger. Two were
scoped in conversation (overflow onto Artemis; heat-based wear
leveling); heat/wear-leveling is built and wired into sk_repl_idle()
via blk_meta_t.write_count. Overflow is deliberately left open,
precisely scoped (needs a slot-lookup-by-device-pointer call site
threaded from WIREBIND) rather than guessed at.

Also flagged, not fixed: BMAPFMT's owner_fp/CLAIMED and the pre-existing
BAM allocator are two parallel, unreconciled accounting systems --
FIRSTTOUCH/relocate only touch the former.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground); logs and DoE CSVs from this session's verification runs
included per this repo's own audit-artifact convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 10:33:47 -04:00
Robert Allan JamesandClaude Sonnet 5 1d468a65b1 FABRIC-3.md §I.1: (user) console prompt segment, closing the 4.4s->4.3->1.11 chain
Extends the REPL prompt to "[VM name] (user) ok>" (e.g. "[Hera]
(zuse) ok>") per the locked FABRIC.md §4.4s spec, unblocked by this
session's own §I.3/§I.8 identity-tracking work. Adds
capsule_wirebind_attached_username() alongside the existing tracked
VMUuid, and a new sk_print_prompt() helper (repl.c) that all three
prompt call sites now go through -- checks Zuse first, then a WIREBIND
user, prints nothing when neither is attached.

Closes 4.4s, 4.3 (console umbrella), and formally settles 1.11
(dirty-event granularity) as region-based per FABRIC-2.md's own "no
independent path" ruling -- a decision closure only, not an
implementation, so §17.4 (framebuffer heat/decay physics) stays open,
re-scoped precisely: blocked on the dirty-region-tracking mechanism
existing, not on 1.11's decision.

Documents a reported-but-unreproduced terminal defect (§I.9) as a new
punch-list item -- investigated the readline/keyboard-bridge code
paths, found nothing conclusive, needs a live repro with a serial log
before it's actionable.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground); logs and DoE CSVs from this session's verification runs
included per this repo's own audit-artifact convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 09:42:26 -04:00
Robert Allan JamesandClaude Sonnet 5 60d9c2520e FABRIC-3.md §I.3/§I.8: WIREBIND EJECT/detach + EXPIRE re-scoped as logout
Closes §I.3 (Milestone 5 remainder): WIREBIND now tracks which VM is
attached via the home-blocks USB path, and a new EJECT word plus the
existing hot-unplug signal both flush/reset-console/kill through it
(FABRIC-3.md §F.10).

Closes §I.8 (EXPIRE/ACL), re-scoped: the original "admit the zuse
session as a Stadium patron and reap on TTL" plan was invalidated a
second time -- Zuse authenticates directly onto Hera, who is patron
zero and permanently pinned, so there is no patron for a reap sweep to
ever find. Built instead as a detach-triggered logout
(capsule_zuse_boot_logout()), the same trigger EJECT/hot-unplug use for
regular WIREBIND users, so neither identity is a special case. Required
a companion fix: install_and_activate() used to skip re-running
ACL-ZUSE-BOOT whenever the cert was already installed, which made a
logout permanent for the rest of the boot; the outer re-attach gate now
checks zuse_session (clears on logout) instead of zuse_cert_installed
(a deliberate permanent one-way ratchet, left untouched).

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground) after both steps; logs and DoE CSVs from this session's
verification runs included per this repo's own audit-artifact
convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
2026-09-04 09:21:01 -04:00
Robert Allan JamesandClaude Sonnet 5 34203613bb FABRIC-4.md: new forward-looking design-notes scratchpad
Not a successor to FABRIC-3.md (still the living document) -- a
separate, lower-discipline space for theory-stage ideas caught before
they have real scope. First entry: the Stadium-level "wheel" idea from
conversation with Captain Bob -- a second, Q48.16 phase-accumulator
clock fed by RWOT + the inference engine, meant to schedule when a
future sieve-stack slips in, rate starting fixed and graduating to
adaptive later, mirroring L8's own hardcoded-to-inferred history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 14:11:08 -04:00
Robert Allan JamesandClaude Sonnet 5 b16b54f5a8 FABRIC-3.md: add §I, consolidated live punch list of open items
Groups the 23 confirmed-still-open items from the 2026-09-03 stale-
checkbox audit (commit 403f53d) by subsystem instead of scattered
document chronology, each pointing back to its full original entry.
Doesn't replace §A/§B as historical record -- it's the live index;
closing an item here should also update its original location.

Two findings surfaced while writing this:
- The block-map first-touch allocation item's own described mechanism
  (blk_meta_t prev_block/next_block/chain_length) is stale -- those
  fields don't exist since §H.12's BMAPFMT rebuild; flagged for
  re-scoping against the current layout.
- EXPIRE (ACL)'s stated blocker ("Phase 8 doesn't exist yet") is now
  stale -- Phase 8 closed 2026-08-26/27 -- but the real remaining gaps
  (no zuse-session lifetime/logout, no Stadium generic ttl-reap
  mechanism) are narrower and still real, so it's flagged, not unblocked.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 13:48:33 -04:00
Robert Allan JamesandClaude Sonnet 5 403f53d056 FABRIC-3.md: retroactively check 11 stale-carried-forward items
Audited all 34 unchecked checklist lines against the actual codebase.
Checked off 11 that were already done -- most were completed in
FABRIC-2.md/FABRIC-3.md sections written after the item's own carry-
forward, never reconciled back to the original checkbox: the DoE
Stadium-substrate re-run (5.1), xHCI stall recovery (G.1), CERTVERIFY,
the whole BINDSTEP cluster (key/lock design, hotplug-to-birth wiring,
USE guard), and the Milestone 6 PKI generation/embedding/signing steps.
Each gets a RETROACTIVELY CHECKED annotation citing real file:line
evidence. One item (MANIFEST_AUTO.md signature column) investigated and
left unchecked on purpose -- the goal was met via a different file
(BLOCK_MAP.md's Signed column), not the one this item names.
The other 23 unchecked items were verified still genuinely open (several
require real hardware, not verifiable from code) and left untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 13:34:29 -04:00
Robert Allan JamesandClaude Sonnet 5 2b9fa02354 §H.12 steps 21-22: ELEVATE-REQUEST + ELEVATE-GRANT + SEND-ELEVATE-REQUEST
Phase 7 complete, closing out §H.12's punch list. MSG-DELIVER turned out
to VM-EXEC payload text directly rather than dispatching by type, so the
"handler" is ELEVATE-GRANT, a word the delivered text calls. New Hera-only
C primitives (ZUSE-ELIGIBLE?, NAME>XT, ELEVATE-PUBKEY-UNPACK) stay plain
and unconditional; capsules/zuse-eligibility.4th composes the actual
eligibility check + ACL-ALLOW!/ACL-TTL! grant in FORTH.
SEND-ELEVATE-REQUEST (common:messaging.4th) builds the payload text and
sends it via the item-20-gated CH-REQUEST.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 13:15:40 -04:00
Robert Allan JamesandClaude Sonnet 5 cb6e079a73 §H.12 step 20: CH-REQUEST initiator-only gate (MY-CH-ID)
Added VARIABLE MY-CH-ID to messaging.4th (fail-closed -1 default) and
set it per-VM in hermes/init.4th and artemis/init.4th. CH-REQUEST now
refuses if the caller-supplied 'from' doesn't match the calling VM's
own id, closing a real spoofing gap found while implementing this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 12:09:29 -04:00
Robert Allan JamesandClaude Sonnet 5 7d53344875 §H.12 step 19: ZUSE-ELIGIBILITY-ADD word, no gating (corrected mid-step)
Plain FORTH word wrapping zuse_eligibility_add() unconditionally. Two
wrong first attempts (C-level zuse_session check, then a FORTH wrapper
checking it) both corrected: zuse_session isn't a special axis needing
its own gate anywhere -- Zuse's authority is the absence of any ACL
restricting her, not a flag any word checks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 11:38:07 -04:00
Robert Allan JamesandClaude Sonnet 5 f4615cf605 §H.12 step 18: zuse_eligibility.c -- read/add/membership-check
is_member() (fail-closed) and add() (idempotent, chains new devblocks
onto the tail as needed) over the item-17 eligibility-list devblock
chain, mirroring capsule_zuse_boot.c's magic/version/CRC-64 validation
convention. No callers yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 11:24:24 -04:00
Robert Allan JamesandClaude Sonnet 5 21ad5f7373 §H.12 step 17: zuse_eligibility_list.h -- eligibility-list record format
Growable owner_pubkey[32]-list devblock type for the metadata fence,
one slot over from zuse_genesis_marker_t (§H.5 Phase 6). Type only,
no read/add/check logic yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QgooKd5hJNtTYqB6CyK5f9
2026-09-03 11:12:37 -04:00
Robert Allan JamesandClaude Opus 5 46d89dd5be §H.12 step 16: block-acl.4th policy capsule -- Phase 5 (BMAPFMT) complete
capsules/block-acl.4th (blocks 4019-4020, next free range per
BLOCK_MAP.md): BLK-ACL-CHECK (block# -- allow?), a real fast-deny check
mirroring vm.c:611-624's pattern for blocks instead of words. First
touch lazily claims the block (allow=1, TTL=256, same base as ACL.4th's
own), matching the word card's default-permissive baseline. Not a stub --
genuinely does something on every call.

Loaded via a new EXEC line in init.4th right after ACL.4th's own;
confirmed ACL.4th's own activation is unaffected. Passed mkcapsule
--lint. Live-tested via QMP keystrokes: 1 BLK-ACL-CHECK executed cleanly.

Phase 5 (BMAPFMT) is now fully complete -- field layout, flags bits, C
accessors, FORTH wrappers, and a real policy word.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 07:44:28 -04:00
Robert Allan JamesandClaude Opus 5 405c713c4a §H.12 step 15: FORTH wrappers for BMAPFMT block-ACL fields
BLK-ACL-ALLOW@/!, BLK-ACL-TTL@/!, BLK-OWNER@ registered in block_words.c.
BLK-OWNER@ packs the 8-byte owner fingerprint into one cell (cell_t is
int64_t). No BLK-OWNER! -- ownership stays a controlled C-only operation.

Live-tested via QMP keystrokes on a running instance: 1 BLK-ACL-ALLOW@
executed cleanly against a real block. Verified 3-arch boot to ok>
(amd64/aarch64/riscv64) plus a hosted sanity build (shared source).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 07:36:57 -04:00
Robert Allan JamesandClaude Opus 5 15e6836ca3 §H.12 step 14: C accessors for BMAPFMT block-ACL fields
blk_owner_fp_get/_set, blk_acl_allow_get/_set, blk_acl_ttl_get/_set,
blk_flags_get/_set -- thin read-modify-write wrappers over the existing
blk_get_meta()/blk_set_meta() (caching/dirty-tracking already owned
there). Sets up the C-primitive layer FORTH wrappers (step 15) will call,
mirroring the word-level ACL system's own split.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 07:29:01 -04:00
Robert Allan JamesandClaude Opus 5 c19cc07ee3 §H.12 step 13: blk_meta_t flags bit constants
BLK_FLAG_CLAIMED/BLK_FLAG_MIGRATING/BLK_FLAG_STALE (bits 0/1/2), matching
the decided §F.4/§H.6 layout. Orthogonal bits, not a mutually-exclusive
enum.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 07:23:27 -04:00
Robert Allan JamesandClaude Opus 5 edd7effb5a §H.12 step 12: BMAPFMT field layout in blk_meta_t
Replaced the old 40-byte owner_id/permissions/acl_block/signature[2]
with owner_fp[8]/acl_allow/acl_ttl (u32)/acl_reserved[3]/reserved_future,
matching the decided §F.4/§H.6 layout.

Found a pre-existing bug via a real offsetof/sizeof compile check
(not hand math, per this step's own instruction): sizeof(blk_meta_t)
was already 344, not the 341 its own BLK_META_PER_BLOCK constant and
"341-byte slice" comment claimed -- harmless since that constant has
zero callers anywhere. New size after this edit's own alignment
padding is 336. Added a _Static_assert matching blk_volume_meta_t's
existing precedent, and fixed the stale comment to point at it.
BLK_META_PER_BLOCK itself untouched -- unused, out of scope.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 07:18:41 -04:00
Robert Allan JamesandClaude Opus 5 a268abe925 §H.12 steps 10-11: creator-ceiling enforcement, birth-time ACL snapshot
dictionary_snapshot_acl_from_parent(child, parent): walks the child's
dictionary, copies acl_allow/acl_mode/acl_pinned/acl_ttl from the
parent's matching word (by name, via vm_find_word() -- FIND's own
lookup, not modified) onto the child's entry. One-time snapshot at
birth, no live sync, matching H.3's decided rationale (a program
developed against one ACL set must not have it silently changed by
later parent changes).

Called once, after dict_hash/parity logging rather than before -- the
snapshot depends on the parent's current ACL state, which can vary
run-to-run once Zuse elevations exist, so applying it earlier would
break the "same capsule twice produces the same dict hash" determinism
invariant.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:44:58 -04:00
Robert Allan JamesandClaude Opus 5 ed86a759e1 §H.12 steps 7-9: thread real parent VMUuid through the birth call chain
Session.parent now comes from the actual birthing VM's own
stadium_vm_id, not a hardcoded vm_uuid_hera(). Added a VMUuid parent
parameter to capsule_birth_baby() and, one level up, to
capsule_console_birth()/capsule_runcap_birth() (neither had a VM* in
their own signature, but every caller did). Updated all 6 real call
sites: BIRTH, CAPSULE-BIRTH, CONNECT-ARTEMIS, CONNECT-HERMES,
RUNCAP-TEST, PAIR-TEST (mama_forth_words.c) and the console+user birth
pair in capsule_wirebind_try_attach() (capsule_wirebind.c). Two
functions had their vm parameter marked __attribute__((unused)), now
genuinely used -- attribute removed.

Steps 8 (Session.name from capsule name) and 9 (identity defaults to
installed=0) were already satisfied by step 5's existing
session_register() call and its identity-zeroing -- confirmed by
inspection, no further code needed.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:38:32 -04:00
Robert Allan JamesandClaude Opus 5 09998af999 §H.12 steps 5-6: pin Hera/Hermes/Artemis in generic capsule-birth admission
capsule_birth.c's generic admission block now registers a session for
every born VM (session_register) and pins it (session_set_pinned) when
the birthing capsule is Hera/Hermes/Artemis.

Bug found and fixed via a temporary probe (written, run, captured,
reverted): the fleet-foundation name check first used an exact-match
comparison against "Hermes"/"Artemis", but capsule_name is actually
"hermes:init.4th"/"artemis:init.4th" (the real namespace:filename
convention) -- the check silently never matched, both would-be-pinned
VMs stayed unpinned. Fixed with a new vm_name_prefix_eq_nocase() helper
matching everything before a literal ':'. Probe confirmed pinned=0 before
the fix, pinned=1 after, on all relevant VMs.

Session.parent is hardcoded to vm_uuid_hera() for now (every birth
through this path is Hera-initiated today); step 7 generalizes this to
the actual birthing VM's own id.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64) on the final,
probe-free code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:26:50 -04:00
Robert Allan JamesandClaude Opus 5 67793ea4a1 §H.12 step 4: Hera registers as session zero; punch list to checkboxes
Rewired stadium_birth_hera() to admit unpinned then register through
session_register()/session_set_pinned() instead of setting
STADIUM_FLAG_PIN directly on the candidate header. Self-referential
parent (vm_uuid_hera(), vm_uuid_hera()), matching capsule_run.h's
parent_vm_id == vm_id root convention. Soft-fail, non-fatal, if
session_register() fails -- Hera's actual Stadium admission is what the
patron-zero invariant is about. Wired session_boot_init() into
kernel_main.c right after stadium_boot_init(), before stadium_birth_hera().

Also converted §H.12's punch list from bold "DONE" markers to this
document's established - [ ]/- [x] checkbox convention (already used
throughout §A), for consistency.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64), no soft-fail message
on any arch, Hermes/Artemis births unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:15:53 -04:00
Robert Allan JamesandClaude Opus 5 a621131ef6 §H.12 step 3: session_set_pinned/session_is_pinned pin-authority choke point
session_is_pinned() reads Session.pinned directly (authoritative, no
Stadium re-derivation); session_set_pinned() writes both Session.pinned
and the mirrored STADIUM_FLAG_PIN bit on the session's own patron cell,
keeping Stadium's internal eviction/admission logic (which must stay
self-contained) in sync without it calling back into session.c.

Added Session.stadium_cell (index into stadium_cells()) -- necessary
plumbing not in the original H.2 field list; the choke point can't reach
the right patron header without it. Moved STADIUM_FLAG_PIN from a
stadium.c-private #define to stadium.h (public) so session.c can
reference it without a duplicate definition.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:10:11 -04:00
Robert Allan JamesandClaude Opus 5 6d9fe3f515 §H.12 step 2: session-slot table, session_find/session_register
src/starkernel/vm/session.c: kmalloc'd-at-boot slot table sized from
stadium_max_vm_count() (mirrors stadium.c's own StadiumVMQuota, not a
fixed compile-time array as originally planned -- that table was already
moved off a fixed array for the same "population isn't knowable in
advance" reason). session_boot_init()/session_find()/session_register()
implemented for real, no stubs; session_register() zeroes identity and
leaves pinned=0, matching VMIdentity's own documented default and
deferring pin policy to callers. Added session.c to Makefile.starkernel's
explicit source lists. No callers yet.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:03:14 -04:00
Robert Allan JamesandClaude Opus 5 668e36bb17 §H.12 step 1: add Session struct (type only)
include/starkernel/session.h: vm_id (VMUuid), pinned (int, authoritative
over Stadium's STADIUM_FLAG_PIN per H.10), parent (VMUuid), name (fixed
64-byte buffer), identity (embedded VMIdentity, reusing the existing
type rather than inventing a new one). No logic yet, no callers -- next
step wires the session-slot array and register/find functions.

Verified 3-arch boot to ok> (amd64/aarch64/riscv64).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 05:57:01 -04:00
Robert Allan JamesandClaude Opus 5 4cd18734ee FABRIC-3.md §H.12: 22-item implementation punch list
One coding task per item across 7 phases, each gated by the mandatory
3-arch QEMU boot acceptance test. Two corrections found while grounding
this against live code: capsule_birth.c's generic admission path already
admits every VM as a Stadium patron (just hardcoded unpinned), so no new
stadium_birth_hermes()/_artemis() functions are needed -- the real task
is making that path pin Hera/Hermes/Artemis specifically. VMIdentity
(vm_identity.h) already exists fully built; Session.identity reuses it
directly rather than inventing a new type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 05:50:00 -04:00
Robert Allan JamesandClaude Opus 5 89d814f9f3 FABRIC-3.md §H: close all three remaining design gaps
Gap #1: closed set of four cards (VM/word/block/message), no new cards
for now. Gap #2: creator-ceiling enforcement is a birth-time snapshot
copy, not a live ACL-RECHECK-time check -- reversed mid-conversation once
the live-check approach's cross-VM dictionary-lookup problem surfaced;
final rationale is child program stability (a program developed against
one ACL set must not have it silently changed by later parent changes).
Gap #3: Zuse's eligibility list persists in the existing growable
metadata-fence mechanism as a simple owner_pubkey[32] list, no extra
per-entry metadata.

Every design-level question in this refactor is now closed. What remains
is pure implementation (5 items) and two intentional deferrals.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 05:43:22 -04:00
Robert Allan JamesandClaude Opus 5 d86b6de9cd FABRIC-3.md §H.11: refreshed gap analysis, end of session
Full sweep across the whole session-refactor design pass -- 7 of the
original 10 §H.9 gaps are now closed. Compiles the current accurate
picture: one genuinely open design question (more cards beyond the four
named?), two small undecided pieces (creator-ceiling enforcement location,
Zuse eligibility-list storage), five pure implementation gaps (design
fully decided, nothing coded), and two explicitly-deferred non-goals
(VM card multi-owner, elevation trigger alternates). Also updates H.10's
stale "elevation trigger not yet usable" note now that H.7 confirmed the
messaging substrate is already real.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 19:04:48 -04:00
Robert Allan JamesandClaude Opus 5 91dfb0a079 FABRIC-3.md §H: close gap #8 -- EXPIRE/D.2 relationship reconciled
No actual conflict between D.2 and H.1. D.2 (2026-08-27, "session ending =
VM detach, reuse COOL") was scoped to user sessions, written before
Hera/Hermes/Artemis were framed as having their own persistent sessions.
D.2 is a special case of H.1's broader pinned/non-pinned model, fully
subsumed: it describes exactly how the non-pinned branch behaves. Pinned
sessions have no D.2-style "ending" at all -- permanent by construction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 19:00:32 -04:00
Robert Allan JamesandClaude Opus 5 26b91f1ca4 FABRIC-3.md §H: close gap #7 -- private-topic traffic stays ungated
Checked MSG-SEND directly -- no ACL check anywhere in it today, on common
or a private topic alike. Confirmed: private-topic traffic stays ungated;
trust is established once at the handshake (CH-REQUEST/CH-ACCEPT/
CH-CONFIRM) and never re-checked per-message afterward. The message
card's scope is now final: it gates the single CH-REQUEST call, nothing
else in the messaging path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:57:06 -04:00
Robert Allan JamesandClaude Opus 5 b15339ca1f FABRIC-3.md §H: close gap #6 -- CH is the topic, and H.7/H.8 are real code
Checked capsules/common/messaging.4th directly instead of assuming: the
H.7 messaging protocol isn't design vision, it's already substantially
built -- COMMON-CH, CH-REQUEST, CH-ACCEPT, CH-CONFIRM, CH-CLOSE, and
local ACK/NACK (MSG-ACK-LAST/MSG-NACK-LAST/MSG-NACKED) all exist and work
today. CH already is the topic, 1:1, no new representation needed.
Upgrades H.7/H.8's framing from "protocol groundwork, not yet real" to
"the mechanism exists, the ACL gate on top of it is the remaining work" --
the message card is now a concrete wiring task, not a hypothetical one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:55:09 -04:00
Robert Allan JamesandClaude Opus 5 33286cb3a2 FABRIC-3.md §H: close gap #3 -- word card IS the existing ACL system
Checked capsules/ACL.4th directly: both existing modes (STRICT, TTL)
already default to allow=1, matching the word card's default-permissive
baseline. Since each VM has its own dictionary, existing per-word ACL
state is already scoped per-session for free. Confirmed: the word card is
the existing acl_ttl/acl_allow/acl_mode/acl_pinned system reused as-is,
not a new parallel structure. Surfaces one new follow-on gap: creator-
ceiling enforcement at VM birth time isn't designed anywhere yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:52:32 -04:00
Robert Allan JamesandClaude Opus 5 fdecb91908 FABRIC-3.md §H: close gap #2 -- parent/name session fields confirmed
Both fields (parent VMUuid, name) confirmed as-is with no adjustment. All
five session fields (vm_id, pinned, parent, name, identity) are now
confirmed, none still model-proposed-only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:50:23 -04:00
Robert Allan JamesandClaude Opus 5 de513483e3 FABRIC-3.md §H: close gap #1 -- non-pinned session mapping
Confirmed: an ephemeral user VM's session lands as a non-pinned,
COOL-subject Stadium patron -- synthesized from D.2's earlier finding
(session ending = VM detach, reuse COOL) rather than a fresh decision.
Thumbdrive detach is the explicit trigger. No exception case for a
temporarily-pinned user VM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:48:25 -04:00
Robert Allan JamesandClaude Opus 5 197ff03963 FABRIC-3.md: BMAPFMT gets FORTH wrappers, design fully closed
Decided: yes, FORTH wrappers for the block-card ACL primitives, mirroring
the word-level ACL split (raw C accessors, policy composed in FORTH).
zuse_cert_seed's C-only precedent doesn't apply -- that's key material,
block ACL fields are ordinary ACL state like DictEntry's. BMAPFMT's
field/API design (owner_fp, acl_allow, acl_ttl, flags bits, FORTH
wrappers) is now fully decided across this and the prior three passes --
only the actual code edit remains.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:36:52 -04:00
Robert Allan JamesandClaude Opus 5 ce1618dcd8 FABRIC-3.md: BMAPFMT flags bit values decided -- CLAIMED/MIGRATING/STALE
blk_meta_t's existing unused flags field (uint64_t) uses orthogonal bits,
not a mutually-exclusive enum: bit 0 = CLAIMED, bit 1 = MIGRATING (serves
MIGSM), bit 2 = STALE (serves UNCLEAN), 61 bits reserved. BMAPFMT's field
design (owner_fp, acl_allow, acl_ttl, and now these flags bits) is fully
decided; only the actual code edit to block_subsystem.h/.c remains.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:29:05 -04:00
Robert Allan JamesandClaude Opus 5 a05e6d60ba FABRIC-3.md: BMAPFMT gets a TTL -- blocks support temporary elevation too
Resolves part of section F.4's deferred item #1 (allow-list/grant shape
beyond the single fast-deny bit): blk_meta_t's acl_reserved[7] becomes a
4-byte acl_ttl (mirroring DictEntry's countdown shape) plus 3 bytes still-
open slack, reusing the same ACL-TTL/Zuse-eligibility-list mechanism as
the word card. Kept lean -- no acl_mode/acl_pinned mirror, since a block
isn't pinned/strict the way a word is. Updated both F.4 (the field design)
and H.6 (the block card) to match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:26:27 -04:00
Robert Allan JamesandClaude Opus 5 316de60671 FABRIC-3.md §H.10: close pin-authority choke point -- session owns both directions
Decided: session_set_pinned()/session_is_pinned() (or equivalent) are the
sole read AND write path for pin state -- nothing, including existing
Stadium code, touches STADIUM_FLAG_PIN on the patron header directly
anymore. Not just a write-side guard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:22:43 -04:00
Robert Allan JamesandClaude Opus 5 a93d4fa2cd FABRIC-3.md §H.10: verify dictionaries are per-VM, not shared
Checked the load-bearing assumption underneath the word card's
creator-ceiling invariant and the H.5 elevation trigger, both of which
live on DictEntry ACL fields -- confirmed each VM gets its own separate
memory/dictionary buffer at birth (vm_bootstrap.c:181), so DictEntry ACL
state is already naturally scoped per-session. No conflict, no redesign.
Also notes two smaller, lower-risk open items: pin-authority sync between
Session and Stadium's flag, and the elevation trigger's dependency on
not-yet-real Hermes messaging.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:20:13 -04:00
Robert Allan JamesandClaude Opus 5 ba97623349 FABRIC-3.md §H: close gap #4 -- temporary Zuse elevation trigger decided
Trigger: live message-based request (ELEVATE-REQUEST on common or a
private topic, Zuse's session grants/NACKs, ACL-ALLOW!/ACL-TTL! write on
receipt), gated by a Zuse-held eligibility list keyed by owner_pubkey.
Grounded against capsules/ACL.4th directly -- ACL-TTL is a recheck-cadence
cache, not a grant mechanism; reuse means calling its ACL-ALLOW!/ACL-TTL!
primitives from new Zuse-triggered code, not new C primitives. Live-console
sudo-style grant and pre-signed capability tickets remain deferred, not
rejected, alternates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:15:44 -04:00
Robert Allan JamesandClaude Opus 5 1349e783aa FABRIC-3.md §H: session refactor capture -- struct shape + identity/ACL cards
Design capture from today's session-refactor discussion, back to Hera:
session-as-Stadium-patron struct shape (references the patron by VMUuid,
pin-authoritative, identity embedded), and the identity ACL "stack of
cards" model with all four named dimensions scoped so far (VM, word,
block, message) plus the PubSub/topics messaging-protocol groundwork the
message card depends on. Closes with a numbered gap-analysis list (§H.9)
of everything still explicitly open.

Capture-only, matching this document's own established discipline -- no
struct written, no code changed. Mirrors §D's Tripod-vision capture in
style and structure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:08:35 -04:00
Robert Allan JamesandClaude Opus 5 f81e9c92bc Fix framebuffer console: scroll drift causes progressive line overlap in TTF mode
fb_scroll_rows() hardcoded the pixel distance it physically shifts the
framebuffer by as char_rows * 16 * scale -- the bitmap-font (font_8x16.c)
cell height -- regardless of which glyph mode vt100.c actually had active.
In TTF mode (the REPL's default, cell height 24px via VT100_TTF_CELL_H_PX)
this meant every scroll_up(1) call physically shifted the framebuffer by
only 16px while the text model (g_vt.rows, py_of()) placed each row 24px
apart. That 8px-per-scroll shortfall compounds with every subsequent
scroll: a few scrolls barely show it, but enough scrolls -- or scrolling
quickly, which is just many scrolls in a short span -- accumulates into
visible pixel overlap between rows, with newer lines drawn on top of the
tail end of older ones.

fb_scroll_rect() (the box-confined scroll added later for 4.4t) already
carried a doc comment calling this out explicitly, describing its own
explicit pixel_rows parameter as the fix for fb_scroll_rows()'s "fixed
16px-row assumption" -- fb_scroll_rows() itself was just never updated to
match.

Fixed by changing fb_scroll_rows()'s parameter from an implicit char_rows
count to an explicit pixel_rows count (matching fb_scroll_rect()'s
existing convention), and having its one caller (vt100.c's scroll_up())
pass lines * cell_h() -- the real active cell height -- instead of a raw
line count for the callee to guess at.

Verified: booted amd64 to the REPL (TTF mode active per sk_repl()'s own
console_fb_enable_ttf() call), let boot chatter + WORDS output scroll the
screen through thousands of accumulated scroll_up() calls, then measured
every visible line's y-position via a QMP screendump. Spacing held at a
perfectly consistent 24px (TTF cell height) top to bottom with zero drift
-- the old hardcoded-16px bug could not have produced that after this many
scrolls. Re-verified boot to ok> on all three architectures
(amd64/aarch64/riscv64) per repo acceptance policy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:25:06 -04:00
Robert Allan JamesandClaude Opus 5 c14324f498 Fix framebuffer console: idle heartbeat corrupts in-progress input line
sk_repl_idle() (called every ~1s from sk_console_readline()'s idle loop)
opens with console_ensure_line_start(), which unconditionally forces a
newline whenever the console isn't at a line boundary -- including
mid-edit, after characters have been typed and echoed but before Enter.
This fired on every elapsed SK_IDLE_BEAT_INTERVAL regardless of whether
sk_repl_idle() had anything to print, visually snapping the in-progress
input line to a fresh empty line -- indistinguishable from Enter having
been pressed. Most noticeable on the space key since it's the most common
key hit during a pause.

Gate the idle beat on n == 0 (no in-progress edit), mirroring the n > 0
guard the prompt reanchor logic just below already uses. Deferring the
xhci/block-sync idle service by at most one more interval while a line
is being edited is within its own documented "coarse cadence, cheap
early-exit" tolerance.

Verified: reproduced via QMP send-key against a live amd64 QEMU boot
(multi-character line typed with pauses across several idle intervals
stayed intact after the fix, where it previously broke on each interval).
Re-verified boot to ok> on all three architectures (amd64/aarch64/riscv64)
per repo acceptance policy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:12:21 -04:00
Robert Allan James daf9021ea5 Initial commit
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
2026-09-01 12:09:20 -04:00
Robert Allan James 58c59e87e5 Initial commit
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
2026-09-01 12:07:32 -04:00
Robert Allan James d2a0305703 Record driving deadlines for #1 (provisional expiry) and #2 (December deliverable)
Clarified 2026-08-29 with the author: "no hurry" is wrong for #1 and #2.

  - #1 (Hosted StarForth): the provisional will expire before conversion. Its
    priority claim is time-boxed (provisional filed ~Dec 2025, window ~Dec
    2026); if the non-provisional isn't filed claiming benefit before the
    window lapses the priority is lost and the same subject matter can't be
    re-staked by refiling thereafter. Hard clock regardless of December scope.
  - #2 (full StarshipOS): the December deliverable that keeps the flagship
    covered; pending counsel confirmation it may also be the conversion
    vehicle for #1's provisional.

Open point to resolve: is #2 (or the December delivery) the conversion vehicle
for #1, or is #1 converted by a filing separate from #2? Decision record only;
no filing made. Authoritative form in ROADMAP.md; FABRIC-3.md tracks it.
2026-08-29 10:36:19 -04:00
Robert Allan James 31dfc5de63 Record IP framing of the three products: 3 patent applications + 3 marks (StarForth, StarshipOS/LithosAnanke, Compudynamics)
The three-product split is treated as three patent applications, each matched
to a trademark (decided 2026-08-29):

  - Patent 1 + mark StarForth                  -> hosted/interpreted runtime
  - Patent 2 + marks StarshipOS (canonical spelling; noted as "StarshopOS"
    in the decision words) + LithosAnanke       -> full standalone OS
  - Patent 3 + mark Compudynamics               -> Zynq steady-state machinery
    with sealed executions, HOL-proven, anchored by the physics-adaptive runtime

Flagged open for counsel (not assumed/filed): the repo already carries a
"Patent pending" USPTO provisional filed Dec 2025 for the Compudynamics
physics-adaptive runtime (docs/patent/). Whether patent 3 is a continuation/
refinement of that provisional, and whether the three product applications are
additive to or fold it in, must be reconciled. Records intent only; no legal
text drafted or filed. Authoritative form in ROADMAP.md; FABRIC-3.md tracks it.
2026-08-29 10:32:04 -04:00
Robert Allan James 936d046ca6 Record the FPGA three-product split: Hosted StarForth / full StarshipOS / HOL-proven sealed-execution hardware
The Zynq FPGA is not a fourth platform to port to — it is the pivot that
forces the project into three distinct products, each with its own host,
delivery, and proof character (decided 2026-08-29):

  1. Hosted StarForth - the existing hosted/interpreted StarForth runtime
     (3-arch acceptance-tested), delivered as a portable embedded runtime.
  2. A full StarshipOS - the standalone OS built on LithosAnanke
     (LithosAnanke -> StarshipOS), a self-booting OS on general silicon
     (SER5/RasPi/Milk-V line).
  3. Hardware steady-state machinery with sealed executions, HOL-proven -
     the FPGA-native product: hardware-enforced sealed executions and
     steady-state machinery machine-checked in a proof assistant (HOL);
     delivery is the bitstream + HOL proof artifacts, not just an OS port.

The coupling is the point: product 3 is born on the FPGA, and its existence
is what cleanly separates 1 from 2 from 3. Product 1 ships hosted on an OS,
product 2 as an OS on general silicon, product 3 as proven hardware. Per-
product gates and the even-major line carrying the three as separate tracks
are scoped at v2.5.0 close / during the coloring-in phase. Complements, and
does not retract, the existing hardware bare-metal release policy.

Authoritative form in ROADMAP.md; FABRIC-3.md tracks the same horizon.
2026-08-29 10:30:09 -04:00
Robert Allan James 8e94522d10 Record trajectory beyond v2.5.0: Zynq FPGA next, after a "coloring in" hardening phase
The next big milestone after the three-board bare-metal cut (v2.5.0) is
transferring the battle-tested amd64/aarch64/riscv64 story to a Zynq (AMD
Xilinx) FPGA SoC — configurable silicon with soft/hard CPU cores, PL fabric,
and a non-standard memory map, a genuinely larger step than any prior board
(expected on a new even-major line). Between v2.5.0 and the Zynq sits a
"coloring in" period: hardening that thickens the shape of what exists rather
than adding silicon (USB BOT/xHCI + block robustness, live-entropy and
Zuse-cert hardening on real ASICs, SMP/multi-core + IRQ routing from the HAL
notes, driver breadth) so the FPGA carries a production-honest shape forward.

Authoritative form in ROADMAP.md "Beyond v2.5.0"; FABRIC-3.md tracks the same
horizon in the post-release section and re-points G.6's Next at the
v2.2.0/v2.4.0/v2.5.0 cadence.
2026-08-29 10:28:22 -04:00
Robert Allan James 25276ae359 Decide board-by-board hardware rollout: v2.2.0 (SER5 amd64) / v2.4.0 (RasPi5 aarch64) / v2.5.0 (all three)
Real silicon arrives incrementally (Beelink SER5 in hand now; RasPi 5 + Milk-V
orderable around Mon 2026-08-31), so the hardware release is split per board
in hand, each an even-minor LTS point-in-time cut on the same line:

  - v2.2.0  amd64 bare metal  — Beelink SER5 (two 16GB sticks: one boots the
                                thumbdrive image, one mints a real Zuse user)
  - v2.4.0  aarch64 bare metal — Raspberry Pi 5
  - v2.5.0  all three bare     — adds Milk-V (riscv64)

Each closes only when its board's items are proven live (boot to ok>, block-
fence Zuse true, backend entropy non-deterministic), never build-only.

Records the decision in the authoritative Release Versioning Policy
(docs/lithosananke/ROADMAP.md, "Board-by-board hardware rollout, decided
2026-08-29") and re-maps G.4/G.5 in FABRIC-3.md onto the new cadence, noting
v2.0.0 was cut (tag v2.0.0).
2026-08-29 10:22:36 -04:00
Robert Allan James 28de700645 v2.0.1: G.4 amd64 RDRAND backend behind rng_get_bytes() (SER5 entropy)
First real per-arch RNG backend, added to the v2.0.0 unified entry point in
src/starkernel/rng/rng.c, #if-guarded to amd64: CPUID.01H:ECX[30] RDRAND
detection + inline-asm rdrand draws feeding rdrand_fill() (whole-byte
emission from the low end; a partial final draw is discarded -- throwing
away entropy is always safe).

Probe order honors the release policy: virtio-rng is tried first, so the
QEMU path stays on virtio-rng unchanged; RDRAND is the fallback only real
hardware (which has no virtio-rng device) reaches. QEMU-verified both ways
on amd64: with virtio-rng present -> "rng: backend = virtio-rng" (unchanged);
with virtio-rng absent and RDRAND exposed (-cpu max) -> "rng: backend =
rdrand" + "entropy: ready" + Zuse attach confirmed. rdrand_fill()'s exact
logic host-proven: fills 32-byte/16-byte buffers and yields differing draws
run-to-run (non-deterministic). aarch64/riscv64 builds unaffected (guarded
off). riscv64 Zkr and aarch64 peripheral-RNG backends remain parked for their
real boards.

FABRIC-3.md G.4 amd64 slice marked BUILT + QEMU-verified.
2026-08-29 10:18:07 -04:00
Robert Allan James 19bc90c97d v2.0.1: document G.6 generic thumbdrive image milestone in FABRIC-3.md 2026-08-29 10:12:58 -04:00
Robert Allan James bd266942ce v2.0.1: generic GPT/FAT32 UEFI bootable thumbdrive image (thumbdrive goal)
New `make -f Makefile.starkernel thumbdrive` goal builds a generic
UEFI-bootable GPT disk image (disk image -> GPT + one FAT32 "STARKERNEL"
EFI System partition with EFI/BOOT/BOOT<ARCH>.EFI + startup.nsh) that can be
written directly to a USB thumbdrive with dd and boots on any real amd64 UEFI
firmware (Beelink SER5 path) as well as under QEMU. The monolithic loader
embeds the whole kernel, so the ESP needs only the UEFI fallback boot path.

Verified under QEMU by attaching the image as a USB mass-storage device (not
cdrom): OVMF BDS auto-selected "UEFI QEMU QEMU USB HARDDRIVE" (Boot0002),
then kernel booted normally -- LithosAnanke v2.0.0, POST 1012/0/0 + ok>,
rng: backend = virtio-rng + entropy: ready, Artemis ready, and the USB BOT/
xHCI storage path enumerated (READ CAPACITY10 -> MSC device ready -> READ10
CSW PASS). This mirrors the real-hardware SER5 flow: firmware boots the USB
thumbdrive's ESP, and the OS's own storage rides the same USB BOT/xHCI path.

Works for all three arches via the arch-mapped EFI boot name.
2026-08-29 10:12:43 -04:00
Robert Allan James 2efd7fe7e7 v2.0.0: QEMU release — bump LITHOS_VERSION to 2.0.0
The §G v2.0.0 QEMU release-gate punch list is complete (G.1 xHCI stall
recovery, G.2 unified rng_get_bytes() entropy entry point, G.3 NVRAM
de-scoped). Bump the kernel version to 2.0.0 (even major = LTS, per the
Release Versioning Policy: X.0.0 = QEMU release, X.5.0 = hardware bare-metal
release). Update README and .claude/CLAUDE.md version references and the
Makefile.starkernel version-roadmap comment.

Verified: all three arches (amd64/aarch64/riscv64) build clean with v2.0.0
embedded; QEMU amd64 boot shows "LithosAnanke v2.0.0", POST 1012/0/0 + ok>,
rng: backend = virtio-rng + entropy: ready, and Zuse identity confirmed from
the attached thumbdrive.
2026-08-29 10:09:37 -04:00
230 changed files with 876700 additions and 255 deletions
+1 -1
View File
@@ -211,7 +211,7 @@ Output: `build/<arch>/kernel/starkernel_loader.efi` + `build/<arch>/kernel/stark
Two independently tracked version strings flow into the generated `include/version.h`: Two independently tracked version strings flow into the generated `include/version.h`:
`VERSION` (`Makefile.starkernel` — the embedded StarForth engine version, currently `3.1.0`; `VERSION` (`Makefile.starkernel` — the embedded StarForth engine version, currently `3.1.0`;
note this does **not** auto-sync with the standalone StarForth repo's own version) and note this does **not** auto-sync with the standalone StarForth repo's own version) and
`LITHOS_VERSION` (`Makefile.starkernel` — the kernel version, currently `1.5.4`). `LITHOS_VERSION` (`Makefile.starkernel` — the kernel version, currently `2.0.1`).
### Build configuration (Kconfig — real, wired, not vestigial) ### Build configuration (Kconfig — real, wired, not vestigial)
+1261 -74
View File
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
# FABRIC-4.md — forward-looking design notes
**Status:** Not a successor to `FABRIC-3.md` and not a punch-list document. `FABRIC-3.md` is
still the living document — nothing here supersedes it, and this file doesn't follow the
close-and-carry-forward discipline `FABRIC.md``FABRIC-2.md``FABRIC-3.md` used (that
chain triggers on *closing* a document; `FABRIC-3.md` isn't closed). This is a separate,
lower-discipline scratchpad for design ideas caught early — theory-stage, pre-punch-list,
often missing a stated "why" on purpose (captured as raised, not fully justified yet). An idea
graduates out of here into `FABRIC-3.md` §I (or wherever `FABRIC-3.md` is by then) once it has
a real scope, not before.
---
## 1. Stadium-level "wheel" — a second clock alongside the heartbeat (2026-09-03)
Raised in conversation with Captain Bob, theory stage — no code, no scope, deliberately not
punch-listed yet.
**The mechanism.** A second clock, independent of but derived from the true heartbeat
(`HeartbeatState`, Loop #7), advanced by a fixed-point (Q48.16, this project's standard)
phase accumulator: each master heartbeat tick adds a `rate` scalar to the wheel's own
`phase`; whenever `phase` crosses `1.0` the wheel fires (advances its own state) and the
crossing remainder carries forward. This is a continuous scalar, not an integer tick-divisor
`rate` can sit anywhere, including above `1.0`. A wheel with `rate > 1` fires more than
once per master tick (multiple threshold-crossings per tick, remainder still carried); one
with `rate < 1` accumulates across several master ticks before firing once. Nothing about the
mechanism privileges either side of `1.0` — "runs ahead of baseline" and "runs stretched
behind baseline" are the same math with a different scalar.
**What feeds it.** Not a new signal source — this wheel listens to two already-real, already-
built mechanisms: `rolling_window_of_truth.c` (Loop #2's circular-buffer execution history —
`rolling_window_measure_diversity()`, `rolling_window_find_hottest_word()`,
`rolling_window_count_transition()`, `rolling_window_pattern_capture_rate()`,
`rolling_window_is_warm()`) and `inference_engine.c` (Loops #5/#6`InferenceOutputs`:
decay-slope, variance-inflection point, fit quality). Both exist today at the **per-VM**
level (each patron/word-owning VM has its own rolling window and runs its own inference
pass) — the wheel itself is meant to live at the **Stadium** level, one layer up. This is a
genuinely new axis: nothing today aggregates RWOT/inference-engine output across the whole
Stadium floor into one fleet-wide signal. **Open, not decided:** what the aggregation actually
is (sum across patrons? mean? the hottest patron's own values only? something else) — flagged
in conversation, not resolved.
**What it's for.** Not a sieve itself. The wheel is a *scheduler/gate*: it decides *when* to
slip an appropriate sieve into a stack of sieves that doesn't exist yet (see §2 below) —
running its own clock, potentially ahead of the true heartbeat, is what buys it lead time to
notice a transition worth reacting to before the baseline heartbeat would get there on its
own. It is not itself the thing doing the sieving.
**Build sequencing, decided in conversation.** `rate` starts as a fixed build parameter (same
shape as `ACL-BASE-TTL`/`Q.SLOT` — a plain constant or Kconfig symbol, not adaptive from day
one). Reasoning, Captain Bob's own: a fixed rate is the only version that can go through this
project's existing DoE apparatus and produce a clean, attributable measurement (rate held
constant, everything else varies) — if the rate self-tunes from day one there's no fixed
baseline to compare "does the wheel actually help" against. Only *after* a real, measured
baseline exists does `rate` itself graduate to adaptive/self-tuning — reusing the same
inference-engine machinery the wheel already listens to, not new plumbing. This mirrors the
L8 Jacquard selector's own real history: hardcoded compudynamics constant first, later
replaced by the VM Fleet Attractor's dynamically-inferred rate
(`docs/working/architecture/VM-FLEET-ATTRACTOR-DESIGN-20260705.md`). Same graduation, one
level up the stack.
**Explicitly not decided yet, per Captain Bob ("we'll talk about why later"):**
- The actual *purpose* — why this wheel, what real problem it solves. Deferred on purpose.
- The sieve stack itself — what a "sieve" is concretely, what gets sieved, how many. A larger,
separate vision (128256 wheels, each fed by an "appropriate" — possibly learned/neural,
vocabulary not yet resolved against anything this codebase currently has — source, forming
a coincidence-pattern sieve) was raised earlier in the same conversation as a *distinct*,
further-out idea; this single-wheel scheduler is deliberately scoped smaller and doesn't
presuppose that larger picture is right.
- Whether "trivial to add a wheel" (an earlier framing) still matters once there's only one —
a generic `{rate, phase, state}` table is a premature abstraction for a single instance;
build the one wheel concretely first, generalize only if/when a second one is actually
needed (this project's own standing convention — three similar lines beat a premature
abstraction).
+95 -6
View File
@@ -71,12 +71,16 @@ MAKEFLAGS += -j$(NPROC)
endif endif
# Version # Version
# Roadmap: # Roadmap (per docs/lithosananke/ROADMAP.md "Release Versioning Policy" and
# FABRIC-3.md §G — X.0.0 = QEMU release, X.5.0 = hardware bare-metal release):
# v1.0.x — serial-only production (released) # v1.0.x — serial-only production (released)
# v1.5.x — framebuffer VT100 terminal/console milestone (current) # v1.5.x — framebuffer VT100 terminal/console milestone (released)
# v2.0.0 — StarForth SDK release; v2.x.x development begins from there # v2.0.0 — QEMU release (even major = LTS): three-arch QEMU story complete
# v2.0.1 — SER5 hardware-track line: RDRAND backend + generic thumbdrive image goal
# v2.2.0 — amd64 bare-metal (Beelink SER5) — see ROADMAP "Board-by-board rollout"
# v2.5.0 — hardware bare-metal release: real per-arch RNG + real-board boot
VERSION ?= 3.1.0 VERSION ?= 3.1.0
LITHOS_VERSION ?= 1.5.4 LITHOS_VERSION ?= 2.0.1
# ============================================================================== # ==============================================================================
# BUILD PATHS # BUILD PATHS
@@ -524,7 +528,8 @@ LOADER_EXTRA_SRCS := \
$(KERNEL_SRC)/vm/q48_stubs.c \ $(KERNEL_SRC)/vm/q48_stubs.c \
$(KERNEL_SRC)/vm/stadium.c \ $(KERNEL_SRC)/vm/stadium.c \
$(KERNEL_SRC)/vm/stadium_words.c \ $(KERNEL_SRC)/vm/stadium_words.c \
$(KERNEL_SRC)/vm/stadium_blocks.c $(KERNEL_SRC)/vm/stadium_blocks.c \
$(KERNEL_SRC)/vm/session.c
KERNEL_EXTRA_SRCS := $(LOADER_EXTRA_SRCS) KERNEL_EXTRA_SRCS := $(LOADER_EXTRA_SRCS)
@@ -554,6 +559,7 @@ KERNEL_OBJS := \
.PHONY: all clean clean-kernel kernel kernel-all .PHONY: all clean clean-kernel kernel kernel-all
.PHONY: qemu qemu-esp qemu-gdb .PHONY: qemu qemu-esp qemu-gdb
.PHONY: thumbdrive iso-usb
.PHONY: info help .PHONY: info help
# ============================================================================== # ==============================================================================
@@ -1000,7 +1006,88 @@ else ifeq ($(ARCH),riscv64)
echo "=== Extracting DOE CSV ==="; \ echo "=== Extracting DOE CSV ==="; \
bash scripts/extract_doe.sh $$LOG $$CSV || true; \ bash scripts/extract_doe.sh $$LOG $$CSV || true; \
cp $$CSV $(DOE_LATEST_DIR)/riscv64.csv 2>/dev/null || true cp $$CSV $(DOE_LATEST_DIR)/riscv64.csv 2>/dev/null || true
endif endif
# thumbdrive — build a generic UEFI-bootable GPT/FAT32 disk image that can be
# written directly to a USB thumbdrive (dd) and boots on real amd64 UEFI
# hardware (e.g. Beelink SER5) as well as under QEMU. This is the "generic
# thumbdrive bootable OS" image for the v2.5.0/SER5 bare-metal path: the
# monolithic loader embeds the whole kernel, so the ESP needs only the UEFI
# fallback boot path EFI/BOOT/BOOT<ARCH>.EFI. Storage on real hardware is the
# USB BOT/xHCI path (already live), not virtio.
thumbdrive: all
@mkdir -p $(BUILD_DIR)
@if ! which sgdisk >/dev/null 2>&1; then echo "Error: sgdisk not found. Install gdisk (apt-get install gdisk)."; exit 1; fi
@if ! which mkfs.fat >/dev/null 2>&1; then echo "Error: mkfs.fat not found. Install dosfstools (apt-get install dosfstools)."; exit 1; fi
@case "$(ARCH)" in \
amd64) BOOTNAME="BOOTX64.EFI" ;; \
aarch64) BOOTNAME="BOOTAA64.EFI" ;; \
riscv64) BOOTNAME="BOOTRISCV64.EFI" ;; \
*) echo "Error: no thumbdrive EFI boot name for ARCH=$(ARCH)"; exit 1 ;; \
esac; \
# Geometry: 128 MiB disk (262144 sectors), GPT partition 1 spans sectors \
# 2048..262110 (the GPT last-usable sector for this disk size), i.e. \
# 260063 sectors. The FAT32 ESP image MUST match the partition size \
# exactly; a larger ESP overruns the disk (GPT grows corrupt) or \
# spills past the partition end, both of which made earlier builds \
# unbootable on hardware. \
DISK=$(BUILD_DIR)/starkernel-thumbdrive.img; \
ESP_SECTORS=260063; \
rm -f $$DISK $(BUILD_DIR)/thumbdrive-esp.img; \
dd if=/dev/zero of=$(BUILD_DIR)/thumbdrive-esp.img bs=512 count=$$ESP_SECTORS 2>/dev/null; \
mkfs.fat -F 32 -n "STARKERNEL" $(BUILD_DIR)/thumbdrive-esp.img >/dev/null 2>&1; \
mmd -i $(BUILD_DIR)/thumbdrive-esp.img ::/EFI; \
mmd -i $(BUILD_DIR)/thumbdrive-esp.img ::/EFI/BOOT; \
mcopy -i $(BUILD_DIR)/thumbdrive-esp.img $(LOADER_EFI) ::/EFI/BOOT/$$BOOTNAME; \
printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$$BOOTNAME" > $(BUILD_DIR)/thumbdrive-startup.nsh; \
mcopy -i $(BUILD_DIR)/thumbdrive-esp.img $(BUILD_DIR)/thumbdrive-startup.nsh ::/startup.nsh; \
dd if=/dev/zero of=$$DISK bs=1M count=128 2>/dev/null; \
sgdisk -n 1:2048:0 -t 1:ef00 -c 1:"EFI System" $$DISK >/dev/null 2>&1; \
dd if=$(BUILD_DIR)/thumbdrive-esp.img of=$$DISK bs=512 seek=2048 conv=notrunc 2>/dev/null; \
rm -f $(BUILD_DIR)/thumbdrive-esp.img $(BUILD_DIR)/thumbdrive-startup.nsh; \
echo "Thumbdrive image: $$DISK"; \
echo "Write to a USB stick with: dd if=$$DISK of=/dev/sdX bs=4M status=progress"
# iso-usb — build a PURE UEFI isohybrid ISO for the Iso Image Writer workflow
# (GNOME Disks "Restore Disk Image...", or dd). Writes a single .iso to a USB
# stick as a raw image; the ISO carries a clean GPT with an EFI System
# Partition holding EFI/BOOT/BOOT<ARCH>.EFI, so real UEFI firmware (e.g.
# Beelink SER5) scans the ESP and boots it. No GRUB, no isolinux, no MBR boot
# code — the protective MBR template is zeroed (partition metadata only).
# Also still boots under QEMU via -cdrom. This is the novice path: one ISO,
# picked with a GUI, written to the stick.
iso-usb: all
@mkdir -p $(BUILD_DIR)
@if ! which xorriso >/dev/null 2>&1; then echo "Error: xorriso not found. Install xorriso (apt-get install xorriso)."; exit 1; fi
@if ! which mformat >/dev/null 2>&1 || ! which mmd >/dev/null 2>&1 || ! which mcopy >/dev/null 2>&1; then echo "Error: mtools not found. Install mtools (apt-get install mtools)."; exit 1; fi
@case "$(ARCH)" in \
amd64) BOOTNAME="BOOTX64.EFI" ;; \
aarch64) BOOTNAME="BOOTAA64.EFI" ;; \
*) echo "Error: iso-usb EFI boot name only defined for amd64/aarch64 yet"; exit 1 ;; \
esac; \
ISODIR=$(BUILD_DIR)/iso-usb; \
rm -rf $$ISODIR; mkdir -p $$ISODIR; \
dd if=/dev/zero of=$$ISODIR/efi.img bs=512 count=8192 2>/dev/null; \
mformat -i $$ISODIR/efi.img :: >/dev/null 2>&1; \
mmd -i $$ISODIR/efi.img ::/EFI; mmd -i $$ISODIR/efi.img ::/EFI/BOOT; \
mcopy -i $$ISODIR/efi.img $(LOADER_EFI) ::/EFI/BOOT/$$BOOTNAME; \
printf 'FS0:\\EFI\\BOOT\\%s\r\n' "$$BOOTNAME" > $$ISODIR/startup.nsh; \
mcopy -i $$ISODIR/efi.img $$ISODIR/startup.nsh ::/startup.nsh; \
head -c 432 /dev/zero > $$ISODIR/protmbr.bin; \
ISO=$(BUILD_DIR)/starkernel-iso-usb.iso; \
rm -f $$ISO; \
xorriso -as mkisofs \
-V STARKERNEL -r -J \
-isohybrid-mbr $$ISODIR/protmbr.bin \
-eltorito-alt-boot -e efi.img -no-emul-boot \
-isohybrid-gpt-basdat \
-o $$ISO $$ISODIR >/dev/null 2>&1; \
rm -rf $$ISODIR; \
echo "Iso Image Writer ISO (pure UEFI): $$ISO"; \
echo " In GNOME Disks, pick the ISO with 'Restore Disk Image...' and select your USB stick."; \
echo " Or: dd if=$$ISO of=/dev/sdX bs=4M status=progress"
# qemu-esp — interactive dev boot from FAT directory (no disk image rebuild, # qemu-esp — interactive dev boot from FAT directory (no disk image rebuild,
# no auto-kill/timeout/DOE-injection logic — stays up until you quit it # no auto-kill/timeout/DOE-injection logic — stays up until you quit it
@@ -1134,6 +1221,8 @@ help:
@echo " qemu — clean boot, serial tee'd live + logs/<session>/<arch>/ + DOE CSV → doe/ (all arches)" @echo " qemu — clean boot, serial tee'd live + logs/<session>/<arch>/ + DOE CSV → doe/ (all arches)"
@echo " qemu-esp — quick boot from FAT directory (amd64, aarch64)" @echo " qemu-esp — quick boot from FAT directory (amd64, aarch64)"
@echo " qemu-gdb — boot with GDB stub on :1234" @echo " qemu-gdb — boot with GDB stub on :1234"
@echo " thumbdrive — build generic GPT/FAT32 UEFI disk image (write to a USB stick with dd; real-hardware/SER5 path)"
@echo " iso-usb — build UEFI isohybrid ISO for Iso Image Writer / GNOME Disks 'Restore Disk Image...' (novice path; real-hardware/SER5)"
@echo "" @echo ""
@echo "QEMU display:" @echo "QEMU display:"
@echo " QEMU_DISPLAY=gtk — framebuffer window backend for 'qemu' goal (default: gtk)" @echo " QEMU_DISPLAY=gtk — framebuffer window backend for 'qemu' goal (default: gtk)"
+1 -1
View File
@@ -1,4 +1,4 @@
# LithosAnanke v1.5.4 # LithosAnanke v2.0.1
**UEFI-bootable FORTH microkernel.** Boots from firmware, initialises memory and interrupts, then runs the StarForth VM as its sole userspace runtime. No libc. No OS. Just stone and necessity. **UEFI-bootable FORTH microkernel.** Boots from firmware, initialises memory and interrupts, then runs the StarForth VM as its sole userspace runtime. No libc. No OS. Just stone and necessity.
+105 -97
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated # Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-29T13:51:54Z --> <!-- Generated by mkcapsule --manifest 2026-09-04T15:02:01Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. --> <!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live --> <!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. --> <!-- in MANIFEST.md alongside this auto-generated index. -->
@@ -9,14 +9,15 @@
| Capsule | Blocks claimed | xxHash64 | Signed | | Capsule | Blocks claimed | xxHash64 | Signed |
|---------|----------------|----------|--------| |---------|----------------|----------|--------|
| `ACL.4th` | 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4015 | `0xd781d22148ff171d` | yes | | `ACL.4th` | 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4015 | `0xd781d22148ff171d` | yes |
| `artemis:init.4th` | 4110, 4111, 4112, 4113, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4177, 4178, 4179, 4180, 4181, 4182, 4851, 4852, 4853, 4854 | `0xfe6e570467368153` | yes | | `artemis:init.4th` | 4110, 4111, 4112, 4113, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4177, 4178, 4179, 4180, 4181, 4182, 4851, 4852, 4853, 4854 | `0x90208e9ab5ae0070` | yes |
| `common:messaging.4th` | 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038 | `0x892fd1c86d8c175e` | yes | | `block-acl.4th` | 4019, 4020 | `0xf5eab0544b962dfa` | yes |
| `common:messaging.4th` | 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040 | `0x9cb26fa2d67465db` | yes |
| `common:msg.4th` | 4055 | `0x850a0382344ea6c4` | yes | | `common:msg.4th` | 4055 | `0x850a0382344ea6c4` | yes |
| `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes | | `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes |
| `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xf154616d248e861f` | yes | | `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xf154616d248e861f` | yes |
| `fabric.4th` | 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 5000, 5001, 5002 | `0x9b1d061339cea98d` | yes | | `fabric.4th` | 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 5000, 5001, 5002 | `0x9b1d061339cea98d` | yes |
| `font.4th` | 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985 | `0x720792b4fc758156` | yes | | `font.4th` | 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985 | `0x720792b4fc758156` | yes |
| `hermes:init.4th` | 4153, 4855, 5116 | `0x9d6119b69d4113af` | yes | | `hermes:init.4th` | 4153, 4855, 5116 | `0x7d4ab35a4d3ffc0c` | yes |
| `init-0.4th` | 2200, 2201 | `0xd0a9550baf786bb3` | yes | | `init-0.4th` | 2200, 2201 | `0xd0a9550baf786bb3` | yes |
| `init-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | yes | | `init-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | yes |
| `init-2.4th` | 4506, 4515, 4525, 4535, 4545 | `0xf113b3d0bcccae47` | yes | | `init-2.4th` | 4506, 4515, 4525, 4535, 4545 | `0xf113b3d0bcccae47` | yes |
@@ -33,21 +34,22 @@
| `init-l8-temporal.4th` | 4830, 4831 | `0x51abd4c138246651` | yes | | `init-l8-temporal.4th` | 4830, 4831 | `0x51abd4c138246651` | yes |
| `init-l8-transition.4th` | 4840, 4841, 4842 | `0xbcc1a81976f0a4c9` | yes | | `init-l8-transition.4th` | 4840, 4841, 4842 | `0xbcc1a81976f0a4c9` | yes |
| `init-l8-volatile.4th` | 4810, 4811, 4812, 4813 | `0x98caabbbd92abac4` | yes | | `init-l8-volatile.4th` | 4810, 4811, 4812, 4813 | `0x98caabbbd92abac4` | yes |
| `init.4th` | 2049, 2050, 2057 | `0x9ac6523d24b80cd0` | yes | | `init.4th` | 2049, 2050, 2057 | `0x5d35c5c6a6eafe04` | yes |
| `lib.4th` | 4050 | `0x4b216635c359ef73` | yes | | `lib.4th` | 4050 | `0x4b216635c359ef73` | yes |
| `process.4th` | 4300, 4301 | `0x781afc1dbd0294f7` | yes | | `process.4th` | 4300, 4301 | `0x781afc1dbd0294f7` | yes |
| `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | yes | | `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | yes |
| `turtle.4th` | 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108 | `0x4d470418ca543365` | yes | | `turtle.4th` | 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108 | `0x4d470418ca543365` | yes |
| `user-font-demo.4th` | 4200, 4201, 4202 | `0xce1fd7d1b581a56d` | yes | | `user-font-demo.4th` | 4200, 4201, 4202 | `0xce1fd7d1b581a56d` | yes |
| `zuse-eligibility.4th` | 4021, 4022 | `0x604ddb82c8fa4db0` | yes |
| `zuse.4th` | 4016, 4017, 4018 | `0x490ded9be257a90b` | yes | | `zuse.4th` | 4016, 4017, 4018 | `0x490ded9be257a90b` | yes |
## Block Map (sorted by LBN) ## Block Map (sorted by LBN)
| LBN | Capsule | xxHash64 | Status | | LBN | Capsule | xxHash64 | Status |
|-----|---------|----------|--------| |-----|---------|----------|--------|
| 2049 | `init.4th` | `0x9ac6523d24b80cd0` | ok | | 2049 | `init.4th` | `0x5d35c5c6a6eafe04` | ok |
| 2050 | `init.4th` | `0x9ac6523d24b80cd0` | ok | | 2050 | `init.4th` | `0x5d35c5c6a6eafe04` | ok |
| 2057 | `init.4th` | `0x9ac6523d24b80cd0` | ok | | 2057 | `init.4th` | `0x5d35c5c6a6eafe04` | ok |
| 2064 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2064 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
| 2065 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2065 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
| 2066 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok | | 2066 | `init-l8-omni.4th` | `0x5979e314d6452045` | ok |
@@ -107,6 +109,10 @@
| 4016 | `zuse.4th` | `0x490ded9be257a90b` | ok | | 4016 | `zuse.4th` | `0x490ded9be257a90b` | ok |
| 4017 | `zuse.4th` | `0x490ded9be257a90b` | ok | | 4017 | `zuse.4th` | `0x490ded9be257a90b` | ok |
| 4018 | `zuse.4th` | `0x490ded9be257a90b` | ok | | 4018 | `zuse.4th` | `0x490ded9be257a90b` | ok |
| 4019 | `block-acl.4th` | `0xf5eab0544b962dfa` | ok |
| 4020 | `block-acl.4th` | `0xf5eab0544b962dfa` | ok |
| 4021 | `zuse-eligibility.4th` | `0x604ddb82c8fa4db0` | ok |
| 4022 | `zuse-eligibility.4th` | `0x604ddb82c8fa4db0` | ok |
| 4050 | `lib.4th` | `0x4b216635c359ef73` | ok | | 4050 | `lib.4th` | `0x4b216635c359ef73` | ok |
| 4055 | `common:msg.4th` | `0x850a0382344ea6c4` | ok | | 4055 | `common:msg.4th` | `0x850a0382344ea6c4` | ok |
| 4060 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok | | 4060 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
@@ -115,52 +121,52 @@
| 4063 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok | | 4063 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4064 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok | | 4064 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4065 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok | | 4065 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4110 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4110 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4111 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4111 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4112 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4112 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4113 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4113 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4122 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4122 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4123 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4123 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4124 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4124 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4125 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4125 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4126 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4126 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4127 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4127 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4128 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4128 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4129 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4129 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4130 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4130 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4131 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4131 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4132 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4132 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4133 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4133 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4134 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4134 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4135 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4135 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4136 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4136 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4137 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4137 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4138 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4138 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4139 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4139 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4140 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4140 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4141 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4141 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4153 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok | | 4153 | `hermes:init.4th` | `0x7d4ab35a4d3ffc0c` | ok |
| 4160 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4160 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4161 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4161 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4162 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4162 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4163 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4163 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4164 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4164 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4165 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4165 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4166 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4166 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4167 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4167 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4168 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4168 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4169 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4169 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4170 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4170 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4171 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4171 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4172 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4172 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4173 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4173 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4174 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4174 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4177 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4177 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4178 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4178 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4179 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4179 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4180 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4180 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4181 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4181 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4182 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4182 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4200 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok | | 4200 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
| 4201 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok | | 4201 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
| 4202 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok | | 4202 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
@@ -200,11 +206,11 @@
| 4840 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok | | 4840 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4841 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok | | 4841 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4842 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok | | 4842 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4851 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4851 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4852 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4852 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4853 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4853 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4854 | `artemis:init.4th` | `0xfe6e570467368153` | ok | | 4854 | `artemis:init.4th` | `0x90208e9ab5ae0070` | ok |
| 4855 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok | | 4855 | `hermes:init.4th` | `0x7d4ab35a4d3ffc0c` | ok |
| 4900 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 4900 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 4901 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 4901 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 4902 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 4902 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
@@ -294,42 +300,44 @@
| 5000 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 5000 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5001 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 5001 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5002 | `fabric.4th` | `0x9b1d061339cea98d` | ok | | 5002 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5003 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5003 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5004 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5004 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5005 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5005 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5006 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5006 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5007 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5007 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5008 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5008 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5009 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5009 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5010 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5010 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5011 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5011 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5012 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5012 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5013 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5013 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5014 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5014 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5015 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5015 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5016 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5016 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5017 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5017 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5018 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5018 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5019 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5019 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5020 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5020 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5021 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5021 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5022 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5022 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5023 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5023 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5024 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5024 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5025 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5025 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5026 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5026 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5027 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5027 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5028 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5028 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5029 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5029 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5030 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5030 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5031 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5031 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5032 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5032 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5033 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5033 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5034 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5034 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5035 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5035 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5036 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5036 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5037 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5037 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5038 | `common:messaging.4th` | `0x892fd1c86d8c175e` | ok | | 5038 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5039 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5040 | `common:messaging.4th` | `0x9cb26fa2d67465db` | ok |
| 5100 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5100 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5101 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5101 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5102 | `turtle.4th` | `0x4d470418ca543365` | ok | | 5102 | `turtle.4th` | `0x4d470418ca543365` | ok |
@@ -346,11 +354,11 @@
| 5113 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok | | 5113 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5114 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok | | 5114 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5115 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok | | 5115 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5116 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok | | 5116 | `hermes:init.4th` | `0x7d4ab35a4d3ffc0c` | ok |
## Conflicts ## Conflicts
None. None.
--- ---
*32 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.* *34 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
+1
View File
@@ -497,5 +497,6 @@ Block 4854
( INIT). Hermes always exists by Artemis's birth. ) ( INIT). Hermes always exists by Artemis's birth. )
S" common:messaging.4th" EXEC S" common:messaging.4th" EXEC
MSG-CD-INIT MSG-CD-INIT
2 MY-CH-ID !
S" 2 COMMON-CH @ CH-ADD-MBR" S" Hermes" VM-EXEC S" 2 COMMON-CH @ CH-ADD-MBR" S" Hermes" VM-EXEC
STARTUP-BANNER STARTUP-BANNER
+25
View File
@@ -0,0 +1,25 @@
Block 4019
( block-acl.4th - Block-Level Access Control BMAPFMT )
( C prims: BLK-ACL-ALLOW@ BLK-ACL-ALLOW! BLK-ACL-TTL@ )
( BLK-ACL-TTL! BLK-OWNER@ )
( Policy words this file: BLK-ACL-CHECK )
( Mirrors ACL.4th's C-primitive/FORTH-policy split, )
( applied to blocks instead of words. )
( FABRIC-3.md H.12 step 16, 2026-09-03. )
256 CONSTANT BLK-ACL-BASE-TTL
Block 4020
( BLK-ACL-CHECK block# -- allow? )
( Fast-deny check, vm.c 611-624's pattern applied to )
( a block. First touch: default-permissive claim -- )
( allow=1, TTL=BLK-ACL-BASE-TTL -- matching the word )
( card's own default. No automatic TTL decrement loop )
( exists for blocks yet -- words decrement per word )
( dispatch, blocks have no equivalent hot path -- but )
( this is a real, working fast-deny gate either way. )
: BLK-ACL-CHECK ( block# -- allow? )
DUP BLK-ACL-TTL@ 0= IF
DUP BLK-ACL-BASE-TTL SWAP BLK-ACL-TTL!
DUP 1 SWAP BLK-ACL-ALLOW!
THEN
BLK-ACL-ALLOW@ ;
+42 -1
View File
@@ -19,6 +19,10 @@ Block 5038
( CONSOLE-CMD-EVENT: console-VM -> paired user-VM command ) ( CONSOLE-CMD-EVENT: console-VM -> paired user-VM command )
( relay message type, async MSG-SEND/MSG-DELIVER. ) ( relay message type, async MSG-SEND/MSG-DELIVER. )
7 CONSTANT CONSOLE-CMD-EVENT 7 CONSTANT CONSOLE-CMD-EVENT
( ELEVATE-REQUEST: H.5/H.8 -- word-ACL elevation ask, )
( carried to Zuse via CH-REQUEST. See SEND-ELEVATE- )
( REQUEST/ELEVATE-GRANT below and in zuse-eligibility.4th. )
8 CONSTANT ELEVATE-REQUEST
Block 5004 Block 5004
( StadiumBehaviour tags, match stadium.h's enum ) ( StadiumBehaviour tags, match stadium.h's enum )
0 CONSTANT SB-MIGRATE 0 CONSTANT SB-MIGRATE
@@ -42,6 +46,7 @@ VARIABLE MBR-FREE-HEAD
VARIABLE MSG-SEQ VARIABLE MSG-SEQ
VARIABLE CH-ACTIVE VARIABLE CH-ACTIVE
VARIABLE COMMON-CH VARIABLE COMMON-CH
VARIABLE MY-CH-ID
Block 5006 Block 5006
( VM name routing table -- same fixed table every VM loads, ) ( VM name routing table -- same fixed table every VM loads, )
( so IDX>NAME resolves identically everywhere. ) ( so IDX>NAME resolves identically everywhere. )
@@ -351,7 +356,10 @@ Block 5031
: CH-MINT-ID ( owner -- id ) : CH-MINT-ID ( owner -- id )
MSG-SEQ @ 1+ DUP MSG-SEQ ! MSG-SEQ @ 1+ DUP MSG-SEQ !
SWAP 32 LSHIFT OR ; SWAP 32 LSHIFT OR ;
( H.8: initiator-only gate. Refuses if `from` doesn't )
( match MY-CH-ID -- no posting while claiming another VM. )
: CH-REQUEST ( type from to paddr plen -- ) : CH-REQUEST ( type from to paddr plen -- )
3 PICK MY-CH-ID @ <> IF 2DROP 2DROP DROP EXIT THEN
COMMON-CH @ CH-STATE@ CH-OPEN = IF COMMON-CH @ CH-STATE@ CH-OPEN = IF
COMMON-CH @ MSG-SEND COMMON-CH @ MSG-SEND
ELSE 2DROP 2DROP DROP THEN ; ELSE 2DROP 2DROP DROP THEN ;
@@ -385,7 +393,7 @@ Block 5033
MBR-INIT-FREE MBR-INIT-FREE
0 MSG-SEQ ! 0 MSG-SEQ !
0 MSG-LAST-MSG ! 0 MSG-LAST-MSG !
0 CH-ACTIVE ! 0 CH-ACTIVE ! -1 MY-CH-ID !
COMMON-INIT COMMON-INIT
VM-NAMES-INIT ; VM-NAMES-INIT ;
Block 5034 Block 5034
@@ -435,3 +443,36 @@ VARIABLE BC-CH VARIABLE BC-SCAN
BC-PADDR @ BC-PLEN @ BC-CH @ MSG-SEND BC-PADDR @ BC-PLEN @ BC-CH @ MSG-SEND
BC-SCAN @ MBR-NEXT@ BC-SCAN ! BC-SCAN @ MBR-NEXT@ BC-SCAN !
REPEAT ; REPEAT ;
Block 5039
( H.8: SEND-ELEVATE-REQUEST payload builder -- )
( scratch text buffer + append primitives. )
CREATE ELEVATE-REQ-BUF 256 ALLOT
VARIABLE ELEVATE-REQ-LEN
: ELEVATE-REQ-RESET ( -- ) 0 ELEVATE-REQ-LEN ! ;
: ELEVATE-REQ-PUTC ( c -- )
ELEVATE-REQ-BUF ELEVATE-REQ-LEN @ + C!
1 ELEVATE-REQ-LEN +! ;
: ELEVATE-REQ-APPEND ( addr u -- )
>R
ELEVATE-REQ-BUF ELEVATE-REQ-LEN @ +
R@ CMOVE
ELEVATE-REQ-LEN @ R> + ELEVATE-REQ-LEN ! ;
: ELEVATE-REQ-NUM ( n -- )
<# 0 SWAP #S #> ELEVATE-REQ-APPEND ;
Block 5040
( SEND-ELEVATE-REQUEST: ask Zuse for word-ACL )
( elevation. pk3..pk0 order so top-down emits )
( pk0 first; waddr/wu = target word name text. )
: SEND-ELEVATE-REQUEST ( pk3 pk2 pk1 pk0 waddr wu -- )
ELEVATE-REQ-RESET
83 ELEVATE-REQ-PUTC 34 ELEVATE-REQ-PUTC
32 ELEVATE-REQ-PUTC
ELEVATE-REQ-APPEND
34 ELEVATE-REQ-PUTC 32 ELEVATE-REQ-PUTC
ELEVATE-REQ-NUM 32 ELEVATE-REQ-PUTC
ELEVATE-REQ-NUM 32 ELEVATE-REQ-PUTC
ELEVATE-REQ-NUM 32 ELEVATE-REQ-PUTC
ELEVATE-REQ-NUM 32 ELEVATE-REQ-PUTC
S" ELEVATE-GRANT" ELEVATE-REQ-APPEND
ELEVATE-REQUEST MY-CH-ID @ 0 ELEVATE-REQ-BUF
ELEVATE-REQ-LEN @ CH-REQUEST ;
+32
View File
@@ -0,0 +1,32 @@
# capsules/contrib/
Milestone 7 (contributor capsules / trust tiers), FABRIC-3.md §I.5.
Any `.4th` file placed here gets `FLAG_CONTRIB` in addition to the usual
`FLAG_PRODUCTION | FLAG_EXPERIMENT` pair — `tools/mkcapsule.c`'s
`flags_from_name()` path-matches on the colon-separated capsule name
starting with `contrib:`, mirroring `FLAG_MAMA_INIT`'s own exact-match
pattern one line up in that same function.
**Trust-tier direction, decided in conversation 2026-09-04:** QEMU-vs-real-
hardware conditional enforcement — a contributor capsule is validated more
strictly on real hardware than under QEMU, using
`timer_calibration_record()->vm_mode` (`include/starkernel/timer.h`) as the
signal. `vm_mode` is a real per-architecture hypervisor-vs-hardware
detection as of this same pass (amd64: `CPUID.1:ECX[31]`; aarch64: ACPI
RSDP OEM ID; riscv64: devicetree `compatible` string) — not a build-time
flag, so the same binary enforces differently depending on where it
actually boots.
**Enforcement rule, built 2026-09-04:** `contrib_capsule_refused()`
(`capsule_birth.c`), called from both `capsule_birth_baby()` and
`capsule_run_experiment()` (never `capsule_birth_mama()` — Mama's own init
can never carry `FLAG_CONTRIB`, mutually exclusive with `FLAG_MAMA_INIT` by
construction). Under QEMU (`vm_mode == 1`): no additional check, same
WARN-only treatment every other capsule gets. On real hardware
(`vm_mode == 0`): a contrib capsule additionally requires `CAPSULE_SIG_OK`
`MISSING`/`NO_ROOT_KEY`, which stay WARN-only for every other capsule
(most machines lack the offline signing key), are refused here specifically
because a contributor's capsule has no other provenance to fall back on.
Additive to, never a replacement for, the existing `CAPSULE_SIG_INVALID`
refusal already enforced on every capsule regardless of `FLAG_CONTRIB`.
+1
View File
@@ -15,6 +15,7 @@ Block 5116
( VM that doesn't exist yet at Hera's own birth. ) ( VM that doesn't exist yet at Hera's own birth. )
S" common:messaging.4th" EXEC S" common:messaging.4th" EXEC
MSG-CD-INIT MSG-CD-INIT
1 MY-CH-ID !
S" lib.4th" EXEC S" lib.4th" EXEC
1 COMMON-CH @ CH-ADD-MBR 1 COMMON-CH @ CH-ADD-MBR
0 COMMON-CH @ CH-ADD-MBR 0 COMMON-CH @ CH-ADD-MBR
+2
View File
@@ -14,6 +14,8 @@ Block 2049
: VM-PARENT ( -- id ) 0 ; : VM-PARENT ( -- id ) 0 ;
: VM-CHILDREN ( -- ) ." (none)" CR ; : VM-CHILDREN ( -- ) ." (none)" CR ;
S" ACL.4th" EXEC S" ACL.4th" EXEC
S" block-acl.4th" EXEC
S" zuse-eligibility.4th" EXEC
S" lib.4th" EXEC S" lib.4th" EXEC
S" fabric.4th" EXEC S" fabric.4th" EXEC
S" font.4th" EXEC S" font.4th" EXEC
+26
View File
@@ -0,0 +1,26 @@
Block 4021
( zuse-eligibility.4th - H.5/H.8 elevation grant )
( C prims: ZUSE-ELIGIBILITY-ADD ZUSE-ELIGIBLE? )
( NAME>XT ELEVATE-PUBKEY-UNPACK )
( Policy word this file: ELEVATE-GRANT. Runs in )
( Hera's own dict -- delivered here by messaging.4th's )
( MSG-DELIVER via VM-EXEC when a session calls the )
( common:messaging.4th SEND-ELEVATE-REQUEST entrypoint. )
( FABRIC-3.md H.12 step 21, 2026-09-03. )
CREATE ELEVATE-PK-BUF 32 ALLOT
Block 4022
( ELEVATE-GRANT ( waddr wu pk0 pk1 pk2 pk3 -- ) )
( Reconstructs the caller's pubkey, checks Zuse's )
( eligibility list, and on match grants the named )
( word ACL-ALLOW!/ACL-TTL! via the same reused )
( ACL-TTL mechanism H.5 decided on. No grant, no )
( error, on any mismatch -- silent refusal. )
: ELEVATE-GRANT ( waddr wu pk0 pk1 pk2 pk3 -- )
ELEVATE-PK-BUF ELEVATE-PUBKEY-UNPACK
ELEVATE-PK-BUF ZUSE-ELIGIBLE? IF
NAME>XT DUP IF
1 OVER ACL-ALLOW!
ACL-BASE-TTL SWAP ACL-TTL!
ELSE DROP THEN
ELSE 2DROP THEN ;
BIN
View File
Binary file not shown.
+108
View File
@@ -30,6 +30,114 @@ Applied to the two planned releases: the **v2.0.0** cut (even major, so LTS) is
release; **v2.5.0** is the hardware bare-metal release that transfers v2.0.0's QEMU story to release; **v2.5.0** is the hardware bare-metal release that transfers v2.0.0's QEMU story to
real boards. See `FABRIC-3.md` §G for the release-gate punch lists. real boards. See `FABRIC-3.md` §G for the release-gate punch lists.
**Board-by-board hardware rollout, decided 2026-08-29 (extends the above as boards come
online).** Real silicon is arriving incrementally (Beelink SER5 in hand now; RasPi 5 + Milk-V
orderable around Mon 2026-08-31), so the hardware release is split per real board in hand,
each its own even-minor cut on the same line (each `X.Y.0` here is an LTS point-in-time cut,
not a separate dev line):
- **v2.2.0 — amd64 bare metal.** Beelink SER5 (in hand). Gate: the generic GPT/FAT32
thumbdrive image (`make -f Makefile.starkernel ARCH=amd64 thumbdrive`) flashes to and boots
on the real SER5 via its real UEFI; POST + `ok>`; the amd64 **RDRAND** backend
(`rng: backend = rdrand`) serves live entropy; and a real Zuse identity is minted on a
second thumbdrive in real hardware and re-attaches. Two 16 GB sticks available: one to boot
the image, one to mint the Zuse user.
- **v2.4.0 — aarch64 bare metal.** Raspberry Pi 5 (orderable ~Mon 2026-08-31). Gate: boots
on the real board, aarch64 peripheral-RNG backend live, Zuse mint/attach on real media.
- **v2.5.0 — all three bare metal.** Adds Milk-V (riscv64) to the above; the Zkr (RNDR)
backend live. This is the full "same story on all three arches on real silicon" cut.
**Beyond v2.5.0 — Zynq FPGA is the next big milestone, after a hardening phase.** Once the
three general-purpose boards close, the next major transfer is to a **Zynq (AMD Xilinx)
FPGA** SoC — the step where the battle-tested amd64/aarch64/riscv64 story rides on
configurable silicon. That is a genuinely bigger milestone than any single prior board: an
FPGA demands its platform be carried forward rather than ported with trivial
architecture-delta work, and it reshapes the hardware story (soft/hard CPU cores, PL fabric,
non-standard memory map, custom peripherals). Expect a new even-major line for it once the
coloring-in period below lands.
**The FPGA creates a three-product split, decided 2026-08-29.** The Zynq is not just a fourth
platform to port to — it is the pivot that forces the project to separate into three
distinct products, each with its own host, delivery, and proof character. This is the neat
partition the FPGA's configurable-silicon nature makes possible and demands:
1. **Hosted StarForth** — the hosted/interpreted StarForth product that already exists
(3-arch acceptance-tested; runs StarForth hosted on an OS). Its delivery is the Forth
+ VM + capsule semantics as a portable, embeddable interpreted runtime.
2. **A full StarshipOS** — the standalone operating system built on LithosAnanke
(LithosAnanke → StarshipOS). Its delivery is a self-booting OS on general-purpose
silicon (the SER5/RasPi/Milk-V line already covers this).
3. **Hardware steady-state machinery with sealed executions, HOL-proven** — the
FPGA-native product: hardware-enforced sealed executions and steady-state machinery
whose guarantees are machine-checked in a proof assistant (HOL). This is the product only
configurable silicon can honor — secret/hardware-boundary enforcement and formally
verified behavior carried in silicon rather than software. Its delivery is the bitstream +
the HOL proof artifacts (not just a port of the OS).
The coupling is the point: the FPGA is where product 3 is born, and product 3's existence is
what cleanly separates 1 from 2 from 3. Product 1 ships hosted on an OS; product 2 ships as
an OS on general silicon; product 3 ships as proven hardware. Anything that straddles those
boundaries after this decision is a conscious product-line choice, not an accident of history.
Scoping of each product's concrete gates, and the new even-major line that carries products 1
through 3 as separate tracks, is defined at v2.5.0 close / during the coloring-in phase.
(This complements, and does not retract, the existing "hardware bare-metal release" policy
above.)
**IP framing of the three products — 3 patent applications + 3 marks, decided 2026-08-29.**
The three products are treated as **three patent applications**, each matched to a trademark,
with one caveat about the pre-existing provisional:
- **Patent 1 + mark StarForth.** The hosted/interpreted StarForth runtime product.
- **Patent 2 + marks StarshipOS + LithosAnanke.** The full standalone OS
(LithosAnanke → StarshipOS). (Noted as "StarshopOS" in the 2026-08-29 decision words;
canonical repo spelling and mark is **StarshipOS** — confirmed as the literal mark
to register.)
- **Patent 3 + mark Compudynamics.** The Zynq hardware steady-state machinery with sealed
executions, HOL-proven — anchored by the physics-adaptive runtime.
**Driving deadlines (why "no hurry" is wrong for #1 and #2), clarified 2026-08-29.** Two
clocks bind the near term, independent of product #3 and the FPGA:
- **#1 — the provisional will expire before conversion.** Its priority claim is time-boxed:
if the non-provisional isn't filed claiming benefit before the provisional's window lapses
(provisional filed ~Dec 2025 → window ~Dec 2026), the provisional's priority is lost and
the same subject matter cannot be re-staked by refiling thereafter. So #1 is on a hard
clock regardless of the December scope.
- **#2 — full StarshipOS is the December deliverable.** This is what "keeps the flagship
covered": the standalone-OS product (and, pending confirmation below, possibly the vehicle
that converts #1's provisional) must deliver by December.
- **Open point to resolve with counsel:** is **#2's** application (or the December delivery)
the **conversion vehicle** for #1's provisional — i.e., does it claim benefit from the
#1 provisional and thereby secure what would otherwise lapse — or is #1 converted by a
filing separate from #2? Captured as a decision record; no filing made.
**Relationship to the existing provisional (must be reconciled, not assumed).** The repo
already carries a **"Patent pending"** USPTO **provisional filed December 2025** for the
physics-grounded self-adaptive runtime (the Compudynamics adaptive runtime), sourced in
`docs/patent/` and referenced in `README.md`. Compudynamics is therefore already staked as
the brand of that foundation. Open points to resolve with counsel before any filing, so
nothing is invented or double-filed: is patent 3 the continuation/refinement of that
provisional (its HOL hardware realization) or a fresh application? Are the three product
applications additive to, or folding in, the Dec-2025 provisional? This record states intent;
it does not file, claim, or draft legal text.
**Before the FPGA — "coloring in", decided 2026-08-29.** The period between the all-three
bare-metal cut (v2.5.0) and starting the Zynq is finishing/hardening work that thickens the
shape of what already exists rather than adding new silicon. This is not idle time; it is
the point where v2.5.0's real-hardware story is made production-honest before the FPGA asks
to carry it further. Concrete items to define during it (draft scope, to be firmed at v2.5.0
close): Zynq-preflight robustness of the USB BOT/xHCI and block paths; live-entropy and
Zuse-cert hardening on the three real boards; SMP/multi-core bring-up and IRQ routing on real
ASICs (parked in the HAL notes); driver set expansion beyond the three boards before
committing an FPGA port; and whatever v2.5.0's real-board validation surfaces. As boards
land and the v2.5.0 gates close, this list is edited down to the concrete coloring-in punch
list, and the Zynq becomes the even-major target after it.
QEMU remains the zero-degradation reference on every line; each `X.Y.0` must reproduce the
QEMU acceptance story (`POST 1012/0/0` + `ok>`, block-fence Zuse true, backend entropy
non-deterministic) on its board before it closes.
--- ---
## Milestone Overview ## Milestone Overview
+193 -9
View File
@@ -199,6 +199,16 @@ typedef struct {
_Static_assert(sizeof(blk_volume_meta_t) == 4096, _Static_assert(sizeof(blk_volume_meta_t) == 4096,
"blk_volume_meta_t must be exactly one 4 KiB devblock"); "blk_volume_meta_t must be exactly one 4 KiB devblock");
/* blk_meta_t.flags bit values -- FABRIC-3.md §F.4/§H.6/§H.12 step 13,
* decided 2026-09-02/03. Orthogonal bits, not a mutually-exclusive enum:
* a block can be both CLAIMED and MIGRATING at once. Grounded in the only
* states §F.4 actually motivated by a real need (MIGSM/UNCLEAN, two
* then-currently-blocked graph nodes) plus CLAIMED/STALE, the names
* already used loosely in that pass's own prose. 61 bits remain reserved. */
#define BLK_FLAG_CLAIMED (1ull << 0) /* owned, per BMAPFMT's owner_fp */
#define BLK_FLAG_MIGRATING (1ull << 1) /* mid-migration; serves MIGSM */
#define BLK_FLAG_STALE (1ull << 2) /* interrupted flush; serves UNCLEAN */
/* Per-1 KiB block metadata (packed into top 1 KiB region of each 4 KiB sector). */ /* Per-1 KiB block metadata (packed into top 1 KiB region of each 4 KiB sector). */
typedef struct { typedef struct {
/* Core integrity (16 bytes) */ /* Core integrity (16 bytes) */
@@ -210,7 +220,7 @@ typedef struct {
uint64_t modified_time; /* Unix timestamp (last write) */ uint64_t modified_time; /* Unix timestamp (last write) */
/* Block status (16 bytes) */ /* Block status (16 bytes) */
uint64_t flags; /* Status flags */ uint64_t flags; /* Status flags -- BLK_FLAG_* bits above */
uint64_t write_count; /* Number of writes (wear leveling) */ uint64_t write_count; /* Number of writes (wear leveling) */
/* Content identification (32 bytes) */ /* Content identification (32 bytes) */
@@ -223,11 +233,37 @@ typedef struct {
uint64_t entropy[4]; /* 256-bit entropy/random seed */ uint64_t entropy[4]; /* 256-bit entropy/random seed */
uint64_t hash[4]; /* SHA-256 (optional) */ uint64_t hash[4]; /* SHA-256 (optional) */
/* Security & ownership (40 bytes) */ /* Security & ownership -- FABRIC-3.md §F.4/§H.6/§H.12 step 12, decided
uint64_t owner_id; /* User/process ID */ * 2026-08-27/2026-09-03: BMAPFMT repurposes this slot rather than
uint64_t permissions; /* rwx-style permissions */ * building a separate on-drive block-map table (distributed
uint64_t acl_block; /* Block number containing ACL (0=none) */ * ownership/ACL, travels with the block itself). Replaces the old
uint64_t signature[2]; /* 128-bit signature */ * owner_id/permissions/acl_block/signature[2] fields, which predated
* and directly conflicted with both the anti-POSIX principle and
* VMIdentity's pubkey-based model. Not the same 40-byte budget the
* old fields occupied -- natural alignment padding (uint32_t acl_ttl
* and uint64_t reserved_future each force a few bytes of compiler-
* inserted padding after the preceding uint8_t fields) makes this
* section's real footprint smaller; verified below via
* _Static_assert on the whole struct's actual sizeof(), not trusted
* by hand (see the blk_volume_meta_t padding-bug lesson this project
* already learned once). */
uint8_t owner_fp[8]; /* truncated fingerprint of owner's VMIdentity
* pubkey -- cheap per-block; full pubkey
* resolves via the drive's own identity
* record. */
uint8_t acl_allow; /* cached fast-deny bit, checked first --
* vm.c:611-624's exact pattern, applied to a
* block instead of a word. */
uint32_t acl_ttl; /* countdown, same shape as DictEntry's
* acl_ttl -- blocks support temporary
* elevation too, same ACL-TTL-reuse
* mechanism and Zuse-eligibility-list gating
* as the word card (§H.5). */
uint8_t acl_reserved[3]; /* still genuinely undecided -- deliberate
* slack per "flexibility until we understand
* the recipe," not a placeholder to fill
* reflexively. */
uint64_t reserved_future; /* untouched budget, same reasoning. */
/* Link/chain support (32 bytes) */ /* Link/chain support (32 bytes) */
uint64_t prev_block; /* Previous in chain (0=none) */ uint64_t prev_block; /* Previous in chain (0=none) */
@@ -238,10 +274,29 @@ typedef struct {
/* Application-specific (120 bytes) */ /* Application-specific (120 bytes) */
uint64_t app_data[15]; /* 15×64-bit app-defined fields */ uint64_t app_data[15]; /* 15×64-bit app-defined fields */
/* Padding to reach 341-byte slice */ uint8_t padding[5]; /* trailing slack, unrelated to any exact size target --
uint8_t padding[5]; * the old "341-byte slice" comment here was already
* inaccurate before FABRIC-3.md §H.12 step 12's edit
* (sizeof(blk_meta_t) was 344, not 341, due to
* ordinary trailing struct-alignment padding after
* this array -- harmless since BLK_META_PER_BLOCK,
* the only thing that constant would matter to, has
* zero callers anywhere in this codebase). Verify
* this struct's real size with the _Static_assert
* below, not by re-deriving it from this comment. */
} blk_meta_t; } blk_meta_t;
/* Verified via offsetof()/sizeof(), not trusted by hand -- see the
* blk_volume_meta_t padding-bug lesson this project already learned once
* (a hand-summed struct padding formula hid a real 4-byte alignment gap).
* 336, not the BLK_META_PER_BLOCK/"341-byte slice" figure this struct's
* own comments have long claimed -- that mismatch predates this assert and
* is harmless today (see padding[5]'s own comment above), but this assert
* now makes any future drift in either direction fail the build instead of
* silently mismatching a constant nothing currently checks against it. */
_Static_assert(sizeof(blk_meta_t) == 336,
"blk_meta_t size changed -- update this assert and check BLK_META_PER_BLOCK");
/* Error codes */ /* Error codes */
enum { enum {
BLK_OK = 0, BLK_OK = 0,
@@ -251,7 +306,8 @@ enum {
BLK_ENODEV = -4, BLK_ENODEV = -4,
BLK_ERESERVED = -5, BLK_ERESERVED = -5,
BLK_EDIRTY = -6, BLK_EDIRTY = -6,
BLK_ENOMEM = -7 BLK_ENOMEM = -7,
BLK_ENOSPC = -8 /* not enough free devblocks -- blk_firsttouch_claim() */
}; };
/* Per-block BAM entry — one per user block in each device slot */ /* Per-block BAM entry — one per user block in each device slot */
@@ -319,6 +375,116 @@ uint64_t blk_subsys_epoch(void);
*/ */
int blk_subsys_relocate_block(uint32_t home_lbn, uint32_t target_lbn); int blk_subsys_relocate_block(uint32_t home_lbn, uint32_t target_lbn);
/* blk_get_device_range - the LBN range (start_lbn, count of 1 KiB FORTH
* blocks) a specific already-attached device occupies (FABRIC-3.md §I.2,
* 2026-09-04). Mirrors blk_subsys_detach_device()'s own dev-pointer slot
* lookup, exposed publicly for the first time -- needed so a caller can
* scope a scan/query to exactly one attached device rather than the
* global, multi-device LBN space blk_get_total_blocks()/blk_get_meta()
* otherwise address. Returns BLK_ENODEV if dev isn't attached.
*/
int blk_get_device_range(struct blkio_dev *dev, uint32_t *out_start_lbn, uint32_t *out_count);
/* blk_get_device_free_blocks - free vs. total 1 KiB FORTH-block count for
* a specific already-attached device (same slot lookup as
* blk_get_device_range()). RAM-backed slots (no on-disk vol_meta) report
* out_total == out_free == 0, matching blk_mark_allocated()/_free()'s own
* "!slot->raw_base" gate on touching free_blocks bookkeeping at all.
* Returns BLK_ENODEV if dev isn't attached.
*/
int blk_get_device_free_blocks(struct blkio_dev *dev, uint64_t *out_free, uint64_t *out_total);
/* blk_get_first_disk_range - the LBN range of first_disk_slot(), i.e.
* whichever disk-backed device blk_get_volume_meta()/blk_meta_zone_read()
* already implicitly target -- Artemis's own disk.img in practice, since
* it attaches at boot before any USB hotplug (the same boot-order
* convention those two functions already rely on, not a new assumption).
* FIRSTTOUCH (below) scans exactly this range, not the global LBN space.
* Returns BLK_ENODEV if no disk-backed device is attached at all.
*/
int blk_get_first_disk_range(uint32_t *out_start_lbn, uint32_t *out_count);
/* blk_firsttouch_claim - FABRIC-3.md §F.11, decisions 1-3, built exactly
* as scoped 2026-08-27 (re-verified against current blk_meta_t 2026-09-04
* before building -- the chain fields below are real and untouched by
* BMAPFMT's unrelated owner_fp/acl_allow/acl_ttl/flags field addition).
*
* One linear scan over blk_get_first_disk_range()'s devblocks (4 KiB
* granularity -- one blk_meta_t per devblock, not per 1 KiB FORTH block),
* via blk_get_meta(). Answers both questions the scan needs in the same
* pass: does owner_fp already own a claim (not reused by this call --
* every call makes a *new* claim of exactly `count` additional devblocks,
* per §F.11's own text; an existing claim is a separate, not-yet-decided
* question), and which devblocks are free (owner_fp all-zero, BLK_FLAG_
* CLAIMED clear). A claim is a scattered chain, not a required contiguous
* run -- links devblocks via blk_meta_t's prev_block/next_block/
* chain_length fields; owner_fp is stamped onto *every* member devblock,
* not just the head, so ownership reads locally from any member without
* walking the chain. Fails outright (BLK_ENOSPC), no partial claim, if
* fewer than `count` free devblocks exist.
*
* @param owner_fp 8-byte fingerprint (this session's convention: the
* first 8 bytes of the claiming identity's 32-byte
* VMIdentity.owner_pubkey -- owner_fp had no real
* producer anywhere in this codebase before this,
* only accessors, so this call site sets the
* convention rather than following one).
* @param count Devblocks to claim (whole devblocks, §F.4 decision
* 4, already inherited, not revisited here).
* @param out_chain_head The claim's identity to the caller: its
* chain-head devblock number (a 1 KiB FORTH-block
* LBN, the representative/first sub-block of that
* devblock -- not a separate devblock-index
* namespace; blk_get_meta()/blk_set_meta() already
* resolve any LBN within a devblock to the same
* shared blk_meta_t, so this is a valid handle for
* blk_meta_relocate_devblock() below).
* @return BLK_OK, BLK_ENODEV (no disk-backed device), BLK_EINVAL (NULL
* arg or count == 0), or BLK_ENOSPC (not enough free devblocks).
*/
int blk_firsttouch_claim(const uint8_t owner_fp[8], uint32_t count, uint32_t *out_chain_head);
/* blk_meta_relocate_devblock - the real migration primitive (FABRIC-3.md
* §I.2, migration state machine, 2026-09-04): moves one devblock's full
* content and blk_meta_t ownership from home_devblock to target_devblock.
* BLK_FLAG_MIGRATING is set on home_devblock for the duration -- the
* state machine genuinely is just this one flag's two states (clear =
* STABLE, set = MIGRATING), matching what BLK_FLAG_MIGRATING was already
* reserved for.
*
* Devblock granularity (4 KiB) holds BLK_PACK_RATIO (3, not 4 -- the 4th
* 1 KiB slice is the packed blk_meta_t metadata region) FORTH blocks
* (1 KiB each); the actual content copy runs blk_subsys_relocate_block()
* BLK_PACK_RATIO times, once per FORTH-block offset within the devblock
* -- that function is the only existing content-relocation primitive,
* and it operates at FORTH-block granularity, not devblock granularity,
* so this function is the bridge between the two. On success, transfers
* owner_fp/acl_allow/acl_ttl from home's blk_meta_t to target's, clears
* home's (freed, BLK_FLAG_CLAIMED unset), and sets BLK_FLAG_CLAIMED on
* target.
*
* NOT atomic across all BLK_PACK_RATIO FORTH-block copies -- a mid-loop
* failure (e.g. blk_subsys_relocate_block()'s own reloc-table
* exhaustion) leaves however many already succeeded in place, redirected, with
* BLK_FLAG_MIGRATING still set on home_devblock and blk_meta_t ownership
* NOT yet transferred. This is a known, documented limitation, not
* silently accepted: true all-or-nothing atomicity across BLK_PACK_RATIO
* separate relocation-table entries would need its own transaction log, out of
* scope for this pass. A caller that hits a non-BLK_OK return should
* treat home_devblock as still MIGRATING and not yet safe to reclaim.
*
* @return BLK_OK, BLK_EINVAL (home == target, or invalid devblock), or
* whichever blk_subsys_relocate_block() error stopped the loop.
*/
int blk_meta_relocate_devblock(uint32_t home_devblock, uint32_t target_devblock);
/* blk_migration_idle_check - heat/wear-leveling migration trigger, meant
* to be called once per idle tick (FABRIC-3.md §I.2, 2026-09-04). See
* block_subsystem.c's own doc comment for the full scan/threshold
* description and what's deliberately left open (overflow-triggered
* migration). */
void blk_migration_idle_check(void);
int blk_subsys_shutdown(void); int blk_subsys_shutdown(void);
uint8_t *blk_get_buffer(uint32_t block_num, int writable); uint8_t *blk_get_buffer(uint32_t block_num, int writable);
@@ -358,6 +524,24 @@ int blk_get_meta(uint32_t block_num, blk_meta_t *meta);
int blk_set_meta(uint32_t block_num, const blk_meta_t *meta); int blk_set_meta(uint32_t block_num, const blk_meta_t *meta);
/* BMAPFMT field accessors -- FABRIC-3.md §F.4/§H.6/§H.12 step 14. Thin
* read-modify-write wrappers over blk_get_meta()/blk_set_meta() (which
* already own the caching/dirty-tracking), one per new blk_meta_t field.
* FORTH wrappers (BLK-ACL-ALLOW@/! etc., §H.12 step 15) call these, not
* blk_get_meta()/blk_set_meta() directly -- same C-primitive/FORTH-policy
* split as the existing word-level ACL system. */
int blk_owner_fp_get(uint32_t block_num, uint8_t out_fp[8]);
int blk_owner_fp_set(uint32_t block_num, const uint8_t fp[8]);
int blk_acl_allow_get(uint32_t block_num, uint8_t *out_allow);
int blk_acl_allow_set(uint32_t block_num, uint8_t allow);
int blk_acl_ttl_get(uint32_t block_num, uint32_t *out_ttl);
int blk_acl_ttl_set(uint32_t block_num, uint32_t ttl);
int blk_flags_get(uint32_t block_num, uint64_t *out_flags);
int blk_flags_set(uint32_t block_num, uint64_t flags);
int blk_is_allocated(uint32_t block_num); int blk_is_allocated(uint32_t block_num);
int blk_mark_allocated(uint32_t block_num); int blk_mark_allocated(uint32_t block_num);
+10
View File
@@ -87,6 +87,16 @@ typedef enum {
/** Mama init flag (exactly one capsule must have this) */ /** Mama init flag (exactly one capsule must have this) */
#define CAPSULE_FLAG_MAMA_INIT 0x00000040 /* (m) Mama's init */ #define CAPSULE_FLAG_MAMA_INIT 0x00000040 /* (m) Mama's init */
/** Contributor capsule flag (FABRIC-3.md §I.5, 2026-09-04) -- path-match
* on capsules/contrib/, mirrors FLAG_MAMA_INIT's own exact-match pattern
* in mkcapsule.c's flags_from_name(). Trust-tier enforcement (QEMU-vs-
* real-hardware, decided in conversation) is a runtime check in
* capsule_validate()'s callers, not encoded in this bit itself -- the
* bit only marks "this capsule's provenance is a contributor, not this
* project's own source," same as CAPSULE_FLAG_PRODUCTION/_EXPERIMENT
* mark mode, not policy. */
#define CAPSULE_FLAG_CONTRIB 0x00000080 /* (c) contributor-submitted */
/** Validate mode flags. /** Validate mode flags.
* Mama: neither (p) nor (e) may be set. * Mama: neither (p) nor (e) may be set.
* Babies: at least one of (p) or (e) must be set (both is fine — D2). */ * Babies: at least one of (p) or (e) must be set (both is fine — D2). */
+9
View File
@@ -127,6 +127,14 @@ CapsuleRunResult capsule_birth_mama(
* @param descs Capsule descriptor array * @param descs Capsule descriptor array
* @param names Capsule name entry array (parallel to descs) * @param names Capsule name entry array (parallel to descs)
* @param arena Capsule payload arena * @param arena Capsule payload arena
* @param parent Who is birthing this VM (FABRIC-3.md §H.12 step 7) --
* the caller's own VMUuid (e.g. vm->stadium_vm_id for
* a FORTH word handler), recorded on the new VM's
* Session.parent. Every current call site has one in
* scope, directly or one level up; traced live rather
* than assumed (checked all 6 call sites across
* mama_forth_words.c/capsule_console.c/
* capsule_runcap.c/capsule_wirebind.c).
* @param skip_pki_sig 0 for every build-time capsule (the normal case -- * @param skip_pki_sig 0 for every build-time capsule (the normal case --
* checked against the compile-time-baked signature * checked against the compile-time-baked signature
* array via capsule_get_signatures()). Non-zero only * array via capsule_get_signatures()). Non-zero only
@@ -154,6 +162,7 @@ CapsuleRunResult capsule_birth_baby(
const CapsuleDesc *descs, const CapsuleDesc *descs,
const CapsuleNameEntry *names, const CapsuleNameEntry *names,
const uint8_t *arena, const uint8_t *arena,
VMUuid parent,
int skip_pki_sig, int skip_pki_sig,
VMUuid *out_vm_id, VMUuid *out_vm_id,
void **out_vm_ctx void **out_vm_ctx

Some files were not shown because too many files have changed in this diff Show More