- docs/lithosananke/ROADMAP.md + M7.1.md: fixed stale "Branch: lithosananke" (no such branch post-split), M7.1's "Design Complete" status (shipped and live, redirected to FABRIC*.md), the M8/success-criteria self-contradiction (OBSOLETE marking vs. unqualified live criterion), and the stale AHCI/SATA claim for M9 (real implementation is virtio_blk.c) -- also corrected BLOCK/BUFFER/UPDATE/FLUSH and block device abstraction to [x] since both are confirmed live in src/word_source/block_words.c and block_subsystem.c. - Top-level ROADMAP.md: marked OBSOLETE (Captain Bob's call -- more than "stale," the architecture/branch topology/terminology it describes no longer exist), pointing to docs/lithosananke/ROADMAP.md and FABRIC*.md for current status. - docs/03-architecture/word-acl/DESIGN.md: fixed the ACL Phase 7 contradiction -- Phase 7 (LithosAnanke kernel parity) is independently verified complete per .claude/CLAUDE.md, not "remaining"; removed the stale lithosananke-branch-parity framing. - VM-FLEET-ATTRACTOR-DESIGN-20260705.md's doe-campaign.4th "broken" claim: investigated, ran SMOKE-CAMPAIGN live (completes clean, fleet heat conserved) -- initially read as contradicting the claim, corrected directly by Captain Bob: a clean execution trace doesn't disprove the doc's actual argument (no real controlled-experimental-factor mechanism). Confirmed accurate, left untouched. - Isabelle/HOL pipeline-metrics model/C-struct mismatch: confirmed a real proof-modeling gap (pm_last_accuracy_num/den has no analogue in the real PipelineGlobalMetrics struct), not stale prose -- tracked here rather than fixed, matching the .thy file's own scope boundary and this project's standing caution that each Isabelle gap needs its own subsystem model. ACL-RWT DoE overhead re-measurement (the 6th item) intentionally not started -- a full multi-architecture DoE campaign, not a doc-text fix, holding for explicit confirmation given the scale. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
16 KiB
Word-Level ACL System
Status: Implemented through Phase 7 (LithosAnanke kernel parity) — independently verified
present in current master (.claude/CLAUDE.md's Word-Level ACL System section). Phase 8
(PKI/thumbdrive minting) is the current open item.
Target branch: master — post-split, this repo's sole production line; there is no
separate lithosananke branch to reach parity with (see .claude/CLAUDE.md's "On the branch
topology" note)
Implementation files: capsules/ACL.4th, capsules/zuse.4th, src/word_source/acl_words.c, src/test_runner/modules/acl_words_test.c
Summary
Overview
A word-level access control system for StarForth VMs, implemented as a
combination of a thin C infrastructure layer and a pure-FORTH policy capsule
(ACL.4th). The C layer provides four DictEntry fields for the hot path
(TTL counter + allow bit + mode + pin). All policy, all adaptive logic, all
inheritance rules live as colon definitions in ACL.4th. A bootstrap
superuser (zuse.4th) provides the sole authenticated escalation path.
ACL Disposition — Three States
Each word in the dictionary has one of three enforcement dispositions:
| State | Behavior |
|---|---|
STRICT |
ACL re-checked on every execution |
TTL |
ACL cached; re-checked only when TTL counter reaches zero |
PINNED |
Current mode and decision frozen permanently; one-way ratchet |
TTL — Statistically Adaptive
The TTL is not a fixed value. It is derived and continuously updated from the existing SSM execution physics:
- Heat (
execution_heat): hotter words earn longer TTLs; check cost amortized over more executions - Rolling window: sudden shift in caller pattern or access rate causes TTL to shrink aggressively
- Decay: quiescent words pull their TTL back down so the next burst re-validates early
- Inference engine (L5/L6): detects oscillating TTL and stabilizes it — same CV threshold logic already used for window-width inference
PINNED is the asymptote: the adaptive process converges, you thumbtack
it, and the accumulator freezes permanently.
A FORTH security word selects enforcement mode per word:
' MY-WORD ACL-STRICT \ check every execution
' MY-WORD ACL-TTL-MODE \ use adaptive TTL
' MY-WORD ACL-PIN \ freeze — mode and decision immutable forever
The Thumbtack / Pin Flag
ACL-PIN ( xt -- ) is a one-way ratchet:
- Transitions:
STRICT → PINNEDorTTL → PINNED— never back - Once pinned,
acl_modeandacl_ttlare immutable for that VM context - Any attempt to change a pinned word's ACL is silently ignored (or errors, depending on policy)
- Kernel primitive words (
BIRTH,EXEC,BYE, etc.) are pinned by Mama at boot before the firstBIRTHfires
Inheritance at Birth
When a child VM is born:
acl_mode = parent->acl_mode \ policy propagates (STRICT or TTL)
acl_pinned = 0 \ always clear — child owns its own lock
acl_ttl = default \ reset; child has no execution history
acl_decision = ALLOW \ re-evaluated on first access
Key properties:
- Pin is contextual, not viral. A parent's pinned words do not force the child to be pinned. The child inherits the mode as a starting point and can tighten, relax, or re-pin freely.
- Security lattice flows downward at birth only. After birth, each VM's ACL state is independent. A compromised child cannot bootstrap its way back to Mama's pinned ACLs.
Interpreter Hook — Two-Level Check
The C interpreter reads only two fields per DictEntry:
if (vm->emergency_console) goto execute; /* 100% bypass — physical access */
if (entry->acl_ttl-- > 0) goto execute; /* TTL good — single decrement */
acl_recheck(vm, entry); /* TTL=0: call FORTH ACL-RECHECK */
if (!entry->acl_allow) goto reject;
Hot path cost: one decrement and a branch — essentially free.
Cold path: calls ACL-RECHECK in ACL.4th, which recomputes the
adaptive TTL, updates acl_allow, and resets the counter. The C side
never reasons about policy; it only reads the result.
Two-Console Architecture
Two permanent, independent console layers exist at all times:
1. Emergency Console (always present)
emergency_console(uint8_t) flag inVMstruct — C-only write; no FORTH word sets it- Checked first in the interpreter hot path — 100% ACL bypass
acl_recheck()uses save/restore around it for re-entrancy protectionEMERGENCY_CONSOLE_ENABLEDMakefile build flag (default=1): when set to 0, strips interactive fallthrough;vm_fault_handler()weak symbol is called instead (override for hardware reset, watchdog, debug probe)BYEreturns to the emergency console- Only
panickills the VM - Prompt:
ok>
2. Zuse Console (omnipresent, awaiting authentication)
zuse_session(uint8_t) flag inVMstruct — C-only write; no FORTH word sets it- Prompt:
zuse)ok> - Full ACL bypass when a Zuse session is active
- Completely independent of
emergency_console— setting one does not affect the other
Superuser: Zuse
Named for Konrad Zuse, pioneer of programmable computers. Zuse is the bootstrap superuser: the sole entity that can own the zuse console and mint user credentials.
- Defined in
capsules/zuse.4th, loaded byACL.4that capsule boot - Software-only for now (no thumbdrive);
zuse.4this a capsule citizen from day one - Zuse's words are pinned by
ACL-ZUSE-BOOTat load time ACL-BOOTis called first, thenS" zuse.4th" EXEC— both from withinACL.4thitself (Block 2067)- Future: replace with thumbdrive PKI (Ed25519 challenge-response);
zuse.4thbecomes the bootstrapper that validates the physical drive
CA Root
- Embedded in
ACL.4th(Block 2066) as constantsACL-CA-KEY-LO/ACL-CA-KEY-HI - Capsule hash = root-of-trust fingerprint: any CA key change changes the capsule hash and the birth protocol detects tampering
- Placeholder (zeros) until
tools/mkcapsuleembeds the real Ed25519 key at build time
Security Model / No-Security Condition
Security is opt-in via init.4th. The toggle is one commented-out line:
\ S" ACL.4th" EXEC
ACL.4th |
zuse.4th |
Result |
|---|---|---|
| absent | absent | No security — open dev mode |
| present | absent | ACL enforced; emergency REPL locked until Zuse provisioned |
| present | present | Full lockdown; Zuse owns the zuse console |
Uncomment the line in init.4th to enable full lockdown. Leave it
commented out for development builds.
Self-Activating Capsule
ACL.4th is self-activating — init.4th only needs one line:
S" ACL.4th" EXEC
Internal structure of ACL.4th:
- Block 2066: CA root placeholder constants (
ACL-CA-KEY-LO/ACL-CA-KEY-HI) - Block 2067: Calls
ACL-BOOTthenS" zuse.4th" EXEC
ACL-BOOT stamps default ACL entries on all existing dictionary words.
After it runs, every subsequent : definition gets an ACL entry via the
defining-word hook. No word can exist without an ACL entry.
Emergency Console — 100% Bypass
vm->emergency_console is set by the C layer when the physical ok> REPL
is active. It is checked first, before any ACL table lookup. Physical
presence always wins. The emergency console is never subject to ACL
constraints regardless of what ACL.4th defines.
The EMERGENCY_CONSOLE_ENABLED=0 build flag strips the interactive
fallthrough for production or embedded builds, routing faults to
vm_fault_handler() instead.
ACL.4th — Pure FORTH Implementation
The ACL table is a CREATEd FORTH array indexed by execution token (XT).
' (tick) gives the XT of any word; XT is just a cell value usable as a
table key.
Core words:
| Word | Stack | Description |
|---|---|---|
ACL-ENTRY |
( xt -- addr ) |
O(1) table lookup by XT |
ACL-MODE@ |
( xt -- mode ) |
read enforcement mode |
ACL-MODE! |
( mode xt -- ) |
set mode (no-op if pinned) |
ACL-PINNED? |
( xt -- flag ) |
test pin bit |
ACL-PIN |
( xt -- ) |
set pin — one-way, irreversible |
ACL-STRICT |
( xt -- ) |
set STRICT mode (no-op if pinned) |
ACL-TTL-MODE |
( xt -- ) |
set TTL mode (no-op if pinned) |
ACL-TTL@ |
( xt -- n ) |
read current TTL counter |
ACL-TTL! |
( n xt -- ) |
write TTL counter |
ACL-ALLOW@ |
( xt -- flag ) |
read cached allow/deny decision |
ACL-ALLOW! |
( flag xt -- ) |
write allow/deny decision |
ACL-INHERIT |
( src dst -- ) |
birth inheritance: copy mode, clear pin, reset ttl+decision |
ACL-RECHECK |
( xt -- ) |
adaptive TTL recomputation; updates allow + new TTL |
ACL-INIT-PRIMITIVES |
( -- ) |
bulk-initialize ACL entries for all existing dictionary words |
Example pin at boot in init.4th:
' BIRTH ACL-STRICT ' BIRTH ACL-PIN
' EXEC ACL-STRICT ' EXEC ACL-PIN
' BYE ACL-STRICT ' BYE ACL-PIN
Bootstrap Sequence
\ In init.4th (one line, opt-in toggle — uncomment to enable):
S" ACL.4th" EXEC \ self-activating: calls ACL-BOOT then loads zuse.4th
\ ACL.4th Block 2067 does internally:
ACL-BOOT \ stamp default ACLs on all existing words
S" zuse.4th" EXEC \ load and pin Zuse's words
\ Subsequent capsule loads (e.g. doe.4th) get ACL entries via : hook
S" doe.4th" EXEC
Every : definition after ACL-BOOT runs creates its own ACL entry at
definition time via a hook in the defining word. No word is ever born
without an ACL entry.
Capsule Namespace
| File | Role |
|---|---|
init.4th |
Mama VM personality (default); contains opt-in ACL toggle |
init-*.4th |
Alternate personalities |
doe.4th |
DoE experiment harness |
ACL.4th |
Word-level ACL subsystem — self-activating; loads zuse.4th |
zuse.4th |
Bootstrap superuser personality; words pinned by ACL-ZUSE-BOOT |
std-blob.4th |
Standard library layer (future) |
Implementation Punch List
Phase 1 — C Infrastructure (master) ✅ COMPLETE
- Add
acl_ttl(uint32_t) toDictEntryininclude/vm.h - Add
acl_allow(uint8_t) toDictEntry - Add
acl_mode(uint8_t: STRICT=0 / TTL=1) toDictEntry - Add
acl_pinned(uint8_t) toDictEntry - Default-initialize all four fields in
word_register():ttl=ACL_OPEN, allow=1, mode=TTL, pinned=0 - Add
emergency_console(uint8_t) flag toVMstruct - Add
zuse_session(uint8_t) flag toVMstruct - Insert two-level ACL check into interpreter loop in
vm.c - Implement
acl_recheck()invm.c— calls FORTHACL-RECHECKwhen TTL=0; save/restoreemergency_consolefor re-entrancy protection - Add
:definition hook to create ACL entry for each newly defined word
Phase 2 — C Primitive Words + ACL.4th Capsule (master) ✅ COMPLETE
- 12 C primitive words in
src/word_source/acl_words.c CREATE ACL-TABLEsized to max dictionary entriesACL-ENTRY ( xt -- addr )— XT-indexed O(1) lookup- Field accessors:
ACL-MODE@,ACL-MODE!,ACL-PINNED?,ACL-TTL@,ACL-TTL!,ACL-ALLOW@,ACL-ALLOW! ACL-PIN ( xt -- )— one-way ratchet; no-op if already pinnedACL-STRICT ( xt -- )— set STRICT mode; no-op if pinnedACL-TTL-MODE ( xt -- )— set TTL mode; no-op if pinnedACL-INHERIT ( src-xt dst-xt -- )— copy mode, clear pin, reset ttl+decisionACL-RECHECK ( xt -- )— recompute adaptive TTL from heat and rolling window; updateacl_allowand reset counterACL-INIT-PRIMITIVES— walk dictionary, create default entry per word- Pin privileged words:
BIRTH,EXEC,BYE, and other Mama-only words
Phase 3 — capsules/ACL.4th Self-Activating Capsule (master) ✅ COMPLETE
ACL.4this self-activating: Block 2067 callsACL-BOOTthenS" zuse.4th" EXEC- Block 2066: CA root placeholder constants (
ACL-CA-KEY-LO/ACL-CA-KEY-HI) ACL-BOOTstamps default ACL entries on all existing dictionary wordscapsules/zuse.4thloaded at end ofACL.4thcapsule- Zuse's words pinned by
ACL-ZUSE-BOOTat load time
Phase 4 — init.4th Opt-In Toggle (master) ✅ COMPLETE
init.4thhas one commented-out line as the opt-in toggle:\ S" ACL.4th" EXEC- Uncomment to enable full lockdown; leave commented for dev/open mode
- No other changes to
init.4threquired —ACL.4this self-contained
Phase 5 — POST Tests (master) ✅ COMPLETE
POST tests implemented in src/test_runner/modules/acl_words_test.c,
registered in src/test_runner/test_runner.c. 800/800 passing.
- POST test:
ACL-PINis one-way — mode cannot change after pin set - POST test: inheritance — child entry has mode copied, pin cleared, ttl and decision reset
- POST test: emergency console bypass —
emergency_console=1skips ACL check entirely - POST test: STRICT mode — ACL re-evaluated on every execution
- POST test: TTL hot path — TTL > 0 bypasses re-evaluation
- POST test: adaptive accumulator — heat increase produces TTL increase
- POST test: privileged words pinned at boot remain pinned after
ACL-INIT-PRIMITIVES
Phase 6 — Isabelle/HOL Formal Verification (master) ✅ COMPLETE
Five .thy files in proof/ alongside existing VM proofs:
ACL_Pin_Monotone.thy— pin bit is set-only; no operation clears it once setACL_Inherit_Clears_Pin.thy—ACL-INHERITalways produces an entry withacl_pinned = 0regardless of source entry stateACL_TTL_Bounded.thy— TTL counter is bounded above byACL-TTL-COMPUTEoutput; cannot grow unboundedlyACL_Emergency_Bypass.thy— whenemergency_console = 1the allow/deny decision is never consultedACL_No_Escalation.thy— a child VM cannot produce a pinned entry with higher privilege than its inherited mode
Phase 7 — LithosAnanke Parity (COMPLETE — independently verified)
There is no separate lithosananke branch to merge/port to (post-split, this repo's master
is the sole production line) — that framing is stale. Verified present directly in current
master: acl_recheck()/zuse_session/emergency_console wiring confirmed in
src/starkernel/vm/vm_core.c; the per-iteration emergency_console = zuse_session ? 0 : 1
assignment confirmed in src/starkernel/repl.c; the old !vm->zuse_session ACL-check bypass
confirmed absent from src/vm.c. See .claude/CLAUDE.md's Word-Level ACL System section for
the full verification writeup.
- Verify
ACL.4thloads cleanly in kernel context (freestanding) ACL-BOOTruns at kernel boot before firstBIRTHvm->emergency_consolewired to kernel REPL active flagvm->zuse_sessionwired to kernel Zuse console authentication path- Three-arch acceptance: amd64, aarch64, riscv64 boot to
ok>with ACL active and no regressions - Acceptance logs — this repo's standing convention commits every acceptance boot's serial
log under
logs/, not a one-time Phase 7 action
Phase 8 — PKI / Thumbdrive Authentication (FUTURE)
- Ed25519 challenge-response authentication for Zuse thumbdrive
tools/mkcapsuleembeds real Ed25519 CA key intoACL.4thBlock 2066 at build time (replacing zero placeholder)- User minting: admin creates thumbdrive with CA-signed certificate + home block image
- Lose the drive → admin mints a new one; no software recovery path by design
zuse.4thbecomes the bootstrapper that validates the physical drive before granting Zuse session access