DataPoint trait gains opt-in encode_blob / decode_blob / blob_pointer_offset
with None defaults. 23 numeric DataPoint impls inherit defaults and behave
unchanged. DiskStore<T> opens a companion .blob file alongside .dat+.idx
ONLY when blob_pointer_offset() is Some(_). Write order: blob bytes first,
then header with patched (offset:u64, len:u32) tail. Read tail opens .blob
read-only and reconstructs string fields. Out-of-range blob pointers are
logged + skipped.
Four string-bearing variants now persist normally:
- BlockTradePoint: 44 B header (32 + 12 tail), blob {block_id}
- AuctionEventPoint: 36 B header (24 + 12 tail), blob {auction_id, state}
- MarketWarningPoint: 20 B header (8 + 12 tail), blob {warning_kind, message}
- OrderbookL3Point: 44 B header (32 + 12 tail), blob {order_id, action}
persistence::is_enabled_for no longer special-cases the 4 string types.
tests/blob_persistence.rs: 9 new tests covering ASCII / UTF-8 / empty /
1KiB strings, full DiskStore append+read_tail round-trip for BlockTrade +
MarketWarning, regression that TradePoint does NOT create .blob files.