diff --git a/FABRIC-3.5.md b/FABRIC-3.5.md index e8e68c2f..f26cb5b6 100644 --- a/FABRIC-3.5.md +++ b/FABRIC-3.5.md @@ -1567,8 +1567,9 @@ Design items, in dependency order. **No code authorized.** `capsules/hestia/init.4th`; `PLOT`/`FB-WIDTH`/`FB-HEIGHT` registration moves to Hestia. 2. ⬜ Allocate Hestia's block range against `capsule-reserved.txt`, avoiding 4997; verify with `mkcapsule --lint` (§XVIII.4). -3. ⬜ Decide §XVIII.5's agent-binding shape: widen the `~user` convention, or a sibling word. - **The only genuinely open design question in this section.** +3. ✅ **SETTLED 2026-09-19 by §XX** — neither option. The pairing is already recorded at bind + time; the `~user` reconstruction is a redundant derivation and is removed. Agent binding + then needs no new mechanism. 4. ⬜ Confirm Hestia in the `is_fleet_foundation` triple (`capsule_birth.c:793-796`) and its birth at `kernel_main.c:865`, replacing Hermes's (§XVII.4). 5. ⬜ Handle the `doe_log.c` CSV schema change (§XIII.3) — still the expensive consequence. @@ -1699,3 +1700,120 @@ relayed one, with nothing reported. the class remains: **if the §XVIII.5 binding work touches that path anyway, making an unresolved or mismatched name *say so* would retire the hazard for every VM name, not just this one.** Raised as punch item 19, not scheduled. + +--- + +## XX. Item 3 SETTLED: delete the suffix from the mechanism — neither widen it nor add a word + +§XVIII.5 posed agent-VM binding as a choice between (a) widening the `~user` convention and +(b) a sibling word for agent binding. **Both options are wrong, because both accept a premise +the code does not support.** Traced 2026-09-18/19: the pairing is *already recorded +explicitly*, and the `~user` reconstruction is a redundant second derivation of information the +mechanism already holds. + +### XX.1 — The relay does not route by name. It routes by a slot recorded at bind time. + +`sk_repl_dispatch_line()` (`repl.c:1225-1265`) does two separate things, and only one of them +involves the suffix: + +1. **The guard** builds `paired_name = console_get_vm_name() + "~user"` + (`repl.c:1243-1247`) and checks `capsule_vm_find_by_name(paired_name, ...)` is `VM_STATE_LIVE`. +2. **The actual relay** then sends `CONSOLE-CMD-EVENT 0 3 S" " 0 MSG-SEND` — **to index + 3**, with this comment verbatim: *"to-index 3: the fixed convention this console's own + `VM-NAME-REG` entry for its paired user VM uses (**set once at pairing time** — see the + pairing word)."* + +`PAIR-TEST`'s own header says the same from the other side (`mama_forth_words.c:1542-1543`): +"**Registers the pairing in the console's own VM-name routing table at the fixed index (3) that +relay uses.**" + +**So the target is already stored, per-proxy, at bind time.** The suffix string is used only to +answer "is my partner alive?" — a question the stored pairing can answer directly, without +deriving anything. + +### XX.2 — This is the documented cause of the known silent-failure bug + +`CONSOLE-ATTACH`'s own doc comment (`mama_forth_words.c:1931-1940`) states it outright: + +> `sk_repl_dispatch_line()`'s own pairing check (`repl.c`) reconstructs the target as +> `console_get_vm_name() + "~user"`... **A console named anything other than the identity's own +> base name reconstructs the wrong target string and silently falls back to direct +> interpretation — no error, just quietly never relays.** + +`CONSOLE-ATTACH` already carries a workaround for this: it "takes exactly one name, not an +independently chosen console name," collapsing two arguments into one *so the reconstruction +cannot disagree*. That is a constraint imposed by the derivation, not by the problem. + +### XX.3 — RULING (proposed): the bind records its target; nothing re-derives it + +**Replace the derivation with a read of what bind time already stored.** + +- **`sk_repl_dispatch_line()`'s guard** asks "does this console have a recorded pairing, and is + that target live?" instead of "does `~user` exist?" +- **`CONSOLE-ATTACH`** resolves the target **as given**, rather than appending `~user` + (`mama_forth_words.c:2000`). +- **`~user` survives as a naming convention, not as a mechanism.** It still disambiguates + `rajames` the proxy from `rajames~user` the identity in the prompt — the whole point of the + `[user@VMName]` form (§XXV follow-up, 2026-09-13). It simply stops being load-bearing. + +**Four things fall out, none of which needed designing:** + +1. **Agent-VM binding stops being a special case.** A GPIO VM named `gpio` binds by the same + unchanged path as `bob~user`, because nothing appends anything to its name. **There is no + agent-binding mechanism to build.** +2. **`CONSOLE-ATTACH`'s one-name constraint can relax** if ever wanted — it exists only to + prevent a reconstruction that no longer happens. Not proposed as work; noted so the + constraint is not later mistaken for a requirement. +3. **The silent-fallback class is dissolved rather than fixed.** With no string to mismatch, + the states are "a pairing is recorded" or "none is" — determinate and reportable. **This + retires punch item 19** (§XIX.7's "make mismatch loud") by removing what could mismatch, + which is strictly better than making it noisy. +4. **The suffix-rename question becomes purely cosmetic** (§XIX.5). Once lookup no longer + derives the suffix, the remaining sites only ever *construct* a name. + +### XX.4 — The six `memcpy` sites split cleanly in two + +This is what makes the change small. Traced 2026-09-18: + +| Site | Role | Under this ruling | +|---|---|---| +| `capsule_wirebind.c:229` | **names** the identity VM at birth | **stays** — naming | +| `mama_forth_words.c:1864` (`UNATTENDED-BIRTH`) | **names** the registry entry | **stays** — naming | +| `mama_forth_words.c:1579` (`PAIR-TEST`) | **names** both halves; diagnostic word | **stays** — naming | +| `repl.c:1247` | **re-derives** the partner for a liveness guard | **goes** | +| `mama_forth_words.c:2000` (`CONSOLE-ATTACH`) | **re-derives** the target | **goes** | + +**Only the two derivation sites change.** The naming sites are untouched, which is why `~user` +can remain a convention without remaining a mechanism. + +### XX.5 — What "binding" means for an agent VM, stated because §V.1 conflated two things + +§V.1 called Hestia "the bind point for users and agent VMs." Worth separating, since the two +need different things and only one of them is binding: + +- **Reachability** — being addressable by other VMs — is **kernel-Hermes's** job (§III), not + Hestia's. A GPIO VM is reachable because routing exists, not because it bound to anything. +- **Fabric access** — a VM that wants to *draw* — is **vocabulary and ACL**, not binding: it + needs Hestia's drawing words (§XVIII.3), gated the `ACL.4th` way if gated at all. +- **Binding proper** — acquiring a console proxy so a human can type at a target — is what + `CONSOLE-ATTACH` does, and after §XX.3 it works for **any** live VM by name. + +**So an agent VM does not routinely bind at all.** It binds only when a human wants to attach +to it for inspection or control — and that is the ordinary console path, unchanged. The +"agent-binding problem" was an artifact of the hardcoded suffix; removing the suffix removes +the problem rather than solving it. + +### XX.6 — Punch list + +- ✅ **Item 3 — SETTLED** (§XX.3): the bind records its target; nothing re-derives it. Agent + binding needs no new mechanism. +- ✅ **Item 19 — RETIRED** (§XX.3.3): dissolved by removing the mismatch, not by making it loud. +- 🔶 **Item 9** — unchanged: is an ordinary peer's `SOS` actionable or advisory, plus its number. +- ⬜ **§VIII.3 first bullet** — where the sinking semaphore mechanically lives. +- ⬜ **Items 16, 17, 18** — unchanged (teardown/`STADIUM-EVICT` check; `BYE` vs. a separate + suicide word; the empty-floor halt). + +**Caveat on scope, per §XIV.1.** `repl.c`'s relay and the routing-slot-3 convention are part of +the FORTH messaging layer Captain Bob ruled legacy. This ruling states the *principle* — the +pairing is recorded, never derived — which kernel-Hermes must carry forward. It is not a +proposal to patch the legacy path in place.