One block-granular read: land the whole block (all kv-heads’ K then V,
block_bytes) into the device slot based at dst_dev_ptr
(== ScratchPool::slot_dev_ptr(slot)). base_key carries kv_head = 0, kind = K by convention; only its layer and block are load-bearing.
Expand each BlockReadRequest into the exact 2·nkv per-head ReadRequests
the un-coalesced path issues, in the SAME order the caller loops emit
(interleaved K(kh), V(kh) for kh in 0..nkv) with device destinations
at dst + kh·gs (K) and dst + (nkv+kh)·gs (V).