M2: KV driver interface, BaseKVDriver, InMemoryKVDriver, conformance suite

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qxbkp4tA7G5SCWjzWuxmE
This commit is contained in:
Claude
2026-10-23 06:53:54 +00:00
parent 69108d1557
commit f1ef4a71e9
11 changed files with 599 additions and 0 deletions
+17
View File
@@ -380,6 +380,23 @@ Decisions taken where the brief was silent. Each is the simplest option consiste
- **Ordering** of strings is by UTF-16 code unit (JS `<`). Drivers that compare UTF-8 bytes agree
except for astral-plane characters vs. U+E000–U+FFFF; noted as a driver-author caveat.
### M2 — KV driver
- **Conformance suite location**: `src/testing/kv-conformance.ts`, exported as `potential-storage/testing`.
It imports `vitest`, which is an *optional peer dependency*; the core entry point never imports it.
- **`InMemoryKVDriver` clones values** on write and read (`structuredClone`, skipped for primitives) so
stored state can't be mutated through shared references, matching serialising drivers. Opt out
with `{ clone: false }`.
- **Scans tolerate concurrent writes**: the in-memory scan remembers the last key yielded and re-seeks
if the map changed while suspended. Read-repair and `deleteTree` rely on this. The conformance suite
requires it of every driver (deleting an already-yielded key mid-scan must not skip keys).
- **`setMany` bulk path**: ≥32 new keys are sorted and merged (O(n + k log k)); fewer are spliced.
- **`BaseKVDriver.deleteRange`** deletes in chunks of 1000 (scan with `limit`, then `deleteMany`,
repeat), so it never deletes from under its own live iterator. It also provides `get`/`set`/`delete`
single-key helpers.
- **No fake `batch`**: `BaseKVDriver` deliberately does not provide a non-atomic `batch`, since stores
use its presence to mean "atomic".
<!-- decisions appended per milestone -->
## 13. Benchmark baselines