FABRIC-3.md: scope BINDSTEP -- extends the live, unguarded USE word

Traced the actual retarget path before assuming new plumbing: USE (mama_forth_words.c:430-480) already looks up a VM by name and calls sk_repl_set_active_vm() directly, completely unguarded. BINDSTEP is concretely "add the ACLKEY comparison to this one call site." Found one real gap: usb_blk_dev/xdev are function-static inside sk_repl_idle(), invisible to USE -- needs a small new accessor mirroring sk_repl_get_active_vm()'s own precedent. Decisions: re-verify the attached drive live on every USE call rather than trust a cached pubkey; VMs with no VMIdentity installed yet (Hera/Hermes/Artemis today) stay freely targetable, no regression; installed=1 targets refuse on no-drive-attached or pubkey mismatch, matching USE's existing refusal style. Zuse's override UX stays deferred per direct instruction.
This commit is contained in:
Robert Allan James
2026-08-27 14:30:30 -04:00
parent a45ea881c9
commit c4f9458ad6
+50 -2
View File
@@ -682,7 +682,10 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
- [ ] Implement the actual attach/bind step — extending `sk_repl_set_active_vm()` (confirmed
to exist, currently an unguarded raw pointer-set) with the key-match check from above, so a
console can only bind to the one VM whose lock matches its key.
console can only bind to the one VM whose lock matches its key. **SCOPED 2026-08-27
(`FABRIC-3.md` §F.9)**: real gate is `USE` (`mama_forth_words.c:430-480`), the live,
already-working, currently-unguarded retarget word — check re-verifies the attached drive
live on every call; `installed=0` VMs stay freely targetable.
- [ ] Implement detach behavior on console disconnect or VM teardown.
@@ -1426,7 +1429,7 @@ graph TD
ACLKEY["❓ ACL 'bumps and holes' comparison<br/>semantics — SAME GAP in M5 and D.4"]
WIREBIND["❌ Wire hotplug → capsule_birth_baby() (M5)"]
BINDSTEP["❌ Extend sk_repl_set_active_vm()<br/>with key-match (M5)"]
BINDSTEP["❌ Extend sk_repl_set_active_vm()<br/>with key-match (M5) — SCOPED 2026-08-27 (§F.9)"]
DETACH["❌ Detach behavior (M5)"]
EXPIRE["✅ EXPIRE reframed: session end<br/>= VM detach via COOL (§B + D.2)"]
@@ -1519,6 +1522,10 @@ finished). Dashed arrows = softer "gates/informs" relationships.
(`CERTVERIFY`, `WIREBIND`, `RUNCAP`, `HOTPLUG`) was already treating raw devblock-0 as the
working format. Dropping GPT converts all of those from "interim, revisit later" to simply
"the design," retroactively.
- **`BINDSTEP` already has a live target to gate, not new plumbing** (§F.9) — `USE`
(`mama_forth_words.c`) is a real, working, currently-unguarded retarget word. The only
genuinely new code this node needs is a small cross-file accessor for the currently-attached
device (mirroring `sk_repl_get_active_vm()`'s own precedent) plus the comparison itself.
**Not yet done:** an ordered plan (which node to attack first, given the graph). Per Captain
Bob's own framing, that's the next pass — "start asking and answering questions iteratively
@@ -1876,6 +1883,47 @@ refuse-on-non-blank-media posture — reasonable by analogy, not decided here. T
is unchanged and already modeled in the graph: `WRITE(10)` still doesn't exist, so `MINT`
cannot write anything to real or QEMU-emulated USB media yet regardless of the above.
### F.9 — `BINDSTEP` (extending `sk_repl_set_active_vm()` with the `ACLKEY` check)
Traced against the live retarget path before assuming new plumbing was needed:
`USE` (`mama_forth_words.c:430-480`) is the real, already-working console-retarget word —
`S" name" USE` looks a VM up by name (case-insensitive) and calls `sk_repl_set_active_vm()`
directly, completely unguarded today. `BINDSTEP` is concretely "add the `ACLKEY` (§F.2)
comparison to this one call site," not a new mechanism.
**Real gap found, not just a policy question:** the "re-verify live" approach (decided below)
needs access to whatever drive is currently attached, but `usb_blk_dev`/`xdev`
(`repl.c:107-108`) are function-static inside `sk_repl_idle()` — invisible to `USE`, which
lives in `mama_forth_words.c`. `BINDSTEP` needs a small new accessor exposing "the currently
attached home-blocks device," mirroring the existing `sk_repl_get_active_vm()` precedent
(`repl.h:67-69`) for exactly this kind of cross-file REPL-state access.
**Decisions made 2026-08-27 (iterative Q&A pass):**
1. **Check freshness: re-verify live, not cached.** Every `USE` call re-runs the
drive-check/`CERTVERIFY` path against whatever is currently attached, rather than trusting a
pubkey cached at original attach time. `USE` is a rare, human-triggered, interactive
operation — the repeated DER-parse + `ed25519_verify()` cost is a non-issue, and this avoids
any staleness question if a drive was swapped without a clean detach.
2. **VMs with no `VMIdentity` installed yet (`installed=0`) — Hera/Hermes/Artemis today, until
`D.5`'s per-VM-identity work lands — stay freely targetable, no check applied.** Preserves
`USE`'s current working behavior exactly; refusing on `installed=0` would be a real
regression today for VMs that were never in scope for this lock in the first place.
3. **For an `installed=1` target:** `BINDSTEP` refuses (matching `USE`'s existing clean
early-refusal style for not-found/dead-VM cases) whenever either no drive is currently
attached, or the freshly re-verified cert's owner pubkey doesn't match the target's
`VMIdentity.owner_pubkey`. No drive attached is a plain refusal, not a special case — it
simply means "no identity presented," which can never match.
4. **Zuse's override UX: deferred**, per direct instruction — this pass confirms the
architectural constraint from `F.2` still stands (a distinct, explicit call path, not a
branch folded into `USE`'s own logic) without committing to the exact word/interaction yet.
**Not yet scoped (deferred within this node):** the new accessor's exact name/signature; the
refusal message text (matching `USE`'s existing console-message style); whether a refused
`BINDSTEP` attempt should produce an audit-log record (this codebase has a real precedent for
this — `capsule_parity_log_birth_failed()` and friends, `parity.c` — but nothing says a
security-relevant refusal here needs the same treatment; not decided).
### D.5 — Scope expansion (2026-08-27): identity is common to every VM, not just users
Surfaced while scoping `ACLKEY`, stated directly: *"the whole object is to deliver a