Compare commits
+598
-13
@@ -1771,24 +1771,45 @@ pubkey-based model — flagged, not silently reused.
|
|||||||
resolves via the drive's own identity record. */
|
resolves via the drive's own identity record. */
|
||||||
uint8_t acl_allow; /* cached fast-deny bit, checked first -- vm.c:611-624's exact
|
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. */
|
pattern, applied to a block instead of a word. */
|
||||||
uint8_t acl_reserved[7]; /* explicitly undecided -- deliberate slack per "flexibility
|
uint32_t acl_ttl; /* countdown, same shape as DictEntry's acl_ttl -- decided
|
||||||
until we understand the recipe," not a placeholder to fill
|
2026-09-02 (FABRIC-3.md §H.6/§H.9 item 5): blocks need
|
||||||
reflexively. */
|
temporary elevation too, same ACL-TTL-reuse mechanism as the
|
||||||
|
word card (§H.5). Kept lean -- "lean, TTL only" -- no
|
||||||
|
acl_mode/acl_pinned mirror, a block isn't "pinned"/"strict"
|
||||||
|
the way a word is. */
|
||||||
|
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. */
|
uint64_t reserved_future; /* untouched budget, same reasoning. */
|
||||||
```
|
```
|
||||||
`flags` (already existing, already generic) does double duty as the **state** field from
|
`flags` (already existing, already generic, `uint64_t` on `blk_meta_t`, confirmed unused —
|
||||||
Step 1 — no new field, just future-defined bit values (`CLAIMED`/`MIGRATING`/`STALE`/etc.).
|
zero callers) does double duty as the **state** field from Step 1. **Bit values decided
|
||||||
Everything else in `blk_meta_t` (`checksum`, timestamps, `content_type`, hash, chain links,
|
2026-09-02**: orthogonal bits, not a mutually-exclusive enum — a block can be both
|
||||||
`app_data[15]`) is untouched.
|
`CLAIMED` and `MIGRATING` at once. Starting set: bit 0 = `CLAIMED`, bit 1 = `MIGRATING`
|
||||||
|
(serves `MIGSM`), bit 2 = `STALE` (serves `UNCLEAN` — interrupted flush), remaining 61 bits
|
||||||
|
reserved. Everything else in `blk_meta_t` (`checksum`, timestamps, `content_type`, hash,
|
||||||
|
chain links, `app_data[15]`) is untouched.
|
||||||
4. **Allocation granularity**: claims quantize to whole devblocks (3 Forth blocks), matching
|
4. **Allocation granularity**: claims quantize to whole devblocks (3 Forth blocks), matching
|
||||||
the existing packing — a cell never needs to describe partial-devblock ranges.
|
the existing packing — a cell never needs to describe partial-devblock ranges.
|
||||||
|
|
||||||
**Not yet scoped (deferred within this node):** the actual allow-list/grant shape beyond the
|
**Resolved 2026-09-02:** blocks need temporary elevation, reusing the same `ACL-TTL`
|
||||||
single fast-deny bit (lands in `acl_reserved`, once designed); the specific `flags` bit
|
mechanism as the word card, gated the same way by Zuse's eligibility list (§H.5) — see the
|
||||||
values for each state; whether `blk_get_meta()`/`blk_set_meta()` need new FORTH word wrappers
|
`acl_ttl` field added above. Also resolved same day: the `flags` bit values above.
|
||||||
or stay C-only like `zuse_cert_seed`'s "no FORTH access" precedent; the actual repurposing
|
|
||||||
edit to `block_subsystem.h`/`.c` itself (this pass produced the field design, not the code
|
**Decided 2026-09-02: yes, FORTH wrappers.** Mirrors the existing word-level ACL split
|
||||||
change).
|
exactly — raw C accessors (e.g. `BLK-ACL-ALLOW@`/`!`, `BLK-ACL-TTL@`/`!`, `BLK-OWNER@`), actual
|
||||||
|
elevation/policy logic composed in FORTH on top, presumably a new capsule alongside `ACL.4th`
|
||||||
|
— per this project's own standing hard rule ("ACL policy belongs in `ACL.4th`, never in C...
|
||||||
|
Compose in FORTH first"). `zuse_cert_seed`'s "no FORTH access" is a different case, not a
|
||||||
|
counter-precedent: that field is private signing-key material, walled off from FORTH for
|
||||||
|
key-material-specific reasons — block ACL fields (`owner_fp`, `acl_allow`, `acl_ttl`, `flags`
|
||||||
|
bits) are ordinary ACL state, same category as `DictEntry`'s `acl_allow`/`acl_ttl` (which
|
||||||
|
already have FORTH accessors), not key material.
|
||||||
|
|
||||||
|
**Only remaining open item on this whole node**: the actual code edit to
|
||||||
|
`block_subsystem.h`/`.c` plus the new FORTH-wrapper primitives and policy capsule — field/API
|
||||||
|
design is now fully decided across this pass and the two before it (`acl_ttl`, `flags` bit
|
||||||
|
values, this FORTH-wrapper decision), nothing implemented yet.
|
||||||
|
|
||||||
### F.5 — `WIREBIND` (breadcrumb only — followed into `RUNCAP` instead, 2026-08-27)
|
### F.5 — `WIREBIND` (breadcrumb only — followed into `RUNCAP` instead, 2026-08-27)
|
||||||
|
|
||||||
@@ -3527,3 +3548,567 @@ by refiling after lapse), so #1 is on a hard clock; **#2 (full StarshipOS) is th
|
|||||||
deliverable** that keeps the flagship covered — and, pending counsel confirmation, may be the
|
deliverable** that keeps the flagship covered — and, pending counsel confirmation, may be the
|
||||||
conversion vehicle for #1. Authoritative form in `ROADMAP.md` "IP framing of the three
|
conversion vehicle for #1. Authoritative form in `ROADMAP.md` "IP framing of the three
|
||||||
products".
|
products".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## H. Session refactor, back to Hera — session struct shape + identity/ACL card model (capture, 2026-09-02)
|
||||||
|
|
||||||
|
Captain Bob announced a major refactor reaching all the way back to Hera's own boot sequence:
|
||||||
|
formally introduce **session** as a first-class concept at the root of the system, rather than
|
||||||
|
bolted on later. This sharpens and extends D.2's 2026-08-27 correction ("a session is any VM
|
||||||
|
client running in the Stadium fabric... Zuse is a player like any other") into a concrete
|
||||||
|
struct shape and, from there, into a full identity/ACL model. **Capture-only pass, matching
|
||||||
|
this document's own established discipline** ("capture EVERYTHING first then we'll build a
|
||||||
|
plan," D's own intro) — nothing here is scoped into implementable items yet.
|
||||||
|
|
||||||
|
### H.1 — Session = Stadium patron, admission restated
|
||||||
|
|
||||||
|
- Hera defines what a session *is* (the concept/type itself). At boot, Hera registers
|
||||||
|
**herself** into her own session first. When Hera births a child VM (Hermes, then Artemis),
|
||||||
|
she also stands up a session for that child at birth time.
|
||||||
|
- **A session is a Stadium patron** — registering a session = admitting a patron to the
|
||||||
|
Stadium, not a new parallel bookkeeping structure. This is the same correction D.2 already
|
||||||
|
made ("a session IS a VM"), now traced down to the concrete admission mechanism already
|
||||||
|
live in `src/starkernel/vm/stadium.c`: `StadiumPatronHeader` (64 bytes — identity, heat,
|
||||||
|
ttl, link, contains, mass, flags [bit 0 = `STADIUM_FLAG_PIN`], behaviour, 32-byte inline
|
||||||
|
payload) and `stadium_birth_hera()`, which already admits Hera as patron zero, pinned, via
|
||||||
|
`stadium_admit(vm_uuid_hera(), &candidate)`. No `stadium_birth_hermes()`/`_artemis()`
|
||||||
|
equivalent exists yet — Hera is the only admitted patron today.
|
||||||
|
- **Pinned** sessions (Hermes, Artemis — the VMs Hera births at boot) are patrons exempt from
|
||||||
|
the normal departure path (heat decay / `COOL`): they never leave, permanently.
|
||||||
|
- Core unifying principle, in the user's own words: **"a process and a virtual machine are
|
||||||
|
going to be exactly the same thing"** inside this OS — VM identity, process identity, and
|
||||||
|
session become one concept, not three.
|
||||||
|
- **A session is a Stadium patron** *(Captain Bob, confirming): "Oh, yeah. God. This is...
|
||||||
|
this becomes a patron of the stadium, I believe, session, that is."* Pinned patrons are
|
||||||
|
exempt from the normal departure path (heat decay / `COOL`) — they never leave.
|
||||||
|
- **Resolved 2026-09-02**: yes, a non-pinned session (an ordinary Stadium patron subject to
|
||||||
|
`COOL`) is where an ephemeral user VM's session lands. Synthesized from D.2's earlier
|
||||||
|
finding rather than a fresh decision — D.2 (2026-08-27) already established "ending a
|
||||||
|
session is a VM detach... far closer to the existing, real, working `COOL`/
|
||||||
|
`capsule_vm_kill()` path" for user sessions tied to a thumbdrive; thumbdrive detach is the
|
||||||
|
explicit trigger, not just passive heat decay while idle. Pinned system VMs (Hera, Hermes,
|
||||||
|
Artemis) are permanently exempt from `COOL` regardless of idle state; non-pinned user VMs
|
||||||
|
are exempt from nothing. No exception case (e.g. a user VM temporarily pinned while
|
||||||
|
actively attached) — ruled out, confirmed as-is.
|
||||||
|
- **`EXPIRE`/D.2 relationship, resolved 2026-09-02**: no actual conflict between D.2 and this
|
||||||
|
section — D.2 was scoped to *user* sessions (thumbdrive attach/detach), written before
|
||||||
|
Hera/Hermes/Artemis were framed as having their own persistent sessions. **D.2 is a special
|
||||||
|
case of H.1, fully subsumed**: D.2 describes exactly how the non-pinned branch behaves
|
||||||
|
(detach triggers `COOL`), matching the mapping above. Pinned sessions simply have no
|
||||||
|
D.2-style "ending" at all — permanent by construction, the question D.2 was answering
|
||||||
|
doesn't apply to them.
|
||||||
|
|
||||||
|
### H.2 — Session struct shape
|
||||||
|
|
||||||
|
Confirmed: **a session is a NEW structure, separate from `StadiumPatronHeader`, that
|
||||||
|
references the patron by `VMUuid`** — not the patron header itself, and not indexed by
|
||||||
|
Stadium cell index. Gets its own header file, same precedent as `VMUuid`/planned-`VMIdentity`
|
||||||
|
(never grow `struct VM` or `StadiumPatronHeader` with inline fields for this).
|
||||||
|
|
||||||
|
Confirmed session fields so far:
|
||||||
|
- `vm_id` (`VMUuid`) — the patron this session references.
|
||||||
|
- `pinned` — **session is authoritative**; Stadium's `STADIUM_FLAG_PIN` bit follows the
|
||||||
|
session's value, not the other way around.
|
||||||
|
- `parent` (`VMUuid`) — who birthed this session (Hera → Hermes/Artemis). **Confirmed
|
||||||
|
as-is 2026-09-02.**
|
||||||
|
- `name` — canonical human-readable name (feeds `console.c`'s `g_active_vm_name` prefix,
|
||||||
|
doesn't replace the console-binding mechanism itself). **Confirmed as-is 2026-09-02.**
|
||||||
|
- `identity` — lives directly embedded in the session struct (confirmed). Contents: the
|
||||||
|
ACL "stack of cards" model, H.3 onward.
|
||||||
|
|
||||||
|
**All five session fields are now confirmed**, none still model-proposed-only. **User's own
|
||||||
|
framing, explicit and important**: "the floor was, who knows? We're gonna be revisiting this
|
||||||
|
part of it around and around for a while." Confirmed-now doesn't mean locked-forever — treat
|
||||||
|
this field list as a live, expected-to-churn working draft, just no longer an open gap.
|
||||||
|
|
||||||
|
### H.3 — Identity model: ACL "stack of cards"
|
||||||
|
|
||||||
|
Identity carries the VM's/word's ACL as a **stack of cards, each with pinholes punched through
|
||||||
|
it** — user's own framing: "a stack of cards... got pinholes going through it, and those
|
||||||
|
pinholes drop all the way down through and give the permission for whatever we're
|
||||||
|
work[ing on]... a set of graduated sieves." Confirmed accurate by the user.
|
||||||
|
|
||||||
|
**Each card is one permission dimension**, not a redundant extra layer of the same check —
|
||||||
|
named dimensions: VM, word, block, message. A compound action (e.g. "execute word X, which
|
||||||
|
touches block Z and sends message M") passes through the word card, the block card, and the
|
||||||
|
message card at once — one card per relevant axis. **Confirmed: an action only consults the
|
||||||
|
cards for the dimensions it actually touches** — a pure VM-level operation only checks the VM
|
||||||
|
card, not the full stack every time.
|
||||||
|
|
||||||
|
**Closed set, resolved 2026-09-03**: VM, word, block, and message are the complete set — "closed
|
||||||
|
set, no new cards, naturally, subject to change." Not permanently frozen, but not open-ended
|
||||||
|
by default either — a fifth card (e.g. a "console" dimension, given the D.2b pentagon names
|
||||||
|
Console as a full peer node) would be a deliberate future decision, not something implicitly
|
||||||
|
already on the table.
|
||||||
|
|
||||||
|
**Word-ACL reconciliation resolved 2026-09-02.** Checked `capsules/ACL.4th` directly: both
|
||||||
|
existing modes (`STRICT` — "always allow, TTL stays 0 (recheck always)"; `TTL` — "compute TTL
|
||||||
|
from heat; set allow=1") already default to `allow=1` — no path in the current system denies
|
||||||
|
by default, already matching the word card's "default-permissive baseline" almost exactly.
|
||||||
|
Since each VM has its own dictionary (H.10), the existing per-word ACL state is already
|
||||||
|
naturally scoped per-session, for free. **Confirmed: the word card is not a new parallel
|
||||||
|
structure — it's the existing `acl_ttl`/`acl_allow`/`acl_mode`/`acl_pinned` system, wholesale,
|
||||||
|
reused as-is.** The stack-of-cards framing is new vocabulary for what already exists, not a
|
||||||
|
new mechanism.
|
||||||
|
|
||||||
|
**The one genuinely new piece, not present in today's system at all**: creator-ceiling
|
||||||
|
enforcement. Nothing today caps a newly-birthed VM's word-ACL state against its parent's.
|
||||||
|
|
||||||
|
**Mechanism decided 2026-09-03, after a mid-conversation reversal.** First proposed: hook the
|
||||||
|
ceiling check into the existing `ACL-RECHECK` cold path (checked later, no birth-time copy) —
|
||||||
|
initially agreed, but this runs into a real problem: each VM has an entirely separate
|
||||||
|
`DictEntry` dictionary (H.10), so `ACL-RECHECK` running inside a child would need a live
|
||||||
|
cross-VM lookup back to the parent's own dictionary state, never designed. On seeing this, the
|
||||||
|
user reconsidered: **"perhaps a fast copy might be cheaper and just as effective."**
|
||||||
|
|
||||||
|
**Final: birth-time snapshot, no live sync, ever.** The child's `acl_allow`/`acl_mode`/
|
||||||
|
`acl_pinned`/`acl_ttl` are copied from the parent once, at birth — no ongoing reference back
|
||||||
|
to the parent afterward, which solves the cross-VM lookup problem outright. The child's own
|
||||||
|
ACL state can still grow/shrink dynamically after birth (the word card's "additive/subtractive"
|
||||||
|
framing still holds); it just starts from the snapshot rather than staying synced to the
|
||||||
|
parent's *current* state. **Explicit rationale, user's own words**: "if something was
|
||||||
|
developed with a particular set of ACLs, it should remain at that — otherwise parent changes
|
||||||
|
break the child's program." Program stability for the child, not administrative convenience,
|
||||||
|
is why live-sync was rejected.
|
||||||
|
|
||||||
|
### H.4 — VM card
|
||||||
|
|
||||||
|
Narrow by design: a single base gate ("who owns / can-touch this VM at all") that other, finer
|
||||||
|
checks sit on top of. Does not itself enumerate operations (birth/kill, console attach,
|
||||||
|
retarget, quota grant, etc.) — those are finer-grained checks built elsewhere.
|
||||||
|
|
||||||
|
- **Zuse is entirely outside the card stack**: "forget Zeus [Zuse]. Zeus will always have 100
|
||||||
|
percent authority" — unconditional, not modeled as an always-allowed path *through* the VM
|
||||||
|
card the way the earlier `ACLKEY` pass (§F.2) had framed it. Zuse bypasses the card stack
|
||||||
|
entirely, full stop.
|
||||||
|
- **Single owner, for now**: exactly one `owner_pubkey` per VM at this gate (match or no
|
||||||
|
match), not a list of authorized identities — "single owner for now," multi-owner
|
||||||
|
explicitly deferred, not in scope.
|
||||||
|
- Matches the `VMIdentity{owner_pubkey[32], installed}` shape already decided in the earlier
|
||||||
|
`ACLKEY` pass (§F.2) — the VM card is effectively that ownership check, non-Zuse case only.
|
||||||
|
|
||||||
|
### H.5 — Word card
|
||||||
|
|
||||||
|
- **Default-permissive baseline**: "will have to pretty much admit any word" — not a
|
||||||
|
default-deny gate that has to explicitly enumerate everything.
|
||||||
|
- **Dynamic, not fixed**: ACLs at this card are "additive/subtractive dynamic entities" — the
|
||||||
|
permission set can grow or shrink over the session's lifetime, not a static list decided
|
||||||
|
once at creation.
|
||||||
|
- **Hard ceiling invariant**: "they can never exceed the creator's permissions" — a session's
|
||||||
|
word permissions can never exceed what its own creator/parent had. Delegation is capped by
|
||||||
|
the parent's own permission set — presumably where H.2's `parent` field earns its keep.
|
||||||
|
- **Escape hatch, mechanism confirmed reused**: the only way to temporarily exceed that
|
||||||
|
creator-ceiling is "some kind of temporary Zuse power" — **confirmed reuse of the existing,
|
||||||
|
already-built-and-measured `ACL-TTL` mechanism** (`acl_ttl` field on `DictEntry`), not a new
|
||||||
|
parallel temporary-grant mechanism.
|
||||||
|
- **Mechanism grounded, checked directly against `capsules/ACL.4th`**: the existing `ACL-TTL`
|
||||||
|
machinery is a recheck-cadence cache, not itself a grant mechanism — the real C-exposed
|
||||||
|
primitives are `ACL-ALLOW!`/`ACL-TTL!` (`ACL-RECHECK` recomputes TTL from execution heat and
|
||||||
|
sets `allow`). Reusing it for elevation means Zuse-triggered code calls these same
|
||||||
|
primitives directly, setting `allow=1` with a TTL that counts down to expiry.
|
||||||
|
- **Trigger, decided 2026-09-02: live message-based request, kept deliberately simple.**
|
||||||
|
Three options were weighed — message-based request/grant, a live-console `sudo`-style
|
||||||
|
command, and a pre-signed capability ticket decoupling grant-time from use-time — user
|
||||||
|
picked the first: "live request, keep it simple for now." Rides the H.7 messaging protocol:
|
||||||
|
the requesting session posts a request (working name `ELEVATE-REQUEST`) on `common` or a
|
||||||
|
private topic with Zuse, Zuse's session responds grant/`NACK`, and the
|
||||||
|
`ACL-ALLOW!`/`ACL-TTL!` write happens on receipt. Fits the standing "nothing is done until
|
||||||
|
it's real Hermes messages" completion criterion (D.1). The other two options are explicitly
|
||||||
|
deferred, not rejected — "keep it simple for now" scopes this decision to the live-request
|
||||||
|
path only.
|
||||||
|
- **Eligibility gate on top of the trigger, user-proposed**: "maybe zuse keeps a list of users
|
||||||
|
that can be granted zuse caps?" — confirmed as a gating layer, not a replacement for the
|
||||||
|
trigger. Zuse checks this list (keyed by `owner_pubkey`, matching H.4's single-owner
|
||||||
|
VM-card shape) before honoring any elevation request.
|
||||||
|
- **Storage decided 2026-09-03**: persists across reboots, living in Zuse's already-built
|
||||||
|
growable metadata fence at the top of Artemis's block device (the same mechanism that
|
||||||
|
already persists Zuse's own `zuse_cert_devblock_t` identity — see Phase 8/Milestone 6).
|
||||||
|
Shape: a simple growable list of `owner_pubkey[32]` entries, no extra per-entry metadata —
|
||||||
|
"simple list, no extra metadata, unless we find a reason this won't work" (provisional
|
||||||
|
lean-by-default, not a permanent ban on adding fields later). Not yet designed: the actual
|
||||||
|
record format added to the metadata fence; how entries get added (presumably a Zuse-only
|
||||||
|
FORTH word, unbuilt); exact relationship to the still-unbuilt `MINT`-a-second-identity flow.
|
||||||
|
|
||||||
|
### H.6 — Block card
|
||||||
|
|
||||||
|
**Confirmed: reuses the already-decided `BMAPFMT` design** from §F.4 — distributed per-block
|
||||||
|
ownership, not a new mechanism. Repurposes the dormant, fully-wired, zero-caller `blk_meta_t`
|
||||||
|
struct: 8-byte owner-pubkey fingerprint + 1-byte fast-deny `acl_allow`, with deliberate
|
||||||
|
reserved slack in the 40-byte block ("flexibility until we understand the recipe"). No
|
||||||
|
separate centralized block-ownership table (makes `homeblocks_sig_t`'s reserved
|
||||||
|
`blockmap_offset`/`blockmap_devblocks` fields unnecessary, already flagged for cleanup).
|
||||||
|
|
||||||
|
**Extended 2026-09-02**: blocks need temporary elevation too, same `ACL-TTL`-reuse mechanism
|
||||||
|
and Zuse-eligibility-list gating as the word card (H.5) — `acl_reserved` in §F.4's layout
|
||||||
|
became a 4-byte `acl_ttl` (mirroring `DictEntry`'s countdown shape) plus 3 bytes still-open
|
||||||
|
slack, kept lean rather than fully mirroring `DictEntry`'s `acl_mode`/`acl_pinned` too
|
||||||
|
("lean, TTL only" — a block isn't "pinned"/"strict" the way a word is).
|
||||||
|
|
||||||
|
**`flags` bit values decided 2026-09-02**: `blk_meta_t`'s existing `flags` field (`uint64_t`,
|
||||||
|
doubling as block state) uses orthogonal bits, not a mutually-exclusive enum. Starting set:
|
||||||
|
bit 0 = `CLAIMED`, bit 1 = `MIGRATING` (serves `MIGSM`), bit 2 = `STALE` (serves `UNCLEAN`),
|
||||||
|
remaining 61 bits reserved.
|
||||||
|
|
||||||
|
**FORTH-wrapper question decided 2026-09-02: yes.** Mirrors the word-level ACL split — raw C
|
||||||
|
accessors (`BLK-ACL-ALLOW@`/`!`, `BLK-ACL-TTL@`/`!`, `BLK-OWNER@`), policy composed in FORTH on
|
||||||
|
top. `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 (TTL + flags bits + FORTH wrappers) is now fully complete but
|
||||||
|
**the code change was never made** — this refactor is presumably where it finally lands.
|
||||||
|
|
||||||
|
### H.7 — Messaging protocol: not groundwork, already real code (verified 2026-09-02)
|
||||||
|
|
||||||
|
Originally captured as design vision — **upgraded 2026-09-02** after checking
|
||||||
|
`capsules/common/messaging.4th` directly instead of assuming. The protocol described below
|
||||||
|
isn't a future design, it's already substantially built:
|
||||||
|
|
||||||
|
- **PubSub, decided.** Terminology is **"topics"** — the existing code's own term is
|
||||||
|
"channel"/`CH`. **Resolved: `CH` already *is* the topic, 1:1, no new representation
|
||||||
|
needed** — "topic" is just today's newly-adopted vocabulary for what the code already calls
|
||||||
|
a channel.
|
||||||
|
- **Every VM always subscribes to one well-known "common" topic.** Real: `COMMON-CH`, the
|
||||||
|
actual variable holding the one canonical common channel, owned by Hermes and wired into
|
||||||
|
`hermes/init.4th` at boot (`CH-ADD-MBR` adds members 0 and 1).
|
||||||
|
- **Handshake flow, real functions**: `CH-REQUEST ( type from to paddr plen -- )` — checks
|
||||||
|
`COMMON-CH` is `CH-OPEN`, sends via `MSG-SEND` — is literally "post a message on `common`
|
||||||
|
requesting a commune." `CH-ACCEPT ( -- ch|0 )` — the receiving side allocates a new private
|
||||||
|
channel, marks it `CH-NEGOTIATING`. `CH-CONFIRM ( ch -- )` transitions
|
||||||
|
`CH-NEGOTIATING` → `CH-OPEN`. `CH-CLOSE ( ch -- )` tears a channel down (`CH-CLOSING`).
|
||||||
|
- **ACK/NACK, real**: `MSG-ACK-LAST`/`MSG-NACK-LAST`/`MSG-NACKED` (253) — "purely local, no
|
||||||
|
VM-EXEC indirection" per the code's own comment — a general reliability mechanism applied to
|
||||||
|
every message on any topic, not specific to the handshake step.
|
||||||
|
|
||||||
|
### H.8 — Message card
|
||||||
|
|
||||||
|
**Scope confirmed narrow and one-sided**: gates only "who's allowed to post on `common`
|
||||||
|
requesting a commune" — the *initiating* side of the H.7 handshake, i.e. who's allowed to
|
||||||
|
call the real `CH-REQUEST` function above. The receiving VM's decision to accept/ACK (i.e.
|
||||||
|
`CH-ACCEPT`) is **not** gated by this card.
|
||||||
|
|
||||||
|
**Private-topic traffic gating, resolved 2026-09-02**: checked `MSG-SEND`
|
||||||
|
(`capsules/common/messaging.4th:213`, the underlying primitive both `CH-REQUEST` and any
|
||||||
|
private-topic traffic use) directly — no ACL check anywhere in it today, purely mechanical.
|
||||||
|
**Confirmed: private-topic traffic stays ungated.** Trust is established once at the
|
||||||
|
handshake, and nothing re-checks permission on every subsequent message within an
|
||||||
|
already-open private topic — consistent with this card's own narrow scope and the elevation
|
||||||
|
trigger's "keep it simple for now."
|
||||||
|
|
||||||
|
**The message card's full, final scope**: gates only the single call to `CH-REQUEST`.
|
||||||
|
Nothing else in the messaging path is ACL-gated by design.
|
||||||
|
|
||||||
|
**Implementation-gap note (2026-09-02)**: since `CH-REQUEST` is real, already-callable code
|
||||||
|
with no ACL gate in front of it today, this card's job is a concrete, well-targeted wiring
|
||||||
|
task — add the gate check to the real function — rather than a hypothetical one waiting on
|
||||||
|
future messaging infrastructure. Not yet built.
|
||||||
|
|
||||||
|
### H.9 — Gap analysis (as of 2026-09-02)
|
||||||
|
|
||||||
|
Explicitly open items surfaced during this capture pass, none decided yet:
|
||||||
|
|
||||||
|
1. **CLOSED 2026-09-02 — non-pinned session mapping (H.1).** Yes — an ephemeral user VM's
|
||||||
|
session lands as a non-pinned, `COOL`-subject Stadium patron, thumbdrive detach as the
|
||||||
|
explicit trigger (synthesized from D.2's earlier finding). No exception case for a
|
||||||
|
temporarily-pinned user VM.
|
||||||
|
2. **CLOSED 2026-09-02 — `parent` and `name` session fields (H.2).** Confirmed as-is, no
|
||||||
|
adjustment. All five session fields now confirmed (still subject to the general
|
||||||
|
"revisiting... around and around" caveat, but no longer an open gap specifically).
|
||||||
|
3. **CLOSED 2026-09-02 — word-level ACL reconciliation (H.3).** The word card *is* the
|
||||||
|
existing `acl_ttl`/`acl_allow`/`acl_mode`/`acl_pinned` system, wholesale, no new parallel
|
||||||
|
structure. New follow-on gap surfaced by this closure: creator-ceiling enforcement at VM
|
||||||
|
birth time isn't designed anywhere yet (nothing today caps a child's word-ACL state against
|
||||||
|
its parent's).
|
||||||
|
4. **CLOSED 2026-09-02 — temporary-elevation invocation path (H.5).** Trigger decided: a live
|
||||||
|
message-based request (`ELEVATE-REQUEST` on `common` or a private topic, Zuse's session
|
||||||
|
grants/`NACK`s, write happens on receipt via `ACL-ALLOW!`/`ACL-TTL!`), gated by a
|
||||||
|
Zuse-held eligibility list keyed by `owner_pubkey`. Still open underneath this closure: the
|
||||||
|
eligibility list's exact representation/storage, and the two explicitly-deferred (not
|
||||||
|
rejected) alternate triggers — live-console `sudo`-style grant, and pre-signed capability
|
||||||
|
tickets.
|
||||||
|
5. **`BMAPFMT` code change (H.6).** Field design was finished in the §F.4 pass but the actual
|
||||||
|
code edit to `blk_meta_t` was never made — a real, concrete implementation gap, not just an
|
||||||
|
open question.
|
||||||
|
6. **CLOSED 2026-09-02 — topic/`CH` reconciliation (H.7).** `CH` already *is* the topic, 1:1.
|
||||||
|
Bigger than expected: this check also upgraded all of H.7/H.8 from "protocol vision" to
|
||||||
|
"already real code" (`COMMON-CH`, `CH-REQUEST`, `CH-ACCEPT`, `CH-CONFIRM`, `CH-CLOSE`,
|
||||||
|
`MSG-ACK-LAST`/`MSG-NACK-LAST` all exist and work today in `capsules/common/messaging.4th`).
|
||||||
|
The message card's gate is now a concrete wiring task onto a real function, not a
|
||||||
|
hypothetical one waiting on future infrastructure.
|
||||||
|
7. **CLOSED 2026-09-02 — private-topic traffic gating (H.8).** Confirmed ungated — `MSG-SEND`
|
||||||
|
has no ACL check today; trust is established once at the handshake, nothing re-checks
|
||||||
|
permission afterward. The message card's scope is now final: it gates `CH-REQUEST` alone.
|
||||||
|
8. **CLOSED 2026-09-02 — the `EXPIRE`/D.2 relationship.** No conflict — D.2 is a special case
|
||||||
|
of H.1, fully subsumed (D.2 describes the non-pinned branch specifically; pinned sessions
|
||||||
|
have no D.2-style "ending" at all).
|
||||||
|
9. **Every other card beyond the four named** (VM, word, block, message) — the model list is
|
||||||
|
confirmed as the *named-so-far* set, not stated as closed/exhaustive.
|
||||||
|
10. **No implementation has started.** Every item above, and every card definition in
|
||||||
|
H.4–H.8, is design capture only — no struct has been written, no `stadium_birth_hermes()`/
|
||||||
|
`_artemis()` exists, no `Session` header exists. Standard for this document's own
|
||||||
|
discipline (see D's intro), but worth stating plainly given the size of this section.
|
||||||
|
|
||||||
|
### H.10 — Verification pass: "are we painting ourselves into a corner?" (2026-09-02)
|
||||||
|
|
||||||
|
Asked directly by Captain Bob. One load-bearing assumption underneath H.3/H.5 got checked
|
||||||
|
against the live code rather than left as an inference.
|
||||||
|
|
||||||
|
**The risk**: the word card's creator-ceiling invariant and the H.5 elevation trigger both
|
||||||
|
live on `DictEntry` (`acl_allow`/`acl_ttl`), which only works per-session if each VM has its
|
||||||
|
own separate dictionary — a shared/global dictionary would make a single `acl_allow` bit
|
||||||
|
unable to mean "yes for session A, no for session B" on the same word.
|
||||||
|
|
||||||
|
**Verified true, no conflict, no redesign needed.** `struct VM` (`include/vm.h:410-412`) owns
|
||||||
|
its own `uint8_t* memory` buffer and its own `DictEntry* latest` chain; `vm_bootstrap.c:181`
|
||||||
|
(`vm->memory = (uint8_t*)vm_host_alloc(vm, VM_MEMORY_SIZE, ...)`) allocates a fresh,
|
||||||
|
independent memory/dictionary buffer on every VM birth. Hera, Hermes, Artemis, and any future
|
||||||
|
child each get their own separate dictionary — `DictEntry` ACL fields are already naturally
|
||||||
|
scoped per-session. H.3's stack-of-cards model and H.5's word card/elevation trigger stand as
|
||||||
|
decided, unchanged by this check.
|
||||||
|
|
||||||
|
Two smaller, lower-risk items flagged in the same pass:
|
||||||
|
- **CLOSED 2026-09-02 — pin-authority choke point (H.2).** Session.pinned is authoritative
|
||||||
|
over Stadium's `STADIUM_FLAG_PIN` bit. Decided: **full choke point at the session level,
|
||||||
|
both directions** — both writing and reading pin state go exclusively through session-owned
|
||||||
|
functions (e.g. `session_set_pinned()` / `session_is_pinned()`); nothing, including existing
|
||||||
|
Stadium code, reads `STADIUM_FLAG_PIN` directly off the patron header anymore. Session is
|
||||||
|
the sole authority for both write and read, not just the write path.
|
||||||
|
- **Elevation trigger, updated 2026-09-02: closer to usable than first thought.** Rides Hermes
|
||||||
|
messaging — at the time this risk was flagged, assumed to not be the real implementation
|
||||||
|
yet. §H.7's later verification found the messaging substrate (`CH-REQUEST`/`CH-ACCEPT`/
|
||||||
|
`CH-CONFIRM`/ACK-NACK) is already real, working code. What's still missing is only the ACL
|
||||||
|
gate itself (H.8) and the `ELEVATE-REQUEST` message type/handler — smaller gaps than
|
||||||
|
originally flagged, not a missing substrate.
|
||||||
|
|
||||||
|
### H.11 — Gap analysis, refreshed (2026-09-02, end of session)
|
||||||
|
|
||||||
|
Full sweep across the whole design pass, not just a re-list of §H.9's original ten items — 7
|
||||||
|
of them are now closed (1, 2, 3, 4, 6, 7, 8). New sub-gaps surfaced while closing the old
|
||||||
|
ones. This supersedes §H.9 as the current accurate picture; §H.9 itself is left intact above
|
||||||
|
as historical record (each item already carries its own closure annotation inline).
|
||||||
|
|
||||||
|
**Genuinely open design question (never asked):**
|
||||||
|
1. **CLOSED 2026-09-03.** Closed set — VM, word, block, message are the complete four, no new
|
||||||
|
cards for now (see H.3).
|
||||||
|
|
||||||
|
**Small design pieces, now resolved 2026-09-03:**
|
||||||
|
2. **CLOSED.** Creator-ceiling enforcement (§H.3) is a birth-time snapshot copy, not a live
|
||||||
|
`ACL-RECHECK`-time check — decided after a mid-conversation reversal once the live-check
|
||||||
|
approach's cross-VM lookup problem surfaced.
|
||||||
|
3. **CLOSED.** Zuse's eligibility list persists in the existing metadata-fence mechanism, as a
|
||||||
|
simple `owner_pubkey[32]` list, no extra metadata (§H.5).
|
||||||
|
|
||||||
|
**Pure implementation gaps — design fully decided, nothing coded yet:**
|
||||||
|
4. `stadium_birth_hermes()`/`_artemis()` don't exist (§H.1).
|
||||||
|
5. The `Session` struct + its own header don't exist (§H.2).
|
||||||
|
6. `BMAPFMT`'s code edit to `block_subsystem.h`/`.c` (§F.4/§H.6 — field/API design fully
|
||||||
|
closed).
|
||||||
|
7. The message card's ACL gate isn't wired onto the real `CH-REQUEST` (§H.8).
|
||||||
|
8. Creator-ceiling enforcement itself — the birth-time copy logic (§H.3, design now fully
|
||||||
|
decided as of item 2's closure above, code not written).
|
||||||
|
9. The eligibility-list's actual metadata-fence record format + the Zuse-only FORTH word to
|
||||||
|
add entries (§H.5, design now fully decided as of item 3's closure above, code not
|
||||||
|
written).
|
||||||
|
|
||||||
|
**Explicitly deferred, not rejected (intentional non-goals for now):**
|
||||||
|
10. VM card multi-owner support (§H.4).
|
||||||
|
11. Elevation trigger alternates — live-console `sudo` path, pre-signed capability tickets
|
||||||
|
(§H.5).
|
||||||
|
|
||||||
|
**Remaining genuinely open design question, after this pass**: none — every design-level
|
||||||
|
question from this list is now closed. What's left is implementation (items 4–9) and
|
||||||
|
intentional deferrals (10–11).
|
||||||
|
|
||||||
|
### H.12 — Implementation punch list (2026-09-03)
|
||||||
|
|
||||||
|
One coding task per item, not a concept per item — each followed by the mandatory
|
||||||
|
amd64/aarch64/riscv64 boot acceptance test (this document's only valid acceptance criterion,
|
||||||
|
see the top-level CLAUDE.md). Grounded against live code, not the earlier design captures'
|
||||||
|
assumptions — two corrections surfaced while building this list, both noted inline below.
|
||||||
|
|
||||||
|
**Correction 1**: `stadium_birth_hermes()`/`_artemis()` (§H.11 item 4) don't need writing from
|
||||||
|
scratch. `capsule_birth.c`'s generic admission path (~lines 574–602, used for every VM birth
|
||||||
|
today) already admits every born VM as a Stadium patron — it's just hardcoded to admit them
|
||||||
|
**unpinned** (`vm_patron.flags = 0`, with a comment explicitly noting "unpinned... unlike
|
||||||
|
Hera"). The real task is making that existing path pin Hera/Hermes/Artemis specifically,
|
||||||
|
leaving ordinary/user VMs unpinned as they already correctly are.
|
||||||
|
|
||||||
|
**Correction 2**: `VMIdentity` (`include/starkernel/vm_identity.h`) already exists, fully
|
||||||
|
built — `owner_pubkey[32]` + `installed` + `acl_caps` (capability bitmask), the VM-card shape
|
||||||
|
from H.4, plus more. `Session.identity` should be a `VMIdentity`, not a new type. Its own doc
|
||||||
|
comment confirms Hera/Hermes/Artemis have no installed identity yet ("before D.5's per-VM-
|
||||||
|
identity work lands") — wiring real identities into them is part of this refactor's remaining
|
||||||
|
work, not new invention.
|
||||||
|
|
||||||
|
**Phase 1 — Session struct + pin-authority choke point**
|
||||||
|
- [x] **1. DONE 2026-09-03.** `include/starkernel/session.h`: `Session{vm_id (VMUuid), pinned
|
||||||
|
(int), parent (VMUuid), name (fixed buffer, `SESSION_NAME_BUF`=64), identity (VMIdentity,
|
||||||
|
embedded)}`. Type only, no logic. No callers yet, so this acceptance run only confirms the
|
||||||
|
header itself is syntactically clean and doesn't break the build. Verified 3-arch boot to
|
||||||
|
`ok>` (amd64/aarch64/riscv64).
|
||||||
|
- [x] **2. DONE 2026-09-03, one deviation from the original wording.**
|
||||||
|
`src/starkernel/vm/session.c` + `session_boot_init()`/`session_find(VMUuid)`/
|
||||||
|
`session_register(...)`. Not a fixed-size array as originally written here — found
|
||||||
|
`stadium.c`'s own `StadiumVMQuota` table had already been moved off a fixed array to a
|
||||||
|
`kmalloc`'d-at-boot, budget-sized one (same "population isn't knowable in advance"
|
||||||
|
reasoning), so `session.c` mirrors that current precedent instead: `session_boot_init()`
|
||||||
|
sizes the slot table from `stadium_max_vm_count()`, must run after `stadium_boot_init()`.
|
||||||
|
Added `session.c` to `Makefile.starkernel`'s explicit `LOADER_EXTRA_SRCS`/
|
||||||
|
`KERNEL_EXTRA_SRCS` list (not a wildcard build). No callers yet. Verified 3-arch boot to
|
||||||
|
`ok>`.
|
||||||
|
- [x] **3. DONE 2026-09-03, one addition found necessary.** `session_set_pinned()`/
|
||||||
|
`session_is_pinned()` implemented — the pin-authority choke point (H.2/H.10).
|
||||||
|
`session_is_pinned()` answers from `Session.pinned` directly (the authoritative copy, no
|
||||||
|
Stadium re-derivation); `session_set_pinned()` writes both `Session.pinned` and the
|
||||||
|
mirrored `STADIUM_FLAG_PIN` bit on the session's own patron header, so Stadium's own
|
||||||
|
internal eviction/admission logic (which must stay self-contained, no call back into
|
||||||
|
session.c) keeps seeing a correct bit. **Addition**: `Session` needed a `stadium_cell`
|
||||||
|
field (index into `stadium_cells()`) that wasn't in the original §H.2 field list — the
|
||||||
|
choke point can't reach the right patron header without it. Necessary plumbing, not a new
|
||||||
|
session-level concept, so not treated as reopening §H.2's design. Also moved
|
||||||
|
`STADIUM_FLAG_PIN`'s `#define` from a `stadium.c`-private constant to `stadium.h` (public)
|
||||||
|
so `session.c` can reference it without duplicating the definition. Verified 3-arch boot to
|
||||||
|
`ok>`.
|
||||||
|
- [x] **4. DONE 2026-09-03.** Rewired `stadium_birth_hera()` to admit unpinned then register
|
||||||
|
through `session_register(vm_uuid_hera(), vm_uuid_hera(), "Hera")` (self-referential
|
||||||
|
parent, matching `capsule_run.h`'s `parent_vm_id == vm_id` root convention) +
|
||||||
|
`session_set_pinned(vm_uuid_hera(), 1)` — Hera is session zero. `stadium_admit()` confirmed
|
||||||
|
to have no admission-time-special pin handling (just copies the candidate header), so
|
||||||
|
admit-unpinned-then-pin-after is safe. Soft-fail (logged, non-fatal) if `session_register()`
|
||||||
|
fails — Hera's actual Stadium admission already succeeded and 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()`. Verified 3-arch boot to `ok>`, no
|
||||||
|
soft-fail message logged on any arch (registration succeeded), Hermes/Artemis births
|
||||||
|
unaffected.
|
||||||
|
|
||||||
|
**Phase 2 — Pin Hermes/Artemis (Correction 1 above)**
|
||||||
|
- [x] **5. DONE 2026-09-03, one bug found and fixed via probe.** `capsule_birth.c`'s generic
|
||||||
|
admission block now registers a session for every born VM and pins it if
|
||||||
|
`is_fleet_foundation` (Hera/Hermes/Artemis). Admits unpinned then pins after, same ordering
|
||||||
|
as step 4 (`stadium_admit()` confirmed to have no admission-time pin handling). **Bug found
|
||||||
|
by step 6's probe**: the fleet-foundation name check first used
|
||||||
|
`vm_name_eq_nocase(capsule_name, "Hermes")`, exact match — but `capsule_name` is actually
|
||||||
|
`"hermes:init.4th"`/`"artemis:init.4th"` (the real "namespace:filename" convention), never
|
||||||
|
a bare name, so the check silently never matched. Fixed with a new
|
||||||
|
`vm_name_prefix_eq_nocase()` helper matching everything before a literal `:`. 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.
|
||||||
|
- [x] **6. DONE 2026-09-03.** Confirmed via a temporary probe (`console_println` after
|
||||||
|
`session_set_pinned()`, captured once then reverted per this project's probe convention):
|
||||||
|
first run showed `hermes:init.4th pinned=0` / `artemis:init.4th pinned=0` (the bug above),
|
||||||
|
second run after the fix showed `pinned=1` for both. Probe code fully reverted before
|
||||||
|
commit — only its finding (the `:`-suffixed capsule-name format) remains, in step 5's doc
|
||||||
|
comment and this entry.
|
||||||
|
|
||||||
|
**Phase 3 — Session fields wired at birth**
|
||||||
|
- [x] **7. DONE 2026-09-03, larger than one line — a real signature-threading pass.**
|
||||||
|
`Session.parent` now comes from the actual birthing VM's own `stadium_vm_id`, not a
|
||||||
|
hardcoded `vm_uuid_hera()`. This meant adding a `VMUuid parent` parameter to
|
||||||
|
`capsule_birth_baby()` and, one level up, to `capsule_console_birth()` and
|
||||||
|
`capsule_runcap_birth()` (neither had a `VM *` in their own signature, but every one of
|
||||||
|
their callers did) — traced all 6 real call sites across `mama_forth_words.c` (4: `BIRTH`,
|
||||||
|
`CAPSULE-BIRTH`, `CONNECT-ARTEMIS`, `CONNECT-HERMES`, plus `RUNCAP-TEST`/`PAIR-TEST` = 6
|
||||||
|
total) and `capsule_wirebind.c` (2: console + user birth in
|
||||||
|
`capsule_wirebind_try_attach()`), confirmed each has a real `VM *` (`vm`/`mama_vm`) in
|
||||||
|
scope, and passed `vm->stadium_vm_id` through at every one. Two functions
|
||||||
|
(`mama_word_connect_artemis`/`_hermes`) had their `vm` parameter marked
|
||||||
|
`__attribute__((unused))`, now genuinely used — attribute removed. User explicitly chose
|
||||||
|
this option (full threading) over leaving the earlier `vm_uuid_hera()` hardcode in place.
|
||||||
|
- [x] **8. Already satisfied by step 5.** `session_register(vm_id, parent, capsule_name)`
|
||||||
|
already passes the capsule's own name string — nothing further needed.
|
||||||
|
- [x] **9. Confirmed by code inspection.** `session_register()` (step 2) zeroes `identity`
|
||||||
|
unconditionally — `installed` reads 0 by construction, matching `VMIdentity`'s own
|
||||||
|
documented default. No behavior change, as expected.
|
||||||
|
|
||||||
|
Verified 3-arch boot to `ok>` (amd64/aarch64/riscv64) for step 7's actual code changes,
|
||||||
|
which also exercises 8 and 9 unchanged.
|
||||||
|
|
||||||
|
**Phase 4 — Creator-ceiling enforcement (H.3, birth-time snapshot)**
|
||||||
|
- [x] **10. DONE 2026-09-03.** `dictionary_snapshot_acl_from_parent(child, parent)` added as a
|
||||||
|
static helper in `capsule_birth.c`: walks `child->latest`'s link chain, looks up each name
|
||||||
|
in `parent` via `vm_find_word()` (the same C-level lookup `FIND` itself uses — not a
|
||||||
|
modification to `FIND`, per the standing "never modify `FIND`" rule), copies
|
||||||
|
`acl_allow`/`acl_mode`/`acl_pinned`/`acl_ttl` onto the child's matching entry when found.
|
||||||
|
Baby-specific words the parent doesn't have are left untouched — nothing to cap them
|
||||||
|
against.
|
||||||
|
- [x] **11. DONE 2026-09-03.** Called once via `vm_find_entry_ptr(parent)` (the same internal
|
||||||
|
registry lookup `capsule_birth_mama()` already uses for Hera's own entry) to get the
|
||||||
|
parent's live `VM*`, right after `dict_hash`/parity logging — deliberately *after*, not
|
||||||
|
before: the snapshot depends on the parent's *current* ACL state, which can vary run-to-run
|
||||||
|
once Zuse-granted elevations exist, so applying it before the hash would make
|
||||||
|
`birth_dict_hash` no longer a pure function of capsule content, breaking the "same capsule
|
||||||
|
booted twice produces the same dict hash" determinism invariant this codebase relies on
|
||||||
|
elsewhere. Verified 3-arch boot to `ok>` (amd64/aarch64/riscv64).
|
||||||
|
|
||||||
|
**Phase 5 — `BMAPFMT` (§F.4/§H.6, independent, can run any time)**
|
||||||
|
- [x] **12. DONE 2026-09-03, one pre-existing bug found along the way.** `blk_meta_t`'s old
|
||||||
|
40-byte `owner_id`/`permissions`/`acl_block`/`signature[2]` replaced with
|
||||||
|
`owner_fp[8]`/`acl_allow`/`acl_ttl` (u32)/`acl_reserved[3]`/`reserved_future`, matching
|
||||||
|
§F.4/§H.6's decided layout exactly. **Verified via a real standalone `offsetof`/`sizeof`
|
||||||
|
compile, not hand math**, per this step's own instruction: found `sizeof(blk_meta_t)` was
|
||||||
|
already **344**, not the `341` its own `BLK_META_PER_BLOCK` constant and "341-byte slice"
|
||||||
|
comment claimed — a pre-existing inaccuracy, not introduced by this edit (ordinary trailing
|
||||||
|
struct-alignment padding after the final `uint8_t padding[5]`). Harmless in practice:
|
||||||
|
`BLK_META_PER_BLOCK` has **zero callers anywhere in the codebase**, consistent with
|
||||||
|
`blk_meta_t` itself being dormant. After this edit's own alignment changes (a `uint32_t`
|
||||||
|
and a `uint64_t` field each force a few bytes of compiler-inserted padding after preceding
|
||||||
|
`uint8_t` fields), the real new size is **336** bytes (8 smaller than before, not the
|
||||||
|
"same 40-byte budget" framing implied — natural alignment, not a bug). Added a
|
||||||
|
`_Static_assert(sizeof(blk_meta_t) == 336, ...)`, matching `blk_volume_meta_t`'s own
|
||||||
|
existing precedent in this same file, and fixed the now-doubly-stale "341-byte slice"
|
||||||
|
comment to point at the assert instead of repeating the wrong number. Did not touch
|
||||||
|
`BLK_META_PER_BLOCK` itself — out of scope, unused, not what this step asked for.
|
||||||
|
Verified 3-arch boot to `ok>` (amd64/aarch64/riscv64).
|
||||||
|
- [x] **13. DONE 2026-09-03.** `BLK_FLAG_CLAIMED`/`BLK_FLAG_MIGRATING`/`BLK_FLAG_STALE`
|
||||||
|
(bits 0/1/2, `1ull << n`) defined in `block_subsystem.h` right above `blk_meta_t`, `flags`
|
||||||
|
field comment updated to point at them. Verified 3-arch boot to `ok>`
|
||||||
|
(amd64/aarch64/riscv64).
|
||||||
|
- [x] **14. DONE 2026-09-03.** `blk_owner_fp_get`/`_set`, `blk_acl_allow_get`/`_set`,
|
||||||
|
`blk_acl_ttl_get`/`_set`, `blk_flags_get`/`_set` added — thin read-modify-write wrappers
|
||||||
|
over the existing `blk_get_meta()`/`blk_set_meta()` (which already own caching/dirty-
|
||||||
|
tracking; these add no new state). FORTH wrappers (step 15) call these, not
|
||||||
|
`blk_get_meta()`/`blk_set_meta()` directly, mirroring the word-level ACL system's own
|
||||||
|
C-primitive/FORTH-policy split. Verified 3-arch boot to `ok>` (amd64/aarch64/riscv64).
|
||||||
|
- [x] **15. DONE 2026-09-03, live-tested.** `BLK-ACL-ALLOW@`/`!`, `BLK-ACL-TTL@`/`!`,
|
||||||
|
`BLK-OWNER@` registered in `block_words.c` (shared/vendored source — verified with both a
|
||||||
|
hosted sanity build and the 3-arch kernel boot). `BLK-OWNER@` packs the 8-byte fingerprint
|
||||||
|
into one cell (`cell_t` is `int64_t`, 8 bytes — exact fit, raw bit reinterpretation). No
|
||||||
|
`BLK-OWNER!` — only the five words step 15 itself listed; setting ownership stays a
|
||||||
|
controlled, C-only operation (MINT/birth), not a general FORTH write. **Live-tested via QMP
|
||||||
|
keystrokes on the running riscv64 instance**: `1 BLK-ACL-ALLOW@` executed cleanly (`ok`, no
|
||||||
|
`UNKNOWN WORD` error) against a real block. Verified 3-arch boot to `ok>`
|
||||||
|
(amd64/aarch64/riscv64).
|
||||||
|
- [x] **16. DONE 2026-09-03, live-tested — Phase 5 complete.** `capsules/block-acl.4th`
|
||||||
|
(blocks 4019–4020, next free range after `zuse.4th`'s 4016–4018, verified against
|
||||||
|
`BLOCK_MAP.md` — CLAUDE.md's block-namespace rule) defines `BLK-ACL-CHECK ( block# --
|
||||||
|
allow? )`: a real, working fast-deny check mirroring `vm.c:611-624`'s pattern applied to a
|
||||||
|
block instead of a word. First touch lazily claims the block (`allow=1`,
|
||||||
|
`TTL=BLK-ACL-BASE-TTL`=256, same base value as `ACL.4th`'s own), matching the word card's
|
||||||
|
default-permissive baseline — not a stub, genuinely does something on every call. No
|
||||||
|
automatic TTL-decrement hot path exists for blocks yet (words decrement per-dispatch in
|
||||||
|
`vm.c`; blocks have no equivalent loop) — out of this step's scope, the fast-deny gate
|
||||||
|
itself is real and complete regardless. Passed `mkcapsule --lint` cleanly. Loaded via a new
|
||||||
|
`S" block-acl.4th" EXEC` line in `init.4th`'s Block 2049, right after `ACL.4th`'s own —
|
||||||
|
confirmed `ACL.4th`'s own activation messages identical before/after this addition (nothing
|
||||||
|
broken). **Live-tested via QMP keystrokes**: `1 BLK-ACL-CHECK` executed cleanly (`ok`, no
|
||||||
|
`UNKNOWN WORD`) on the running amd64 instance. Verified 3-arch boot to `ok>`
|
||||||
|
(amd64/aarch64/riscv64).
|
||||||
|
|
||||||
|
**Phase 5 (`BMAPFMT`) is now fully complete** — field layout, `flags` bits, C accessors,
|
||||||
|
FORTH wrappers, and a real policy word all landed and verified.
|
||||||
|
|
||||||
|
**Phase 6 — Zuse eligibility list (H.5)**
|
||||||
|
- [ ] **17.** Extend the metadata-fence record format with a new growable
|
||||||
|
`owner_pubkey[32]`-list record type.
|
||||||
|
- [ ] **18.** Implement read/add/membership-check functions in C.
|
||||||
|
- [ ] **19.** Add a Zuse-only FORTH word to add an entry, gated by `zuse_session`.
|
||||||
|
|
||||||
|
**Phase 7 — Message card gate + `ELEVATE-REQUEST` (H.8)**
|
||||||
|
- [ ] **20.** Add the initiator-only ACL gate at `CH-REQUEST`'s entry point
|
||||||
|
(default-permissive baseline, real hook point established).
|
||||||
|
- [ ] **21.** Define `ELEVATE-REQUEST` and a minimal real handler checking the eligibility
|
||||||
|
list, granting via `ACL-ALLOW!`/`ACL-TTL!` on match.
|
||||||
|
- [ ] **22.** Add the FORTH entrypoint a session actually calls to send one.
|
||||||
|
|
||||||
|
**Excluded, per H.11's deferred items 10–11**: VM card multi-owner support, live-console
|
||||||
|
`sudo`-style elevation, pre-signed capability tickets.
|
||||||
|
|||||||
+2
-1
@@ -528,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)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
|
<!-- Generated by mkcapsule --manifest 2026-09-03T11:42:42Z -->
|
||||||
<!-- Generated by mkcapsule --manifest 2026-08-30T08:47:40Z -->
|
|
||||||
<!-- 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. -->
|
||||||
@@ -11,6 +10,7 @@
|
|||||||
|---------|----------------|----------|--------|
|
|---------|----------------|----------|--------|
|
||||||
| `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 | `0xfe6e570467368153` | 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 | `0x892fd1c86d8c175e` | 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 |
|
||||||
| `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 |
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
| `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 | `0xa94a7b63db15021b` | 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 |
|
||||||
@@ -46,9 +46,9 @@
|
|||||||
|
|
||||||
| LBN | Capsule | xxHash64 | Status |
|
| LBN | Capsule | xxHash64 | Status |
|
||||||
|-----|---------|----------|--------|
|
|-----|---------|----------|--------|
|
||||||
| 2049 | `init.4th` | `0x9ac6523d24b80cd0` | ok |
|
| 2049 | `init.4th` | `0xa94a7b63db15021b` | ok |
|
||||||
| 2050 | `init.4th` | `0x9ac6523d24b80cd0` | ok |
|
| 2050 | `init.4th` | `0xa94a7b63db15021b` | ok |
|
||||||
| 2057 | `init.4th` | `0x9ac6523d24b80cd0` | ok |
|
| 2057 | `init.4th` | `0xa94a7b63db15021b` | 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 |
|
||||||
@@ -108,6 +108,8 @@
|
|||||||
| 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 |
|
||||||
| 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 |
|
||||||
@@ -354,4 +356,4 @@
|
|||||||
None.
|
None.
|
||||||
|
|
||||||
---
|
---
|
||||||
*32 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
*33 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
||||||
|
|||||||
@@ -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@ ;
|
||||||
@@ -14,6 +14,7 @@ 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" lib.4th" EXEC
|
S" lib.4th" EXEC
|
||||||
S" fabric.4th" EXEC
|
S" fabric.4th" EXEC
|
||||||
S" font.4th" EXEC
|
S" font.4th" EXEC
|
||||||
|
|||||||
Binary file not shown.
@@ -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,
|
||||||
@@ -358,6 +413,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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -35,11 +35,13 @@
|
|||||||
* "CaptBob"); sk_repl_dispatch_line() looks for a
|
* "CaptBob"); sk_repl_dispatch_line() looks for a
|
||||||
* live "<name>~user" counterpart to decide
|
* live "<name>~user" counterpart to decide
|
||||||
* whether a given active VM is a console.
|
* whether a given active VM is a console.
|
||||||
|
* @param parent Who is birthing this VM (FABRIC-3.md §H.12 step 7)
|
||||||
|
* -- passed straight through to capsule_birth_baby().
|
||||||
* @param out_vm_id Output: assigned VM ID.
|
* @param out_vm_id Output: assigned VM ID.
|
||||||
* @param out_vm_ctx Output: new VM context (may be NULL).
|
* @param out_vm_ctx Output: new VM context (may be NULL).
|
||||||
* @return CAPSULE_RUN_OK on success, error code otherwise.
|
* @return CAPSULE_RUN_OK on success, error code otherwise.
|
||||||
*/
|
*/
|
||||||
CapsuleRunResult capsule_console_birth(const char *console_name,
|
CapsuleRunResult capsule_console_birth(const char *console_name, VMUuid parent,
|
||||||
VMUuid *out_vm_id, void **out_vm_ctx);
|
VMUuid *out_vm_id, void **out_vm_ctx);
|
||||||
|
|
||||||
#endif /* __STARKERNEL__ */
|
#endif /* __STARKERNEL__ */
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ struct blkio_dev;
|
|||||||
* @param vm_name Symbolic name for the new VM (becomes both the
|
* @param vm_name Symbolic name for the new VM (becomes both the
|
||||||
* capsule's own single directory entry name and the
|
* capsule's own single directory entry name and the
|
||||||
* VM registry name).
|
* VM registry name).
|
||||||
|
* @param parent Who is birthing this VM (FABRIC-3.md §H.12 step 7) --
|
||||||
|
* passed straight through to capsule_birth_baby().
|
||||||
* @param out_vm_id Output: assigned VM ID.
|
* @param out_vm_id Output: assigned VM ID.
|
||||||
* @param out_vm_ctx Output: new VM context (may be NULL if not needed).
|
* @param out_vm_ctx Output: new VM context (may be NULL if not needed).
|
||||||
* @return CAPSULE_RUN_OK on success, error code otherwise.
|
* @return CAPSULE_RUN_OK on success, error code otherwise.
|
||||||
@@ -66,6 +68,7 @@ CapsuleRunResult capsule_runcap_birth(
|
|||||||
struct blkio_dev *dev,
|
struct blkio_dev *dev,
|
||||||
const homeblocks_sig_t *sig,
|
const homeblocks_sig_t *sig,
|
||||||
const char *vm_name,
|
const char *vm_name,
|
||||||
|
VMUuid parent,
|
||||||
VMUuid *out_vm_id,
|
VMUuid *out_vm_id,
|
||||||
void **out_vm_ctx
|
void **out_vm_ctx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -100,16 +100,22 @@ void fb_draw_orientation_test(void);
|
|||||||
* --------------------------------------------------------------------- */
|
* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll the framebuffer up by `char_rows` character rows (each 16 px).
|
* Scroll the whole framebuffer up by `pixel_rows` pixel rows. The vacated
|
||||||
* The vacated rows at the bottom are filled with bg.
|
* rows at the bottom are filled with bg. Takes an explicit pixel-row count
|
||||||
|
* (not a hardcoded 8x16-cell assumption) so callers with a non-8x16 cell
|
||||||
|
* height (e.g. TTF mode, 24px) pass their own cell height directly --
|
||||||
|
* same convention fb_scroll_rect() below already uses, for the same reason
|
||||||
|
* (a caller-computed char_rows * fixed-16px assumption drifts out of sync
|
||||||
|
* with the text model's own row height in TTF mode, and that drift
|
||||||
|
* compounds with every scroll).
|
||||||
*/
|
*/
|
||||||
void fb_scroll_rows(uint32_t char_rows, uint32_t bg);
|
void fb_scroll_rows(uint32_t pixel_rows, uint32_t bg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll a sub-rectangle of the framebuffer up by `pixel_rows` pixel rows
|
* Scroll a sub-rectangle of the framebuffer up by `pixel_rows` pixel rows
|
||||||
* (FABRIC.md item 4.4t: box-confined REPL scrolling). Unlike fb_scroll_rows()
|
* (FABRIC.md item 4.4t: box-confined REPL scrolling). Unlike fb_scroll_rows()
|
||||||
* (whole-framebuffer, fixed 16px-row assumption), this is bounded to
|
* (whole-framebuffer), this is bounded to
|
||||||
* [x, x+w) x [y, y+h) and takes an explicit pixel-row count so callers with
|
* [x, x+w) x [y, y+h). Both take an explicit pixel-row count so callers with
|
||||||
* a non-8x16 cell height (e.g. TTF mode) pass their own cell height directly.
|
* a non-8x16 cell height (e.g. TTF mode) pass their own cell height directly.
|
||||||
* Pixels outside the rect are untouched. The vacated rows at the bottom of
|
* Pixels outside the rect are untouched. The vacated rows at the bottom of
|
||||||
* the rect are filled with bg.
|
* the rect are filled with bg.
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
StarForth — Steady-State Virtual Machine Runtime
|
||||||
|
|
||||||
|
Copyright (c) 2023–2025 Robert A. James
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
This file is part of the StarForth project.
|
||||||
|
|
||||||
|
Licensed under the StarForth License, Version 1.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
|
||||||
|
You may obtain a copy of the License at:
|
||||||
|
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||||||
|
|
||||||
|
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
express or implied, including but not limited to the warranties of
|
||||||
|
merchantability, fitness for a particular purpose, and noninfringement.
|
||||||
|
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session.h - Per-VM session (FABRIC-3.md §H, decided 2026-09-02/03)
|
||||||
|
*
|
||||||
|
* A session is a Stadium patron (FABRIC-3.md §H.1) -- registering a session
|
||||||
|
* IS admitting a patron to the Stadium, not a new parallel bookkeeping
|
||||||
|
* structure. This struct is the piece that sits ALONGSIDE the patron,
|
||||||
|
* referencing it by VMUuid rather than being indexed by Stadium cell index
|
||||||
|
* or grown as inline fields on StadiumPatronHeader/struct VM (deliberately
|
||||||
|
* its own header, mirroring VMUuid's/VMIdentity's own precedent -- standing
|
||||||
|
* instruction: give real-shaped data its own header and integrate as a
|
||||||
|
* field, don't grow existing structs ad hoc).
|
||||||
|
*
|
||||||
|
* Fields (FABRIC-3.md §H.2, all five confirmed 2026-09-02/03):
|
||||||
|
* vm_id -- the patron this session references.
|
||||||
|
* pinned -- session is AUTHORITATIVE over Stadium's STADIUM_FLAG_PIN
|
||||||
|
* bit (§H.10): the sole read/write path for pin state is
|
||||||
|
* session_set_pinned()/session_is_pinned() below, nothing
|
||||||
|
* else (including existing Stadium code) may touch
|
||||||
|
* STADIUM_FLAG_PIN directly.
|
||||||
|
* parent -- who birthed this session (Hera -> Hermes/Artemis, etc).
|
||||||
|
* name -- canonical human-readable name; feeds console.c's
|
||||||
|
* g_active_vm_name prefix, does not replace the
|
||||||
|
* console-binding mechanism itself.
|
||||||
|
* identity -- embedded VMIdentity (FABRIC-3.md §H.4's VM card is
|
||||||
|
* effectively VMIdentity's existing ownership check; reused
|
||||||
|
* directly here, not reinvented).
|
||||||
|
*
|
||||||
|
* Explicit user framing (2026-09-02), still true: "we're gonna be
|
||||||
|
* revisiting this part of it around and around for a while" -- treat this
|
||||||
|
* shape as a live working draft, not permanently locked.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARKERNEL_SESSION_H
|
||||||
|
#define STARKERNEL_SESSION_H
|
||||||
|
|
||||||
|
#ifdef __STARKERNEL__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "starkernel/vm_uuid.h"
|
||||||
|
#include "starkernel/vm_identity.h"
|
||||||
|
|
||||||
|
/* Matches console.c's CONSOLE_VM_NAME_BUF precedent -- same order of
|
||||||
|
* magnitude for the same kind of data (a short human-readable VM name). */
|
||||||
|
#define SESSION_NAME_BUF 64
|
||||||
|
|
||||||
|
/* Sentinel meaning "no Stadium cell recorded yet" -- same shape as
|
||||||
|
* STADIUM_CELL_NONE (stadium.c), duplicated here rather than pulled in via
|
||||||
|
* stadium.h to avoid this header depending on Stadium's internal cell-index
|
||||||
|
* type. Session's own callers set stadium_cell after their own
|
||||||
|
* stadium_admit() call returns a real index (§H.12 step 3 doc). */
|
||||||
|
#define SESSION_STADIUM_CELL_NONE ((size_t)-1)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VMUuid vm_id; /* the patron this session references */
|
||||||
|
int pinned; /* authoritative over STADIUM_FLAG_PIN; see
|
||||||
|
* session_set_pinned()/session_is_pinned() */
|
||||||
|
VMUuid parent; /* who birthed this session */
|
||||||
|
char name[SESSION_NAME_BUF]; /* canonical human-readable name */
|
||||||
|
VMIdentity identity; /* embedded, not referenced -- see vm_identity.h */
|
||||||
|
size_t stadium_cell; /* index of this session's own patron cell in
|
||||||
|
* stadium_cells() -- SESSION_STADIUM_CELL_NONE
|
||||||
|
* until the caller that admits this session's
|
||||||
|
* patron (stadium_admit()'s return value) sets it.
|
||||||
|
* session_set_pinned()/session_is_pinned() need
|
||||||
|
* this to reach the right patron header; added
|
||||||
|
* §H.12 step 3, not part of the original H.2 field
|
||||||
|
* list -- necessary plumbing, not a new session-
|
||||||
|
* level concept, so not itself renegotiated. */
|
||||||
|
} Session;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* session_boot_init - Boot-time allocation, mirroring stadium_boot_init()'s
|
||||||
|
* own kmalloc-sized-from-budget shape rather than a fixed compile-time
|
||||||
|
* array (stadium.c's own StadiumVMQuota table was moved off a fixed array
|
||||||
|
* for the same reason -- population isn't knowable in advance). Must run
|
||||||
|
* after stadium_boot_init() (session slot count is sized from
|
||||||
|
* stadium_max_vm_count()) and before the first session is registered.
|
||||||
|
* No callers yet (§H.12 step 2) -- wiring into the boot sequence happens
|
||||||
|
* in a later punch-list step.
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 if kmalloc failed or stadium_max_vm_count() is 0
|
||||||
|
* (Stadium not yet initialized).
|
||||||
|
*/
|
||||||
|
int session_boot_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* session_find - Look up a session by the VMUuid of the patron it
|
||||||
|
* references. Linear scan, same shape as stadium.c's own
|
||||||
|
* quota_slot_for_vm() -- the population this searches is small (one entry
|
||||||
|
* per VM, not per word/block).
|
||||||
|
*
|
||||||
|
* @return Pointer to the live session, or NULL if none is registered for
|
||||||
|
* vm_id.
|
||||||
|
*/
|
||||||
|
Session *session_find(VMUuid vm_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* session_register - Register a new session for vm_id. identity starts
|
||||||
|
* zeroed (VMIdentity's own documented default: installed=0, "no lock,
|
||||||
|
* allow freely" -- §H.12 Correction 2). pinned starts 0 (unpinned); use
|
||||||
|
* session_set_pinned() separately to pin, keeping this function's job to
|
||||||
|
* "create the session record" only, not "create and also decide pin
|
||||||
|
* policy" -- callers (e.g. the capsule-birth admission path, §H.12 phase 2)
|
||||||
|
* decide pinning themselves.
|
||||||
|
*
|
||||||
|
* @param vm_id The patron this session references. Must not already have
|
||||||
|
* a registered session (session_find(vm_id) must be NULL).
|
||||||
|
* @param parent Who birthed this session (vm_uuid_hera() for Hera's own
|
||||||
|
* self-registration -- self-referential, matching the
|
||||||
|
* existing parent_vm_id convention documented in
|
||||||
|
* capsule_run.h).
|
||||||
|
* @param name Copied into the new session's name buffer, truncated to
|
||||||
|
* SESSION_NAME_BUF - 1 if longer.
|
||||||
|
* @return Pointer to the new session, or NULL if the slot table is full,
|
||||||
|
* not yet initialized, or vm_id is already registered.
|
||||||
|
*/
|
||||||
|
Session *session_register(VMUuid vm_id, VMUuid parent, const char *name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* session_set_pinned / session_is_pinned - The pin-authority choke point
|
||||||
|
* (FABRIC-3.md §H.2/§H.10, decided 2026-09-02: "full choke point at the
|
||||||
|
* session level, both directions"). Session is authoritative for every
|
||||||
|
* EXTERNAL reader -- nothing else, including existing Stadium code, reads
|
||||||
|
* or writes STADIUM_FLAG_PIN on a patron header directly anymore.
|
||||||
|
*
|
||||||
|
* session_is_pinned() answers from the session's own `pinned` field
|
||||||
|
* directly (the authoritative copy) -- it does not re-derive the answer
|
||||||
|
* from Stadium. session_set_pinned() writes both: the session's own
|
||||||
|
* `pinned` field (authoritative) AND the mirrored STADIUM_FLAG_PIN bit on
|
||||||
|
* the session's own patron header (stadium_cells()[session->stadium_cell]),
|
||||||
|
* so the Stadium engine's own internal eviction/admission logic -- which
|
||||||
|
* must stay self-contained and cannot call back into session.c -- keeps
|
||||||
|
* seeing a correct, in-sync bit.
|
||||||
|
*
|
||||||
|
* Both no-op (return 0 / do nothing) if vm_id has no registered session, or
|
||||||
|
* if stadium_cell is still SESSION_STADIUM_CELL_NONE (patron not admitted
|
||||||
|
* yet) for the set path.
|
||||||
|
*/
|
||||||
|
void session_set_pinned(VMUuid vm_id, int pinned);
|
||||||
|
int session_is_pinned(VMUuid vm_id);
|
||||||
|
|
||||||
|
#endif /* __STARKERNEL__ */
|
||||||
|
|
||||||
|
#endif /* STARKERNEL_SESSION_H */
|
||||||
@@ -46,6 +46,16 @@
|
|||||||
* conflating "contains Hera" with "contains nothing." */
|
* conflating "contains Hera" with "contains nothing." */
|
||||||
#define STADIUM_CONTAINS_NONE ((uint32_t)-1)
|
#define STADIUM_CONTAINS_NONE ((uint32_t)-1)
|
||||||
|
|
||||||
|
/* `flags` bit 0 -- pinned, exempt from eviction/reap. Moved here from a
|
||||||
|
* stadium.c-private #define (FABRIC-3.md §H.12 step 3) so session.c's pin-
|
||||||
|
* authority choke point (session_set_pinned()/session_is_pinned()) can
|
||||||
|
* write/read this same bit without a duplicate definition. Session is
|
||||||
|
* authoritative for every EXTERNAL reader (FABRIC-3.md §H.10) -- this bit
|
||||||
|
* on the raw patron header stays a mirrored copy purely for the Stadium
|
||||||
|
* engine's own internal eviction/admission logic (stadium.c), which must
|
||||||
|
* stay self-contained and not call back into session.c. */
|
||||||
|
#define STADIUM_FLAG_PIN 0x01u
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* StadiumPatronHeader - one member of the closed two-valued cell union
|
* StadiumPatronHeader - one member of the closed two-valued cell union
|
||||||
* (FABRIC.md §3). Nine wires: identity, heat, TTL, pin (a bit in `flags`),
|
* (FABRIC.md §3). Nine wires: identity, heat, TTL, pin (a bit in `flags`),
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user