Stage 4 verified: reap mechanism proven, real WIREBIND multiuser+multitasking confirmed live (FABRIC-3.md §XXX)
Reap mechanism (increments 2+3): temporary probe using Artemis as a safe stand-in parked identity, 3/3 checks PASS on all 3 architectures (refuse on SWITCHED_OUT, correct post-reap state, switch-signal slot released). Probe reverted, all 3 architectures re-verified clean. Live multiuser verification (increment 4, no code changes): a real previously-unattached identity thumbdrive attached via QMP on a running boot on all 3 architectures. VM-EXEC dispatch into her own live VM computed correctly, tagged with her own name in console output, full Tripod fleet unaffected. EJECT cleanly tore down both her VMs and released the switch-signal slot -- confirms increment 1's per-device fix under a real live attach/detach. Found and flagged, not fixed: interactive USE on a freshly-attached identity halts the kernel outright. Confirmed NOT caused by Stage 4 -- reproduced identically on the commit before any Stage 4 work. Direct VM-EXEC dispatch into the same identity works correctly; this is specific to the USE/BINDSTEP codepath, plausibly never caught before since every prior identity campaign used VM-EXEC, never interactive USE. Stage 4's original scope is complete: multitasking (Tripod) and multiuser (WIREBIND) are now genuinely composed, verified against real hardware-driven identity attach on all 3 architectures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d9da82b065
commit
597f5a6cd8
+94
@@ -3988,3 +3988,97 @@ indicated a larger new initiative is coming that will be introduced during Stage
|
|||||||
-- not detailed here since it hasn't been scoped yet, flagged only so this closing note doesn't
|
-- not detailed here since it hasn't been scoped yet, flagged only so this closing note doesn't
|
||||||
read as "nothing more is coming."
|
read as "nothing more is coming."
|
||||||
|
|
||||||
|
## XXX. Stage 4 -- WIREBIND-scope extension, built and verified live (2026-09-14/15)
|
||||||
|
|
||||||
|
**Bob's call: proceed with Stage 4 immediately rather than wait, folding the two §XXIX-deferred
|
||||||
|
bugs in only where they turned out to actually block the work** (neither did, in the end --
|
||||||
|
both stay open, tracked below in their original form). Built in the same staged,
|
||||||
|
one-commit-per-increment discipline as Stages 0-3.
|
||||||
|
|
||||||
|
**Increment 1 (commit `9f0f33d`) -- de-singleton WIREBIND detach tracking.** Found before
|
||||||
|
writing any Stage 4 code, on advisor review: `capsule_wirebind_unclean_detach()`/`eject()`
|
||||||
|
tracked "the attached identity" as a single global (`g_wirebind_attached_*`), correct for the
|
||||||
|
one-physical-console UX but wrong for detach safety once §XV/§XVI's own campaign already proved
|
||||||
|
multiple identities live simultaneously via this same attach path -- every attach after the
|
||||||
|
first silently overwrote the singleton, so an unclean detach of any but the *most recently
|
||||||
|
attached* identity was silently ignored: no console trace, no teardown, the VM and its native
|
||||||
|
stack leaked forever. Added a per-device live-identity table (`g_wirebind_live[]`, sized off
|
||||||
|
messaging.4th's own `VM-MAX` minus Tripod's 3 reserved slots -- 13, not an invented number),
|
||||||
|
kept separate from the console-pairing singleton, which is untouched and still governs the
|
||||||
|
`(user)` prompt exactly as before. Corrected the stale "single-USB-device constraint (§F.8)"
|
||||||
|
claim in `capsule_wirebind.h`'s own doc comments, false since §XV/§XVI.
|
||||||
|
|
||||||
|
**Increments 2+3 (commit `d9da82b`) -- switch-signal participation + mark-and-defer tombstone
|
||||||
|
reap.** WIREBIND *user* VMs (the ones that run real FORTH work; console VMs are pure REPL
|
||||||
|
proxies with nothing for a switch-in to preempt) now register as Stage 3 switch-signal
|
||||||
|
participants at attach (`sk_vm_switch_signal_register()`), unregister at teardown. Slot table
|
||||||
|
bumped 8 -> 16 (`VM-MAX`, the same real ceiling increment 1 used). Added
|
||||||
|
`sk_vm_switch_signal_unregister()` (compaction-based -- Tripod never needed removal, WIREBIND
|
||||||
|
VMs cycle constantly and would otherwise exhaust the bounded table).
|
||||||
|
|
||||||
|
Implements the plan's own ratified option (A) for the async-detach UAF risk named all the way
|
||||||
|
back when Stage 4 was first scoped (`logical-snuggling-bear.md`): mark-and-defer via a new
|
||||||
|
`pending_reap` flag on `VMRegistryEntry` -- deliberately a plain flag, not a new `VMState`
|
||||||
|
(`capsule_vm_kill()` already treats `VM_STATE_DEAD` as idempotent success, which would silently
|
||||||
|
swallow a reap attempt; `SWITCHED_OUT` still accurately describes a tombstoned-but-not-yet-freed
|
||||||
|
VM). `unclean_detach()` sets it when `capsule_vm_kill()` refuses a `SWITCHED_OUT` target instead
|
||||||
|
of just logging and dropping it on the floor; the Stage 3 checkpoint (`vm_core.c`) checks it
|
||||||
|
*before* ever attempting to resume a pending switch target, and calls the new
|
||||||
|
`capsule_vm_force_reap()` instead -- the one caller allowed to bypass `capsule_vm_kill()`'s own
|
||||||
|
refusal, because it runs at the exact safe cooperative point the switcher itself controls, the
|
||||||
|
same reasoning the original plan named. A new idle-tick sweep
|
||||||
|
(`capsule_wirebind_reap_idle_check()`) cleans up the stale live-table entry once the reap has
|
||||||
|
actually happened.
|
||||||
|
|
||||||
|
**Reap-mechanism verification (temporary probe, reverted, per this project's write-probe-
|
||||||
|
capture-revert discipline):** the mechanism has no real hardware timing dependency by design
|
||||||
|
(it operates purely on registry/switch-signal state), so proving it live against real WIREBIND
|
||||||
|
hardware timing would have tested the choreography, not the mechanism. Used Artemis as a safe
|
||||||
|
stand-in "parked identity" instead: force her into `VM_STATE_SWITCHED_OUT`, confirm
|
||||||
|
`capsule_vm_kill()` refuses, set `pending_reap`, call `capsule_vm_force_reap()` directly, confirm
|
||||||
|
`state == DEAD`/`vm_ptr == NULL`/`pending_reap == 0`/switch-signal slot released. 3/3 checks PASS
|
||||||
|
on all 3 architectures (Artemis is deliberately left dead for the remainder of each probe boot --
|
||||||
|
documented as expected, not a defect). Probe reverted; all 3 architectures re-verified clean at
|
||||||
|
rest afterward, no `REAP-TEST` output, Artemis alive and normal.
|
||||||
|
|
||||||
|
**Increment 4 -- live multiuser verification against real WIREBIND hardware (no code changes,
|
||||||
|
verification only).** A real, previously-unattached identity thumbdrive (`bob-thumb-ident.img`,
|
||||||
|
whose on-disk username is actually `rajames` -- confirmed live, not assumed) attached via QMP
|
||||||
|
`device_add` on a running boot, sequential per §XIV's own established workaround (one identity,
|
||||||
|
wait for `WIREBIND: rajames attached and ready`, no simultaneous-attach race attempted -- §XIV
|
||||||
|
itself remains open, sidestepped not fixed, exactly as §XXIX left it). Verified on all 3
|
||||||
|
architectures: `S" 1 1 + . " S" rajames~user" VM-EXEC` correctly computed `2` inside her own
|
||||||
|
live VM, tagged `[zuse@rajames~user]` in the console output, with the full Tripod fleet
|
||||||
|
simultaneously live and unaffected. `EJECT` (amd64) cleanly tore down both the console and user
|
||||||
|
VM, flushed, and released the switch-signal slot -- no leak, no crash, confirming increment 1's
|
||||||
|
per-device fix holds under a real live attach/detach, not just the reap probe's synthetic one.
|
||||||
|
|
||||||
|
**A real, pre-existing bug found during this verification, confirmed NOT caused by Stage 4:**
|
||||||
|
interactive `USE <identity>` on a freshly-WIREBIND-attached identity halts the kernel outright
|
||||||
|
(`VM fault -- emergency console disabled; halting`, the genuine C-level fault handler, not a
|
||||||
|
graceful FORTH-level error) -- reproduced identically on commit `1c220ad` (the last commit
|
||||||
|
before any Stage 4 work) via a temporary `git checkout` to that commit, same attach, same `USE
|
||||||
|
rajames`, same crash. Root cause not chased further this pass (out of Stage 4's own scope) --
|
||||||
|
plausibly never caught before because every prior identity-correctness campaign (§XII.4, §XV,
|
||||||
|
§XVI) drove identities via direct `VM-EXEC` dispatch, never through the interactive
|
||||||
|
`USE`/BINDSTEP console-relay path this specific crash requires. `VM-EXEC` dispatch into the same
|
||||||
|
identity, immediately before and after, works correctly -- this is specific to the `USE`
|
||||||
|
codepath (`mama_word_use()`, `mama_forth_words.c`), not a general identity-attach defect.
|
||||||
|
Flagged for a future pass, not fixed here.
|
||||||
|
|
||||||
|
**Verification method note, matching prior sessions' own established practice:** live device
|
||||||
|
attach used real QMP `blockdev-add`/`device_add` against the running instance's own QMP socket,
|
||||||
|
not a build-time `QEMU_EXTRA` mechanism -- confirmed identical to the technique §XIV/§XV already
|
||||||
|
used. Interactive console input used QMP `send-key`, extended this pass to handle uppercase
|
||||||
|
letters (shift+lowercase) and symbols needed for real command lines (`~`, `"`, `+`) -- the
|
||||||
|
existing `1 1 + .` probe from §XXVIII.2 only needed digits and `+`.
|
||||||
|
|
||||||
|
**Status: Stage 4's original scope (WIREBIND VMs as switch-signal participants, with the async-
|
||||||
|
detach UAF risk closed per the plan's own ratified design) is complete and verified live on all
|
||||||
|
3 architectures, real hardware-driven identity attach included.** Multitasking (fixed Tripod
|
||||||
|
fleet) and multiuser (WIREBIND identities) are now genuinely composed, not just coexisting.
|
||||||
|
Remaining open items, unchanged in status from §XXIX plus the one new finding: §XIV (concurrent
|
||||||
|
attach detection gap, still open, sidestepped via sequential attach), the MSG-TICK/Stage-3
|
||||||
|
dual-ownership rough edge (still open, not observed failing), and the newly-found pre-existing
|
||||||
|
`USE`/BINDSTEP crash (flagged, not fixed).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-09-15T04:46:38Z -->
|
<!-- Generated by mkcapsule --manifest 2026-09-15T07:25:25Z -->
|
||||||
<!-- 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. -->
|
||||||
|
|||||||
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
Reference in New Issue
Block a user