§H.12 steps 10-11: creator-ceiling enforcement, birth-time ACL snapshot

dictionary_snapshot_acl_from_parent(child, parent): walks the child's
dictionary, copies acl_allow/acl_mode/acl_pinned/acl_ttl from the
parent's matching word (by name, via vm_find_word() -- FIND's own
lookup, not modified) onto the child's entry. One-time snapshot at
birth, no live sync, matching H.3's decided rationale (a program
developed against one ACL set must not have it silently changed by
later parent changes).

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

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-03 06:44:58 -04:00
co-authored by Claude Opus 5
parent ed86a759e1
commit a268abe925
10 changed files with 27624 additions and 6 deletions
+15 -5
View File
@@ -4024,11 +4024,21 @@ work, not new invention.
which also exercises 8 and 9 unchanged.
**Phase 4 — Creator-ceiling enforcement (H.3, birth-time snapshot)**
- [ ] **10.** `dictionary_snapshot_acl_from_parent(child, parent)`: for each word also present
in the parent's dictionary, copy `acl_allow`/`acl_mode`/`acl_pinned`/`acl_ttl` into the
child's matching entry.
- [ ] **11.** Call it once, right after a child's dictionary finishes loading in
`capsule_birth.c`.
- [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)**
- [ ] **12.** Edit `blk_meta_t` in `include/block_subsystem.h`: replace the old 4 ownership
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-09-03T10:36:42Z -->
<!-- Generated by mkcapsule --manifest 2026-09-03T10:43:13Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
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
+41
View File
@@ -104,6 +104,33 @@ static VMRegistryEntry *vm_find_entry_ptr(VMUuid vm_id) {
return (void *)0;
}
/* FABRIC-3.md §H.12 step 10: creator-ceiling enforcement, birth-time
* snapshot only, no live sync (§H.3, decided 2026-09-03 -- "if something
* was developed with a particular set of ACLs, it should remain at
* that... otherwise parent changes break the child's program"). For
* every word in child's dictionary also present, by name, in parent's,
* copy parent's CURRENT acl_allow/acl_mode/acl_pinned/acl_ttl onto
* child's matching entry -- caps the child at whatever the parent
* allowed at this exact moment, once, never re-applied afterward. Words
* the child has that the parent doesn't (baby-specific vocabulary) are
* left untouched -- there's nothing to cap them against. vm_find_word()
* is the same C-level lookup FIND itself uses; not modifying FIND, just
* calling the same lookup it does (CLAUDE.md: "FIND is a proven, tested,
* registered word. Never modify it" -- this doesn't). */
static void dictionary_snapshot_acl_from_parent(VM *child, VM *parent) {
DictEntry *ce;
if (!child || !parent) return;
for (ce = child->latest; ce != NULL; ce = ce->link) {
DictEntry *pe = vm_find_word(parent, ce->name, ce->name_len);
if (!pe) continue;
ce->acl_allow = pe->acl_allow;
ce->acl_mode = pe->acl_mode;
ce->acl_pinned = pe->acl_pinned;
ce->acl_ttl = pe->acl_ttl;
}
}
void capsule_vm_registry_init(void *mama_vm_ptr) {
uint32_t i;
vm_node_t *node;
@@ -674,6 +701,20 @@ CapsuleRunResult capsule_birth_baby(
capsule_parity_log_birth(vm_id, cap->capsule_id, cap->content_hash, dict_hash);
/* §H.12 step 11: applied AFTER dict_hash/parity logging above, not
* before -- a runtime ACL snapshot depends on the parent's CURRENT
* 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. */
{
VMRegistryEntry *parent_entry = vm_find_entry_ptr(parent);
if (parent_entry && parent_entry->vm_ptr) {
dictionary_snapshot_acl_from_parent(new_vm, (VM *)parent_entry->vm_ptr);
}
}
if (out_vm_id) *out_vm_id = vm_id;
if (out_vm_ctx) *out_vm_ctx = new_vm;