docs: scope the bounds track's unattended run

Six steps an agent can execute: reclamation, the bounds build check, and
the four user-space USB/xHCI bounds where the hardware already reports the
number we guessed.

Deliberately excluded: the authorisation gate and moving the device
inventory to the manager. Both decide whether the OS is secure and both are
a direction rather than a specification — what a device capability is, which
syscalls change, what replaces device_claim for its seven callers. They want
a design session, not an agent.

Three open questions are written down rather than guessed: device_enumerate
most likely narrows to the firmware-discovered roots rather than retiring
(the manager cannot ask itself for the PCI host bridge); a manager restart
has no re-enumerate handshake, so it comes back blind while its buses live;
and "add adversarial tests" is not executable until the attacks are named.
This commit is contained in:
Daniel Samson
2026-08-08 11:13:20 +01:00
parent a86559648e
commit 4398eb7cc4
+68
View File
@@ -3,6 +3,74 @@
*Plan, 2026-08-08. Follows [fixed-bounds-audit.md](fixed-bounds-audit.md) (235 ceilings, *Plan, 2026-08-08. Follows [fixed-bounds-audit.md](fixed-bounds-audit.md) (235 ceilings,
139 on quantities we do not choose) and the AMD Ryzen that found the first one.* 139 on quantities we do not choose) and the AMD Ryzen that found the first one.*
---
## Live state — the unattended run
*This table is the progress view. It is updated at the end of every step, before the
next one starts.*
| Step | What | State |
|---|---|---|
| L1 | Reclamation: a dead task's registrations die with its claims | not started |
| L2 | Bounds build check + allowlist; declare what we have already touched | not started |
| L3 | xHCI: slot count from `HCSPARAMS1.MaxSlots`, not 8 | not started |
| L4 | USB: configuration descriptor sized by `wTotalLength`, not 512 | not started |
| L5 | USB: interfaces from the descriptor, and the misattributed-endpoint bug | not started |
| L6 | xHCI: a failed `allocateDevice` stops leaking an enabled slot | not started |
**Suite:** 115/115 at the start of the run.
**Branch:** `claude/bounds-track`.
### What this run deliberately does not touch
Phases 2 and 3 below — the authorisation gate and moving the inventory to the device
manager — are **out of scope for unattended work**. They decide whether the OS is
secure, and they are currently a direction rather than a specification: what a device
capability *is*, which syscalls change, what replaces `device_claim` for its seven
callers, how a driver spawned bare behaves. Those want a design session, the way
`/protocol` had one.
Also out of scope: anything touching `maximum_device_resources` (a wire struct, so a
trust-boundary change, not a resize), and the non-device bounds the audit found in FAT,
the VFS, logger, init, display and boot.
### Open questions this run must not answer on its own
Recorded here rather than guessed. If a step runs into one, it stops and writes the
question down instead of inventing an answer.
1. **`device_enumerate` probably narrows rather than retires.** The device manager
calls it to find `pci_host_bridge` nodes — it cannot ask itself. The likely shape is
that the kernel keeps the *firmware-discovered roots* (which by principle 5 it holds
for real reasons, since they come from ACPI rather than a driver's say-so) and
everything a driver registered lives in the manager. Not decided.
2. **A device-manager restart has no re-enumerate handshake.** If only the manager
dies, the buses are alive and never re-send `child_added`, so a restarted manager
comes back blind. The manager is restartable by design; nothing implements this.
3. **Which adversarial tests I1–I3 need.** The audit's six real defects were all found
by asking what an attacker would do, and the suite had never asked. "Add adversarial
cases" is not executable until the attacks are named.
### Working rules for the run
- Work in `/Users/danielsamson/Gitea/daniel/danos` (not a worktree), on
`claude/bounds-track`.
- **Every step lands with a test that fails before the fix**, verified by temporarily
restoring the old behaviour and watching exactly the intended assertion flip. A test
that passes both ways is not a test.
- Full QEMU suite green before each commit. Never run two suites at once — check
`pgrep -f qemu_test.py` first; a second concurrent run produces false triple faults
because both share `zig-out`.
- Check at least 60 GiB free before starting a suite.
- Commit with `git commit -F <file>`, never `-m` (a backtick in a message is executed
by the shell and silently eats a word). No `Co-Authored-By` trailers.
- Update the Live state table **before** starting the next step.
- If a step needs a decision that is not written down here, stop, add it to the open
questions above, and move to the next step.
---
## The principles this is derived from ## The principles this is derived from
1. **danOS is a microkernel.** Minimise what the kernel is responsible for; move 1. **danOS is a microkernel.** Minimise what the kernel is responsible for; move