From d565a6b845da7532ef8e1c33a3b5dfacb5d23672 Mon Sep 17 00:00:00 2001 From: Daniel Samson <12231216+daniel-samson@users.noreply.github.com> Date: Sun, 9 Aug 2026 13:58:29 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20the=20hot-plug=20matrix=20plan=20?= =?UTF-8?q?=E2=80=94=20unplug=20anything,=20replug=20anywhere?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/hot-plug-matrix-plan.md | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/hot-plug-matrix-plan.md diff --git a/docs/hot-plug-matrix-plan.md b/docs/hot-plug-matrix-plan.md new file mode 100644 index 0000000..21106fc --- /dev/null +++ b/docs/hot-plug-matrix-plan.md @@ -0,0 +1,47 @@ +# The hot-plug matrix: unplug anything, replug anywhere + +*2026-08-09. The requirement, verbatim: "i want to be able to unplug devices and +plug them back in, in any order and on any hub." The machinery exists end to end — +per-device driver processes, cascading teardown (`tearDownHubDevice` recurses a +departing hub's subtree, children first), reap-on-removal in the manager, idempotent +per-port registration identity, lineage rebinding — but only one cell of the matrix +is verified: a leaf keyboard behind a hub, unplugged and replugged on the same port +(`usb-hub-unplug`). This plan verifies the rest and fixes what verification flushes +out. The cascade path has never executed; expect it to carry at least one bug.* + +**Out of scope, stated up front:** unplugging the BOOT stick (the drivers handle it; +fat holds a dead block channel until M21 remount gives it re-acquisition), and +real-hardware root-port timing (the Ryzen bench is the acceptance run for that, as +always — QEMU proves the logic, not the silicon). + +## The discrimination lever + +Every case's rebind tail (— reaping → delegated → second-generation `ok`) is +impossible without the manager's reap: stashing the reap out of +`onChildRemoved`/`pruneChildrenOf` makes every matrix case fail at the dedupe wall. +That is the standing discrimination check for the whole matrix — run it once per +case shape, not per commit. + +## The matrix + +| Case | Topology | Event sequence | What it proves | +|---|---|---|---| +| H1 `usb-root-replug` | keyboard on a 2nd controller's ROOT port | del @8s, add @14s (same port) | the `tearDownPort` path + reap + rebind; root-port changes arrive via the 250 ms reconcile tick (QEMU raises no root-port events) | +| H2 `usb-hub-yank` | hub on 2nd controller; keyboard AND mouse behind it | del the HUB @8s; re-add hub @14s, kbd @17s, mouse @18s | the recursive cascade: one event removes the subtree, EVERY bound driver is reaped, and the rebuilt hub re-binds both | +| H3 `usb-hub-nested-yank` | hub → hub → keyboard | del the OUTER hub @8s; re-add all three @14–18s | the cascade recursion depth ≥ 2, and a nested rebuild | +| H4 `usb-replug-moved` | keyboard behind hub port 1.1 | del @8s; add on port 1.2 @14s | a replug on a DIFFERENT port is simply a new device: new port identity, new id, fresh match — no stale state ties a driver to the old port | +| H5 `usb-replug-cycles` | keyboard behind hub | del/add three times (6 hooks) | no state leaks across generations: slots, the bus's open table, driver entries (reaped entries must be reusable) | + +Ordered expects follow the `usb-hub-unplug` shape: the boot devices' `ok` lines all +precede the first unplug, so a tail of `removed → reaping → delegated → ok` can only +be satisfied by the generation the sequence created. H2/H3 require one `reaping` per +bound child; H5 requires three. + +## Order and discipline + +H1 → H2 → H3 → H4 → H5, one commit per case (plus its fix if it finds a bug — the +case and the fix land together, the case having failed first). The standing +discrimination run once for H1 and once for H2's shape. Full suite green at the end, +docs touched where behavior was corrected, memory updated. Fixes stay within the +settled design: teardown order (children first), reap-on-removal, identity per port +— anything design-shaped that surfaces stops the loop and asks.