diff --git a/FABRIC-3.md b/FABRIC-3.md
index 05f00bb..e271541 100644
--- a/FABRIC-3.md
+++ b/FABRIC-3.md
@@ -115,10 +115,11 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
goal — *"keeps xhci.c decoupled from block_subsystem.c"* — and that decoupling is real,
live on all three arches. Closed as written; no further design work on this node itself.
-- [ ] Implement CBW/data/CSW for SCSI WRITE(10) — this is where the earlier "read/write,
- unquestionable" requirement actually gets satisfied. Still the single biggest functional
- gap in the xHCI driver — blocks writing to a real USB thumb drive at all (`blkio_usb.c` is
- read-only today specifically because of this).
+- [x] **BUILT + VERIFIED 2026-08-28 (`FABRIC-3.md` §F.17).** CBW/data/CSW for SCSI WRITE(10),
+ a direct mirror of READ(10) with the data direction flipped. Verified live via a genuine
+ cold-reboot round-trip on all three architectures (amd64/aarch64/riscv64), not just a
+ same-session read. `blkio_usb.c` is read-write now; `read_only` flipped to `0`. Real hardware
+ (Milestone 8) remains untested — QEMU-only so far.
- [ ] Implement basic error/stall recovery (CSW failure status, endpoint stall clear) — at
minimum enough to not wedge the controller on a single bad transfer. **SCOPED 2026-08-27
@@ -1459,7 +1460,7 @@ punch list hides that; a graph doesn't.
```mermaid
graph TD
- W10["❌ WRITE(10) SCSI support
(Milestone 2 — biggest single blocker)"]
+ W10["✅ WRITE(10) SCSI support
BUILT + VERIFIED 2026-08-28 (§F.17), all 3 arches"]
HOTPLUG["✅ Hotplug event surfacing
CLOSED 2026-08-27, M2 (§F.3)"]
STALL["❌ USB error/stall recovery (M2)
SCOPED 2026-08-27 (§F.14) — full BOT-spec recovery designed"]
@@ -1490,11 +1491,12 @@ graph TD
ROUNDTRIP["✅ Session state round-trip
across attaches — CLOSED 2026-08-27 (§F.16)"]
POLYBLOCK["✅ Polymorphic block-boundary
behavior — CLOSED 2026-08-27 (§F.16), already true"]
PROMPTBUG["🐛 (Zuse)ok> prompt typo
CLOSED 2026-08-27 (§F.16) — doc-comment only, not live code"]
+ EMPTYBUFBUG["🐛 EMPTY-BUFFERS mass-zeros every
block on every device (§F.17) — found 2026-08-28, NOT FIXED"]
- W10 -->|blocks| BMAPWRITE
- W10 -->|blocks| MINT
- W10 -->|blocks| DETACH
- W10 -.->|blocks real-hardware testing of everything below| M8["Milestone 8 — bare metal"]
+ W10 -->|unblocked, §F.17| BMAPWRITE
+ W10 -->|unblocked, §F.17| MINT
+ W10 -->|unblocked, §F.17| DETACH
+ W10 -.->|QEMU-verified; real hardware still untested| M8["Milestone 8 — bare metal"]
M6 -->|unblocks| CERTVERIFY
PH8 -->|supplies crypto primitives| CERTVERIFY
@@ -1528,8 +1530,8 @@ graph TD
classDef unblocked fill:#a83,stroke:#333,color:#fff
classDef open fill:#666,stroke:#333,color:#fff
classDef partial fill:#883,stroke:#333,color:#fff
- class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG,BMAPWRITE,BMAPREAD,SSDSCOPE,ROUNDTRIP,POLYBLOCK done
- class W10,STALL,FIRSTTOUCH,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP,UNCLEAN,MSGMIGRATE,ACLKEY blocked
+ class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG,BMAPWRITE,BMAPREAD,SSDSCOPE,ROUNDTRIP,POLYBLOCK,W10 done
+ class STALL,FIRSTTOUCH,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP,UNCLEAN,MSGMIGRATE,ACLKEY blocked
class MIGSM partial
```
@@ -1607,6 +1609,12 @@ finished). Dashed arrows = softer "gates/informs" relationships.
substantial vision expansion (§D.6): blank-media minting is meant to be an interactive,
Console-driven onboarding form, connecting forward into both `RUNCAP`'s deferred
"default personality content" question and `MINT`'s own scope.
+- **`WRITE(10)` (§F.17), the graph's original highest-leverage node, is built and verified —
+ the whole arc's single hard blocker is gone.** `BMAPWRITE`, `MINT`, and `DETACH`/`EJECT` all
+ move from "scoped, blocked" to "scoped, genuinely buildable." Validating it surfaced a real,
+ separate, serious bug (`EMPTYBUFBUG`) — a stark reminder that this pile still has more
+ surprises in it than the scoping pass alone can find; the "full codebase audit pass" already
+ flagged as deferred (§D.5) has real work waiting for it.
**Not yet done:** an ordered plan (which node to attack first, given the graph). Per Captain
Bob's own framing, that's the next pass — "start asking and answering questions iteratively
@@ -2448,3 +2456,44 @@ mediated rather than a direct Hera-side check; how this reconciles with `PENTAGO
Hera↔Console edge, not the other nine.
+
+### F.17 — `WRITE(10)` implemented and verified (2026-08-28) — the graph's last hard blocker, closed
+
+Implemented exactly as scoped in `F.1`, a direct mirror of the existing `READ(10)` machinery
+with the data direction flipped: new `XHCI_XFER_BOT_DATA_OUT`/`XHCI_NEXT_ACTION_BOT_DATA_OUT`
+states, `xhci_bot_send_write10()`/`xhci_bot_write_block()`/`xhci_bot_write_data_out()`
+(`xhci.c`), new `SCSI_CMD_WRITE10` opcode and `BOT_CMD_WRITE10`/`BOT_TUR_CHAIN_WRITE10` enum
+values (`xhci_driver.h`, kept as fully separate fields from the `bot_read10_*` ones rather than
+renamed/reused, so the already-tested `READ10` path is never touched). `usb_blk_write()`
+(`blkio_usb.c`) is real now, no longer the `BLKIO_ENOSUP` stub — `read_only` in `blkio_info()`
+flips to `0`, per `F.1` decision 1, now that it's proven.
+
+**Verified live, all three architectures, with a genuine cold-reboot round-trip** — not just a
+same-session read, the real proof this class of change needs: `BLK-CONFIRM-FORMAT`'s BAM/reloc
+zero-page writes and an explicit block-content write both completed via clean `WRITE10` cycles
+(CSW PASS every time), then a full kernel rebuild + fresh boot read the written byte back
+correctly — `amd64=65`, `aarch64=170`, `riscv64=201`, each at LBN 32734 on a disposable
+`disk/usbwrite-test.img` attached via QEMU `usb-storage`, matching `F.1` decision 2's validation
+plan exactly.
+
+**One real methodology finding, not project-specific:** the disposable test drive must be
+hotplugged via QMP *after* boot reaches `ok>`, never attached at QEMU launch — attaching before
+`xhci_bringup()`'s controller reset means the port already reads as connected when the driver
+starts, so no fresh Port Status Change event ever fires and hotplug detection looks broken even
+though it isn't (already documented in `project_xhci_milestone_2d_polling`, re-confirmed here
+the hard way on the first attempt).
+
+**A real, serious, pre-existing bug found and reported (not fixed) during validation:**
+`EMPTY-BUFFERS` (`empty_all_buffers()`, `block_words.c:148-158`) does not implement standard
+Forth-79 semantics — it force-writes zero to *every* block on *every* attached device, rather
+than discarding cache-slot assignments without writing. Calling it during testing (reasonably
+assuming standard semantics) mass-zeroed blocks across the whole system, including
+`disk/artemis.img` — ~3.3 million bytes, essentially its entire content region. Restored from
+git, confirmed byte-identical to `HEAD`. Avoided for the rest of validation (detach/reattach via
+QMP used instead to force a fresh device read, which is non-destructive).
+
+**Consequence for the rest of the graph:** `W10` was the single hub gating `BMAPWRITE`
+(already independently confirmed working, §F.12), `MINT`, and `DETACH`/`EJECT`'s flush step —
+all three are now genuinely unblocked, not just scoped. Nothing about their own design changes;
+they can now actually be built and tested rather than only designed. Real hardware (Milestone
+8) remains untested — this verification is QEMU-only, per `F.1`'s own acknowledged scope.