diff --git a/FABRIC-3.md b/FABRIC-3.md index 8515e78..e1079b4 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -153,7 +153,11 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR its stale POSIX-flavored ownership fields with a pubkey-fingerprint owner + a fast-deny ACL bit + deliberate reserved slack. Field design done; the actual code edit is not. -- [ ] Implement writing the block-map to a drive. +- [x] **CLOSED 2026-08-27 (`FABRIC-3.md` §F.12) — already built, not a separate item.** + `blk_set_meta()`'s dirty-tracking already flows through the exact same `cache_writeback()`/ + `blk_flush()` path ordinary block data uses; the whole devblock (data + metadata) already + 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. @@ -1433,10 +1437,10 @@ graph TD CERTVERIFY["❌ Zuse-signed user-cert verification (M3)
SCOPED 2026-08-27 (§F.7) — X.509/DER, own trust root"] FIRSTTOUCH["❌ First-touch identity→block-range
allocation (M3) — SCOPED 2026-08-27 (§F.11)"] BMAPFMT["❌ On-drive block-map format (M3)
SCOPED 2026-08-27 (§F.4) — repurpose blk_meta_t"] - BMAPWRITE["❌ Write block-map to drive (M3)"] + BMAPWRITE["✅ Write block-map to drive (M3)
CLOSED 2026-08-27 (§F.12) — already built, blocked only on W10"] BMAPREAD["❌ Read/validate block-map on insert (M3)"] MIGSM["🟡 Migration state machine (M3)
partially answered: ACL decides *when*"] - UNCLEAN["✅ Unclean-removal handling (M3)
CLOSED 2026-08-27 (§F.10) — same kill path as EJECT, minus flush"] + UNCLEAN["❌ Unclean-removal handling (M3)
DESIGN CLOSED 2026-08-27 (§F.10), code not yet written"] ACLKEY["❓ ACL 'bumps and holes' comparison
semantics — SAME GAP in M5 and D.4"] WIREBIND["❌ Wire hotplug → capsule_birth_baby() (M5)"] @@ -1491,8 +1495,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,UNCLEAN done - class W10,STALL,FIRSTTOUCH,BMAPWRITE,BMAPREAD,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP blocked + class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG,BMAPWRITE done + class W10,STALL,FIRSTTOUCH,BMAPREAD,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP,UNCLEAN blocked class ACLKEY,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open class MIGSM partial ``` @@ -1551,6 +1555,10 @@ finished). Dashed arrows = softer "gates/informs" relationships. mechanism against the current design. A second, unrelated discovery in the same pass — `blk_meta_t`'s existing chain fields — turned what looked like a fragmentation problem into a non-issue for free. +- **`BMAPWRITE` was already done** (§F.12) — `BMAPFMT`'s decision to repurpose the existing + `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. **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 @@ -2059,6 +2067,36 @@ room (matching the pool-scope clarification in §F.6: the thumb is the default p node is specifically the *overflow* case) — implied yes by that clarification, not explicitly re-confirmed here. +### F.12 — `BMAPWRITE` (closed — already built, blocked only on `WRITE(10)`) + +Traced `blk_set_meta()`/`cache_writeback()`/`blk_flush()` fully before assuming any new write +path was needed. **Finding: this node is already done.** `blk_set_meta()` +(`block_subsystem.c:1198-1210`) marks the same cache-buffer entry's `meta_dirty` flag that +ordinary block-data writes use; `cache_writeback()` (`block_subsystem.c:274-285`) — called from +both `blk_flush()`'s targeted and flush-all paths, the exact function `blk_vm_flush_all()` and +`SAVE-BUFFERS` already exercise — packs the in-memory `blk_meta_t[]` array back into the +devblock's metadata region (`meta_to_slice()`) and writes the *whole* 4 KiB devblock (data + +metadata together, since they share one physical buffer) via `write_devblock_4k()`, real and +unstubbed all the way down to `dev->write()`. + +**Why this closes rather than just narrows:** the M3 item as originally written assumed a +*separate* block-map structure that would need its own bespoke write mechanism. `BMAPFMT`'s +decision (§F.4) to repurpose the already-existing, already-wired `blk_meta_t` accessors instead +of building a new table means "writing the map" and "writing a block" were never actually two +different operations — the infrastructure that already existed for ordinary block persistence +already covers metadata identically, with zero new code. The only reason this hasn't been +observed working end-to-end is the same hard blocker already modeled in the graph: `WRITE(10)` +doesn't exist yet, so `dev->write()` never actually reaches physical media for a USB-attached +drive today. Nothing else stands between this and working. + +**Handoff note for `BMAPREAD`'s own future pass:** the read side (`cache_load_devblock()`, +`block_subsystem.c:308-322`) already unpacks and validates metadata (`meta_from_slice()`, +magic-checked, resets to a clean default on a bad/missing magic) on every devblock load — very +likely the same "already built, not a separate item" outcome, but not confirmed here; that +node may have its own distinct question (e.g. whether a home-blocks drive needs an explicit +validate-on-insert step beyond ordinary lazy per-devblock read-through-cache), left for its own +pass rather than assumed away. + ### 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