FABRIC-3.5.md §XX: item 3 settled -- delete the suffix from the mechanism

§XVIII.5 posed agent binding as widen-the-convention vs. add-a-word.
Both accept a premise the code does not support: the pairing is already
recorded explicitly at bind time, and the ~user reconstruction is a
redundant second derivation of information the mechanism already holds.

sk_repl_dispatch_line() does two separable things. The guard builds
console_get_vm_name() + "~user" and checks it is live. The actual relay
then sends to index 3 -- and repl.c's own comment says that slot is "set
once at pairing time," which PAIR-TEST's header confirms from the other
side. Routing never uses the derived string; only the liveness guard
does, and the stored pairing can answer that question without deriving
anything.

This is also the documented cause of a known silent failure.
CONSOLE-ATTACH's own comment records that a console named anything other
than the identity's base name reconstructs the wrong target and quietly
falls back to direct interpretation with no error. Its "takes exactly one
name" constraint is a workaround for that derivation, not a requirement
of the problem.

Ruling: the guard reads the recorded pairing, CONSOLE-ATTACH resolves the
target as given, and ~user survives as a naming convention rather than a
mechanism. Agent binding then stops being a special case -- a GPIO VM
binds by the same unchanged path, because nothing appends anything to its
name. Punch item 19 is retired rather than fixed: with no string to
mismatch there is nothing to make loud.

The six memcpy sites split cleanly -- three name a VM at birth and stay,
two re-derive a partner for lookup and go. Only the derivation sites
change, which is why the convention can survive without the mechanism.

Also separates what §V.1 conflated: reachability is kernel-Hermes's,
fabric access is vocabulary and ACL, and binding proper is the console
path. An agent VM does not routinely bind at all.

Scoped per §XIV.1: this states the principle kernel-Hermes must carry
forward, not a proposal to patch the legacy FORTH path in place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkM1zHGvBerLF6aqkHPweP
This commit is contained in:
Claude
2026-09-19 09:58:10 +00:00
parent 7a9a8ed698
commit d984b16102
+120 -2
View File
@@ -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" <line>" 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 `<name>~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.