FABRIC-3.md: close BMAPREAD as already-built, fix a real devblock-0 header collision

Confirmed the F.12 handoff: cache_load_devblock() already unpacks/validates metadata on load, same "already built" story as BMAPWRITE. But tracing "validate on insertion" surfaced a real, load-bearing conflict unrelated to blk_meta_t: blk_subsys_attach_device() always runs the generic block-subsystem's own STFR/v2 header check at devblock 0, which would always read a home-blocks drive's 'LAHB' magic as "unrecognized" and leave it permanently write-refused (BLK_FMT_PROVISIONAL) -- or, if force-formatted via blk_subsys_confirm_format(), overwrite homeblocks_sig_t outright, since both want the same devblock 0. This was invisible to CERTVERIFY/WIREBIND/RUNCAP/MINT because none of them traced the generic attach path alongside homeblocks_sig_check(). Fixed: homeblocks_sig_t relocates to devblock 1 (a call-site change only, sig_start_fblock was already a plain parameter); MINT must also run the ordinary format-confirm path at devblock 0 so the drive is writable through the normal block-buffer path.
This commit is contained in:
Robert Allan James
2026-08-27 14:49:52 -04:00
parent 198e82a029
commit 6a3eb5997f
+60 -4
View File
@@ -159,7 +159,13 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
gets written to the device, real and unstubbed. Blocked only on `WRITE(10)` itself, already
modeled in the graph — nothing else stands between this and working.
- [ ] Implement reading/validating the block-map from a drive on insertion.
- [x] **CLOSED 2026-08-27 (`FABRIC-3.md` §F.13) — already built, not a separate item.**
`cache_load_devblock()` already unpacks and validates every devblock's metadata on load.
Tracing "on insertion" surfaced a real, separate, previously-unflagged conflict instead:
`homeblocks_sig_t` and the block-subsystem's own generic `'STFR'`/v2 header both wanted
devblock 0, which would leave a home-blocks drive permanently write-refused or overwrite its
own identity header. Fixed by relocating `homeblocks_sig_t` to devblock 1; `MINT` must also
run the ordinary format-confirm path at devblock 0.
- [ ] Design the migration state machine (Section U item 5) — states, transition triggers.
Session direction, 2026-08-25: **ACL manages *when* to relocate** (capacity pressure, or a
@@ -1438,7 +1444,7 @@ graph TD
FIRSTTOUCH["❌ First-touch identity→block-range<br/>allocation (M3) — SCOPED 2026-08-27 (§F.11)"]
BMAPFMT["❌ On-drive block-map format (M3)<br/>SCOPED 2026-08-27 (§F.4) — repurpose blk_meta_t"]
BMAPWRITE["✅ Write block-map to drive (M3)<br/>CLOSED 2026-08-27 (§F.12) — already built, blocked only on W10"]
BMAPREAD[" Read/validate block-map on insert (M3)"]
BMAPREAD[" Read/validate block-map on insert (M3)<br/>CLOSED 2026-08-27 (§F.13) — already built"]
MIGSM["🟡 Migration state machine (M3)<br/>partially answered: ACL decides *when*"]
UNCLEAN["❌ Unclean-removal handling (M3)<br/>DESIGN CLOSED 2026-08-27 (§F.10), code not yet written"]
@@ -1471,6 +1477,7 @@ graph TD
BMAPFMT --> BMAPWRITE
BMAPFMT --> BMAPREAD
BMAPFMT --> FIRSTTOUCH
BMAPREAD -.->|found: sig must relocate off devblock 0, §F.13| MINT
CERTVERIFY --> RUNCAP
RUNCAP --> MINT
@@ -1495,8 +1502,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 done
class W10,STALL,FIRSTTOUCH,BMAPREAD,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP,UNCLEAN blocked
class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG,BMAPWRITE,BMAPREAD done
class W10,STALL,FIRSTTOUCH,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP,UNCLEAN blocked
class ACLKEY,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open
class MIGSM partial
```
@@ -1559,6 +1566,13 @@ finished). Dashed arrows = softer "gates/informs" relationships.
`blk_meta_t` accessors instead of a new table meant "write the map" and "write a block" were
never actually two operations. The only reason this hasn't been seen working is `WRITE(10)`
itself, already the graph's known hub.
- **`BMAPREAD` closed the same way, but tracing it surfaced a real, load-bearing bug that had
nothing to do with reading at all** (§F.13) — `homeblocks_sig_t` and the block-subsystem's
own generic disk header physically collide at devblock 0. Every earlier node that touched
`homeblocks_sig_t` (`CERTVERIFY`, `WIREBIND`, `RUNCAP`, `MINT`) inherited this without anyone
noticing, because each only traced `homeblocks_sig_check()` itself, never the ordinary attach
path running alongside it. Fixed now (relocate to devblock 1) rather than left to surface
later as a real, confusing runtime failure.
**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
@@ -1870,6 +1884,10 @@ resolved before any design decision was needed:
cert + identity-source regions; everything past that is the user's own general block-storage
pool directly, consistent with `FIRSTTOUCH`'s pool clarification in §F.6). No GPT-parser
node needed in the graph at all — this closes that thread rather than deferring it.
**Correction, 2026-08-27 (§F.13): `homeblocks_sig_t` itself moved off devblock 0** to
devblock 1 (forth-block 4) once a real collision with the block-subsystem's own generic
disk header was found — the "devblocks `0..N`" metadata-region framing above still holds,
it just now starts one devblock later than stated here.
2. **Single-device USB driver.** `xhci_dev_t`'s BOT/MSC state (`device_ctx`, `bulk_in_ring`,
`bulk_out_ring`, `bot_data_buf`) are singular fields, not per-slot arrays — only one USB MSC
device is usable at a time today. This looked like it might conflict with the vision's
@@ -2097,6 +2115,44 @@ node may have its own distinct question (e.g. whether a home-blocks drive needs
validate-on-insert step beyond ordinary lazy per-devblock read-through-cache), left for its own
pass rather than assumed away.
### F.13 — `BMAPREAD` (closed — already built) — and a real header collision found and fixed
Confirmed the handoff note from `F.12`: `cache_load_devblock()` (`block_subsystem.c:308-322`)
already unpacks and validates every devblock's metadata on load (`meta_from_slice()`,
magic-checked, resets cleanly on a bad/missing magic) — the read side is exactly as "already
built, not a separate item" as the write side. Same closure, no new mechanism needed.
**But tracing "validate on insertion" turned up a real, previously-unflagged conflict that has
nothing to do with `blk_meta_t` at all.** `blk_subsys_attach_device()` — the *general* attach
path every device goes through, USB drives included — always calls `blk_format_or_load_disk()`
(`block_subsystem.c:581-613`), which reads devblock 0 looking for the block-subsystem's own
`'STFR'`/v2 volume header. `homeblocks_sig_t`'s magic is `'LAHB'`, not `'STFR'`, so a minted
home-blocks drive always reads as "unrecognized" here and lands in `BLK_FMT_PROVISIONAL` —
and `blk_get_buffer()` (`block_subsystem.c:894`) **refuses all writes** to a `PROVISIONAL`
slot until `blk_subsys_confirm_format()` is called. That function
(`blk_commit_format()`, `block_subsystem.c:546-571`) writes a fresh STFR header to the *same*
devblock 0 — which would physically overwrite `homeblocks_sig_t`. Neither outcome (stay
`PROVISIONAL` forever, or get STFR-formatted and lose the identity header) works. This was
invisible to `CERTVERIFY`/`WIREBIND`/`MINT` because each only ever traced
`homeblocks_sig_check()` itself, never the generic attach path running alongside it.
**Decision made 2026-08-27:** `homeblocks_sig_t` relocates to **devblock 1** (forth-block 4),
leaving devblock 0 for the generic STFR/v2 header untouched — no changes to the already-tested
block-subsystem code. `homeblocks_sig_check()` already takes its starting forth-block as a
plain parameter (`sig_start_fblock`, not hardcoded), so this is a call-site change, not a
format-logic change. `MINT` (§F.8) must also run the ordinary `blk_subsys_confirm_format()`
path at mint time (writing a ordinary fresh STFR/v2 header at devblock 0) so the drive is
immediately writable through the normal block-buffer path, in addition to writing
`homeblocks_sig_t`/cert/identity-source starting at devblock 1. `F.8`'s own text has been
corrected in place to point here rather than restate this.
**Not yet scoped (deferred within this node):** whether `MINT`'s STFR-format-then-sig-write
sequence needs a specific ordering/atomicity guarantee (e.g. what state a drive is left in if
power is lost between the two writes) — real question, not addressed here; the exact
`sig_start_fblock` value call sites (`CERTVERIFY`, `WIREBIND`, `RUNCAP`, `MINT`) all need
updating from their currently-recorded devblock-0-relative assumption to devblock-1, a
mechanical follow-up once any of this is actually coded, not re-litigated here.
### D.5 — Scope expansion (2026-08-27): identity is common to every VM, not just users
Surfaced while scoping `ACLKEY`, stated directly: *"the whole object is to deliver a