diff --git a/.gitignore b/.gitignore
index f8f635b22..86bf4e458 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,5 +11,9 @@ __pycache__
 node_modules/
 .envrc
 package-lock.json
-
 bun.lock
+uv.lock
+.gemini/
+.claude/
+.codex/
+.mcp.json
diff --git a/attic/kv/Cargo.toml b/attic/kv/Cargo.toml
deleted file mode 100644
index 38f449847..000000000
--- a/attic/kv/Cargo.toml
+++ /dev/null
@@ -1,50 +0,0 @@
-[package]
-name = "tetra-kv"
-version.workspace = true
-edition.workspace = true
-authors.workspace = true
-homepage.workspace = true
-description = "Tetra key-value: pluggable storage backend"
-repository.workspace = true
-
-[lints]
-workspace = true
-
-[features]
-default = ["rocksdb", "heed"]
-rocksdb = ["dep:rocksdb", "dep:librocksdb-sys"]
-heed = ["dep:heed"]
-
-[dependencies]
-tetra-core.workspace = true
-rand.workspace = true
-tempfile.workspace = true
-parking_lot.workspace = true
-postcard.workspace = true
-serde.workspace = true
-bytes.workspace = true
-smallvec.workspace = true
-derive_more.workspace = true
-derive-where.workspace = true
-thiserror.workspace = true
-smol_str.workspace = true
-serde_cbor.workspace = true
-triomphe.workspace = true
-futures.workspace = true
-tokio.workspace = true
-blake3.workspace = true
-anyhow.workspace = true
-heapless.workspace = true
-ahash.workspace = true
-bon.workspace = true
-heed = { workspace = true, optional = true }
-rocksdb = { workspace = true, optional = true }
-librocksdb-sys = { workspace = true, optional = true }
-
-[dev-dependencies]
-criterion.workspace = true
-rayon.workspace = true
-
-[[bench]]
-name = "kvops"
-harness = false
diff --git a/attic/kv/README.md b/attic/kv/README.md
deleted file mode 100644
index cbd8b43de..000000000
--- a/attic/kv/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# tetra-kv
-
-Pluggable key–value storage for Tetra with both in‑memory and RocksDB
-implementations.
diff --git a/attic/kv/benches/kvops.rs b/attic/kv/benches/kvops.rs
deleted file mode 100644
index 2f3170662..000000000
--- a/attic/kv/benches/kvops.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-use std::{sync::Arc, time::Duration};
-
-use bytes::Bytes;
-use criterion::{Bencher, BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
-use rand::{Rng, RngCore, SeedableRng, rngs::StdRng};
-use rayon::prelude::*;
-use tetra_kv::{Store, Write, WriteBatch, ops};
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, derive_more::From, derive_more::Into)]
-pub struct Lcg64(pub u64);
-
-impl rand::RngCore for Lcg64 {
-   #[inline]
-   fn next_u32(&mut self) -> u32 {
-      self.next_u64() as u32
-   }
-
-   #[inline]
-   fn next_u64(&mut self) -> u64 {
-      self.0 = self
-         .0
-         .wrapping_mul(6364136223846793005)
-         .wrapping_add(1442695040888963407);
-      self.0
-   }
-
-   #[inline]
-   fn fill_bytes(&mut self, dest: &mut [u8]) {
-      let (qwords, rest) = dest.as_chunks_mut();
-      for q in qwords {
-         *q = self.next_u64().to_le_bytes();
-      }
-      if !rest.is_empty() {
-         let n = rest.len();
-         let buf = self.next_u64().to_le_bytes();
-         dest[..n].copy_from_slice(&buf[..n]);
-      }
-   }
-}
-
-// A generic benchmark configuration
-struct BenchConfig {
-   // Number of operations to perform
-   num_ops: usize,
-   // Size of values in bytes
-   value_size: usize,
-   // Number of threads to use (1 for single-threaded)
-   threads: usize,
-   // Batch size
-   batch_size: usize,
-   // (Read, Write, Update + name of the flavor) distributions
-   rwu: (usize, usize, usize, &'static str),
-   // Whether to prepare data before benchmarking
-   prepare_data: bool,
-}
-
-impl BenchConfig {
-   fn step<'a, S: Store>(
-      &self,
-      store: &'a S,
-      key: &[u8],
-      data: &[u8],
-      batch: Option<&mut S::WriteBatch<'a>>,
-      rng: &mut Lcg64,
-   ) {
-      let (pct_r, pct_w, pct_u, _) = self.rwu;
-      let pct_sum = pct_r + pct_w + pct_u;
-
-      let mut val = rng.random_range(0..pct_sum);
-
-      val = val.saturating_sub(pct_r);
-      if val == 0 {
-         // Read operation
-         let _ = store.get(key).unwrap();
-         return;
-      }
-      val = val.saturating_sub(pct_w);
-      if val == 0 {
-         // Write operation
-         if let Some(batch) = batch {
-            batch.put(key, data);
-         } else {
-            store.put(key, data).unwrap();
-         }
-         return;
-      }
-
-      // Update operation
-      if let Some(batch) = batch {
-         batch.update(key, &ops::Append(data));
-      } else {
-         store.update(key, &ops::Append(data)).unwrap();
-      }
-   }
-
-   fn step_n(
-      &self,
-      num_ops: usize,
-      store: &impl Store,
-      keys: &[Bytes],
-      dataz: &[Bytes],
-      rng: &mut Lcg64,
-   ) {
-      if self.batch_size == 1 {
-         for _ in 0..num_ops {
-            let key = &keys[rng.next_u64() as usize % keys.len()];
-            let data = &dataz[rng.next_u64() as usize % dataz.len()];
-            self.step(store, key, data, None, rng);
-         }
-      } else {
-         let mut batch = store.batch();
-
-         let mut at = 0;
-         while at < num_ops {
-            for _ in at..std::cmp::min(at + self.batch_size, num_ops) {
-               let key = &keys[rng.next_u64() as usize % keys.len()];
-               let data = &dataz[rng.next_u64() as usize % dataz.len()];
-               self.step(store, key, data, Some(&mut batch), rng);
-               at += 1;
-            }
-            batch.commit().unwrap();
-            batch.reset();
-         }
-      }
-   }
-}
-
-// Generate random data
-fn generate_data(size: usize) -> Bytes {
-   let mut rng = StdRng::seed_from_u64(42);
-   let mut data = vec![0u8; size];
-   rng.fill(&mut data[..]);
-   data.into()
-}
-
-// Generate a key for the given index
-fn generate_key(index: usize) -> Bytes {
-   format!("key_{index:010}").into()
-}
-
-// Pre-generate a list of keys
-fn generate_keys(count: usize) -> Arc<[Bytes]> {
-   (0..count).map(generate_key).collect()
-}
-
-trait BenchableStore {
-   fn bench(&self, bencher: &mut Bencher, config: &BenchConfig);
-}
-
-struct StoreBench<S: Store> {
-   store: S,
-}
-
-impl<S: Store> BenchableStore for StoreBench<S> {
-   fn bench(&self, bencher: &mut Bencher, config: &BenchConfig) {
-      bencher.iter_with_setup(
-         move || {
-            // Pre-generate all keys we'll use (1/3 the ops, allow some collision to
-            // simulate hot keys)
-            let keys = generate_keys(config.num_ops / 3);
-
-            // Pre-generate data to write
-            let data = (0..1000)
-               .map(|_| generate_data(config.value_size))
-               .collect::<Arc<[Bytes]>>();
-
-            // Prepare data if needed
-            if config.prepare_data {
-               let mut rng = Lcg64(42);
-               let wb = self.store.batch();
-               for key in &keys[..(keys.len() * 3 / 4)] {
-                  let rand_data = &data[rng.next_u64() as usize % data.len()];
-                  wb.put(key, rand_data.as_ref());
-               }
-               wb.commit().unwrap();
-            }
-
-            // Return the prepared store and pre-generated keys/data
-            (keys, data)
-         },
-         |(keys, data)| {
-            // Actual benchmark
-            if config.threads == 1 {
-               // Single-threaded benchmark
-               let mut rng = Lcg64(42);
-               config.step_n(config.num_ops, &self.store, &keys[..], &data[..], &mut rng);
-            } else {
-               (0..config.threads).into_par_iter().for_each(|tid| {
-                  let num_ops = config.num_ops;
-                  let mut rng = Lcg64(42);
-
-                  let ops_per_thread = num_ops / config.threads;
-                  let thread_start = tid * ops_per_thread;
-                  let thread_end = std::cmp::min(thread_start + ops_per_thread, num_ops);
-                  let thread_cnt = thread_end - thread_start;
-                  config.step_n(thread_cnt, &self.store, &keys[..], &data[..], &mut rng);
-               });
-            }
-         },
-      );
-   }
-}
-
-// Benchmark any Store implementation
-fn bench_kv(c: &mut Criterion, stores: &[(&str, Box<dyn BenchableStore>)]) {
-   const C: usize = 24;
-
-   // Single-threaded read benchmark
-   const CONFIGS: &[BenchConfig] = &[
-      // Small values, single-threaded reads
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: 1,
-         batch_size: 1,
-         rwu: (100, 0, 0, "read"),
-         prepare_data: true,
-      },
-      // Small values, single-threaded writes
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: 1,
-         batch_size: 1,
-         rwu: (0, 100, 0, "write"),
-         prepare_data: false,
-      },
-      // Small values, single-threaded writes, with batching
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: 1,
-         batch_size: 128,
-         rwu: (0, 100, 0, "write_batch"),
-         prepare_data: false,
-      },
-      // Small values, single-threaded mixed (75% reads, 25% writes)
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: 1,
-         batch_size: 1,
-         rwu: (75, 25, 0, "mixed"),
-         prepare_data: true,
-      },
-      // Small values, single-threaded update/reads
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: 1,
-         batch_size: 1,
-         rwu: (25, 0, 75, "update"),
-         prepare_data: true,
-      },
-      // Small values, multi-threaded reads
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: C,
-         batch_size: 1,
-         rwu: (100, 0, 0, "read"),
-         prepare_data: true,
-      },
-      // Small values, multi-threaded writes
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: C,
-         batch_size: 1,
-         rwu: (0, 100, 0, "write"),
-         prepare_data: false,
-      },
-      // Small values, multi-threaded mixed (75% reads, 25% writes)
-      BenchConfig {
-         num_ops: 100_000,
-         value_size: 64,
-         threads: C,
-         batch_size: 1,
-         rwu: (75, 25, 0, "mixed"),
-         prepare_data: true,
-      },
-      // Larger values, single-threaded reads
-      BenchConfig {
-         num_ops: 5_000,
-         value_size: 1024,
-         threads: 1,
-         batch_size: 1,
-         rwu: (100, 0, 0, "read"),
-         prepare_data: true,
-      },
-      // Larger values, multi-threaded reads
-      BenchConfig {
-         num_ops: 50_000,
-         value_size: 1024,
-         threads: C,
-         batch_size: 1,
-         rwu: (100, 0, 0, "read"),
-         prepare_data: true,
-      },
-   ];
-
-   for config in CONFIGS {
-      let operation_type = config.rwu.3;
-      let thread_type = if config.threads == 1 {
-         "single"
-      } else {
-         "multi"
-      };
-      let mut group = c.benchmark_group(format!(
-         "{}_{}_{}",
-         operation_type, thread_type, config.value_size
-      ));
-      group.throughput(Throughput::Elements(config.num_ops as u64));
-
-      for (name, store) in stores {
-         let benchmark_id = BenchmarkId::new((*name).to_string(), config.num_ops);
-         group.bench_with_input(benchmark_id, config, |b, config| {
-            store.bench(b, config);
-         });
-      }
-      group.finish();
-   }
-}
-
-fn criterion_benchmark(c: &mut Criterion) {
-   let mut stores = Vec::<(&str, Box<dyn BenchableStore>)>::new();
-
-   #[cfg(feature = "rocksdb")]
-   {
-      stores.push((
-         "rocksdb",
-         Box::new(StoreBench {
-            store: tetra_kv::RocksDb::temp().expect("failed to create rocksdb"),
-         }),
-      ));
-   }
-   {
-      stores.push((
-         "memory",
-         Box::new(StoreBench {
-            store: tetra_kv::MemoryDb::new(),
-         }),
-      ));
-   }
-   {
-      stores.push((
-         "memory_erased",
-         Box::new(StoreBench {
-            store: tetra_kv::AnyDb::new(tetra_kv::MemoryDb::new()),
-         }),
-      ));
-   }
-   #[cfg(feature = "heed")]
-   {
-      stores.push((
-         "lmdb",
-         Box::new(StoreBench {
-            store: tetra_kv::Lmdb::temp().expect("failed to create lmdb"),
-         }),
-      ));
-   }
-
-   bench_kv(c, &stores);
-}
-
-criterion_group!(
-    name = benches;
-    config = Criterion::default().sample_size(10).measurement_time(Duration::from_secs(5));
-    targets = criterion_benchmark
-);
-criterion_main!(benches);
diff --git a/attic/kv/src/erased.rs b/attic/kv/src/erased.rs
deleted file mode 100644
index a39a0bc82..000000000
--- a/attic/kv/src/erased.rs
+++ /dev/null
@@ -1,353 +0,0 @@
-use std::{fmt, iter};
-
-use bytes::Bytes;
-use smol_str::SmolStr;
-use tetra_core::containers::smol_box::SmolBox;
-
-use crate::{
-   IVec, IVecs, Operator, Options,
-   error::Result,
-   traits::{self, IterMode},
-};
-
-type Unique<T> = SmolBox<T>;
-
-/// Holds a dynamic, boxed [`traits::WriteBatch`].
-pub struct AnyWriteBatch<'a>(pub Unique<dyn traits::WriteBatch<'a>>);
-
-impl<'a> fmt::Debug for AnyWriteBatch<'a> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_tuple("AnyWriteBatch").field(&self.0).finish()
-   }
-}
-
-impl<'a> traits::Write for AnyWriteBatch<'a> {
-   type Result = ();
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.0.delete(key);
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      self.0.delete_range(from, to);
-   }
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self.0.put(key, value);
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      self.0.update(key, op);
-   }
-}
-
-impl<'a> traits::WriteBatch<'a> for AnyWriteBatch<'a> {
-   fn reset(&mut self) {
-      self.0.reset();
-   }
-   fn commit(&self) -> Result<()> {
-      self.0.commit()
-   }
-}
-
-pub trait KeyIterator {
-   fn next_key(&mut self) -> Option<&[u8]>;
-}
-
-pub(crate) fn adapt_key_iter<I: KeyIterator + ?Sized>(
-   it: &mut I,
-) -> impl IntoIterator<Item: AsRef<[u8]>> {
-   iter::from_fn(|| {
-      if let Some(key) = it.next_key() {
-         // TODO: Fix the lifetime here, although for now this is safe as long as the
-         // iterator is not used after the lifetime of the view which always holds.
-         let slice: &[u8] = key;
-         let static_slice: &'static [u8] = unsafe { &*(slice as *const [u8]) };
-         Some(static_slice)
-      } else {
-         None
-      }
-   })
-}
-
-struct KeyIteratorAdapter<I: Iterator<Item: AsRef<[u8]>>> {
-   iter: I,
-   peek: Option<I::Item>,
-}
-
-impl<I: Iterator<Item: AsRef<[u8]>>> KeyIterator for KeyIteratorAdapter<I> {
-   fn next_key(&mut self) -> Option<&[u8]> {
-      self.peek = self.iter.next();
-      self.peek.as_ref().map(|item| item.as_ref())
-   }
-}
-
-/// Object safe wrapper around [`traits::View`].
-pub trait DynView: fmt::Debug {
-   /// Gets the value for the given key.
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>>;
-   /// Returns true if the key exists in the store.
-   fn contains(&self, key: &[u8]) -> Result<bool>;
-   /// Iterates over key-value pairs.
-   fn iter<'a>(
-      &'a self,
-      mode: IterMode<'_>,
-   ) -> Unique<dyn Iterator<Item = Result<(Bytes, Bytes)>> + 'a>;
-   /// Scans all keys with the given prefix.
-   fn prefix_scan<'a>(
-      &'a self,
-      prefix: &'a [u8],
-      mode: IterMode<'_>,
-   ) -> Unique<dyn Iterator<Item = Result<(Bytes, Bytes)>> + 'a>;
-
-   /// Gets the values for multiple keys at once.
-   fn get_many(&self, keys: &mut dyn KeyIterator) -> Result<IVecs<'_>>;
-}
-
-pub trait DynViewable: fmt::Debug {
-   fn viewable(&self) -> &(dyn DynView + '_);
-}
-
-pub struct AnyView<'a>(pub Unique<dyn DynView + 'a>);
-
-impl<'a> AnyView<'a> {
-   pub fn new(view: impl traits::View + 'a) -> Self {
-      AnyView(Unique::new(view))
-   }
-}
-
-impl fmt::Debug for AnyView<'_> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_tuple("AnyView").field(&self.0).finish()
-   }
-}
-
-impl<'a> DynViewable for AnyView<'a> {
-   fn viewable(&self) -> &(dyn DynView + '_) {
-      self.0.as_ref()
-   }
-}
-
-impl<Q: DynViewable + ?Sized> traits::View for Q {
-   type Iter<'a>
-      = Unique<dyn Iterator<Item = Result<(Bytes, Bytes)>> + 'a>
-   where
-      Self: 'a;
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      DynView::contains(self.viewable(), key)
-   }
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      DynView::get(self.viewable(), key)
-   }
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      DynView::get_many(self.viewable(), &mut KeyIteratorAdapter {
-         iter: keys.into_iter(),
-         peek: None,
-      })
-   }
-   fn iter<'a>(&'a self, mode: IterMode<'_>) -> Self::Iter<'a> {
-      DynView::iter(self.viewable(), mode)
-   }
-}
-
-impl<T: traits::View> DynView for T {
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      traits::View::get(self, key)
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      traits::View::contains(self, key)
-   }
-
-   fn iter<'a>(
-      &'a self,
-      mode: IterMode<'_>,
-   ) -> Unique<dyn Iterator<Item = Result<(Bytes, Bytes)>> + 'a> {
-      Unique::new(traits::View::iter(self, mode))
-   }
-
-   fn prefix_scan<'a>(
-      &'a self,
-      prefix: &'a [u8],
-      mode: IterMode<'_>,
-   ) -> Unique<dyn Iterator<Item = Result<(Bytes, Bytes)>> + 'a> {
-      Unique::new(traits::View::prefix_scan(self, prefix, mode))
-   }
-
-   fn get_many(&self, keys: &mut dyn KeyIterator) -> Result<IVecs<'_>> {
-      traits::View::get_many(self, adapt_key_iter(keys))
-   }
-}
-
-/// Object safe wrapper around [`traits::Store`].
-pub trait DynStore: DynView + Send + Sync {
-   /// Creates a new write batch.
-   fn batch(&self) -> AnyWriteBatch<'_>;
-   /// Returns the namespace of this store.
-   fn namespace(&self) -> &str;
-   /// Creates a child store.
-   fn child(&self, name: &str, opts: Options) -> Result<AnyDb>;
-   /// Returns an iterator over the child stores.
-   fn children(&self) -> Vec<SmolStr>;
-   /// Sets the value for the given key.
-   fn put(&self, key: &[u8], value: &[u8]) -> Result<()>;
-   /// Deletes the value for the given key.
-   fn delete(&self, key: &[u8]) -> Result<()>;
-   /// Deletes all keys in the range [from, to)
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Result<()>;
-   /// Clears all data in the store.
-   fn clear(&self) -> Result<()>;
-   /// Flushes all data in the store to the underlying storage.
-   fn flush(&self) -> Result<()>;
-   /// Creates a snapshot of the store.
-   fn snapshot(&self) -> AnyView<'_>;
-   /// Estimate the size of the store.
-   fn estimate_size(&self) -> Option<u64>;
-   /// Returns the options for this store.
-   fn options(&self) -> &Options;
-   /// Merge the value for the given key with the given operation.
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Result<()>;
-}
-
-impl<T: traits::Store + Clone + Send + Sync + 'static> DynStore for T {
-   fn batch(&self) -> AnyWriteBatch<'_> {
-      AnyWriteBatch(Unique::new(traits::Store::batch(self)))
-   }
-
-   fn namespace(&self) -> &str {
-      traits::Store::namespace(self)
-   }
-
-   fn child(&self, name: &str, opts: Options) -> Result<AnyDb> {
-      Ok(AnyDb::new(traits::Store::child(self, name, opts)?))
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      traits::Store::children(self)
-   }
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Result<()> {
-      traits::Write::put(self, key, value)
-   }
-
-   fn delete(&self, key: &[u8]) -> Result<()> {
-      traits::Write::delete(self, key)
-   }
-
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Result<()> {
-      traits::Write::update(self, key, op)
-   }
-
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Result<()> {
-      traits::Write::delete_range(self, from, to)
-   }
-
-   fn clear(&self) -> Result<()> {
-      traits::Store::clear(self)
-   }
-
-   fn flush(&self) -> Result<()> {
-      traits::Store::flush(self)
-   }
-
-   fn snapshot(&self) -> AnyView<'_> {
-      AnyView(Unique::new(traits::Store::snapshot(self)))
-   }
-
-   fn estimate_size(&self) -> Option<u64> {
-      traits::Store::estimate_size(self)
-   }
-
-   fn options(&self) -> &Options {
-      traits::Store::options(self)
-   }
-}
-
-pub struct AnyDb(pub triomphe::Arc<dyn DynStore>);
-
-impl fmt::Debug for AnyDb {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_tuple("AnyDb").field(&self.0).finish()
-   }
-}
-
-impl AnyDb {
-   /// Create a new [`AnyDb`] from a [`Store`].
-   pub fn new(store: impl traits::Store + 'static) -> Self {
-      let arc = triomphe::Arc::new(store);
-      let ptr = triomphe::Arc::into_raw(arc);
-      AnyDb(unsafe { triomphe::Arc::from_raw(ptr as *const _) })
-   }
-}
-
-impl Clone for AnyDb {
-   fn clone(&self) -> Self {
-      AnyDb(triomphe::Arc::clone(&self.0))
-   }
-}
-
-impl DynViewable for AnyDb {
-   fn viewable(&self) -> &(dyn DynView + '_) {
-      self.0.as_ref()
-   }
-}
-
-impl traits::Write for AnyDb {
-   type Result = Result<()>;
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      DynStore::delete(self.0.as_ref(), key)
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      DynStore::delete_range(self.0.as_ref(), from, to)
-   }
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      DynStore::put(self.0.as_ref(), key, value)
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      DynStore::update(self.0.as_ref(), key, op)
-   }
-}
-
-impl traits::Store for AnyDb {
-   type WriteBatch<'a>
-      = AnyWriteBatch<'a>
-   where
-      Self: 'a;
-   type Snapshot<'a>
-      = AnyView<'a>
-   where
-      Self: 'a;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      DynStore::batch(self.0.as_ref())
-   }
-
-   fn namespace(&self) -> &str {
-      DynStore::namespace(self.0.as_ref())
-   }
-
-   fn child(&self, name: &str, opts: Options) -> Result<Self> {
-      DynStore::child(self.0.as_ref(), name, opts)
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      DynStore::children(self.0.as_ref())
-   }
-
-   fn flush(&self) -> Result<()> {
-      DynStore::flush(self.0.as_ref())
-   }
-
-   fn clear(&self) -> Result<()> {
-      DynStore::clear(self.0.as_ref())
-   }
-
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      DynStore::snapshot(self.0.as_ref())
-   }
-
-   fn estimate_size(&self) -> Option<u64> {
-      DynStore::estimate_size(self.0.as_ref())
-   }
-
-   fn options(&self) -> &Options {
-      DynStore::options(self.0.as_ref())
-   }
-}
diff --git a/attic/kv/src/error.rs b/attic/kv/src/error.rs
deleted file mode 100644
index 25d866ee8..000000000
--- a/attic/kv/src/error.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use smol_str::SmolStr;
-use thiserror::Error;
-
-#[derive(Error, Debug)]
-pub enum Error {
-   #[error("Postcard serialization error: {0}")]
-   PostcardSerialization(#[from] postcard::Error),
-
-   #[error("CBOR serialization error: {0}")]
-   CborSerialization(#[from] serde_cbor::Error),
-
-   #[cfg(feature = "rocksdb")]
-   #[error("RocksDB error: {0}")]
-   RocksDb(#[from] rocksdb::Error),
-
-   #[cfg(feature = "heed")]
-   #[error("Heed error: {0}")]
-   Heed(#[from] heed::Error),
-
-   #[error("Column family not found: {0}")]
-   ColumnFamilyNotFound(SmolStr),
-
-   #[error("I/O error: {0}")]
-   Io(#[from] std::io::Error),
-
-   #[error("Invalid operation: {0}")]
-   InvalidOperation(String),
-
-   #[error("Database corrupted: {0}")]
-   Corrupted(String),
-
-   #[error("Other error: {0}")]
-   Other(String),
-
-   #[error("Invalid UTF-8 sequence: {0}")]
-   InvalidUtf8(#[from] std::str::Utf8Error),
-}
-
-pub type Result<T, E = Error> = std::result::Result<T, E>;
diff --git a/attic/kv/src/ivec.rs b/attic/kv/src/ivec.rs
deleted file mode 100644
index 69b045ebf..000000000
--- a/attic/kv/src/ivec.rs
+++ /dev/null
@@ -1,1014 +0,0 @@
-//! A flexible, zero‑cost abstraction for owning or borrowing byte buffers.
-//!
-//! `IVec` can store a wide range of backing types (`&[u8]`, `Vec<u8>`, `Bytes`,
-//! etc.) without additional allocations.  For short slices (≤ 23 bytes on
-//! 64‑bit) the bytes are stored **inline**; otherwise the backing value is kept
-//! on the heap and referenced through a custom vtable.  Conversions back to the
-//! original container are zero‑cost as well.
-//!
-//! The implementation makes heavy use of `unsafe` to achieve this.  Every
-//! `unsafe` block is documented with a **SAFETY** comment that explains the
-//! invariants the block relies on.
-
-use std::{
-   fmt, iter,
-   marker::PhantomData,
-   mem::{self, ManuallyDrop, MaybeUninit},
-   ops::Deref,
-   ptr, slice,
-};
-
-use crate::{Error, Result};
-
-/// Trait implemented by every container that can back an [`IVec`].
-///
-/// The trait is intentionally minimal: each method either
-/// *returns* a borrowed slice, or *consumes* `self` and returns an owned
-/// buffer. Implementors must ensure that the memory pointed to by `as_slice`
-/// outlives `self`.
-pub trait IVecRef: Sized {
-   /// Borrow the contents as `&[u8]`.
-   fn as_slice(&self) -> &[u8];
-   /// Consume `self` and return a `Vec<u8>` with identical bytes.
-   fn into_vec(self) -> Vec<u8>;
-   /// Consume `self` and return a [`bytes::Bytes`] with identical bytes.
-   fn into_bytes(self) -> bytes::Bytes;
-}
-
-/// A wrapper for static slices that avoids allocations.
-#[derive(Clone, Copy)]
-struct StaticIVec(&'static [u8]);
-
-impl IVecRef for StaticIVec {
-   fn as_slice(&self) -> &[u8] {
-      self.0
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.0.into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_static(self.0)
-   }
-}
-
-// Blanket implementations for standard byte containers
-impl IVecRef for &[u8] {
-   fn as_slice(&self) -> &[u8] {
-      self
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::copy_from_slice(self)
-   }
-}
-
-impl IVecRef for Box<[u8]> {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self)
-   }
-}
-
-impl IVecRef for bytes::Bytes {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      self
-   }
-}
-
-impl IVecRef for String {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      String::into_bytes(self)
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self.into_bytes())
-   }
-}
-
-impl IVecRef for &str {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.as_bytes().into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::copy_from_slice(self.as_ref())
-   }
-}
-
-impl IVecRef for Box<str> {
-   fn as_slice(&self) -> &[u8] {
-      str::as_bytes(self)
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.into_boxed_bytes().into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self.into_boxed_bytes())
-   }
-}
-
-impl IVecRef for Vec<u8> {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self)
-   }
-}
-
-const MAX_INLINE: usize = 8 * 3;
-
-/// A tiny, inline buffer used by [`IVec`] for very small slices.
-///
-/// The buffer reserves space for `MAX_INLINE - 1` bytes so that the entire
-/// structure fits exactly into one [`IVecRepr`].
-#[derive(Debug, Clone, Copy)]
-#[repr(C, packed)]
-struct SmallIVec {
-   /// Uninitialised storage – only the first `len` bytes hold valid data.
-   data: MaybeUninit<[u8; MAX_INLINE - 1]>,
-   /// Number of valid bytes inside `data` (0‥=23).
-   len: u8,
-}
-
-const _: () = assert!(IVecVtable::is_inline::<SmallIVec>());
-
-impl SmallIVec {
-   /// Try to build an inline buffer from `slice`.
-   /// Returns `None` if `slice` is too large.
-   pub const fn try_from(slice: &[u8]) -> Option<Self> {
-      if slice.len() < MAX_INLINE {
-         let mut data = MaybeUninit::uninit();
-         // SAFETY: we just checked that `slice.len()` ≤ 23 ≤ capacity of
-         // `data`, and both pointers are non‑overlapping.  `data` is still
-         // uninitialised, so writing arbitrary bytes is allowed.
-         unsafe {
-            ptr::copy_nonoverlapping(slice.as_ptr(), data.as_mut_ptr() as *mut u8, slice.len());
-         }
-         Some(Self {
-            data,
-            len: slice.len() as u8,
-         })
-      } else {
-         None
-      }
-   }
-}
-
-impl IVecRef for SmallIVec {
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.as_ref().into()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self)
-   }
-}
-
-impl AsRef<[u8]> for SmallIVec {
-   fn as_ref(&self) -> &[u8] {
-      // SAFETY: `len` never exceeds the capacity of `data` (MAX_INLINE - 1) thanks to
-      // the check in `try_from`.  `data` was fully initialised up to `len`
-      // bytes when the value was constructed and neither `data` nor `len` are
-      // ever mutated afterwards, so the bytes remain valid for the lifetime of
-      // `self`.
-      unsafe { slice::from_raw_parts(self.data.as_ptr() as *const u8, self.len as usize) }
-   }
-}
-
-/// `MAX_INLINE`‑byte storage that can either hold any container implementing
-/// [`IVecRef`], either inline (in `inl`) or a raw pointer to a boxed heap
-/// allocation (in `ext`).
-#[derive(Clone, Copy)]
-#[repr(align(8))]
-union IVecRepr {
-   inl: MaybeUninit<[u8; MAX_INLINE]>,
-   ext: *mut (),
-}
-
-/// Methods needed to convert/destroy an erased backing value.
-struct IVecVtable {
-   into_vec: unsafe fn(&mut IVecRepr) -> Vec<u8>,
-   into_bytes: unsafe fn(&mut IVecRepr) -> bytes::Bytes,
-   drop: unsafe fn(&mut IVecRepr),
-   as_ref: unsafe fn(&IVecRepr) -> *const [u8],
-}
-
-impl IVecVtable {
-   /// Does `T` fit inside the inline storage?  (Compile‑time check.)
-   #[inline]
-   const fn is_inline<T: IVecRef>() -> bool {
-      mem::size_of::<T>() <= mem::size_of::<IVecRepr>()
-         && mem::align_of::<T>() <= mem::align_of::<IVecRepr>()
-   }
-
-   /// Re‑interpret `storage` as `&T`.
-   ///
-   /// # Safety
-   /// The caller must ensure that `storage` actually contains a valid `T`,
-   /// either inline or via a valid pointer.
-   #[inline]
-   const fn as_ref<T: IVecRef>(storage: &IVecRepr) -> &T {
-      unsafe {
-         &*if Self::is_inline::<T>() {
-            storage.inl.as_ptr().cast::<T>()
-         } else {
-            storage.ext as *const T
-         }
-      }
-   }
-
-   /// Consume and return the stored value as `T`.
-   #[inline]
-   fn into_inner<T: IVecRef>(storage: &mut IVecRepr) -> T {
-      unsafe {
-         if Self::is_inline::<T>() {
-            // SAFETY: when the value was packed inline we wrote a valid `T`
-            // into `storage.inl`; reading it back is safe and leaves the
-            // memory uninitialised again.
-            storage.inl.as_mut_ptr().cast::<T>().read()
-         } else {
-            // SAFETY: `storage.ext` originated from `Box::into_raw`, so it
-            // is a valid pointer obtained by `Box::into_raw` for T.
-            *Box::from_raw(storage.ext as *mut T)
-         }
-      }
-   }
-
-   /// Store `value` in an `IVecRepr` and build the corresponding vtable.
-   #[inline]
-   fn pack<T: IVecRef>(value: T) -> (IVecRepr, &'static IVecVtable) {
-      let repr = if Self::is_inline::<T>() {
-         let mut storage = IVecRepr {
-            inl: MaybeUninit::uninit(),
-         };
-         // SAFETY: The inline storage is large & aligned enough by
-         // `is_inline` check.  We immediately overwrite it with a valid `T`.
-         unsafe {
-            ptr::write(storage.inl.as_mut_ptr().cast::<T>(), value);
-            storage
-         }
-      } else {
-         let boxed: Box<T> = Box::new(value);
-         IVecRepr {
-            ext: Box::into_raw(boxed) as *mut (),
-         }
-      };
-      // The vtable is `const`, hence it lives for the entire program run.
-      let vtable = &const { Self::new::<T>() };
-      (repr, vtable)
-   }
-
-   /// Build a vtable specialised for `T`.
-   #[inline]
-   const fn new<T: IVecRef>() -> Self {
-      Self {
-         into_vec: |x| Self::into_inner::<T>(x).into_vec(),
-         into_bytes: |x| Self::into_inner::<T>(x).into_bytes(),
-         drop: |x| drop(Self::into_inner::<T>(x)),
-         as_ref: |x| Self::as_ref::<T>(x).as_slice() as *const [u8],
-      }
-   }
-}
-
-#[derive(derive_more::Debug)]
-#[debug("IVec({:?})", self.as_ref())]
-pub struct IVec<'a> {
-   /// Inline storage or pointer to box.
-   storage: IVecRepr,
-   /// Associated vtable (missing only after `into_vec`/`into_bytes` or `drop`).
-   vtable: Option<&'static IVecVtable>,
-   /// Ties the lifetime parameter to the contained reference variants.
-   _marker: PhantomData<&'a ()>,
-}
-
-impl<'a, V: IVecRef + 'a> From<V> for IVec<'a> {
-   fn from(value: V) -> Self {
-      Self::new(value)
-   }
-}
-
-pub(crate) struct IVecRaw {
-   storage: IVecRepr,
-   vtable: &'static IVecVtable,
-}
-
-impl<'a> IVec<'a> {
-   pub(crate) fn into_raw(mut self) -> IVecRaw {
-      IVecRaw {
-         storage: self.storage,
-         vtable: self.vtable.take().unwrap(),
-      }
-   }
-
-   pub(crate) fn from_raw(raw: IVecRaw) -> Self {
-      Self {
-         storage: raw.storage,
-         vtable: Some(raw.vtable),
-         _marker: PhantomData,
-      }
-   }
-
-   /// Create a new `IVec` from `value`.
-   ///
-   /// Small inputs are stored inline, larger ones on the heap.
-   pub fn new<T: IVecRef + 'a>(value: T) -> Self {
-      let (storage, vtable) = if let Some(svec) = SmallIVec::try_from(value.as_slice()) {
-         IVecVtable::pack(svec)
-      } else {
-         IVecVtable::pack(value)
-      };
-      Self {
-         storage,
-         vtable: Some(vtable),
-         _marker: PhantomData,
-      }
-   }
-
-   /// Same as [`IVec::new`] but takes `&T` and therefore *clones* the value
-   /// when needed.  Convenience helper for ergonomic usage.
-   pub fn from_ref<T: IVecRef + Clone + 'a>(value: &T) -> Self {
-      let (storage, vtable) = if let Some(svec) = SmallIVec::try_from(value.as_slice()) {
-         IVecVtable::pack(svec)
-      } else {
-         IVecVtable::pack(value.clone())
-      };
-      Self {
-         storage,
-         vtable: Some(vtable),
-         _marker: PhantomData,
-      }
-   }
-
-   /// Create an `IVec` from a static slice. This is optimized for static data
-   /// that doesn't need to be copied or cloned.
-   pub fn from_static(slice: &'static [u8]) -> Self {
-      let (storage, vtable) = IVecVtable::pack(StaticIVec(slice));
-      Self {
-         storage,
-         vtable: Some(vtable),
-         _marker: PhantomData,
-      }
-   }
-}
-
-// Safety: `IVec` is Send+Sync as long as the backing types are Send+Sync.  We
-// only ever refer to them through immutable references or by *moving* the value
-// out (which transfers ownership to the caller).  There are no aliasing issues.
-unsafe impl<'a> Send for IVec<'a> {}
-unsafe impl<'a> Sync for IVec<'a> {}
-
-impl<'a> AsRef<[u8]> for IVec<'a> {
-   #[inline]
-   fn as_ref(&self) -> &[u8] {
-      // SAFETY: The vtable *must* be present unless the value has already been
-      // moved out via `From<IVec>` impls.  In that case callers are not
-      // allowed to use `self` anymore (it would be after‑move use) – Rust’s
-      // move semantics guarantee this.  Therefore the `unwrap` is safe.
-      unsafe { &*(self.vtable.unwrap().as_ref)(&self.storage) }
-   }
-}
-
-impl<'a> Deref for IVec<'a> {
-   type Target = [u8];
-   fn deref(&self) -> &Self::Target {
-      self.as_ref()
-   }
-}
-
-impl<'a> From<IVec<'a>> for Vec<u8> {
-   fn from(mut val: IVec<'a>) -> Self {
-      // Take ownership of the vtable so we can no longer be used afterwards.
-      let vft = val.vtable.take().unwrap();
-      // SAFETY: `vft.into_vec` was constructed to accept exactly our storage.
-      unsafe { (vft.into_vec)(&mut val.storage) }
-   }
-}
-
-impl<'a> From<IVec<'a>> for bytes::Bytes {
-   fn from(mut val: IVec<'a>) -> Self {
-      // Take ownership of the vtable so we can no longer be used afterwards.
-      let vft = val.vtable.take().unwrap();
-      // SAFETY: `vft.into_bytes` was constructed to accept exactly our storage.
-      unsafe { (vft.into_bytes)(&mut val.storage) }
-   }
-}
-
-impl<'a> Drop for IVec<'a> {
-   fn drop(&mut self) {
-      if let Some(vft) = self.vtable.take() {
-         // SAFETY: `vft.drop` was constructed to accept exactly our storage.
-         unsafe { (vft.drop)(&mut self.storage) }
-      }
-   }
-}
-
-#[cfg(test)]
-mod tests {
-   use super::*;
-
-   #[test]
-   fn ivec_from_small_slice() {
-      let data = b"hello world";
-      let ivec = IVec::new(&data[..]);
-      assert_eq!(ivec.as_ref(), data);
-      let vec: Vec<u8> = ivec.into();
-      assert_eq!(vec, data);
-   }
-
-   #[test]
-   fn ivec_from_large_vec() {
-      let data = vec![42u8; 100];
-      let ivec = IVec::from(data.clone());
-      assert_eq!(ivec.as_ref(), &data[..]);
-      let bytes: bytes::Bytes = ivec.into();
-      assert_eq!(bytes.as_ref(), &data[..]);
-   }
-
-   #[test]
-   fn ivec_from_string() {
-      let s = "a somewhat longer string".to_owned();
-      let ivec = IVec::from(s.clone());
-      assert_eq!(ivec.as_ref(), s.as_bytes());
-   }
-
-   #[test]
-   fn ivec_from_bytes() {
-      let data = bytes::Bytes::from_static(b"bytes data");
-      let ivec = IVec::from(data.clone());
-      assert_eq!(ivec.as_ref(), data.as_ref());
-   }
-
-   #[test]
-   fn ivec_zero_len() {
-      let data: &[u8] = b"";
-      let ivec = IVec::new(data);
-      assert!(ivec.as_ref().is_empty());
-      let vec: Vec<u8> = ivec.into();
-      assert!(vec.is_empty());
-   }
-
-   #[test]
-   fn ivec_from_static_slice() {
-      // Test with small static slice
-      const SMALL_STATIC: &[u8] = b"small data";
-      let ivec_small = IVec::from_static(SMALL_STATIC);
-      assert_eq!(ivec_small.as_ref(), SMALL_STATIC);
-      let vec_small: Vec<u8> = ivec_small.into();
-      assert_eq!(vec_small, SMALL_STATIC);
-
-      // Test with large static slice
-      const LARGE_STATIC: &[u8] =
-         b"this is a much longer static slice that exceeds the inline capacity";
-      let ivec_large = IVec::from_static(LARGE_STATIC);
-      assert_eq!(ivec_large.as_ref(), LARGE_STATIC);
-
-      // Convert to Bytes - this should use Bytes::from_static internally (no
-      // allocation)
-      let bytes_large: bytes::Bytes = ivec_large.into();
-      assert_eq!(bytes_large.as_ref(), LARGE_STATIC);
-
-      // Verify pointer equality - Bytes::from_static should preserve the pointer
-      assert_eq!(bytes_large.as_ptr(), LARGE_STATIC.as_ptr());
-
-      // Test that regular from with non-static slice allocates (different behavior)
-      let non_static_slice: &[u8] = &LARGE_STATIC[..10];
-      let ivec_regular = IVec::from(non_static_slice);
-      assert_eq!(ivec_regular.as_ref(), &LARGE_STATIC[..10]);
-   }
-}
-
-// Maximum number of IVec items that can be stored inline without heap
-// allocation
-const MAX_INLINE_VECS: usize = 6;
-// Configuration flag for whether to attempt inlining when converting from Box
-const TRY_INLINE_WITH_BOX: bool = false;
-
-/// Union type that can either store IVec items inline or as a pointer to heap
-/// storage. This is the core storage mechanism for IVecs, similar to IVecRepr
-/// but for collections.
-#[repr(C)]
-union IVecsRepr {
-   // Inline storage using heapless::Vec for small collections (up to MAX_INLINE_VECS items)
-   // Each item is Result<Option<IVecRaw>, Error> to handle errors and missing values
-   inl: ManuallyDrop<heapless::Vec<Result<Option<IVecRaw>, Error>, MAX_INLINE_VECS>>,
-   // External storage as a raw pointer and length for larger collections
-   ext: (*mut (), usize),
-}
-
-impl IVecsRepr {
-   /// Collect an iterator of IVecsResult items into an IVecsRepr with
-   /// appropriate vtable. Intelligently chooses between inline and heap
-   /// storage based on size hints.
-   pub fn collect<T: IVecsResult>(iter: impl Iterator<Item = T>) -> (Self, &'static IVecsVtable) {
-      let (low, high) = iter.size_hint();
-      // If we have a reliable upper bound that fits inline, use bounded collection
-      if high.is_some_and(|x| x <= MAX_INLINE_VECS || x == low) {
-         Self::collect_bounded(iter, high.unwrap_or(low))
-      } else {
-         // Otherwise use unbounded collection that may spill to heap
-         Self::collect_unbounded(iter)
-      }
-   }
-
-   /// Handle collection when size is unknown or potentially large.
-   /// Starts with inline storage and spills to heap if needed.
-   #[cold]
-   fn collect_unbounded<T: IVecsResult>(
-      mut iter: impl Iterator<Item = T>,
-   ) -> (Self, &'static IVecsVtable) {
-      // Try to collect into inline buffer first
-      let mut buffer = heapless::Vec::<T, MAX_INLINE_VECS>::new();
-      for item in iter.by_ref() {
-         // Still have space in the inline buffer
-         if let Err(e) = buffer.push(item) {
-            // Buffer full - switch to heap allocation
-            return Self::from_boxed(
-               buffer
-                  .into_iter()
-                  .chain(iter::once(e))
-                  .chain(iter.by_ref())
-                  .collect::<Box<[T]>>(),
-            );
-         }
-      }
-
-      // All items fit inline - transform to internal representation
-      let mut transformed = heapless::Vec::<Result<Option<IVecRaw>, Error>, MAX_INLINE_VECS>::new();
-      for mut item in buffer {
-         transformed
-            .push(item.take().map(|x| x.map(|x| x.into_raw())))
-            .map_err(|_| ())
-            .expect("inline overflow");
-      }
-
-      (
-         Self {
-            inl: ManuallyDrop::new(transformed),
-         },
-         &IVecsVtable::INLINE_VTABLE,
-      )
-   }
-
-   /// Collect when we know the upper bound of items.
-   /// Directly chooses inline or heap storage based on size.
-   fn collect_bounded<T: IVecsResult>(
-      iter: impl Iterator<Item = T>,
-      higher_bound: usize,
-   ) -> (Self, &'static IVecsVtable) {
-      if higher_bound <= MAX_INLINE_VECS {
-         // Fits inline - collect directly into inline storage
-         let mut inline = heapless::Vec::new();
-         for mut item in iter {
-            inline
-               .push(item.take().map(|x| x.map(|x| x.into_raw())))
-               .map_err(|_| ())
-               .expect("inline overflow");
-         }
-         (
-            Self {
-               inl: ManuallyDrop::new(inline),
-            },
-            &IVecsVtable::INLINE_VTABLE,
-         )
-      } else {
-         // Too large for inline - allocate on heap
-         let vec = iter.collect::<Vec<_>>();
-         let count = vec.len();
-         let boxed = Box::into_raw(vec.into_boxed_slice());
-         (
-            Self {
-               ext: (boxed.as_mut_ptr() as *mut (), count),
-            },
-            // Create type-specific vtable for external storage
-            &const { IVecsVtable::new_external::<T>() },
-         )
-      }
-   }
-
-   /// Convert a boxed slice into IVecsRepr.
-   /// May attempt to inline if TRY_INLINE_WITH_BOX is enabled and size permits.
-   pub fn from_boxed<T: IVecsResult>(boxd: Box<[T]>) -> (Self, &'static IVecsVtable) {
-      let len = boxd.len();
-      if TRY_INLINE_WITH_BOX && len <= MAX_INLINE_VECS {
-         // Try to inline the boxed content
-         let mut inline = heapless::Vec::new();
-         for mut item in boxd {
-            inline
-               .push(item.take().map(|x| x.map(|x| x.into_raw())))
-               .map_err(|_| ())
-               .expect("inline overflow");
-         }
-         (
-            Self {
-               inl: ManuallyDrop::new(inline),
-            },
-            &IVecsVtable::INLINE_VTABLE,
-         )
-      } else {
-         // Keep as external storage
-         let boxd = Box::into_raw(boxd);
-         (
-            Self {
-               ext: (boxd.as_mut_ptr() as *mut (), len),
-            },
-            &const { IVecsVtable::new_external::<T>() },
-         )
-      }
-   }
-}
-
-/// Virtual function table for IVecs operations.
-/// Provides polymorphic behavior for inline vs external storage.
-struct IVecsVtable {
-   // Get a reference to the item at index without consuming it
-   get: unsafe fn(&IVecsRepr, usize) -> Result<Option<*const [u8]>>,
-   // Take ownership of the item at index, leaving None in its place
-   take: unsafe fn(&mut IVecsRepr, usize) -> Result<Option<IVecRaw>>,
-   // Drop the entire collection
-   drop: unsafe fn(&mut IVecsRepr),
-   // Flag indicating if storage is inline
-   is_inline: bool,
-}
-
-/// A collection of IVec values with efficient storage.
-/// Like IVec, but for multiple values with support for None and Error variants.
-pub struct IVecs<'a> {
-   // Storage representation (inline or external)
-   repr: IVecsRepr,
-   // Virtual function table for operations
-   vtable: &'static IVecsVtable,
-   // Lifetime marker for borrowed data
-   _lifetime: PhantomData<&'a ()>,
-}
-
-impl<'a> fmt::Debug for IVecs<'a> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      let mut list = f.debug_list();
-      // Debug print each item in the collection
-      for i in 0..self.len() {
-         list.entry(&self.get(i));
-      }
-      list.finish()
-   }
-}
-
-/// Trait for types that can be stored in IVecs.
-/// Supports both getting references and taking ownership.
-pub trait IVecsResult {
-   // Get a reference to the underlying byte slice
-   fn get(&self) -> Result<Option<&[u8]>>;
-   // Take ownership and convert to IVec
-   fn take(&mut self) -> Result<Option<IVec<'_>>>;
-}
-
-// Implementation for Result<Option<T>, E> types
-impl<T: IVecRef, E: Into<Error> + std::error::Error> IVecsResult for Result<Option<T>, E> {
-   fn get(&self) -> Result<Option<&[u8]>> {
-      match self {
-         Ok(Some(x)) => Ok(Some(x.as_slice())),
-         Ok(None) => Ok(None),
-         Err(e) => Err(Error::Other(format!("IVecsResult::get: {e:?}"))),
-      }
-   }
-   fn take(&mut self) -> Result<Option<IVec<'_>>> {
-      match mem::replace(self, Ok(None)) {
-         Ok(Some(x)) => Ok(Some(IVec::from(x))),
-         Ok(None) => Ok(None),
-         Err(e) => Err(e.into()),
-      }
-   }
-}
-
-// Implementation for Option<T> types (simpler case without errors)
-impl<T: IVecRef> IVecsResult for Option<T> {
-   fn get(&self) -> Result<Option<&[u8]>> {
-      match self {
-         Some(x) => Ok(Some(x.as_slice())),
-         None => Ok(None),
-      }
-   }
-   fn take(&mut self) -> Result<Option<IVec<'_>>> {
-      match self.take() {
-         Some(x) => Ok(Some(IVec::from(x))),
-         None => Ok(None),
-      }
-   }
-}
-
-// Conversion implementations for common collection types
-impl<'a, T: IVecsResult> From<Vec<T>> for IVecs<'a> {
-   fn from(value: Vec<T>) -> Self {
-      Self::from_vec(value)
-   }
-}
-
-impl<'a, T: IVecsResult + Clone> From<&'a [T]> for IVecs<'a> {
-   fn from(value: &'a [T]) -> Self {
-      Self::from_iter(value.iter().cloned())
-   }
-}
-
-impl<'a, const N: usize, T: IVecsResult + Clone> From<[T; N]> for IVecs<'a> {
-   fn from(value: [T; N]) -> Self {
-      Self::from_iter(value)
-   }
-}
-
-impl<'a, T: IVecsResult> FromIterator<T> for IVecs<'a> {
-   fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-      let (repr, vtable) = IVecsRepr::collect(iter.into_iter());
-      Self {
-         repr,
-         vtable,
-         _lifetime: PhantomData,
-      }
-   }
-}
-
-impl<'a> IVecs<'a> {
-   /// Create IVecs from a Vec, converting to boxed slice for efficiency
-   pub fn from_vec<T: IVecsResult>(vec: Vec<T>) -> Self {
-      let (repr, vtable) = IVecsRepr::from_boxed(vec.into_boxed_slice());
-      Self {
-         repr,
-         vtable,
-         _lifetime: PhantomData,
-      }
-   }
-
-   /// Get the number of items in the collection
-   #[inline]
-   pub fn len(&self) -> usize {
-      if self.vtable.is_inline {
-         // For inline storage, get length from heapless::Vec
-         unsafe { self.repr.inl.len() }
-      } else {
-         // For external storage, length is stored in the second field
-         unsafe { self.repr.ext.1 }
-      }
-   }
-
-   /// Check if the collection is empty
-   #[inline]
-   pub fn is_empty(&self) -> bool {
-      self.len() == 0
-   }
-
-   /// Get a reference to the item at the given index
-   #[inline]
-   pub fn get(&self, idx: usize) -> Result<Option<&[u8]>> {
-      if idx >= self.len() {
-         return Ok(None);
-      }
-      // Call the appropriate vtable function and convert pointer to reference
-      unsafe { (self.vtable.get)(&self.repr, idx).map(|x| x.map(|x| &*x)) }
-   }
-
-   /// Take ownership of the item at the given index
-   #[inline]
-   pub fn take(&mut self, idx: usize) -> Result<Option<IVec<'_>>> {
-      if idx >= self.len() {
-         return Ok(None);
-      }
-      // Call the appropriate vtable function and convert raw to IVec
-      unsafe { (self.vtable.take)(&mut self.repr, idx).map(|x| x.map(IVec::from_raw)) }
-   }
-}
-
-impl<'a> Drop for IVecs<'a> {
-   fn drop(&mut self) {
-      // Use vtable to properly drop the storage
-      unsafe { (self.vtable.drop)(&mut self.repr) }
-   }
-}
-
-/// Iterator over IVecs that consumes the collection
-#[derive(Debug)]
-pub struct IVecsIter<'a> {
-   // The IVecs being iterated (ownership transferred)
-   inner: IVecs<'a>,
-   // Current index in the iteration
-   idx: usize,
-}
-
-impl<'a> IntoIterator for IVecs<'a> {
-   type Item = Result<Option<IVec<'a>>>;
-   type IntoIter = IVecsIter<'a>;
-
-   fn into_iter(self) -> Self::IntoIter {
-      IVecsIter {
-         inner: self,
-         idx: 0,
-      }
-   }
-}
-
-impl<'a> Iterator for IVecsIter<'a> {
-   type Item = Result<Option<IVec<'a>>>;
-
-   fn next(&mut self) -> Option<Self::Item> {
-      if self.idx == self.inner.len() {
-         return None;
-      }
-      let i = self.idx;
-      self.idx += 1;
-      // Take the item at current index and transmute lifetime
-      let ivec: IVec<'_> = match self.inner.take(i) {
-         Ok(Some(ivec)) => ivec,
-         Ok(None) => return Some(Ok(None)),
-         Err(e) => return Some(Err(e)),
-      };
-
-      // SAFETY: The lifetime is valid because we own the IVecs
-      Some(Ok(Some(unsafe {
-         mem::transmute::<IVec<'_>, IVec<'a>>(ivec)
-      })))
-   }
-
-   fn size_hint(&self) -> (usize, Option<usize>) {
-      let n = self.inner.len() - self.idx;
-      (n, Some(n))
-   }
-}
-impl<'a> ExactSizeIterator for IVecsIter<'a> {}
-
-impl IVecsVtable {
-   /// Create a vtable for external (heap) storage of type T
-   const fn new_external<T: IVecsResult>() -> Self {
-      Self {
-         get: |repr, idx| {
-            // Cast raw pointer back to T and call get()
-            let t: &T = unsafe { &*(repr.ext.0 as *const T).add(idx) };
-            t.get().map(|x| x.map(|x| x as *const [u8]))
-         },
-         take: |repr, idx| {
-            // Cast raw pointer back to mutable T and call take()
-            let t: &mut T = unsafe { &mut *(repr.ext.0 as *mut T).add(idx) };
-            t.take().map(|x| x.map(|x| x.into_raw()))
-         },
-         drop: |repr| unsafe {
-            // Reconstruct the Box and drop it properly
-            let t: &mut [T] = slice::from_raw_parts_mut(repr.ext.0 as *mut T, repr.ext.1);
-            drop(Box::<[T]>::from_raw(t as *mut [T]));
-         },
-         is_inline: false,
-      }
-   }
-
-   /// Static vtable for inline storage
-   const INLINE_VTABLE: Self = Self {
-      get: |repr, idx| unsafe {
-         // Access inline heapless::Vec and get item
-         let r: &heapless::Vec<_, MAX_INLINE_VECS> = &repr.inl;
-         match &r[idx] {
-            Ok(Some(x)) => Ok(Some((x.vtable.as_ref)(&x.storage))),
-            Ok(None) => Ok(None),
-            Err(e) => Err(Error::Other(format!("IVecsResult::get: {e:?}"))),
-         }
-      },
-      take: |repr, idx| unsafe {
-         // Access inline heapless::Vec and take item
-         let m: &mut heapless::Vec<_, MAX_INLINE_VECS> = &mut repr.inl;
-         mem::replace(&mut m[idx], Ok(None))
-      },
-      drop: |repr| unsafe { ManuallyDrop::drop(&mut repr.inl) },
-      is_inline: true,
-   };
-}
-
-#[cfg(test)]
-mod ivecs_tests {
-   use super::*;
-
-   #[test]
-   fn test_basic_functionality() {
-      let data = vec![
-         Some(vec![1u8, 2, 3]),
-         Some(vec![4, 5, 6]),
-         None,
-         Some(vec![7, 8, 9]),
-      ];
-
-      let ivecs = IVecs::from_vec(data);
-      assert_eq!(ivecs.len(), 4);
-      assert!(!ivecs.is_empty());
-
-      // Test get
-      assert_eq!(ivecs.get(0).unwrap(), Some(&[1, 2, 3][..]));
-      assert_eq!(ivecs.get(1).unwrap(), Some(&[4, 5, 6][..]));
-      assert_eq!(ivecs.get(2).unwrap(), None);
-      assert_eq!(ivecs.get(3).unwrap(), Some(&[7, 8, 9][..]));
-      assert_eq!(ivecs.get(4).unwrap(), None); // Out of bounds
-   }
-
-   #[test]
-   fn test_take() {
-      let data = vec![Some(vec![1u8, 2, 3]), Some(vec![4, 5, 6])];
-
-      let mut ivecs = IVecs::from_vec(data);
-
-      // Take first element
-      let taken = ivecs.take(0).unwrap().unwrap();
-      assert_eq!(taken.as_ref(), &[1, 2, 3]);
-      drop(taken);
-
-      // Try to take again - should be None
-      assert!(ivecs.take(0).unwrap().is_none());
-
-      // Take second element
-      let taken = ivecs.take(1).unwrap().unwrap();
-      assert_eq!(taken.as_ref(), &[4, 5, 6]);
-   }
-
-   #[test]
-   fn test_iterator() {
-      let data = vec![Some(vec![1u8, 2, 3]), None, Some(vec![4, 5, 6])];
-
-      let ivecs = IVecs::from_vec(data);
-      let mut iter = ivecs.into_iter();
-
-      let first = iter.next().unwrap().unwrap().unwrap();
-      assert_eq!(first.as_ref(), &[1, 2, 3]);
-
-      let second = iter.next().unwrap().unwrap();
-      assert!(second.is_none());
-
-      let third = iter.next().unwrap().unwrap().unwrap();
-      assert_eq!(third.as_ref(), &[4, 5, 6]);
-
-      assert!(iter.next().is_none());
-   }
-
-   #[test]
-   fn test_from_slice() {
-      let data = [Some(vec![1u8, 2, 3]), Some(vec![4, 5, 6])];
-
-      let ivecs = IVecs::from(data.as_ref());
-      assert_eq!(ivecs.len(), 2);
-      assert_eq!(ivecs.get(0).unwrap(), Some(&[1, 2, 3][..]));
-      assert_eq!(ivecs.get(1).unwrap(), Some(&[4, 5, 6][..]));
-   }
-
-   #[test]
-   fn test_result_type() {
-      let data: Vec<Result<Option<Vec<u8>>, std::io::Error>> = vec![
-         Ok(Some(vec![1, 2, 3])),
-         Err(std::io::Error::other("test error")),
-         Ok(None),
-      ];
-
-      let ivecs = IVecs::from_vec(data);
-      assert_eq!(ivecs.len(), 3);
-
-      assert_eq!(ivecs.get(0).unwrap(), Some(&[1, 2, 3][..]));
-      assert!(ivecs.get(1).is_err());
-      assert_eq!(ivecs.get(2).unwrap(), None);
-   }
-
-   #[test]
-   fn test_empty_ivecs() {
-      let data: Vec<Option<Vec<u8>>> = vec![];
-      let ivecs = IVecs::from_vec(data);
-
-      assert_eq!(ivecs.len(), 0);
-      assert!(ivecs.is_empty());
-      assert_eq!(ivecs.get(0).unwrap(), None);
-
-      let mut iter = ivecs.into_iter();
-      assert!(iter.next().is_none());
-   }
-
-   #[test]
-   fn test_debug_impl() {
-      let data = vec![Some(vec![1u8, 2, 3]), None, Some(vec![4, 5, 6])];
-
-      let ivecs = IVecs::from_vec(data);
-      let debug_str = format!("{ivecs:?}");
-      assert!(debug_str.contains("Ok(Some([1, 2, 3]))"));
-      assert!(debug_str.contains("Ok(None)"));
-      assert!(debug_str.contains("Ok(Some([4, 5, 6]))"));
-   }
-}
diff --git a/attic/kv/src/lib.rs b/attic/kv/src/lib.rs
deleted file mode 100644
index c5d7b19b4..000000000
--- a/attic/kv/src/lib.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-#![feature(btree_cursors)]
-#![feature(slice_ptr_get)]
-#![feature(bigint_helper_methods)]
-#![feature(array_windows)]
-
-#[cfg(feature = "rocksdb")]
-pub mod rocksdb;
-#[cfg(feature = "rocksdb")]
-pub use rocksdb::RocksDb;
-
-pub mod memorydb;
-pub use memorydb::MemoryDb;
-
-#[cfg(feature = "heed")]
-pub mod lmdb;
-#[cfg(feature = "heed")]
-pub use lmdb::{Lmdb, LmdbOptions};
-
-pub mod traits;
-pub use traits::*;
-
-pub mod typed;
-pub use typed::*;
-
-pub mod erased;
-pub use erased::AnyDb;
-
-pub mod ttl;
-pub use ttl::{TtlDb, TtlExt};
-
-pub mod prefixed;
-pub use prefixed::{PrefixExt, Prefixed};
-
-pub mod error;
-pub use error::{Error, Result};
-
-pub mod rmw;
-pub use rmw::*;
-
-pub mod ivec;
-pub use ivec::*;
-
-pub mod pfx_iter;
-
-#[cfg(test)]
-mod tests;
diff --git a/attic/kv/src/lmdb.rs b/attic/kv/src/lmdb.rs
deleted file mode 100644
index 47aa7774d..000000000
--- a/attic/kv/src/lmdb.rs
+++ /dev/null
@@ -1,723 +0,0 @@
-//! LMDB implementation of the [`crate::traits::Store`] API using the heed
-//! crate.
-//!
-//! This implementation provides:
-//! - Efficient key-value storage using LMDB
-//! - Support for namespaces via LMDB databases
-//! - Atomic batch operations via LMDB transactions
-//! - Consistent snapshots via read transactions
-//! - Manual merge operator implementation for update operations
-
-use std::{
-   borrow::Cow,
-   cell::UnsafeCell,
-   fmt, fs,
-   ops::Bound,
-   path::{Path, PathBuf},
-   sync::{Arc, RwLock},
-};
-
-use ahash::AHashMap;
-use bytes::Bytes;
-use heed::{Database, Env, EnvFlags, EnvOpenOptions, RoTxn, RwTxn, WithoutTls};
-use smol_str::{SmolStr, ToSmolStr};
-use tempfile::TempDir;
-
-use super::{error::Result, traits};
-use crate::{IVec, IVecRef, IVecs, Operator, Options, Store};
-
-/// LMDB environment configuration
-const DEFAULT_MAP_SIZE: usize = 10 * 1024 * 1024 * 1024; // 10GB
-const MAX_DBS: u32 = 1000;
-
-/// LMDB-specific options
-#[derive(Debug, Clone, Copy)]
-pub struct LmdbOptions {
-   /// Map size in bytes (virtual address space reserved)
-   pub map_size: usize,
-   /// Maximum number of named databases
-   pub max_dbs: u32,
-}
-
-impl Default for LmdbOptions {
-   fn default() -> Self {
-      Self {
-         map_size: DEFAULT_MAP_SIZE,
-         max_dbs: MAX_DBS,
-      }
-   }
-}
-
-/// Type alias for the LMDB database
-type LmdbDatabase = Database<heed::types::Bytes, heed::types::Bytes>;
-
-/// Shared state for the LMDB environment
-struct Core {
-   /// The LMDB environment
-   env: Env<WithoutTls>,
-   /// Map of database names to their handles
-   dbs: RwLock<AHashMap<SmolStr, LmdbDatabase>>,
-   /// Optional temporary directory for cleanup
-   _tempdir: Option<TempDir>,
-   /// Root path of the database
-   path: PathBuf,
-}
-
-impl Core {
-   /// Opens or creates a database with the given name
-   fn open_db(&self, name: &str) -> Result<LmdbDatabase> {
-      // Fast path: check if database already exists
-      let dbs = self.dbs.read().unwrap();
-      if let Some(db) = dbs.get(name) {
-         return Ok(*db);
-      }
-      drop(dbs);
-
-      // Slow path: need to create the database
-      let mut dbs = self.dbs.write().unwrap();
-      // Double-check after acquiring write lock
-      if let Some(db) = dbs.get(name) {
-         return Ok(*db);
-      }
-
-      // Try to open existing database first
-      let rtxn = self.env.read_txn()?;
-      match self.env.open_database(&rtxn, Some(name)) {
-         Ok(Some(db)) => {
-            drop(rtxn);
-            dbs.insert(SmolStr::from(name), db);
-            Ok(db)
-         },
-         Ok(None) => {
-            // Database doesn't exist, need to create it
-            drop(rtxn);
-            let mut wtxn = self.env.write_txn()?;
-            let db = self.env.create_database(&mut wtxn, Some(name))?;
-            wtxn.commit()?;
-            dbs.insert(SmolStr::from(name), db);
-            Ok(db)
-         },
-         Err(e) => Err(e.into()),
-      }
-   }
-}
-
-/// A namespace in the LMDB hierarchy
-struct Namespace {
-   /// Full name of this namespace
-   full_name: SmolStr,
-   /// Offset to child name
-   name_offset: usize,
-   /// The LMDB database handle
-   db: LmdbDatabase,
-   /// Child namespaces
-   children: RwLock<AHashMap<SmolStr, Arc<Namespace>>>,
-   /// Shared core state
-   core: Arc<Core>,
-   /// Store options
-   opts: Options,
-}
-
-impl Namespace {
-   #[inline]
-   fn is_root(&self) -> bool {
-      self.name_offset == 0
-   }
-
-   fn format_child_name(&self, name: &str) -> SmolStr {
-      if self.is_root() {
-         name.to_smolstr()
-      } else {
-         format!("{}.{}", self.full_name, name).to_smolstr()
-      }
-   }
-}
-
-/// LMDB-backed key-value store
-#[derive(Clone)]
-pub struct Lmdb {
-   inner: Arc<Namespace>,
-}
-
-impl fmt::Debug for Lmdb {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("Lmdb")
-         .field("namespace", &self.namespace())
-         .field("path", &self.inner.core.path)
-         .finish()
-   }
-}
-
-impl Lmdb {
-   /// Creates a new LMDB store with the given path, options, and LMDB-specific
-   /// options
-   pub fn with_lmdb_opts(
-      path: Option<&Path>,
-      opts: Options,
-      lmdb_opts: LmdbOptions,
-   ) -> Result<Self> {
-      let mut temp_dir = None;
-      let path = if let Some(path) = path {
-         path.to_path_buf()
-      } else {
-         temp_dir = Some(TempDir::with_prefix("tetra-lmdb-")?);
-         temp_dir.as_ref().unwrap().path().to_path_buf()
-      };
-
-      // Ensure directory exists
-      fs::create_dir_all(&path)?;
-
-      // Open LMDB environment with performance optimizations
-      let mut env_builder = EnvOpenOptions::new();
-      env_builder.map_size(lmdb_opts.map_size);
-      env_builder.max_dbs(lmdb_opts.max_dbs);
-
-      let env = unsafe {
-         let mut flags = if opts.sync {
-            EnvFlags::empty()
-         } else {
-            EnvFlags::NO_SYNC | EnvFlags::MAP_ASYNC
-         };
-         flags |= EnvFlags::WRITE_MAP; // Use memory-mapped writes
-         flags |= EnvFlags::NO_META_SYNC; // Don't sync metadata
-         flags |= EnvFlags::NO_MEM_INIT; // Don't initialize memory
-         env_builder.flags(flags);
-         env_builder.read_txn_without_tls().open(&path)?
-      };
-
-      let core = Arc::new(Core {
-         env,
-         dbs: RwLock::new(AHashMap::new()),
-         _tempdir: temp_dir,
-         path,
-      });
-
-      // Open root database with empty name to match RocksDB convention
-      let root_name = SmolStr::new_static("");
-      let db = core.open_db("$")?; // Use internal name for LMDB since it doesn't support empty names
-
-      Ok(Self {
-         inner: Arc::new(Namespace {
-            full_name: root_name,
-            name_offset: 0,
-            db,
-            children: RwLock::new(AHashMap::new()),
-            core,
-            opts,
-         }),
-      })
-   }
-
-   /// Creates a new LMDB store with the given path and options
-   pub fn with_opts(path: Option<&Path>, opts: Options) -> Result<Self> {
-      Self::with_lmdb_opts(path, opts, LmdbOptions::default())
-   }
-
-   /// Opens an LMDB store at the given path
-   pub fn open(path: impl AsRef<Path>) -> Result<Self> {
-      Self::with_opts(Some(path.as_ref()), Options::default())
-   }
-
-   /// Creates a temporary LMDB store
-   pub fn temp() -> Result<Self> {
-      Self::with_opts(None, Options::default())
-   }
-
-   /// Returns a reference to the underlying LMDB environment
-   #[inline]
-   pub fn env(&self) -> &Env<WithoutTls> {
-      &self.inner.core.env
-   }
-
-   /// Opens a child namespace
-   fn open_child(&self, name: &str, opts: Options) -> Result<Self> {
-      // Fast path: check if child already exists
-      {
-         let children = self.inner.children.read().unwrap();
-         if let Some(child) = children.get(name) {
-            return Ok(Self {
-               inner: child.clone(),
-            });
-         }
-      }
-
-      // Slow path: need to create the child
-      // Acquire write lock on children first to establish consistent lock ordering
-      let mut children = self.inner.children.write().unwrap();
-
-      // Double-check after acquiring write lock
-      if let Some(child) = children.get(name) {
-         return Ok(Self {
-            inner: child.clone(),
-         });
-      }
-
-      // Now open/create the database (this will acquire dbs lock internally)
-      let full_name = self.inner.format_child_name(name);
-      let db = self.inner.core.open_db(&full_name)?;
-
-      let child = Arc::new(Namespace {
-         name_offset: full_name.len() - name.len(),
-         full_name: full_name.clone(),
-         db,
-         children: RwLock::new(AHashMap::new()),
-         core: self.inner.core.clone(),
-         opts,
-      });
-
-      children.insert(name.to_smolstr(), child.clone());
-      Ok(Self { inner: child })
-   }
-}
-
-/// LMDB snapshot using a read transaction
-///
-/// Note: LMDB snapshots have limitations compared to other backends:
-/// - They hold a read transaction which can become invalid if too many write
-///   transactions occur (LMDB has a limited number of reader slots)
-/// - Long-lived snapshots can prevent LMDB from reclaiming space
-/// - The snapshot may fail with BadRslot error if the environment is heavily
-///   modified
-pub struct Snapshot<'a> {
-   txn: RoTxn<'a, WithoutTls>,
-   store: &'a Lmdb,
-}
-
-impl<'a> fmt::Debug for Snapshot<'a> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("Snapshot")
-         .field("namespace", &self.store.namespace())
-         .finish()
-   }
-}
-
-/// Inner iterator state
-enum IterVariant<'a> {
-   Error(Option<heed::Error>),
-   Forward(heed::RoIter<'a, heed::types::Bytes, heed::types::Bytes>),
-   Reverse(heed::RoRevIter<'a, heed::types::Bytes, heed::types::Bytes>),
-   ForwardRange(heed::RoRange<'a, heed::types::Bytes, heed::types::Bytes>),
-   ReverseRange(heed::RoRevRange<'a, heed::types::Bytes, heed::types::Bytes>),
-}
-
-pub struct PrefixIter<'a, T> {
-   _txn: T,
-   inner: Option<heed::Result<heed::RoPrefix<'a, heed::types::Bytes, heed::types::Bytes>>>,
-}
-
-impl<'a> PrefixIter<'a, ()> {
-   fn new(db: &'a Lmdb, txn: &'_ RoTxn<'a, WithoutTls>, prefix: &[u8]) -> Self {
-      let txn = unsafe { &*(txn as *const _ as *const RoTxn<'a, WithoutTls>) };
-      Self {
-         _txn: (),
-         inner: Some(db.inner.db.prefix_iter(txn, prefix)),
-      }
-   }
-}
-
-impl<'a> PrefixIter<'a, RoTxn<'a, WithoutTls>> {
-   fn new(db: &'a Lmdb, prefix: &[u8]) -> Self {
-      let txn = db.env().read_txn().unwrap();
-      Self {
-         inner: PrefixIter::<()>::new(db, &txn, prefix).inner,
-         _txn: txn,
-      }
-   }
-}
-
-impl<'a, T> Iterator for PrefixIter<'a, T> {
-   type Item = Result<(Bytes, Bytes)>;
-
-   fn next(&mut self) -> Option<Self::Item> {
-      match &mut self.inner {
-         Some(Ok(it)) => it.next().map(|x| {
-            x.map(|(k, v)| (Bytes::copy_from_slice(k), Bytes::copy_from_slice(v)))
-               .map_err(Into::into)
-         }),
-         x @ Some(Err(_)) => Some(Err(x.take().unwrap().unwrap_err().into())),
-         None => None,
-      }
-   }
-}
-
-/// Iterator wrapper for LMDB
-pub struct Iter<'a, T> {
-   // Keeps the read-txn alive for store-level iterators.
-   _txn: T,
-   inner: IterVariant<'a>,
-}
-
-impl<'a> Iter<'a, ()> {
-   fn new(db: &'a Lmdb, txn: &'_ RoTxn<'a, WithoutTls>, mode: traits::IterMode<'_>) -> Self {
-      let txn = unsafe { &*(txn as *const _ as *const RoTxn<'a, WithoutTls>) };
-      use traits::IterMode::*;
-      let inner = match mode {
-         Forward(start) => {
-            if let Some(start_key) = start {
-               db.inner
-                  .db
-                  .range(txn, &(Bound::Included(start_key), Bound::Unbounded))
-                  .map(IterVariant::ForwardRange)
-                  .unwrap_or_else(|e| IterVariant::Error(Some(e)))
-            } else {
-               db.inner
-                  .db
-                  .iter(txn)
-                  .map(IterVariant::Forward)
-                  .unwrap_or_else(|e| IterVariant::Error(Some(e)))
-            }
-         },
-         Reverse(start) => {
-            if let Some(start_key) = start {
-               db.inner
-                  .db
-                  .rev_range(txn, &(Bound::Unbounded, Bound::Included(start_key)))
-                  .map(IterVariant::ReverseRange)
-                  .unwrap_or_else(|e| IterVariant::Error(Some(e)))
-            } else {
-               db.inner
-                  .db
-                  .rev_iter(txn)
-                  .map(IterVariant::Reverse)
-                  .unwrap_or_else(|e| IterVariant::Error(Some(e)))
-            }
-         },
-      };
-
-      Self { _txn: (), inner }
-   }
-}
-
-impl<'a> Iter<'a, RoTxn<'a, WithoutTls>> {
-   fn new(db: &'a Lmdb, mode: traits::IterMode<'_>) -> Self {
-      let txn = db.env().read_txn().unwrap();
-      Self {
-         inner: Iter::<()>::new(db, &txn, mode).inner,
-         _txn: txn,
-      }
-   }
-}
-
-impl<'a, T> Iterator for Iter<'a, T> {
-   type Item = Result<(Bytes, Bytes)>;
-
-   #[inline]
-   fn next(&mut self) -> Option<Self::Item> {
-      let map = |r: heed::Result<(&[u8], &[u8])>| -> Result<_> {
-         r.map(|(k, v)| (Bytes::copy_from_slice(k), Bytes::copy_from_slice(v)))
-            .map_err(Into::into)
-      };
-      match &mut self.inner {
-         IterVariant::Error(e) => e.take().map(|e| Err(e.into())),
-         IterVariant::Forward(it) => it.next().map(map),
-         IterVariant::Reverse(it) => it.next().map(map),
-         IterVariant::ForwardRange(it) => it.next().map(map),
-         IterVariant::ReverseRange(it) => it.next().map(map),
-      }
-   }
-}
-
-impl<'a> traits::View for Snapshot<'a> {
-   type Iter<'b>
-      = Iter<'b, ()>
-   where
-      Self: 'b;
-
-   #[inline]
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      Ok(self.store.inner.db.get(&self.txn, key)?.map(IVec::from))
-   }
-
-   #[inline]
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      Ok(self.store.inner.db.get(&self.txn, key)?.is_some())
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      Ok(IVecs::from_iter(keys.into_iter().map(
-         |k| -> Result<Option<&[u8]>> {
-            self
-               .store
-               .inner
-               .db
-               .get(&self.txn, k.as_ref())
-               .map_err(Into::into)
-         },
-      )))
-   }
-
-   fn iter<'b>(&'b self, mode: traits::IterMode<'_>) -> Self::Iter<'b> {
-      Self::Iter::new(self.store, &self.txn, mode)
-   }
-
-   fn scan<'b>(
-      &'b self,
-      prefix: &[u8],
-   ) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'b, 'a> {
-      PrefixIter::<()>::new(self.store, &self.txn, prefix)
-   }
-}
-
-/// Write batch for LMDB
-pub struct WriteBatch<'a> {
-   parent: &'a Lmdb,
-   wtxn: UnsafeCell<Option<RwTxn<'a>>>,
-}
-
-impl<'a> WriteBatch<'a> {
-   fn new(parent: &'a Lmdb) -> Self {
-      Self {
-         parent,
-         wtxn: UnsafeCell::new(None),
-      }
-   }
-
-   fn wtxn(&self) -> &mut RwTxn<'a> {
-      let opt = unsafe { &mut *self.wtxn.get() };
-      if let Some(txn) = opt {
-         return txn;
-      };
-
-      let txn = self.parent.env().write_txn().unwrap();
-      *opt = Some(txn);
-
-      let Some(txn) = opt.as_mut() else {
-         panic!("Failed to get write transaction");
-      };
-      txn
-   }
-}
-
-impl<'a> fmt::Debug for WriteBatch<'a> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("WriteBatch")
-         .field("namespace", &self.parent.namespace())
-         .finish()
-   }
-}
-
-impl<'a> traits::Write for WriteBatch<'a> {
-   type Result = ();
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self.parent.inner.db.put(self.wtxn(), key, value).unwrap();
-   }
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.parent.inner.db.delete(self.wtxn(), key).unwrap();
-   }
-
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      let range = (Bound::Included(from), Bound::Excluded(to));
-      self
-         .parent
-         .inner
-         .db
-         .delete_range(self.wtxn(), &range)
-         .unwrap();
-   }
-
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      // Get current value
-      let prev_data = self.parent.inner.db.get(self.wtxn(), key).unwrap();
-      let result = op.apply(key, prev_data.map(Cow::Borrowed));
-      self.parent.inner.db.put(self.wtxn(), key, &result).unwrap();
-   }
-}
-
-impl<'a> traits::WriteBatch<'a> for WriteBatch<'a> {
-   fn commit(&self) -> Result<()> {
-      let opt = unsafe { &mut *self.wtxn.get() };
-      if let Some(txn) = opt.take() {
-         txn.commit()?;
-      }
-      Ok(())
-   }
-
-   fn reset(&mut self) {
-      let opt = unsafe { &mut *self.wtxn.get() };
-      if let Some(txn) = opt.take() {
-         txn.abort();
-      }
-   }
-}
-
-// ==============================  View  ==================================== //
-
-struct SliceWithOwner<T> {
-   _rtxn: T,
-   slice: *const [u8],
-}
-
-impl<T> IVecRef for SliceWithOwner<T> {
-   fn as_slice(&self) -> &[u8] {
-      unsafe { &*self.slice }
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.as_slice().to_vec()
-   }
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::copy_from_slice(self.as_slice())
-   }
-}
-
-impl<'a, T> SliceWithOwner<T> {
-   fn new(rtxn: T, vec: *const [u8]) -> Self {
-      Self {
-         _rtxn: rtxn,
-         slice: vec,
-      }
-   }
-}
-
-impl traits::View for Lmdb {
-   type Iter<'a>
-      = Iter<'a, RoTxn<'a, WithoutTls>>
-   where
-      Self: 'a;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      let rtxn = self.env().read_txn()?;
-      let value = self.inner.db.get(&rtxn, key)?;
-
-      match value.map(|x| x as *const [u8]) {
-         Some(v) => Ok(Some(IVec::from(SliceWithOwner::new(rtxn, v)))),
-         None => Ok(None),
-      }
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      let rtxn = self.env().read_txn()?;
-      Ok(self
-         .inner
-         .db
-         .lazily_decode_data()
-         .get(&rtxn, key)?
-         .is_some())
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      // Reuse a single transaction for all reads
-      let rtxn = Arc::new(self.env().read_txn()?);
-      Ok(IVecs::from_iter(keys.into_iter().map(
-         |k| -> Result<Option<SliceWithOwner<_>>> {
-            match self.inner.db.get(&rtxn, k.as_ref()) {
-               Ok(Some(v)) => Ok(Some(SliceWithOwner::new(Arc::clone(&rtxn), v))),
-               Ok(None) => Ok(None),
-               Err(e) => Err(e.into()),
-            }
-         },
-      )))
-   }
-
-   fn iter<'a>(&'a self, mode: traits::IterMode<'_>) -> Self::Iter<'a> {
-      Self::Iter::new(self, mode)
-   }
-
-   fn scan<'b>(&'b self, prefix: &[u8]) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'b> {
-      PrefixIter::<RoTxn<'b, WithoutTls>>::new(self, prefix)
-   }
-}
-
-// ==============================  Write  =================================== //
-
-impl traits::Write for Lmdb {
-   type Result = Result<()>;
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      let mut wtxn = self.env().write_txn()?;
-      self.inner.db.put(&mut wtxn, key, value)?;
-      wtxn.commit()?;
-      Ok(())
-   }
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      let mut wtxn = self.env().write_txn()?;
-      self.inner.db.delete(&mut wtxn, key)?;
-      wtxn.commit()?;
-      Ok(())
-   }
-
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      let mut wtxn = self.env().write_txn()?;
-
-      let range = (Bound::Included(from), Bound::Excluded(to));
-      self.inner.db.delete_range(&mut wtxn, &range)?;
-      wtxn.commit()?;
-      Ok(())
-   }
-
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      let mut wtxn = self.env().write_txn()?;
-      let prev_data = self
-         .inner
-         .db
-         .get(unsafe { &mut *(&mut wtxn as *mut RwTxn<'_>) }, key)?;
-      let result = op.apply(key, prev_data.map(Cow::Borrowed));
-      self.inner.db.put(&mut wtxn, key, &result)?;
-      wtxn.commit()?;
-      Ok(())
-   }
-}
-
-// ==============================  Store  =================================== //
-
-impl traits::Store for Lmdb {
-   type WriteBatch<'a> = WriteBatch<'a>;
-   type Snapshot<'a> = Snapshot<'a>;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      WriteBatch::new(self)
-   }
-
-   fn namespace(&self) -> &str {
-      &self.inner.full_name[self.inner.name_offset..]
-   }
-
-   fn child(&self, name: &str, opts: Options) -> Result<Self> {
-      self.open_child(name, opts)
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      self
-         .inner
-         .children
-         .read()
-         .unwrap()
-         .keys()
-         .cloned()
-         .collect()
-   }
-
-   fn clear(&self) -> Result<()> {
-      let mut wtxn = self.env().write_txn()?;
-      self.inner.db.clear(&mut wtxn)?;
-      wtxn.commit()?;
-      Ok(())
-   }
-
-   fn flush(&self) -> Result<()> {
-      if self.inner.opts.sync {
-         self.env().force_sync()?;
-      }
-      Ok(())
-   }
-
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      // Note: snapshot() doesn't return Result, so we must panic on error
-      // This is a design limitation of the trait
-      let txn = self
-         .env()
-         .read_txn()
-         .expect("Failed to create read transaction for snapshot");
-      Snapshot { txn, store: self }
-   }
-
-   fn options(&self) -> &Options {
-      &self.inner.opts
-   }
-
-   fn estimate_size(&self) -> Option<u64> {
-      self.env().non_free_pages_size().ok()
-   }
-}
diff --git a/attic/kv/src/memorydb.rs b/attic/kv/src/memorydb.rs
deleted file mode 100644
index 400ab3c12..000000000
--- a/attic/kv/src/memorydb.rs
+++ /dev/null
@@ -1,688 +0,0 @@
-//! In-memory implementation of the [`crate::traits::Store`] API that supports
-//! cheap, copy-on-write snapshots.  The design is centred around the
-//! [`Transaction`] structure which represents *one* version chain of a logical
-//! namespace.  Each call to [`Store::snapshot`] freezes the current state by
-//! creating a new empty *live* layer and returning an `Arc` to the previous
-//! chain head.  Any further writes are appended to the live layer.  When the
-//! last `Arc` that still references the frozen head gets dropped we try to
-//! merge ("compact") the live overlay back into the previous layer so that the
-//! total memory usage stays bounded.
-//!
-//! The implementation is *optimised for simplicity* rather than ultimate
-//! performance because it is mainly used in unit tests where correctness and
-//! determinism matter more than speed.
-
-use std::{
-   borrow::Cow,
-   cell::RefCell,
-   cmp::Ordering,
-   collections::{btree_map, BTreeMap},
-   fmt,
-   iter::FusedIterator,
-   marker::PhantomData,
-   mem,
-   ops::{Bound, Deref, Range},
-   sync::LazyLock,
-};
-
-use ahash::AHashMap;
-use bytes::{Bytes, BytesMut};
-use parking_lot::RwLock;
-use smallvec::SmallVec;
-use smol_str::{SmolStr, ToSmolStr};
-use tetra_core::alloc::quickbuf;
-use traits::IterMode;
-use triomphe::Arc;
-
-use super::{error::Result, traits};
-use crate::{IVec, IVecs, Operator, OperatorRepr, Options, Store, WriteBatch as _};
-
-// =======================  Underlying map utils ============================ //
-
-/// Overlay map that distinguishes between *set* (Some) and *delete* (None).
-type Map = BTreeMap<Bytes, Option<Bytes>>;
-
-#[derive(Clone)]
-struct MapIter<'a> {
-   cursor: btree_map::Cursor<'a, Bytes, Option<Bytes>>,
-   rev: bool,
-}
-
-impl<'a> fmt::Debug for MapIter<'a> {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("MapIter")
-         .field(
-            "cursor",
-            &format_args!(
-               "<prev: {:?}, next: {:?}>",
-               self.cursor.peek_prev(),
-               self.cursor.peek_next()
-            ),
-         )
-         .field("rev", &self.rev)
-         .finish()
-   }
-}
-
-impl<'a> MapIter<'a> {
-   fn new<'b>(vns: &'a Map, at: Option<&'b [u8]>, rev: bool) -> Self {
-      let bound = at.map_or(Bound::Unbounded, Bound::Included);
-      let cursor = if rev {
-         vns.upper_bound(bound)
-      } else {
-         vns.lower_bound(bound)
-      };
-      Self { cursor, rev }
-   }
-
-   fn with_mode(vns: &'a Map, mode: IterMode<'_>) -> Self {
-      Self::new(vns, mode.at(), mode.is_reverse())
-   }
-
-   fn peek(&mut self) -> Option<(&'a Bytes, &'a Option<Bytes>)> {
-      if self.rev {
-         self.cursor.peek_prev()
-      } else {
-         self.cursor.peek_next()
-      }
-   }
-}
-
-impl<'a> Iterator for MapIter<'a> {
-   type Item = (&'a Bytes, &'a Option<Bytes>);
-
-   fn next(&mut self) -> Option<Self::Item> {
-      if self.rev {
-         self.cursor.prev()
-      } else {
-         self.cursor.next()
-      }
-   }
-}
-
-impl<'a> FusedIterator for MapIter<'a> {}
-
-// =======================  Versioned namespace  ============================ //
-
-/// One *version* of a namespace.  `live` keeps the local changes while `prev`
-/// points to the (immutable) previous state.
-#[derive(Default)]
-struct Transaction {
-   /// Previous, immutable state (if any).
-   prev: Option<Arc<Transaction>>, // None means this is the root.
-   /// The overlay with changes that happened *after* `prev` was frozen.
-   /// `None` means the key was deleted.
-   live: Map,
-}
-
-impl fmt::Debug for Transaction {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("Transaction")
-         .field("prev", &self.prev)
-         .field("live", &self.live)
-         .finish()
-   }
-}
-
-static EMPTY_TXN: LazyLock<Arc<Transaction>> = LazyLock::new(|| Arc::new(Transaction::default()));
-
-fn kv_to_bytes(key: &[u8], value: &[u8]) -> (Bytes, Bytes) {
-   let mut bmut = BytesMut::with_capacity(key.len() + value.len());
-   bmut.extend_from_slice(key);
-   bmut.extend_from_slice(value);
-   let mut value = bmut.freeze();
-   let key = value.split_to(key.len());
-   (key, value)
-}
-
-impl Transaction {
-   const TXN_INTERN_THRESHOLD: usize = 32;
-
-   #[inline]
-   fn find<'a, R>(&'a self, f: impl Fn(&'a Transaction) -> Option<R>) -> Option<R> {
-      let mut at: Option<&'a Transaction> = Some(self);
-      while let Some(txn) = at {
-         if let Some(r) = f(txn) {
-            return Some(r);
-         }
-         at = txn.prev.as_deref();
-      }
-      None
-   }
-
-   /// Recursively look up `key` starting from the current version.
-   fn get(&self, key: &[u8]) -> Option<&Bytes> {
-      self
-         .find(|tx| tx.live.get(key).map(|v| v.as_ref()))
-         .flatten()
-   }
-
-   /// Apply a *put* operation to the live layer.
-   fn put(&mut self, key: &[u8], value: &[u8]) {
-      let (key, value) = kv_to_bytes(key, value);
-      self.live.insert(key, Some(value));
-   }
-
-   /// Apply a *delete* operation to the live layer.
-   fn delete(&mut self, key: &[u8]) {
-      if let Some((key, Some(_))) = self.find(|tx| tx.live.get_key_value(key)) {
-         self.live.insert(key.clone(), None);
-      }
-      // Otherwise we don't care as either:
-      // - None: value does not exist
-      // - Some(K, None): value exists but is in tombstone state
-   }
-
-   fn update<T: Operator + ?Sized>(&mut self, key: &[u8], op: &T) -> Result<()> {
-      let prev = self
-         .live
-         .get(key)
-         .and_then(|x| x.as_ref().map(|v| v.as_ref()));
-
-      let result = op.apply(key, prev.map(Cow::Borrowed));
-      let (key_bytes, value_bytes) = kv_to_bytes(key, &result);
-      self.live.insert(key_bytes, Some(value_bytes));
-      Ok(())
-   }
-
-   /// Freeze the current version and return an `Arc` to it, creating a fresh
-   /// empty *live* layer so that new writes do not mutate the snapshot.
-   fn snapshot(&mut self) -> Arc<Transaction> {
-      // If there are *no* local changes we can just reuse the previous head.
-      if self.live.is_empty() {
-         return self.prev.clone().unwrap_or_else(|| EMPTY_TXN.clone());
-      }
-
-      let mut frozen = mem::take(self);
-
-      if Self::TXN_INTERN_THRESHOLD > 0 {
-         while let Some(prev) = frozen.prev.as_deref() {
-            if prev.live.len() < Self::TXN_INTERN_THRESHOLD {
-               for (k, v_opt) in prev.live.iter() {
-                  frozen.live.entry(k.clone()).or_insert(v_opt.clone());
-               }
-               frozen.prev = prev.prev.clone();
-            } else {
-               break;
-            }
-         }
-      }
-
-      let frozen = Arc::new(frozen);
-      *self = Transaction {
-         prev: Some(frozen.clone()),
-         live: Map::new(),
-      };
-      frozen
-   }
-
-   /// Try to merge (`compact`) the *live* changes back into the previous layer
-   /// if it is uniquely owned (i.e. no snapshot still references it).
-   fn compact(&mut self) {
-      let Some(prev_arc) = &mut self.prev else {
-         return;
-      }; // no previous layer
-      if let Some(prev_mut) = Arc::get_mut(prev_arc) {
-         // Safe to mutate.
-         for (k, v_opt) in mem::take(&mut self.live) {
-            match v_opt {
-               Some(v) => {
-                  prev_mut.live.insert(k, Some(v));
-               },
-               None => {
-                  prev_mut.live.insert(k, None);
-               },
-            }
-         }
-         // After merging we can drop the prev arc and point to its prev to
-         // shorten the chain the next time.
-         self.prev = prev_mut.prev.clone();
-      }
-   }
-}
-
-#[derive(Clone, derive_more::Debug)]
-enum TransactionRef<'a> {
-   #[debug("Owned({:?})", self.as_ref())]
-   Owned(Arc<Transaction>),
-   #[debug("Borrowed({:?})", self.as_ref())]
-   Borrowed(&'a Transaction),
-}
-
-impl<'a> From<&'a Transaction> for TransactionRef<'a> {
-   fn from(vns: &'a Transaction) -> Self {
-      Self::Borrowed(vns)
-   }
-}
-
-impl<'a> From<Arc<Transaction>> for TransactionRef<'a> {
-   fn from(vns: Arc<Transaction>) -> Self {
-      Self::Owned(vns)
-   }
-}
-
-impl<'a> AsRef<Transaction> for TransactionRef<'a> {
-   fn as_ref(&self) -> &Transaction {
-      match self {
-         Self::Owned(vns) => vns.as_ref(),
-         Self::Borrowed(vns) => vns,
-      }
-   }
-}
-
-impl<'a> Deref for TransactionRef<'a> {
-   type Target = Transaction;
-   fn deref(&self) -> &Self::Target {
-      self.as_ref()
-   }
-}
-
-impl<'a> TransactionRef<'a> {
-   /// Returns a reference to the underlying `Transaction`.
-   ///
-   /// This method escapes the lifetime constraint only when holding an
-   /// `Arc<Transaction>`. In the `Owned` variant, it converts the reference
-   /// with lifetime tied to the `Arc` into a reference with lifetime 'a.
-   ///
-   /// # Safety
-   ///
-   /// This is safe as long as iterators or other values using the returned
-   /// reference do not outlive the lifetime 'a. The `Arc` ensures the
-   /// `Transaction` remains valid for the `Owned` variant, while the
-   /// `Borrowed` variant directly respects the 'a lifetime.
-   unsafe fn as_ref_ext(&self) -> &'a Transaction {
-      match self {
-         Self::Owned(vns) => {
-            let r: &'_ Transaction = vns.as_ref();
-            // SAFETY: `r` is a valid reference to the `Transaction` for as long as the Arc
-            // exists, which is at least as long as 'self' exists
-            unsafe { &*(r as *const Transaction) }
-         },
-         Self::Borrowed(vns) => vns,
-      }
-   }
-}
-
-#[derive(derive_more::Debug)]
-#[debug("TransactionIter {{ iters: {:?} }}", iters)]
-pub struct TransactionIter<'a> {
-   _refn: TransactionRef<'a>,
-   iters: SmallVec<[(MapIter<'a>, bool); 8]>,
-}
-
-impl<'a> TransactionIter<'a> {
-   fn new(txn: impl Into<TransactionRef<'a>>, mode: IterMode<'_>) -> Self {
-      let mut iters = SmallVec::new();
-      let txref: TransactionRef<'a> = txn.into();
-
-      let mut vref: &'a Transaction = unsafe { txref.as_ref_ext() };
-      loop {
-         iters.push((MapIter::with_mode(&vref.live, mode), false));
-         if let Some(prev) = &vref.prev {
-            vref = prev.as_ref();
-         } else {
-            break;
-         }
-      }
-      Self {
-         iters,
-         _refn: txref,
-      }
-   }
-}
-
-impl<'a> Iterator for TransactionIter<'a> {
-   type Item = Result<(Bytes, Bytes)>;
-
-   fn next(&mut self) -> Option<Self::Item> {
-      let mut yielded = None;
-      while yielded.is_none() {
-         let mut min_key: Option<Bytes> = None;
-         let mut last_val: Option<&Bytes> = None;
-
-         let mut skiptail = 0;
-         for (i, (iter, skip)) in self.iters.iter_mut().enumerate().rev() {
-            *skip = false;
-            if let Some((key, value)) = iter.peek() {
-               let value: Option<&Bytes> = value.as_ref();
-               let cmp = min_key
-                  .as_ref()
-                  .map(|k| k.as_ref().cmp(key.as_ref()))
-                  .unwrap_or(Ordering::Less);
-               if cmp == Ordering::Greater {
-                  continue;
-               }
-               if cmp == Ordering::Less {
-                  min_key = Some(key.clone());
-                  skiptail = i + 1;
-               }
-               last_val = value;
-               *skip = true;
-            }
-         }
-
-         match (&min_key, last_val) {
-            // If we have no min key, we are done as all iterators are exhausted
-            (None, _) => return None,
-            // If last value is not a tombstone, we can yield the min key and value
-            (Some(k), Some(v)) => yielded = Some(Ok((k.clone(), v.clone()))),
-            // Otherwise we will skip to the next key, but we still have to forward the
-            // iterators.
-            _ => {},
-         }
-
-         // Skip the iterators that were at this key
-         for (iter, skip) in &mut self.iters[..skiptail] {
-            if *skip {
-               let at = iter.next();
-               debug_assert_eq!(at.unwrap().0, min_key.as_ref().unwrap());
-            }
-         }
-      }
-      yielded
-   }
-}
-
-// ===========================  Namespace  ================================== //
-
-#[derive(Debug)]
-struct Namespace {
-   name: SmolStr,
-   opts: Options,
-   txn: RwLock<Transaction>,
-   children: RwLock<AHashMap<SmolStr, Arc<Namespace>>>,
-}
-
-impl Namespace {
-   fn new(name: SmolStr, opts: Options) -> Self {
-      Self {
-         name,
-         opts,
-         txn: RwLock::new(Transaction::default()),
-         children: RwLock::new(AHashMap::new()),
-      }
-   }
-
-   fn get(&self, key: &[u8]) -> Option<Bytes> {
-      self.txn.read().get(key).cloned()
-   }
-
-   fn put(&self, key: &[u8], value: &[u8]) {
-      self.txn.write().put(key, value);
-   }
-
-   fn delete(&self, key: &[u8]) {
-      self.txn.write().delete(key);
-   }
-
-   fn snapshot(&self) -> Arc<Transaction> {
-      self.txn.write().snapshot()
-   }
-
-   fn update<T: Operator + ?Sized>(&self, key: &[u8], op: &T) -> Result<()> {
-      self.txn.write().update(key, op)
-   }
-
-   fn try_compact(&self) {
-      self.txn.write().compact();
-   }
-
-   fn emplace_child(&self, name: &str, opts: Options) -> Arc<Namespace> {
-      let mut guard = self.children.upgradable_read();
-      if let Some(child) = guard.get(name) {
-         return child.clone();
-      }
-      guard.with_upgraded(|children| {
-         use std::collections::hash_map::Entry;
-         match children.entry(name.to_smolstr()) {
-            Entry::Occupied(child) => child.get().clone(),
-            Entry::Vacant(entry) => {
-               let child = Arc::new(Namespace::new(name.to_smolstr(), opts));
-               entry.insert(child.clone());
-               child
-            },
-         }
-      })
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      self.children.read().keys().cloned().collect()
-   }
-}
-
-// ============================  MemoryDb  ================================== //
-
-#[derive(Clone, Debug)]
-pub struct MemoryDb {
-   ns: Arc<Namespace>,
-}
-
-impl Default for MemoryDb {
-   fn default() -> Self {
-      Self::new()
-   }
-}
-
-impl MemoryDb {
-   pub fn new() -> Self {
-      Self {
-         ns: Arc::new(Namespace::new(SmolStr::new_static("$"), Options::default())),
-      }
-   }
-
-   fn namespace(&self) -> &Arc<Namespace> {
-      &self.ns
-   }
-}
-
-#[derive(Debug)]
-pub struct Snapshot<'a> {
-   vns: Arc<Transaction>,
-   ns: Arc<Namespace>,
-   _phantom: PhantomData<&'a ()>,
-}
-impl<'a> Drop for Snapshot<'a> {
-   fn drop(&mut self) {
-      if Arc::strong_count(&self.vns) == 1 {
-         self.ns.try_compact();
-      }
-   }
-}
-
-impl<'a> traits::View for Snapshot<'a> {
-   type Iter<'b>
-      = TransactionIter<'b>
-   where
-      Self: 'b;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'a>>> {
-      Ok(self.vns.get(key).map(IVec::from_ref))
-   }
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      Ok(self.vns.get(key).is_some())
-   }
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      Ok(keys
-         .into_iter()
-         .map(|k| self.vns.get(k.as_ref()))
-         .map(|x| x.cloned())
-         .collect())
-   }
-   fn iter(&self, mode: IterMode) -> Self::Iter<'_> {
-      TransactionIter::new(self.vns.clone(), mode)
-   }
-}
-
-#[derive(Debug, Default)]
-struct WriteBatchInner {
-   ops: SmallVec<[Op; 8]>,
-   pool: quickbuf::StackBuffer,
-}
-
-impl WriteBatchInner {
-   fn stash_range(&mut self, data: &[u8]) -> Range<usize> {
-      let beg = self.pool.len();
-      self.pool.extend_from_slice(data);
-      let end = self.pool.len();
-      beg..end
-   }
-}
-
-#[derive(Debug)]
-pub struct WriteBatch<'a> {
-   inner: RefCell<WriteBatchInner>,
-   parent: &'a MemoryDb,
-}
-
-#[derive(Debug)]
-enum Op {
-   Put(Bytes, Bytes),
-   Del(Range<usize>),
-   Rmw(Range<usize>, Range<usize>),
-}
-
-impl<'a> traits::Write for WriteBatch<'a> {
-   type Result = ();
-   fn put(&self, k: &[u8], v: &[u8]) -> Self::Result {
-      let (key, value) = kv_to_bytes(k, v);
-      self.inner.borrow_mut().ops.push(Op::Put(key, value));
-   }
-   fn delete(&self, k: &[u8]) -> Self::Result {
-      let mut inner = self.inner.borrow_mut();
-      let rng = inner.stash_range(k);
-      inner.ops.push(Op::Del(rng));
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      use crate::traits::{IterMode, View};
-
-      // Collect keys in the range
-      for (k, _) in self.parent.iter(IterMode::Forward(Some(from))).flatten() {
-         if k.as_ref() >= to {
-            break;
-         }
-         self.delete(k.as_ref());
-      }
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      let mut inner = self.inner.borrow_mut();
-      let k = inner.stash_range(key);
-      let v = op.write_to(&mut inner.pool);
-      inner.ops.push(Op::Rmw(k, v));
-   }
-}
-
-impl<'a> traits::WriteBatch<'a> for WriteBatch<'a> {
-   fn commit(&self) -> Result<()> {
-      let ns = self.parent.namespace();
-      let mut inner = self.inner.borrow_mut();
-      let WriteBatchInner { ops, pool } = &mut *inner;
-      for op in ops.drain(..) {
-         match op {
-            Op::Put(k, v) => ns.put(&k, &v),
-            Op::Del(rng) => ns.delete(&pool[rng]),
-            Op::Rmw(k, v) => {
-               let k = &pool[k];
-               let op = OperatorRepr::from_bytes(&pool[v]);
-               ns.update(k, &op)?;
-            },
-         }
-      }
-      Ok(())
-   }
-   fn reset(&mut self) {
-      let inner = self.inner.get_mut();
-      inner.ops.clear();
-      inner.pool.clear();
-   }
-}
-
-// ==============================  View  ==================================== //
-impl traits::View for MemoryDb {
-   type Iter<'b>
-      = TransactionIter<'b>
-   where
-      Self: 'b;
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      Ok(self.namespace().get(key).map(IVec::new))
-   }
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      Ok(self.namespace().get(key).is_some())
-   }
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      Ok(keys
-         .into_iter()
-         .map(|k| self.namespace().get(k.as_ref()))
-         .collect())
-   }
-   fn iter(&self, mode: IterMode) -> Self::Iter<'_> {
-      TransactionIter::new(self.namespace().snapshot(), mode)
-   }
-}
-
-// ==============================  Store  =================================== //
-
-impl traits::Write for MemoryDb {
-   type Result = crate::Result<()>;
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Result<()> {
-      self.namespace().put(key, value);
-      Ok(())
-   }
-   fn delete(&self, key: &[u8]) -> Result<()> {
-      self.namespace().delete(key);
-      Ok(())
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Result<()> {
-      self.namespace().update(key, op)
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Result<()> {
-      let wb = self.batch();
-      wb.delete_range(from, to);
-      wb.commit()
-   }
-}
-
-impl traits::Store for MemoryDb {
-   type WriteBatch<'a> = WriteBatch<'a>;
-   type Snapshot<'a> = Snapshot<'a>;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      WriteBatch {
-         inner: Default::default(),
-         parent: self,
-      }
-   }
-   fn options(&self) -> &Options {
-      &self.ns.opts
-   }
-   fn namespace(&self) -> &str {
-      &self.ns.name
-   }
-   fn clear(&self) -> Result<()> {
-      let ns = self.namespace();
-      {
-         let mut lock = ns.txn.write();
-         *lock = Transaction::default();
-      }
-      Ok(())
-   }
-   fn child(&self, name: &str, opts: Options) -> Result<Self> {
-      Ok(Self {
-         ns: self.ns.emplace_child(name, opts),
-      })
-   }
-   fn children(&self) -> Vec<SmolStr> {
-      self.ns.children()
-   }
-   fn flush(&self) -> Result<()> {
-      Ok(())
-   }
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      let snap = self.namespace().snapshot();
-      Snapshot {
-         vns: snap,
-         ns: self.ns.clone(),
-         _phantom: PhantomData,
-      }
-   }
-}
diff --git a/attic/kv/src/pfx_iter.rs b/attic/kv/src/pfx_iter.rs
deleted file mode 100644
index b3b4453c4..000000000
--- a/attic/kv/src/pfx_iter.rs
+++ /dev/null
@@ -1,754 +0,0 @@
-use std::{cmp, fmt, iter::Peekable};
-
-use bytes::{Buf, Bytes};
-use tetra_core::alloc::quickbuf;
-
-use super::{
-   error::Result,
-   traits::{IterMode, View},
-};
-
-/// A helper struct for efficiently checking key prefixes.
-///
-/// This stores a prefix with a hybrid strategy:
-/// - For prefixes ≤ [`INLINE`] bytes: store inline in the buffer
-/// - For prefixes > [`INLINE`] bytes: store first 8 bytes, last 8 bytes, and
-///   hash the middle (16 bytes total)
-pub struct CompactPrefix {
-   /// Length of the original prefix
-   len: usize,
-   /// Fixed-size buffer for prefix storage:
-   /// - For prefixes ≤ [`INLINE`] bytes: stores the entire prefix
-   /// - For prefixes > [`INLINE`] bytes: stores
-   ///   [first_8_bytes][last_8_bytes][16_byte_hash]
-   key: [u8; Self::INLINE],
-}
-
-impl CompactPrefix {
-   /// Maximum size for inline prefix storage
-   const INLINE: usize = 64;
-   /// Length of the hash
-   const HASH_LEN: usize = 32;
-
-   /// Hash function.
-   fn hash(src: &[u8]) -> [u8; Self::HASH_LEN] {
-      *blake3::hash(src).as_bytes()
-   }
-
-   /// Creates a new [`CompactPrefix`] from the given source prefix.
-   ///
-   /// For prefixes ≤ [`INLINE`] bytes, stores the entire prefix inline.
-   /// For prefixes > [`INLINE`] bytes, stores the first and last parts, and
-   /// a hash of the middle portion.
-   pub fn new(src: &[u8]) -> Self {
-      let len = src.len();
-      let mut key = [0u8; Self::INLINE];
-
-      if len <= Self::INLINE {
-         // Store the entire prefix inline
-         key[..len].copy_from_slice(src);
-         Self { len, key }
-      } else {
-         let mut result = Self {
-            len,
-            key: [0u8; Self::INLINE],
-         };
-
-         let (parts, hash) = result.key.split_last_chunk_mut().unwrap();
-         let (front, back) = parts.split_at_mut(parts.len() / 2);
-         front.copy_from_slice(&src[..front.len()]);
-         back.copy_from_slice(&src[len - back.len()..]);
-
-         // Hash the middle portion and store as HASH_SIZE bytes
-         *hash = Self::hash(&src[front.len()..len - back.len()]);
-
-         result
-      }
-   }
-
-   /// Checks if the given key matches the stored prefix.
-   ///
-   /// # Returns
-   /// `true` if `key` starts with the prefix stored in this
-   /// [`CompactPrefix`], `false` otherwise.
-   pub fn matches(&self, key: &[u8]) -> bool {
-      if self.len <= Self::INLINE {
-         key.starts_with(&self.key[..self.len])
-      } else {
-         let Some(key) = key.get(..self.len) else {
-            return false;
-         };
-
-         let (parts, hash) = self.key.split_last_chunk().unwrap();
-         let (front, back) = parts.split_at(parts.len() / 2);
-
-         let Some(rem) = key.strip_prefix(front) else {
-            return false;
-         };
-         let Some(rem) = rem.strip_suffix(back) else {
-            return false;
-         };
-         Self::hash(rem) == *hash
-      }
-   }
-}
-
-impl fmt::Debug for CompactPrefix {
-   /// Formats the [`CompactPrefix`] for debugging.
-   ///
-   /// Displays the length of the stored prefix and the stored key portions.
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      let mut debug = f.debug_struct("CompactPrefix");
-
-      debug.field("len", &self.len);
-
-      if self.len <= Self::INLINE {
-         // Show the entire inline prefix
-         debug.field("key", &format_args!("{:x?}", &self.key[..self.len]));
-      } else {
-         let (parts, hash) = self.key.split_last_chunk::<{ Self::HASH_LEN }>().unwrap();
-         let (front, back) = parts.split_at(parts.len() / 2);
-         debug.field("key", &format_args!("{front:x?}..{back:x?}"));
-         debug.field("hash", &format_args!("{hash:x?}"));
-      }
-
-      debug.finish()
-   }
-}
-
-#[derive(Debug)]
-pub enum PrefixIter<I: Iterator<Item = Result<(Bytes, Bytes)>>> {
-   Alive {
-      it: Peekable<I>,
-      prefix: CompactPrefix,
-      strip: usize,
-   },
-   Ended,
-}
-
-struct PrefixCmp<'a>(&'a [u8], u8); // prefix + filler
-
-impl<'a> Eq for PrefixCmp<'a> {}
-
-impl<'a> PartialEq for PrefixCmp<'a> {
-   fn eq(&self, other: &Self) -> bool {
-      self.0 == other.0 && self.1 == other.1
-   }
-}
-
-impl<'a> PartialOrd for PrefixCmp<'a> {
-   fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
-      Some(self.cmp(other))
-   }
-}
-
-impl<'a> Ord for PrefixCmp<'a> {
-   fn cmp(&self, other: &Self) -> cmp::Ordering {
-      let n = self.0.len().max(other.0.len());
-      for i in 0..n {
-         let a = self.0.get(i).unwrap_or(&self.1);
-         let b = other.0.get(i).unwrap_or(&other.1);
-         if a != b {
-            return a.cmp(b);
-         }
-      }
-      cmp::Ordering::Equal
-   }
-}
-
-impl<I: Iterator<Item = Result<(Bytes, Bytes)>>> PrefixIter<I> {
-   fn new_forward<'a, V: View<Iter<'a> = I> + ?Sized + 'a>(
-      view: &'a V,
-      pfx: impl AsRef<[u8]>,
-      seek: Option<&[u8]>,
-   ) -> Peekable<V::Iter<'a>> {
-      let pfx = pfx.as_ref();
-      match seek {
-         Some(seek) if PrefixCmp(seek, 0) >= PrefixCmp(pfx, 0) => {
-            view.iter(IterMode::Forward(Some(seek))).peekable()
-         },
-         _ => view.iter(IterMode::Forward(Some(pfx))).peekable(),
-      }
-   }
-
-   fn new_backward<'a, V: View<Iter<'a> = I> + ?Sized + 'a>(
-      view: &'a V,
-      pfx: impl AsRef<[u8]>,
-      seek: Option<&[u8]>,
-   ) -> Peekable<V::Iter<'a>> {
-      let pfx = pfx.as_ref();
-      match seek {
-         Some(seek) if PrefixCmp(seek, 0xff) < PrefixCmp(pfx, 0xff) => {
-            view.iter(IterMode::Reverse(Some(seek))).peekable()
-         },
-         _ => quickbuf::with(|buf| {
-            let n = pfx.len();
-            buf.extend_from_slice(pfx);
-            let mut end = None;
-            for i in (0..n).rev() {
-               if let Some(x) = buf[i].checked_add(1) {
-                  buf[i] = x;
-                  end = Some(i + 1);
-                  break;
-               }
-            }
-            let pos = if let Some(i) = end {
-               &buf[0..i]
-            } else {
-               buf.extend_from_slice(&[0xFF; 1]);
-               &buf[0..(n + 1)]
-            };
-
-            let seek = IterMode::Reverse(Some(pos));
-            let mut iter = view.iter(seek).peekable();
-            while let Some(Ok((key, _))) = iter.peek() {
-               if key.as_ref() < pfx {
-                  break;
-               }
-               if key.starts_with(pfx) {
-                  break;
-               }
-               iter.next();
-            }
-            iter
-         }),
-      }
-   }
-
-   pub fn new<'a, V: View<Iter<'a> = I> + ?Sized + 'a>(
-      view: &'a V,
-      prefix: impl AsRef<[u8]>,
-      mode: IterMode<'_>,
-   ) -> Self {
-      let pfx = prefix.as_ref();
-      let it = match mode {
-         IterMode::Forward(seek) => Self::new_forward(view, pfx, seek),
-         IterMode::Reverse(seek) => Self::new_backward(view, pfx, seek),
-      };
-      Self::Alive {
-         it,
-         prefix: CompactPrefix::new(pfx),
-         strip: 0,
-      }
-   }
-
-   pub(crate) fn with_strip(self, strip: usize) -> Self {
-      if let Self::Alive { it, prefix, .. } = self {
-         Self::Alive {
-            it,
-            strip: strip.min(prefix.len),
-            prefix,
-         }
-      } else {
-         self
-      }
-   }
-}
-
-impl<I: Iterator<Item = Result<(Bytes, Bytes)>>> Iterator for PrefixIter<I> {
-   type Item = Result<(Bytes, Bytes)>;
-
-   fn next(&mut self) -> Option<Self::Item> {
-      let Self::Alive { it, prefix, strip } = self else {
-         return None;
-      };
-
-      let result = it.next()?;
-      match result {
-         Ok((mut key, value)) => {
-            if !prefix.matches(&key) {
-               *self = Self::Ended;
-               return None;
-            }
-            if *strip > 0 {
-               key.advance(*strip);
-            }
-            Some(Ok((key, value)))
-         },
-         Err(err) => {
-            *self = Self::Ended;
-            Some(Err(err))
-         },
-      }
-   }
-}
-
-#[cfg(test)]
-mod tests {
-   use super::*;
-
-   fn long_prefix_part_size() -> usize {
-      (CompactPrefix::INLINE - CompactPrefix::HASH_LEN) / 2
-   }
-
-   #[test]
-   fn test_empty_prefix() {
-      let prefix = CompactPrefix::new(&[]);
-
-      // Empty prefix should match everything (everything starts with nothing)
-      assert!(prefix.matches(&[]));
-      assert!(prefix.matches(&[1]));
-      assert!(prefix.matches(&[1, 2, 3]));
-      assert!(prefix.matches(b"hello"));
-      assert!(prefix.matches(&[0u8; 100]));
-   }
-
-   #[test]
-   fn test_single_byte_prefix() {
-      let prefix = CompactPrefix::new(&[42]);
-
-      // Should match keys that start with 42
-      assert!(prefix.matches(&[42]));
-      assert!(prefix.matches(&[42, 0]));
-      assert!(prefix.matches(&[42, 1, 2, 3]));
-
-      // Should not match keys that don't start with 42
-      assert!(!prefix.matches(&[]));
-      assert!(!prefix.matches(&[41]));
-      assert!(!prefix.matches(&[43]));
-      assert!(!prefix.matches(&[0, 42]));
-   }
-
-   #[test]
-   fn test_short_prefix_exact_match() {
-      let prefix = CompactPrefix::new(b"hello");
-
-      // Exact match
-      assert!(prefix.matches(b"hello"));
-
-      // Longer keys with same prefix
-      assert!(prefix.matches(b"hello world"));
-      assert!(prefix.matches(b"hello!"));
-      assert!(prefix.matches(b"hello, how are you?"));
-   }
-
-   #[test]
-   fn test_short_prefix_no_match() {
-      let prefix = CompactPrefix::new(b"hello");
-
-      // Too short
-      assert!(!prefix.matches(b""));
-      assert!(!prefix.matches(b"h"));
-      assert!(!prefix.matches(b"hell"));
-
-      // Wrong prefix
-      assert!(!prefix.matches(b"world"));
-      assert!(!prefix.matches(b"HELLO")); // case sensitive
-      assert!(!prefix.matches(b"hallo"));
-      assert!(!prefix.matches(b"help"));
-   }
-
-   #[test]
-   fn test_boundary_just_under_inline() {
-      let key_len = CompactPrefix::INLINE - 1;
-      let key = vec![0xAA; key_len];
-      let prefix = CompactPrefix::new(&key);
-
-      assert_eq!(prefix.len, key_len);
-
-      // Exact match
-      assert!(prefix.matches(&key));
-
-      // Longer keys with same prefix
-      let mut longer = key.clone();
-      longer.push(0xBB);
-      assert!(prefix.matches(&longer));
-
-      // Different prefix
-      let mut different = key.clone();
-      different[key_len - 1] = 0xBB;
-      assert!(!prefix.matches(&different));
-
-      // Too short
-      assert!(!prefix.matches(&key[..key_len - 1]));
-   }
-
-   #[test]
-   fn test_boundary_exactly_inline() {
-      let key_len = CompactPrefix::INLINE;
-      let key = vec![0xCC; key_len];
-      let prefix = CompactPrefix::new(&key);
-
-      assert_eq!(prefix.len, key_len);
-
-      // Exact match
-      assert!(prefix.matches(&key));
-
-      // Longer keys with same prefix
-      let mut longer = key.clone();
-      longer.extend_from_slice(b"extra");
-      assert!(prefix.matches(&longer));
-
-      // Different at last byte
-      let mut different = key.clone();
-      different[key_len - 1] = 0xDD;
-      assert!(!prefix.matches(&different));
-
-      // Too short
-      assert!(!prefix.matches(&key[..key_len - 1]));
-   }
-
-   #[test]
-   fn test_boundary_just_over_inline() {
-      let key_len = CompactPrefix::INLINE + 1;
-      let key = vec![0xEE; key_len];
-      let prefix = CompactPrefix::new(&key);
-
-      assert_eq!(prefix.len, key_len);
-
-      // Exact match
-      assert!(prefix.matches(&key));
-
-      // Longer keys with same prefix
-      let mut longer = key.clone();
-      longer.push(0xFF);
-      assert!(prefix.matches(&longer));
-
-      let part_size = long_prefix_part_size();
-
-      // Different in first part
-      let mut different = key.clone();
-      different[0] = 0xFF;
-      assert!(!prefix.matches(&different));
-      different = key.clone();
-      different[part_size - 1] = 0xFF;
-      assert!(!prefix.matches(&different));
-
-      // Different in last part
-      let mut different = key.clone();
-      different[key_len - 1] = 0xFF;
-      assert!(!prefix.matches(&different));
-      different = key.clone();
-      different[key_len - part_size] = 0xFF;
-      assert!(!prefix.matches(&different));
-
-      // Different in middle (should fail hash check)
-      let mut different = key.clone();
-      different[key_len / 2] = 0xFF;
-      assert!(!prefix.matches(&different));
-   }
-
-   #[test]
-   fn test_long_prefix_comprehensive() {
-      let part_size = long_prefix_part_size();
-      let key_len = CompactPrefix::INLINE * 3; // Sufficiently long
-
-      // Create a key with recognizable pattern
-      let mut key = Vec::new();
-      key.extend_from_slice(&vec![0x11; part_size]); // First part
-      key.extend_from_slice(&vec![0x22; key_len - 2 * part_size]); // Middle
-      key.extend_from_slice(&vec![0x33; part_size]); // Last part
-      assert_eq!(key.len(), key_len);
-
-      let prefix = CompactPrefix::new(&key);
-
-      // Exact match
-      assert!(prefix.matches(&key));
-
-      // Extended key
-      let mut extended = key.clone();
-      extended.extend_from_slice(b"_suffix");
-      assert!(prefix.matches(&extended));
-
-      // Test each component that's checked:
-
-      // 1. Wrong first part
-      for i in 0..part_size {
-         let mut wrong = key.clone();
-         wrong[i] = 0xFF;
-         assert!(
-            !prefix.matches(&wrong),
-            "Failed to detect change in first section at position {i}"
-         );
-      }
-
-      // 2. Wrong last part
-      for i in (key_len - part_size)..key_len {
-         let mut wrong = key.clone();
-         wrong[i] = 0xFF;
-         assert!(
-            !prefix.matches(&wrong),
-            "Failed to detect change in last section at position {i}"
-         );
-      }
-
-      // 3. Wrong middle (hash should catch this)
-      let mut wrong_middle = key.clone();
-      wrong_middle[key_len / 2] = 0xFF;
-      assert!(!prefix.matches(&wrong_middle));
-
-      // 4. Too short
-      assert!(!prefix.matches(&key[..key_len - 1]));
-   }
-
-   #[test]
-   fn test_hash_sensitivity() {
-      // Test that even small changes in the middle are detected
-      let key_len = CompactPrefix::INLINE * 2;
-      let base = vec![0u8; key_len];
-      let prefix = CompactPrefix::new(&base);
-
-      let part_size = long_prefix_part_size();
-
-      // Test changing each byte in the middle section
-      for i in part_size..(key_len - part_size) {
-         let mut modified = base.clone();
-         modified[i] = 1;
-         assert!(
-            !prefix.matches(&modified),
-            "Failed to detect change at position {i}"
-         );
-      }
-   }
-
-   #[test]
-   fn test_various_lengths() {
-      // Test various lengths around boundaries
-      let inline_size = CompactPrefix::INLINE;
-      let lengths = vec![
-         0,
-         1,
-         8,
-         16,
-         inline_size / 4,
-         inline_size / 2,
-         inline_size * 3 / 4,
-         inline_size - 1,
-         inline_size,
-         inline_size + 1,
-         inline_size + 8,
-         inline_size * 2,
-         inline_size * 4,
-         inline_size * 16,
-      ];
-
-      for len in lengths {
-         let key = vec![0xAA; len];
-         let prefix = CompactPrefix::new(&key);
-
-         // Should match itself
-         assert!(
-            prefix.matches(&key),
-            "Prefix of length {len} should match itself"
-         );
-
-         // Should match extended version
-         let mut extended = key.clone();
-         extended.push(0xBB);
-         assert!(
-            prefix.matches(&extended),
-            "Prefix of length {len} should match extended version"
-         );
-
-         // Should not match if too short (unless empty)
-         if len > 0 {
-            assert!(
-               !prefix.matches(&key[..len - 1]),
-               "Prefix of length {len} should not match shorter key"
-            );
-         }
-      }
-   }
-
-   #[test]
-   fn test_unicode_strings() {
-      // Test with UTF-8 strings
-      let inline_size = CompactPrefix::INLINE;
-      let test_cases = vec![
-         "hello".to_string(),
-         "a".repeat(inline_size - 10),
-         "b".repeat(inline_size + 20),
-      ];
-
-      for s in test_cases {
-         let prefix = CompactPrefix::new(s.as_bytes());
-
-         // Should match itself
-         assert!(prefix.matches(s.as_bytes()));
-
-         // Should match with suffix
-         let with_suffix = format!("{s}_suffix");
-         assert!(prefix.matches(with_suffix.as_bytes()));
-
-         // Should not match different string
-         assert!(!prefix.matches(b"different"));
-      }
-   }
-
-   #[test]
-   fn test_binary_data() {
-      // Test with non-UTF8 binary data
-      let binary_data: Vec<u8> = (0..=255).collect();
-      let inline_size = CompactPrefix::INLINE;
-
-      // Test prefix within INLINE threshold
-      let prefix_short = CompactPrefix::new(&binary_data[..inline_size / 2]);
-      assert!(prefix_short.matches(&binary_data[..inline_size / 2]));
-      assert!(prefix_short.matches(&binary_data)); // Full data includes prefix
-      assert!(!prefix_short.matches(&binary_data[..inline_size / 2 - 1])); // Too short
-
-      // Test prefix exceeding INLINE threshold
-      let prefix_long = CompactPrefix::new(&binary_data[..inline_size + 20]);
-      assert!(prefix_long.matches(&binary_data[..inline_size + 20]));
-      assert!(prefix_long.matches(&binary_data));
-      assert!(!prefix_long.matches(&binary_data[..inline_size + 19]));
-
-      // Modified version
-      let mut modified = binary_data.clone();
-      modified[inline_size / 2] = 255 - modified[inline_size / 2];
-      assert!(!prefix_long.matches(&modified[..inline_size + 20]));
-   }
-
-   #[test]
-   fn test_consistency() {
-      // Same input should always produce same CompactPrefix
-      let key = b"this is a test key that is longer than the inline threshold which triggers the hash-based storage strategy for efficient prefix checking";
-
-      let prefix1 = CompactPrefix::new(key);
-      let prefix2 = CompactPrefix::new(key);
-
-      // Internal representation should be identical
-      assert_eq!(prefix1.len, prefix2.len);
-      assert_eq!(prefix1.key, prefix2.key);
-
-      // Both should match the same keys
-      assert_eq!(prefix1.matches(key), prefix2.matches(key));
-      assert_eq!(prefix1.matches(b"different"), prefix2.matches(b"different"));
-   }
-
-   #[test]
-   fn test_edge_case_exactly_part_size() {
-      // Special case: exactly the size of one part in long prefix
-      let part_size = long_prefix_part_size();
-      let key = vec![0x42; part_size];
-      let prefix = CompactPrefix::new(&key);
-
-      assert!(prefix.matches(&key));
-      assert!(prefix.matches(&[&key[..], b"_more"].concat()));
-      assert!(!prefix.matches(&key[..part_size - 1]));
-   }
-
-   #[test]
-   fn test_pathological_cases() {
-      let key_len = CompactPrefix::INLINE * 3;
-
-      // All zeros
-      let zeros = vec![0u8; key_len];
-      let prefix_zeros = CompactPrefix::new(&zeros);
-      assert!(prefix_zeros.matches(&zeros));
-
-      // All ones
-      let ones = vec![0xFFu8; key_len];
-      let prefix_ones = CompactPrefix::new(&ones);
-      assert!(prefix_ones.matches(&ones));
-
-      // They should not match each other
-      assert!(!prefix_zeros.matches(&ones));
-      assert!(!prefix_ones.matches(&zeros));
-   }
-
-   #[test]
-   fn test_realistic_key_patterns() {
-      // Test with realistic key patterns (like database keys)
-
-      // Path-like keys
-      let prefix1 = CompactPrefix::new(b"/users/alice/documents/projects/2024/quarterly-reports/");
-      assert!(prefix1.matches(b"/users/alice/documents/projects/2024/quarterly-reports/"));
-      assert!(prefix1.matches(b"/users/alice/documents/projects/2024/quarterly-reports/Q1.pdf"));
-      assert!(!prefix1.matches(b"/users/alice/documents/projects/2024/annual-reports/"));
-
-      // Long UUID-like keys that exceed INLINE
-      let uuid_base = b"550e8400-e29b-41d4-a716-446655440000-";
-      let mut long_uuid = uuid_base.to_vec();
-      while long_uuid.len() <= CompactPrefix::INLINE {
-         long_uuid.extend_from_slice(uuid_base);
-      }
-      long_uuid.extend_from_slice(b"-extra-data");
-
-      let prefix_len = CompactPrefix::INLINE + 10;
-      let prefix2 = CompactPrefix::new(&long_uuid[..prefix_len]);
-      assert!(prefix2.matches(&long_uuid));
-
-      // Different UUID
-      let mut different_uuid = long_uuid.clone();
-      different_uuid[10] = b'X';
-      assert!(!prefix2.matches(&different_uuid));
-
-      // Versioned keys with metadata
-      let versioned = b"data:v2:user:123456789:metadata:created=2024-01-01T00:00:00Z:updated=2024-12-01T00:00:00Z";
-      let prefix3 = CompactPrefix::new(&versioned[..CompactPrefix::INLINE / 2]);
-      assert!(prefix3.matches(versioned));
-      assert!(!prefix3.matches(b"data:v2:user:987654321:metadata:created=2024-01-01T00:00:00Z"));
-   }
-
-   #[test]
-   fn test_prefix_matching_semantics() {
-      // Ensure prefix matching works correctly at all boundaries
-      let max_len = CompactPrefix::INLINE * 2;
-      let base = b"a".repeat(max_len);
-
-      // Test prefixes of various lengths
-      let prefix_lengths = vec![
-         1,
-         long_prefix_part_size(),
-         CompactPrefix::INLINE / 2,
-         CompactPrefix::INLINE - 1,
-         CompactPrefix::INLINE,
-         CompactPrefix::INLINE + 1,
-         CompactPrefix::INLINE + long_prefix_part_size(),
-         max_len,
-      ];
-
-      for prefix_len in prefix_lengths {
-         let prefix = CompactPrefix::new(&base[..prefix_len]);
-
-         // Should match any key that starts with this prefix
-         for key_len in prefix_len..=(max_len + 20) {
-            let key = b"a".repeat(key_len);
-            assert!(
-               prefix.matches(&key),
-               "Prefix len {prefix_len} should match key len {key_len}"
-            );
-         }
-
-         // Should not match shorter keys
-         if prefix_len > 0 {
-            let short_key = b"a".repeat(prefix_len - 1);
-            assert!(
-               !prefix.matches(&short_key),
-               "Prefix len {} should not match key len {}",
-               prefix_len,
-               prefix_len - 1
-            );
-         }
-      }
-   }
-
-   #[test]
-   fn test_hash_distribution() {
-      // Test that similar keys with small differences are distinguished
-      let key_len = CompactPrefix::INLINE * 2;
-      let base = vec![0x42; key_len];
-      let part_size = long_prefix_part_size();
-
-      // Create variations with single bit flips in the middle section
-      for i in part_size..(key_len - part_size) {
-         for bit in 0..8 {
-            let mut variant = base.clone();
-            variant[i] ^= 1 << bit; // Flip one bit
-
-            let prefix_base = CompactPrefix::new(&base);
-            let prefix_variant = CompactPrefix::new(&variant);
-
-            assert!(
-               !prefix_base.matches(&variant),
-               "Should detect bit flip at byte {i} bit {bit}"
-            );
-            assert!(
-               !prefix_variant.matches(&base),
-               "Should detect bit flip at byte {i} bit {bit} (reverse)"
-            );
-         }
-      }
-   }
-}
diff --git a/attic/kv/src/prefixed.rs b/attic/kv/src/prefixed.rs
deleted file mode 100644
index 917afabf2..000000000
--- a/attic/kv/src/prefixed.rs
+++ /dev/null
@@ -1,285 +0,0 @@
-use std::fmt;
-
-use bytes::Bytes;
-use tetra_core::alloc::quickbuf;
-
-use super::traits;
-use crate::{pfx_iter::PrefixIter, IVec, IVecs, Operator, Options, Result};
-
-#[derive(Clone, Copy, Debug)]
-pub struct Prefixed<V, P: AsRef<[u8]>>(pub V, pub P);
-impl<V, P: AsRef<[u8]>> Prefixed<V, P> {
-   pub fn new(inner: V, prefix: impl Into<P>) -> Self {
-      Self(inner, prefix.into())
-   }
-   pub fn inner(&self) -> &V {
-      &self.0
-   }
-   pub fn inner_mut(&mut self) -> &mut V {
-      &mut self.0
-   }
-   pub fn prefix(&self) -> &[u8] {
-      self.1.as_ref()
-   }
-   fn with_key<'a, R>(&'a self, key: &[u8], f: impl FnOnce(&'a V, &[u8]) -> R) -> R {
-      quickbuf::with(|buf| {
-         let Self(inner, pfx) = self;
-         buf.extend_from_slice(pfx.as_ref());
-         buf.extend_from_slice(key);
-         f(inner, buf.as_ref())
-      })
-   }
-}
-
-pub type PfxStore<S> = Prefixed<S, Box<[u8]>>;
-pub type PfxWriteBatch<'a, W> = Prefixed<W, &'a [u8]>;
-pub type PfxSnapshot<'a, S> = Prefixed<S, &'a [u8]>;
-
-impl<'a, W: traits::WriteBatch<'a>> traits::Write for PfxWriteBatch<'a, W> {
-   type Result = ();
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self.with_key(key, |db, k| db.put(k, value));
-   }
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.with_key(key, |db, k| db.delete(k));
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      quickbuf::with(|buf| {
-         let pfx = self.prefix();
-
-         // Create prefixed from key
-         let from_start = buf.len();
-         buf.extend_from_slice(pfx);
-         buf.extend_from_slice(from);
-         let from_end = buf.len();
-
-         // Create prefixed to key
-         let to_start = buf.len();
-         buf.extend_from_slice(pfx);
-         buf.extend_from_slice(to);
-         let to_end = buf.len();
-
-         self
-            .inner()
-            .delete_range(&buf[from_start..from_end], &buf[to_start..to_end]);
-      });
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      self.with_key(key, |db, k| db.update(k, op));
-   }
-}
-
-impl<'a, W: traits::WriteBatch<'a>> traits::WriteBatch<'a> for PfxWriteBatch<'a, W> {
-   fn commit(&self) -> Result<()> {
-      self.inner().commit()
-   }
-   fn reset(&mut self) {
-      self.inner_mut().reset();
-   }
-}
-
-impl<V: traits::View, P: AsRef<[u8]> + Send + Sync + fmt::Debug> traits::View for Prefixed<V, P> {
-   type Iter<'b>
-      = PrefixIter<V::Iter<'b>>
-   where
-      V: 'b,
-      Self: 'b;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      self.with_key(key, |db, k| db.get(k))
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      struct KeyIteratorAdapter<'a, I: Iterator<Item: AsRef<[u8]>>> {
-         iter: I,
-         prefix: usize,
-         buf: &'a mut quickbuf::StackBuffer,
-      }
-      impl<'a, I: Iterator<Item: AsRef<[u8]>>> crate::erased::KeyIterator for KeyIteratorAdapter<'a, I> {
-         fn next_key(&mut self) -> Option<&[u8]> {
-            let key = self.iter.next()?;
-            self.buf.truncate(self.prefix);
-            self.buf.extend_from_slice(key.as_ref());
-            Some(self.buf.as_ref())
-         }
-      }
-
-      quickbuf::with(|buf| {
-         buf.extend_from_slice(self.prefix());
-         let mut iter = KeyIteratorAdapter {
-            iter: keys.into_iter(),
-            prefix: buf.len(),
-            buf,
-         };
-         self
-            .inner()
-            .get_many(crate::erased::adapt_key_iter(&mut iter))
-      })
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      self.with_key(key, |db, k| db.contains(k))
-   }
-
-   fn iter<'b>(&'b self, mode: traits::IterMode<'_>) -> Self::Iter<'b> {
-      quickbuf::with(|buf| {
-         let prefix = self.prefix();
-
-         buf.extend_from_slice(prefix);
-         if let Some(seek) = mode.inner() {
-            buf.extend_from_slice(seek);
-         }
-
-         let mode = mode.replace_bound(Some(buf.as_ref()));
-         PrefixIter::new(self.inner(), prefix, mode).with_strip(prefix.len())
-      })
-   }
-
-   fn prefix_scan<'a>(
-      &'a self,
-      prefix: &[u8],
-      mode: crate::IterMode<'_>,
-   ) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'a, V, P> {
-      quickbuf::with(|buf| {
-         let root: &[u8] = self.prefix();
-         let user: &[u8] = prefix;
-
-         buf.extend_from_slice(root);
-         buf.extend_from_slice(user);
-         let pfx = buf.len();
-
-         let seek = if let Some(seek) = mode.inner() {
-            if seek.starts_with(user) {
-               buf.extend_from_slice(&seek[user.len()..]);
-               Some(0..buf.len())
-            } else {
-               buf.extend_from_slice(root);
-               buf.extend_from_slice(seek);
-               Some(pfx..buf.len())
-            }
-         } else {
-            None
-         };
-
-         let mode = mode.replace_bound(seek.map(|r| &buf[r]));
-         PrefixIter::new(self.inner(), &buf[0..pfx], mode).with_strip(root.len())
-      })
-   }
-}
-
-impl<S: traits::Store> traits::Write for PfxStore<S> {
-   type Result = crate::Result<()>;
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.with_key(key, |db, k| db.delete(k))
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      quickbuf::with(|buf| {
-         let Self(inner, pfx) = self;
-         buf.extend_from_slice(pfx.as_ref());
-         buf.extend_from_slice(from);
-         let from_p = buf.len();
-         buf.extend_from_slice(pfx.as_ref());
-         buf.extend_from_slice(to);
-
-         let (from, to) = buf.as_ref().split_at(from_p);
-         inner.delete_range(from, to)
-      })
-   }
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self.with_key(key, |db, k| db.put(k, value))
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      self.with_key(key, |db, k| db.update(k, op))
-   }
-}
-
-impl<S: traits::Store> traits::Store for PfxStore<S> {
-   type WriteBatch<'a>
-      = PfxWriteBatch<'a, S::WriteBatch<'a>>
-   where
-      S: 'a;
-   type Snapshot<'a>
-      = PfxSnapshot<'a, S::Snapshot<'a>>
-   where
-      S: 'a;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      PfxWriteBatch::new(self.inner().batch(), self.prefix())
-   }
-
-   fn namespace(&self) -> &str {
-      self.inner().namespace()
-   }
-
-   fn child(&self, name: &str, opts: Options) -> Result<Self> {
-      Ok(Self(self.inner().child(name, opts)?, self.1.clone()))
-   }
-
-   fn children(&self) -> Vec<smol_str::SmolStr> {
-      self.inner().children()
-   }
-
-   fn clear(&self) -> Result<()> {
-      quickbuf::with(|buf| {
-         let prefix = self.prefix();
-
-         // Create range start (prefix)
-         let from_start = buf.len();
-         buf.extend_from_slice(prefix);
-         let from_end = buf.len();
-
-         // Create range end (prefix + 1)
-         let to_start = buf.len();
-         buf.extend_from_slice(prefix);
-
-         // Find the first byte we can increment
-         let mut found = false;
-         for i in (0..prefix.len()).rev() {
-            if let Some(incremented) = buf[to_start + i].checked_add(1) {
-               buf[to_start + i] = incremented;
-               found = true;
-               break;
-            }
-            // If byte is 0xFF, it will overflow, so continue to previous
-            // byte
-         }
-
-         if found {
-            // We successfully incremented a byte in the prefix
-            let to_end = to_start + prefix.len();
-            self
-               .inner()
-               .delete_range(&buf[from_start..from_end], &buf[to_start..to_end])
-         } else {
-            // All bytes were 0xFF, so we need to delete everything from prefix onwards
-            // Use a very high byte sequence as the upper bound
-            buf.extend_from_slice(&[0xFF; 8]); // Add some 0xFF bytes
-            let to_end = buf.len();
-            self
-               .inner()
-               .delete_range(&buf[from_start..from_end], &buf[to_start..to_end])
-         }
-      })
-   }
-
-   fn flush(&self) -> Result<()> {
-      self.inner().flush()
-   }
-
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      PfxSnapshot::new(self.inner().snapshot(), self.prefix())
-   }
-
-   fn options(&self) -> &Options {
-      self.inner().options()
-   }
-}
-
-pub trait PrefixExt: traits::Store + Sized {
-   fn with_prefix(self, prefix: impl AsRef<[u8]>) -> PfxStore<Self> {
-      PfxStore::new(self, prefix.as_ref().to_vec())
-   }
-}
-impl<T: traits::Store> PrefixExt for T {}
diff --git a/attic/kv/src/rmw.rs b/attic/kv/src/rmw.rs
deleted file mode 100644
index bb188f16a..000000000
--- a/attic/kv/src/rmw.rs
+++ /dev/null
@@ -1,423 +0,0 @@
-//! Read-modify-write operator abstraction for the KV store.
-//!
-//! This module provides a small, self-contained framework that allows the
-//! key-value engine to attach *read-modify-write operators* to write requests.
-//! A read-modify-write operator receives the key being written together with
-//! the current value (if any) and must compute the new value that will be
-//! stored.  The framework is purposely designed to work with zero-copy
-//! deserialization via [`postcard`](https://docs.rs/postcard) which keeps allocations to a minimum
-//! and allows read-modify-write operators to borrow their parameters directly
-//! from a transient buffer.
-//!
-//! In order to make read-modify-write operators transferable over the network
-//! (or across thread boundaries) we distinguish between two layers:
-//!
-//! * [`OperatorDefn`] – the *definition* of an operator.  Because definitions
-//!   may borrow data, the trait has an explicit lifetime parameter. Definitions
-//!   are (de)serializable via *postcard*.
-//! * [`Operator`] – an object-safe, type-erased wrapper around a definition
-//!   that hides the lifetime and can therefore be stored behind a trait object.
-//!
-//! A globally shared registry (see [`registry::GLOBAL`]) maps each concrete
-//! operator type to a function pointer that can *apply* the operator without
-//! knowing its concrete type.  This indirection makes it possible to
-//! deserialize an [`OperatorRepr`] coming from the wire and invoke it
-//! immediately without pulling it through a full boxing step first.
-//!
-//! The bottom of this file contains a set of small but useful
-//! *built-in* operators – feel free to use them as inspiration for your own.
-
-use std::{any::TypeId, borrow::Cow, fmt, marker::PhantomData, sync::LazyLock};
-
-use parking_lot::RwLock;
-use serde::{de::Deserialize, Serialize};
-use tetra_core::{alloc::quickbuf, containers::append_vec::AppendVec};
-
-/// Unique identifier for an operator type in the registry.
-///
-/// This is used to look up the appropriate implementation in the
-/// [`registry::GLOBAL`] when deserializing an operator from the wire.
-pub type OperatorId = u8;
-
-/// Definition of a read-modify-write operator with potentially borrowed data.
-///
-///
-/// This trait represents the core logic of a read-modify-write operator.
-/// Implementations define how to combine an existing value with new data when
-/// writing to a key. Because definitions may borrow data, the trait has an
-/// explicit lifetime parameter. Definitions are serializable/deserializable
-/// via [`postcard`](https://docs.rs/postcard).
-pub trait OperatorDefn<'a>: Serialize + Deserialize<'a> + fmt::Debug + 'a {
-   /// Version of `Self` where all borrows have been rebound to the lifetime
-   /// `'b`.
-   ///
-   /// This associated type is crucial for deserialization: when we read a
-   /// value from a byte slice we obviously cannot give it the original
-   /// lifetime `'a`; instead we need to *re-borrow* every reference from the
-   /// freshly read slice.  The compiler takes care of the heavy lifting here –
-   /// all you have to do is write `type Extend<'b> = Self` for operator types
-   /// that do not actually borrow anything.
-   type Extend<'b>: OperatorDefn<'b>;
-
-   /// Apply the operator to `value` which is currently stored under `key`.
-   ///
-   /// * `key` – the full database key (namespaces included).  The operator may
-   ///   inspect the key but must **never modify it**.
-   /// * `value` – the value currently stored for `key`.  `None` signifies that
-   ///   the key is absent in the database.
-   ///
-   /// The function must return the new value that should be written.  It is
-   /// perfectly fine to return a borrowed slice (`Cow::Borrowed`) if the data
-   /// lives long enough.
-   fn apply<'d>(&self, key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-   where
-      Self: 'd;
-}
-
-/// Object-safe, type-erased wrapper around an [`OperatorDefn`].
-///
-/// This trait hides the lifetime parameter of [`OperatorDefn`], allowing
-/// operators to be stored behind trait objects and passed across thread
-/// boundaries. It provides methods to apply the operator and serialize it
-/// for network transmission.
-pub trait Operator: fmt::Debug {
-   /// Returns the *operator id* – an index into the global
-   /// [`registry::GLOBAL`].
-   fn opid(&self) -> OperatorId;
-   /// Applies the operator (see [`OperatorDefn::apply`]).
-   fn apply<'d>(&self, key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-   where
-      Self: 'd;
-
-   /// Serialises the operator into a [`OperatorRepr`] that can be sent over
-   /// the network.
-   ///
-   /// Returns the range in the buffer where the serialized operator is stored.
-   fn write_to(&self, pool: &mut quickbuf::StackBuffer) -> std::ops::Range<usize>;
-}
-
-/// Blanket implementation of [`Operator`] for any type implementing
-/// [`OperatorDefn`].
-///
-/// This automatically provides the type-erased interface for all concrete
-/// operator definitions, handling the registration with the global registry and
-/// serialization.
-impl<'a, T: OperatorDefn<'a>> Operator for T {
-   fn opid(&self) -> OperatorId {
-      registry::GLOBAL.emplace_if::<T::Extend<'static>>()
-   }
-
-   fn apply<'d>(&self, key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-   where
-      Self: 'd,
-   {
-      self.apply(key, value)
-   }
-
-   fn write_to(&self, pool: &mut quickbuf::StackBuffer) -> std::ops::Range<usize> {
-      let beg = pool.len();
-      pool.extend_from_slice(&self.opid().to_le_bytes());
-      postcard::to_extend(self, &mut *pool).unwrap();
-      beg..pool.len()
-   }
-}
-
-/// Compact on-wire representation of an [`Operator`].
-///
-/// The structure contains nothing more than the operator id and the raw
-/// *postcard* payload that represents the original [`OperatorDefn`].
-#[derive(Debug, Copy, Clone)]
-pub struct OperatorRepr<'a> {
-   opid: OperatorId,
-   rest: &'a [u8],
-}
-
-impl<'a> OperatorRepr<'a> {
-   /// Returns the operator ID for this representation.
-   pub fn opid(&self) -> OperatorId {
-      self.opid
-   }
-
-   /// Creates a new [`OperatorRepr`] from a byte slice.
-   ///
-   /// The byte slice should contain a serialized operator, with the first 8
-   /// bytes being the operator ID in little-endian format, followed by the
-   /// serialized operator data.
-   ///
-   /// # Panics
-   ///
-   /// Panics if the input slice is too small to contain an operator ID.
-   pub fn from_bytes(bytes: &'a [u8]) -> Self {
-      let (opid, rest) = bytes.split_first_chunk().unwrap();
-      Self {
-         opid: OperatorId::from_le_bytes(*opid),
-         rest,
-      }
-   }
-
-   /// Applies this operator to the given key and value.
-   ///
-   /// This method consumes the operator representation and applies it to the
-   /// provided key and optional value, returning the resulting value.
-   ///
-   /// The implementation looks up the appropriate operator implementation from
-   /// the global registry using the stored operator ID, then delegates to that
-   /// implementation.
-   pub fn apply<'d>(self, key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-   where
-      Self: 'd,
-   {
-      let applier = registry::GLOBAL.get(self.opid());
-      applier.apply(self.rest, key, value)
-   }
-}
-
-impl<'a> Operator for OperatorRepr<'a> {
-   fn opid(&self) -> OperatorId {
-      self.opid
-   }
-
-   fn apply<'d>(&self, key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-   where
-      Self: 'd,
-   {
-      OperatorRepr::apply(*self, key, value)
-   }
-
-   fn write_to(&self, pool: &mut quickbuf::StackBuffer) -> std::ops::Range<usize> {
-      let beg = pool.len();
-      pool.extend_from_slice(&self.opid().to_le_bytes());
-      pool.extend_from_slice(self.rest);
-      beg..pool.len()
-   }
-}
-
-pub mod ops {
-   use derive_more::Constructor;
-   use serde::{Deserialize, Serialize};
-
-   use super::*;
-
-   /// Append read-modify-write operator.
-   ///
-   /// This operator appends the provided bytes to the existing value. If no
-   /// value exists, it treats the existing value as empty and simply returns
-   /// the bytes to append.
-   #[derive(Debug, Clone, Copy, Serialize, Deserialize, Constructor)]
-   pub struct Append<'a>(pub &'a [u8]);
-
-   impl<'a> OperatorDefn<'a> for Append<'a> {
-      type Extend<'b> = Append<'b>;
-
-      fn apply<'d>(&self, _key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-      where
-         'a: 'd,
-      {
-         let mut v = value.unwrap_or_default().into_owned();
-         v.extend_from_slice(self.0);
-         Cow::Owned(v)
-      }
-   }
-
-   /// Compare-and-exchange read-modify-write operator.
-   ///
-   /// If the current value equals [`expected`], it is **replaced** by
-   /// [`desired`].  Otherwise the value remains unchanged.
-   #[derive(Debug, Clone, Copy, Serialize, Deserialize, Constructor)]
-   pub struct CompareExchange<'a> {
-      pub expected: Option<&'a [u8]>,
-      pub desired: &'a [u8],
-   }
-
-   impl<'a> OperatorDefn<'a> for CompareExchange<'a> {
-      type Extend<'b> = CompareExchange<'b>;
-
-      fn apply<'d>(&self, _key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-      where
-         'a: 'd,
-      {
-         if self.expected == value.as_deref() {
-            Cow::Borrowed(self.desired)
-         } else {
-            value.unwrap_or_default()
-         }
-      }
-   }
-
-   /// Increment read-modify-write operator.
-   ///
-   /// This operator treats the value as a little-endian encoded
-   /// multi-precision integer and increments it by the specified amount.
-   /// If the value is empty, it's treated as zero.
-   ///
-   /// # Implementation Details
-   ///
-   /// The value is processed as a sequence of 8-byte chunks in little-endian
-   /// order. The increment is applied to the first chunk, with any overflow
-   /// carrying to subsequent chunks. If all chunks overflow, a new chunk is
-   /// appended to handle the remaining carry.
-   #[derive(Debug, Clone, Copy, Serialize, Deserialize, Constructor)]
-   #[serde(transparent)]
-   pub struct Inc(pub u64);
-
-   impl<'a> OperatorDefn<'a> for Inc {
-      type Extend<'b> = Inc;
-
-      fn apply<'d>(&self, _key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-      where
-         Self: 'd,
-      {
-         let mut v = value.unwrap_or_default().into_owned();
-         let qword_count = v.len().div_ceil(8);
-         if v.len() != qword_count * 8 {
-            v.resize(qword_count * 8, 0);
-         }
-
-         let mut inc = self.0;
-         let (chunks, _) = v.as_chunks_mut::<8>();
-         for chunk in chunks {
-            let current = u64::from_le_bytes(*chunk);
-            let (current, of) = current.overflowing_add(inc);
-            *chunk = current.to_le_bytes();
-            inc = of as u64;
-            if !of {
-               break;
-            }
-         }
-         if inc != 0 {
-            v.extend_from_slice(&inc.to_le_bytes());
-         }
-         Cow::Owned(v)
-      }
-   }
-
-   /// Saturating decrement read-modify-write operator.
-   ///
-   /// This operator treats the value as a little-endian encoded
-   /// multi-precision integer and decrements it by the specified amount.
-   /// If the result would be negative, the value is set to zero
-   /// (saturating behavior).
-   ///
-   /// # Implementation Details
-   ///
-   /// The value is processed as a sequence of 8-byte chunks in little-endian
-   /// order. The decrement is applied to the first chunk, with any underflow
-   /// borrowing from subsequent chunks. If the entire value would underflow
-   /// (result would be negative), the value is set to zero.
-   #[derive(Debug, Clone, Copy, Serialize, Deserialize, Constructor)]
-   #[serde(transparent)]
-   pub struct SaturatingDec(pub u64);
-
-   impl<'a> OperatorDefn<'a> for SaturatingDec {
-      type Extend<'b> = SaturatingDec;
-
-      fn apply<'d>(&self, _key: &[u8], value: Option<Cow<'d, [u8]>>) -> Cow<'d, [u8]>
-      where
-         Self: 'd,
-      {
-         let mut v = value.unwrap_or_default().into_owned();
-         let qword_count = v.len().div_ceil(8);
-         if v.len() != qword_count * 8 {
-            v.resize(qword_count * 8, 0);
-         }
-
-         let mut dec = self.0;
-         let (chunks, _) = v.as_chunks_mut::<8>();
-         for chunk in chunks {
-            let current = u64::from_le_bytes(*chunk);
-            let (current, of) = current.overflowing_sub(dec);
-            *chunk = current.to_le_bytes();
-            dec = of as u64;
-            if !of {
-               break;
-            }
-         }
-         if dec != 0 {
-            v.clear();
-            v.resize(8, 0);
-         }
-         Cow::Owned(v)
-      }
-   }
-}
-
-mod registry {
-   use ahash::AHashMap;
-
-   use super::*;
-
-   #[derive(Default)]
-   pub struct Registry {
-      values: AppendVec<&'static dyn OperatorVmt>,
-      types: RwLock<LazyLock<AHashMap<TypeId, usize>>>,
-   }
-
-   pub trait OperatorVmt: 'static + Send + Sync {
-      fn apply<'a, 'd>(
-         &self,
-         this: &'a [u8],
-         key: &[u8],
-         value: Option<Cow<'d, [u8]>>,
-      ) -> Cow<'d, [u8]>
-      where
-         'a: 'd;
-   }
-
-   struct DefnVmt<T: OperatorDefn<'static>>(PhantomData<fn() -> T>);
-   impl<T: OperatorDefn<'static>> DefnVmt<T> {
-      const DEFN: Self = Self(PhantomData);
-   }
-
-   impl<T: OperatorDefn<'static>> OperatorVmt for DefnVmt<T> {
-      fn apply<'a, 'd>(
-         &self,
-         this: &'a [u8],
-         key: &[u8],
-         value: Option<Cow<'d, [u8]>>,
-      ) -> Cow<'d, [u8]>
-      where
-         'a: 'd,
-      {
-         let this: T::Extend<'a> = postcard::from_bytes(this).unwrap();
-         <T::Extend<'a> as OperatorDefn<'a>>::apply(&this, key, value)
-      }
-   }
-
-   impl Registry {
-      pub const fn new() -> Self {
-         Self {
-            values: AppendVec::new(),
-            types: RwLock::new(LazyLock::new(AHashMap::new)),
-         }
-      }
-
-      pub fn emplace_if<T: OperatorDefn<'static>>(&self) -> OperatorId {
-         let mut guard = self.types.upgradable_read();
-         let type_id = TypeId::of::<T>();
-         guard
-            .get(&type_id)
-            .copied()
-            .unwrap_or_else(
-               #[cold]
-               || {
-                  guard.with_upgraded(|map| {
-                     if let Some(idx) = map.get(&type_id) {
-                        return *idx;
-                     }
-                     let idx = self.values.push(&DefnVmt::<T>::DEFN);
-                     map.insert(type_id, idx);
-                     idx
-                  })
-               },
-            )
-            .try_into()
-            .expect("invalid operator id")
-      }
-
-      pub fn get(&self, opid: OperatorId) -> &'static dyn OperatorVmt {
-         *self.values.get(opid as usize).expect("invalid operator id")
-      }
-   }
-
-   pub static GLOBAL: Registry = Registry::new();
-}
diff --git a/attic/kv/src/rocksdb.rs b/attic/kv/src/rocksdb.rs
deleted file mode 100644
index 91008c369..000000000
--- a/attic/kv/src/rocksdb.rs
+++ /dev/null
@@ -1,729 +0,0 @@
-use std::{borrow::Cow, cell::RefCell, fmt, mem, path::Path, sync::Arc};
-
-use ahash::{AHashMap, AHashSet};
-use bytes::Bytes;
-pub use librocksdb_sys as rocks_sys;
-use parking_lot::RwLock;
-pub use rocksdb as rocks_api;
-use rocksdb::{BlockBasedOptions, Cache};
-use smol_str::{format_smolstr, SmolStr, ToSmolStr};
-use tetra_core::alloc::quickbuf;
-use traits::IterMode;
-
-use super::{
-   error::{Error, Result},
-   traits,
-};
-use crate::{IVec, IVecRef, IVecs, Operator, OperatorRepr, Options, Store};
-
-type Db = rocksdb::DBWithThreadMode<rocksdb::MultiThreaded>;
-
-/// A column family in RocksDB with a static lifetime.
-struct InternedColumnFamily {
-   /// The RocksDB column family handle with a static lifetime.
-   inner: Arc<rocksdb::BoundColumnFamily<'static>>,
-}
-
-impl InternedColumnFamily {
-   /// Creates a new interned column family, creating it if it doesn't exist.
-   ///
-   /// # Arguments
-   ///
-   /// * `db` - The RocksDB database instance.
-   /// * `opts` - The options to use when creating the column family.
-   /// * `name` - The name of the column family.
-   ///
-   /// # Returns
-   ///
-   /// A new [`InternedColumnFamily`] instance.
-   ///
-   /// # Errors
-   ///
-   /// Returns an error if the column family cannot be created.
-   fn new(db: &Db, opts: &rocksdb::Options, name: &SmolStr) -> Result<Self> {
-      let handle = match db.cf_handle(name) {
-         Some(handle) => handle,
-         None => {
-            db.create_cf(name, opts)?;
-            db.cf_handle(name)
-               .ok_or_else(|| Error::ColumnFamilyNotFound(name.clone()))?
-         },
-      };
-
-      let cf = unsafe {
-         mem::transmute::<
-            Arc<rocksdb::BoundColumnFamily<'_>>,
-            Arc<rocksdb::BoundColumnFamily<'static>>,
-         >(handle)
-      };
-      Ok(Self { inner: cf })
-   }
-}
-
-/// The core shared state of a RocksDB instance.
-struct Core {
-   /// The RocksDB database instance.
-   db: Db,
-   /// The options used for creating column families.
-   db_opts: rocksdb::Options,
-   /// Optional temporary directory that will be cleaned up when the Core is
-   /// dropped.
-   _tempdir: Option<tempfile::TempDir>,
-   /// Map of column family names to their handles.
-   cfs: RwLock<AHashMap<SmolStr, InternedColumnFamily>>,
-}
-
-impl Core {
-   fn open_cf(
-      &self,
-      name: &SmolStr,
-      opts: &rocksdb::Options,
-   ) -> Result<*mut librocksdb_sys::rocksdb_column_family_handle_t> {
-      let mut cfs = self.cfs.upgradable_read();
-      if let Some(i) = cfs.get(name) {
-         return Ok(rocksdb::AsColumnFamilyRef::inner(&i.inner));
-      }
-      cfs.with_upgraded(|cfs| {
-         if let Some(i) = cfs.get(name) {
-            return Ok(rocksdb::AsColumnFamilyRef::inner(&i.inner));
-         }
-         let cf = InternedColumnFamily::new(&self.db, opts, name)?;
-         let handle = rocksdb::AsColumnFamilyRef::inner(&cf.inner);
-         cfs.insert(name.clone(), cf);
-         Ok(handle)
-      })
-   }
-}
-
-impl Drop for Core {
-   fn drop(&mut self) {
-      self.cfs.write().clear();
-   }
-}
-
-/// A column family in the RocksDB hierarchy.
-struct ColumnFamily {
-   /// The full name of this column family.
-   full_name: SmolStr,
-   /// Offset to child name.
-   name_offset: usize,
-   /// The RocksDB column family handle
-   handle: *mut librocksdb_sys::rocksdb_column_family_handle_t,
-   /// Child column families.
-   children: RwLock<AHashMap<SmolStr, Arc<ColumnFamily>>>,
-   /// The shared core state.
-   core: Arc<Core>,
-   /// Store options we're using within this space.
-   opts: Options,
-   /// The default read options.
-   ro: rocksdb::ReadOptions,
-   /// The default write options.
-   wo: rocksdb::WriteOptions,
-}
-
-impl ColumnFamily {
-   fn is_root(&self) -> bool {
-      self.name_offset == 0
-   }
-   fn format_child_name(&self, name: &str) -> SmolStr {
-      if self.is_root() && name != ROOT_CF {
-         name.to_smolstr() // If child doesn't conflict with the root, we can
-                           // just use it as is
-      } else {
-         format_smolstr!("{}.{}", self.full_name, name) // Otherwise, let's use
-                                                        // a seperator
-      }
-   }
-}
-
-unsafe impl Send for ColumnFamily {}
-unsafe impl Sync for ColumnFamily {}
-
-impl rocksdb::AsColumnFamilyRef for ColumnFamily {
-   fn inner(&self) -> *mut librocksdb_sys::rocksdb_column_family_handle_t {
-      self.handle
-   }
-}
-
-#[derive(Clone)]
-pub struct RocksDb {
-   /// The current column family.
-   inner: Arc<ColumnFamily>,
-}
-
-impl fmt::Debug for RocksDb {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_struct("RocksDb")
-         .field("cf", &self.namespace())
-         .field("db", &self.inner.core.db)
-         .finish()
-   }
-}
-
-const ROOT_CF: &str = "default";
-
-impl RocksDb {
-   /// Returns the default options and column families for opening a RocksDB
-   /// instance.
-   ///
-   /// # Arguments
-   ///
-   /// * `path` - Optional path to the database. If provided, existing column
-   ///   families will be listed.
-   ///
-   /// # Returns
-   ///
-   /// A tuple containing the options and a list of column family names.
-   fn default_open_options(path: Option<&Path>) -> (rocksdb::Options, AHashSet<SmolStr>) {
-      const KB: usize = 1024;
-      const MB: usize = 1024 * KB;
-      const GB: usize = 1024 * MB;
-      let mut opts = rocksdb::Options::default();
-      opts.create_if_missing(true);
-      opts.set_write_buffer_size(64 * MB);
-      opts.set_max_write_buffer_number(8);
-      opts.set_min_write_buffer_number_to_merge(2);
-      opts.set_compression_type(rocksdb::DBCompressionType::Lz4);
-
-      // Enable blob storage for large values
-      opts.set_enable_blob_files(true);
-      opts.set_min_blob_size(8 * KB as u64); // Store values >= 8KB in blob files
-      opts.set_blob_file_size(256 * MB as u64); // 256MB blob files
-      opts.set_blob_compression_type(rocksdb::DBCompressionType::Lz4);
-      opts.set_enable_blob_gc(true);
-      opts.set_blob_gc_age_cutoff(0.25); // GC oldest 25% of blob files
-      opts.set_blob_gc_force_threshold(1.0);
-
-      // Use bloom filters
-      let mut block_opts = BlockBasedOptions::default();
-      block_opts.set_bloom_filter(10.0, false);
-      block_opts.set_block_cache(&Cache::new_lru_cache(GB)); // 1GB cache
-      opts.set_block_based_table_factory(&block_opts);
-
-      // Optimize for sequential writes
-      opts.set_use_direct_io_for_flush_and_compaction(true);
-      opts.set_compaction_style(rocksdb::DBCompactionStyle::Level);
-
-      opts.set_merge_operator(
-         "merge",
-         |key, val, ops| {
-            let mut val = val.map(Cow::Borrowed);
-            for op in ops.iter() {
-               let op = OperatorRepr::from_bytes(op);
-               val = Some(op.apply(key, val));
-            }
-            val.map(|v| v.into_owned())
-         },
-         |_, _, _| None,
-      );
-      opts.create_missing_column_families(true);
-      opts.optimize_level_style_compaction(1024 * 1024 * 1024);
-      opts.increase_parallelism(
-         std::thread::available_parallelism()
-            .map(|p| p.get().min(32) as i32)
-            .unwrap_or_default()
-            >> 2,
-      );
-
-      // https://github.com/facebook/rocksdb/wiki/Setup-Options-and-Basic-Tuning#other-general-options
-      opts.set_level_compaction_dynamic_level_bytes(true);
-      //pts.set_bytes_per_sync(1048576);
-      opts.set_compaction_pri(rocksdb::CompactionPri::MinOverlappingRatio);
-
-      let mut cfs = path.map_or(AHashSet::new(), |path| {
-         Db::list_cf(&opts, path)
-            .unwrap_or_default()
-            .into_iter()
-            .map(|x| x.to_smolstr())
-            .collect()
-      });
-      cfs.insert(SmolStr::new_static(ROOT_CF));
-      (opts, cfs)
-   }
-
-   /// Creates a new RocksDB instance with the given database and options.
-   ///
-   /// # Arguments
-   ///
-   /// * `db` - The RocksDB database instance.
-   /// * `opts` - The options used for creating column families.
-   /// * `cfs` - The list of column family names.
-   /// * `tempdir` - Optional temporary directory.
-   ///
-   /// # Returns
-   ///
-   /// A new [`RocksDb`] instance.
-   ///
-   /// # Errors
-   ///
-   /// Returns an error if any column family cannot be created.
-   fn new(
-      db: Db,
-      db_opts: rocksdb::Options,
-      cfs: AHashSet<SmolStr>,
-      tempdir: Option<tempfile::TempDir>,
-      opts: Options,
-   ) -> Result<Self> {
-      let core = Arc::new(Core {
-         _tempdir: tempdir,
-         cfs: RwLock::new(AHashMap::new()),
-         db,
-         db_opts,
-      });
-
-      // Initialize all column families
-      for name in &cfs {
-         let interned_cf = InternedColumnFamily::new(&core.db, &core.db_opts, name)?;
-         core.cfs.write().insert(name.clone(), interned_cf);
-      }
-
-      // Get the root column family
-      let root_name = SmolStr::new_static(ROOT_CF);
-      let handle = core.open_cf(&root_name, &core.db_opts)?;
-
-      Ok(Self {
-         inner: Arc::new(ColumnFamily {
-            full_name: root_name,
-            name_offset: 0,
-            handle,
-            children: RwLock::new(AHashMap::new()),
-            core,
-            opts,
-            ro: Self::new_read_options(&opts),
-            wo: Self::new_write_options(&opts),
-         }),
-      })
-   }
-
-   /// Opens a RocksDB instance at the given path with the given options.
-   ///
-   /// # Arguments
-   ///
-   /// * `path` - The path to the database, if `None` is provided, a temporary
-   ///   directory will be used.
-   /// * `opts` - The options to use for the database.
-   ///
-   /// # Returns
-   ///
-   /// A new [`RocksDb`] instance.
-   ///
-   /// # Errors
-   ///
-   /// Returns an error if the database cannot be opened.
-   pub fn with_opts(path: Option<&Path>, opts: Options) -> Result<Self> {
-      let (db_opts, cfs) = Self::default_open_options(path);
-      let mut temp_dir = None;
-      let path = if let Some(path) = path {
-         path
-      } else {
-         temp_dir = Some(tempfile::TempDir::with_prefix("tetra-")?);
-         temp_dir.as_ref().unwrap().path()
-      };
-      let db = Db::open_cf_descriptors(
-         &db_opts,
-         path,
-         cfs.iter()
-            .map(|x| rocksdb::ColumnFamilyDescriptor::new(x.to_string(), db_opts.clone())),
-      )?;
-      Self::new(db, db_opts, cfs, temp_dir, opts)
-   }
-
-   /// Opens a RocksDB instance at the given path with the default options.
-   ///
-   /// # Arguments
-   ///
-   /// * `path` - The path to the database.
-   ///
-   /// # Returns
-   ///
-   /// A new [`RocksDb`] instance.
-   ///
-   /// # Errors
-   ///
-   /// Returns an error if the database cannot be opened.
-   pub fn open(path: impl AsRef<Path>) -> Result<Self> {
-      Self::with_opts(Some(path.as_ref()), Options::DEF)
-   }
-
-   /// Creates a temporary RocksDB instance.
-   ///
-   /// # Returns
-   ///
-   /// A new [`RocksDb`] instance backed by a temporary directory.
-   ///
-   /// # Errors
-   ///
-   /// Returns an error if the temporary database cannot be created.
-   pub fn temp() -> Result<Self> {
-      Self::with_opts(None, Options::DEF)
-   }
-
-   /// Returns a reference to the underlying RocksDB database.
-   pub fn db(&self) -> &Db {
-      &self.inner.core.db
-   }
-
-   /// Returns the shared default instance of the [`rocksdb::ReadOptions`]
-   /// struct.
-   pub fn read_options(&self) -> &rocksdb::ReadOptions {
-      &self.inner.ro
-   }
-
-   /// Returns a new instance of the [`rocksdb::ReadOptions`] struct given the
-   /// options set on the store.
-   pub fn new_read_options(_no: &Options) -> rocksdb::ReadOptions {
-      rocksdb::ReadOptions::default()
-   }
-
-   /// Returns the shared default instance of the [`rocksdb::WriteOptions`]
-   /// struct.
-   pub fn write_options(&self) -> &rocksdb::WriteOptions {
-      &self.inner.wo
-   }
-
-   /// Returns a new instance of the [`rocksdb::WriteOptions`] struct given the
-   /// options set on the store.
-   pub fn new_write_options(no: &Options) -> rocksdb::WriteOptions {
-      let mut opts = rocksdb::WriteOptions::default();
-      opts.disable_wal(!no.wal);
-      opts.set_sync(no.sync);
-      opts
-   }
-
-   /// Returns a reference to the current column family handle.
-   pub fn handle(&self) -> &impl rocksdb::AsColumnFamilyRef {
-      self.inner.as_ref()
-   }
-
-   /// Opens a new child column family with the given name and options.
-   ///
-   /// # Arguments
-   ///
-   /// * `name` - The name of the child column family.
-   /// * `opts` - The options to use for the child column family.
-   /// * `fndb` - The function callback to mutate the db options.
-   pub fn open_child(
-      &self,
-      name: &str,
-      opts: Options,
-      fndb: impl Fn(&rocksdb::Options) -> Cow<rocksdb::Options>,
-   ) -> Result<Self> {
-      let mut cfs = self.inner.children.upgradable_read();
-      if let Some(inst) = cfs.get(name) {
-         return Ok(Self {
-            inner: inst.clone(),
-         });
-      }
-
-      cfs.with_upgraded(|cfs| {
-         use std::collections::hash_map::Entry;
-         let core: &Core = &self.inner.core;
-         let entry = cfs.entry(name.to_smolstr());
-         let inst = match entry {
-            Entry::Vacant(e) => {
-               let full_name = self.inner.format_child_name(name);
-               let db_opts = fndb(&core.db_opts);
-               let handle = core.open_cf(&full_name, db_opts.as_ref())?;
-               e.insert(Arc::new(ColumnFamily {
-                  name_offset: full_name.len() - name.len(),
-                  full_name,
-                  handle,
-                  children: RwLock::new(AHashMap::new()),
-                  core: self.inner.core.clone(),
-                  opts,
-                  ro: Self::new_read_options(&opts),
-                  wo: Self::new_write_options(&opts),
-               }))
-               .clone()
-            },
-            Entry::Occupied(e) => e.get().clone(),
-         };
-         Ok(Self { inner: inst })
-      })
-   }
-}
-
-fn to_iter<R>(mode: IterMode, iterator_cf: impl Fn(rocksdb::IteratorMode) -> R) -> R {
-   iterator_cf(match mode {
-      IterMode::Forward(Some(&[])) | IterMode::Forward(None) => rocksdb::IteratorMode::Start,
-      IterMode::Reverse(None) => rocksdb::IteratorMode::End,
-      IterMode::Forward(Some(seek)) => {
-         rocksdb::IteratorMode::From(seek, rocksdb::Direction::Forward)
-      },
-      IterMode::Reverse(Some(seek)) => {
-         rocksdb::IteratorMode::From(seek, rocksdb::Direction::Reverse)
-      },
-   })
-}
-
-#[derive(derive_more::Debug)]
-pub struct Snapshot<'a> {
-   #[debug("<rocksdb::Snapshot>")]
-   snapshot: rocksdb::SnapshotWithThreadMode<'a, Db>,
-   db: &'a RocksDb,
-   #[debug(skip)]
-   ro: rocksdb::ReadOptions,
-}
-
-impl<'a> IVecRef for rocksdb::DBPinnableSlice<'a> {
-   fn into_bytes(self) -> bytes::Bytes {
-      bytes::Bytes::from_owner(self.to_vec())
-   }
-   fn as_slice(&self) -> &[u8] {
-      self.as_ref()
-   }
-   fn into_vec(self) -> Vec<u8> {
-      self.to_vec()
-   }
-}
-
-#[derive(derive_more::From, derive_more::Debug)]
-pub struct Iter<'a> {
-   #[debug("<rocksdb::DBIterator>")]
-   iter: rocksdb::DBIteratorWithThreadMode<'a, Db>,
-}
-
-impl<'a> Iterator for Iter<'a> {
-   type Item = Result<(Bytes, Bytes)>;
-   fn next(&mut self) -> Option<Self::Item> {
-      self.iter.by_ref().next().map(|r| -> Result<_> {
-         let (k, v) = r?;
-         Ok((Bytes::from_owner(k), Bytes::from_owner(v)))
-      })
-   }
-}
-
-impl<'a> traits::View for Snapshot<'a> {
-   type Iter<'b>
-      = Iter<'b>
-   where
-      Self: 'b;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      Ok(self
-         .db
-         .db()
-         .get_pinned_cf_opt(self.db.handle(), key, &self.ro)?
-         .map(IVec::new))
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      let db = self.db.db();
-      if db.key_may_exist_cf_opt(self.db.handle(), key, &self.ro) {
-         Ok(db
-            .get_pinned_cf_opt(self.db.handle(), key, &self.ro)?
-            .is_some())
-      } else {
-         Ok(false)
-      }
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      // TODO: Remove the collect, currently needed to AsRef<[u8]> -> &'a AsRef<[u8]>
-      let vec = keys.into_iter().collect::<Vec<_>>();
-      Ok(self
-         .db
-         .db()
-         .batched_multi_get_cf(self.db.handle(), &vec, false)
-         .into())
-   }
-
-   fn iter(&self, mode: IterMode) -> Self::Iter<'_> {
-      Iter::from(to_iter(mode, |mode| {
-         self.snapshot.iterator_cf(self.db.handle(), mode)
-      }))
-   }
-}
-
-#[derive(derive_more::Debug)]
-pub struct WriteBatch<'a> {
-   #[debug("<rocksdb::WriteBatch>")]
-   inner: RefCell<rocksdb::WriteBatch>,
-   parent: &'a RocksDb,
-}
-
-impl<'a> traits::Write for WriteBatch<'a> {
-   type Result = ();
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self
-         .inner
-         .borrow_mut()
-         .put_cf(self.parent.handle(), key, value);
-   }
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.inner.borrow_mut().delete_cf(self.parent.handle(), key);
-   }
-
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      self
-         .inner
-         .borrow_mut()
-         .delete_range_cf(self.parent.handle(), from, to);
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      quickbuf::with(|buf| {
-         let rng = op.write_to(buf);
-         self
-            .inner
-            .borrow_mut()
-            .merge_cf(self.parent.handle(), key, &buf[rng]);
-      });
-   }
-}
-
-impl<'a> traits::WriteBatch<'a> for WriteBatch<'a> {
-   fn commit(&self) -> Result<()> {
-      Ok(self
-         .parent
-         .db()
-         .write_opt(self.inner.take(), self.parent.write_options())?)
-   }
-
-   fn reset(&mut self) {
-      self.inner.get_mut().clear();
-   }
-}
-
-impl traits::View for RocksDb {
-   type Iter<'a>
-      = Iter<'a>
-   where
-      Self: 'a;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      Ok(self
-         .db()
-         .get_pinned_cf_opt(self.handle(), key, self.read_options())?
-         .map(IVec::new))
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      let db = self.db();
-      if db.key_may_exist_cf_opt(self.handle(), key, self.read_options()) {
-         Ok(db
-            .get_pinned_cf_opt(self.handle(), key, self.read_options())?
-            .is_some())
-      } else {
-         Ok(false)
-      }
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      // TODO: Remove the collect, currently needed to AsRef<[u8]> -> &'a AsRef<[u8]>
-      let vec = keys.into_iter().collect::<Vec<_>>();
-      Ok(self
-         .db()
-         .batched_multi_get_cf(self.handle(), &vec, false)
-         .into())
-   }
-
-   fn iter(&self, mode: IterMode) -> Self::Iter<'_> {
-      Iter::from(to_iter(mode, |mode| {
-         self.db().iterator_cf(self.handle(), mode)
-      }))
-   }
-}
-
-impl traits::Write for RocksDb {
-   type Result = Result<()>;
-
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      quickbuf::with(|buf| {
-         let rng = op.write_to(buf);
-         let op = &buf[rng];
-         Ok(self
-            .db()
-            .merge_cf_opt(self.handle(), key, op, self.write_options())?)
-      })
-   }
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      Ok(self
-         .db()
-         .put_cf_opt(self.handle(), key, value, self.write_options())?)
-   }
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      Ok(self
-         .db()
-         .delete_cf_opt(self.handle(), key, self.write_options())?)
-   }
-
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      Ok(self
-         .db()
-         .delete_range_cf_opt(self.handle(), from, to, self.write_options())?)
-   }
-}
-
-impl traits::Store for RocksDb {
-   type WriteBatch<'a> = WriteBatch<'a>;
-   type Snapshot<'a> = Snapshot<'a>;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      WriteBatch {
-         inner: Default::default(),
-         parent: self,
-      }
-   }
-
-   fn options(&self) -> &Options {
-      &self.inner.opts
-   }
-
-   fn namespace(&self) -> &str {
-      &self.inner.full_name[self.inner.name_offset..]
-   }
-
-   fn flush(&self) -> Result<()> {
-      Ok(self.db().flush_cf(self.handle())?)
-   }
-
-   fn clear(&self) -> Result<()> {
-      let max_key = self
-         .db()
-         .iterator_cf(self.handle(), rocksdb::IteratorMode::End)
-         .next()
-         .map(|x| x.map(|(k, _)| k));
-
-      if let Some(Ok(max_key)) = max_key {
-         let empty: &[u8] = &[];
-         self
-            .db()
-            .delete_range_cf_opt(self.handle(), empty, &max_key, self.write_options())?;
-         self
-            .db()
-            .delete_cf_opt(self.handle(), &max_key, self.write_options())?;
-      }
-
-      Ok(())
-   }
-
-   fn child(&self, name: &str, opts: Options) -> Result<Self> {
-      self.open_child(name, opts, |x| Cow::Borrowed(x))
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      self.inner.children.read().keys().cloned().collect()
-   }
-
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      let snap = self.db().snapshot();
-      let mut ro = Self::new_read_options(&self.inner.opts);
-      ro.set_snapshot(&snap);
-      Snapshot {
-         snapshot: snap,
-         db: self,
-         ro,
-      }
-   }
-
-   fn estimate_size(&self) -> Option<u64> {
-      self
-         .db()
-         .property_int_value_cf(self.handle(), rocksdb::properties::TOTAL_SST_FILES_SIZE)
-         .ok()
-         .flatten()
-   }
-}
diff --git a/attic/kv/src/tests.rs b/attic/kv/src/tests.rs
deleted file mode 100644
index 54ad3f33c..000000000
--- a/attic/kv/src/tests.rs
+++ /dev/null
@@ -1,603 +0,0 @@
-use ahash::AHashMap;
-
-use crate::{
-   TypedStore, TypedView, TypedWriteBatch, Write,
-   error::Result,
-   ops,
-   traits::{IterMode, Options, Store, View, WriteBatch},
-   typed::ser::IntoTypedStore,
-};
-
-/// Test basic operations of a key-value store implementation
-fn test_basic_kv_ops<S: Store>(store: &S) -> Result<()> {
-   // Test set and get
-   store.put(b"key1", b"value1")?;
-   let val = store.get(b"key1")?;
-   assert_eq!(val.as_deref(), Some(b"value1".as_ref()));
-
-   // Test contains
-   assert!(store.contains(b"key1")?);
-   assert!(!store.contains(b"nonexistent")?);
-
-   // Test delete
-   store.delete(b"key1")?;
-   assert!(!store.contains(b"key1")?);
-
-   // Test batch operations
-   let batch = store.batch();
-   batch.put(b"batch1", b"batch_value1");
-   batch.put(b"batch2", b"batch_value2");
-   batch.commit()?;
-
-   assert_eq!(
-      store.get(b"batch1")?.as_deref(),
-      Some(b"batch_value1".as_ref())
-   );
-   assert_eq!(
-      store.get(b"batch2")?.as_deref(),
-      Some(b"batch_value2".as_ref())
-   );
-
-   // Test iteration
-   let mut iter_pairs = Vec::new();
-   for result in store.iter(IterMode::forward()) {
-      let (k, v) = result?;
-      iter_pairs.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(iter_pairs.len(), 2);
-   assert!(iter_pairs.contains(&(b"batch1".to_vec(), b"batch_value1".to_vec())));
-   assert!(iter_pairs.contains(&(b"batch2".to_vec(), b"batch_value2".to_vec())));
-
-   // Test backward iteration
-   let mut backward_pairs = Vec::new();
-   for result in store.iter(IterMode::reverse()) {
-      let (k, v) = result?;
-      backward_pairs.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(backward_pairs.len(), 2);
-   // Should be in reverse lexicographical order
-   assert_eq!(backward_pairs[0].0, b"batch2");
-   assert_eq!(backward_pairs[1].0, b"batch1");
-
-   // Test get_many
-   let values = store.get_many([
-      b"batch1".as_ref(),
-      b"batch2".as_ref(),
-      b"nonexistent".as_ref(),
-   ])?;
-   assert_eq!(values.len(), 3);
-   assert_eq!(values.get(0)?, Some(b"batch_value1".as_ref()));
-   assert_eq!(values.get(1)?, Some(b"batch_value2".as_ref()));
-   assert_eq!(values.get(2)?, None);
-
-   // Test seeking
-   store.put(b"seek1", b"seek_value1")?;
-   store.put(b"seek2", b"seek_value2")?;
-
-   let mut seek_pairs = Vec::new();
-   for result in store.iter(IterMode::lower_bound(b"seek")) {
-      let (k, v) = result?;
-      seek_pairs.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(seek_pairs.len(), 2);
-   assert!(seek_pairs.contains(&(b"seek1".to_vec(), b"seek_value1".to_vec())));
-   assert!(seek_pairs.contains(&(b"seek2".to_vec(), b"seek_value2".to_vec())));
-
-   Ok(())
-}
-
-/// Test snapshot functionality
-fn test_snapshot<S: Store>(store: &S) -> Result<()> {
-   // Setup initial data
-   store.put(b"snap1", b"snap_value1")?;
-   store.put(b"snap2", b"snap_value2")?;
-
-   // Create snapshot
-   let snapshot = store.snapshot();
-
-   // Modify data after snapshot
-   store.put(b"snap1", b"modified_value1")?;
-   store.put(b"snap3", b"snap_value3")?;
-
-   // Verify snapshot has original values
-   assert_eq!(
-      snapshot.get(b"snap1")?.as_deref(),
-      Some(b"snap_value1".as_ref())
-   );
-   assert_eq!(
-      snapshot.get(b"snap2")?.as_deref(),
-      Some(b"snap_value2".as_ref())
-   );
-   assert_eq!(snapshot.get(b"snap3")?.as_deref(), None);
-
-   // Verify store has new values
-   assert_eq!(
-      store.get(b"snap1")?.as_deref(),
-      Some(b"modified_value1".as_ref())
-   );
-   assert_eq!(
-      store.get(b"snap3")?.as_deref(),
-      Some(b"snap_value3".as_ref())
-   );
-
-   Ok(())
-}
-
-/// Test prefix scanning functionality
-fn test_prefix_scan<S: Store>(store: &S) -> Result<()> {
-   // Clear and setup test data with specific prefixes
-   let batch = store.batch();
-   batch.put(b"prefix1_a", b"value1a");
-   batch.put(b"prefix1_b", b"value1b");
-   batch.put(b"prefix2_a", b"value2a");
-   batch.put(b"prefix2_b", b"value2b");
-   batch.commit()?;
-
-   // Scan with prefix1
-   let mut prefix1_results = Vec::new();
-   for result in store.prefix_scan(b"prefix1_", IterMode::forward()) {
-      let (k, v) = result?;
-      prefix1_results.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(prefix1_results.len(), 2);
-   println!("prefix1_results: {prefix1_results:?}");
-   assert!(prefix1_results.contains(&(b"prefix1_a".to_vec(), b"value1a".to_vec())));
-   assert!(prefix1_results.contains(&(b"prefix1_b".to_vec(), b"value1b".to_vec())));
-
-   // Scan with prefix2
-   let mut prefix2_results = Vec::new();
-   for result in store.prefix_scan(b"prefix2_", IterMode::forward()) {
-      let (k, v) = result?;
-      prefix2_results.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(prefix2_results.len(), 2);
-   assert!(prefix2_results.contains(&(b"prefix2_a".to_vec(), b"value2a".to_vec())));
-   assert!(prefix2_results.contains(&(b"prefix2_b".to_vec(), b"value2b".to_vec())));
-
-   // Backward scan
-   let mut backward_results = Vec::new();
-   for result in store.prefix_scan(b"prefix1_", IterMode::reverse()) {
-      let (k, v) = result?;
-      backward_results.push((k.to_vec(), v.to_vec()));
-   }
-
-   assert_eq!(backward_results.len(), 2);
-   assert_eq!(backward_results[0].0, b"prefix1_b");
-   assert_eq!(backward_results[1].0, b"prefix1_a");
-
-   Ok(())
-}
-
-/// Test child namespace functionality
-fn test_child_namespaces<S: Store>(store: &S) -> Result<()> {
-   // Set value in parent namespace
-   store.put(b"parent_key", b"parent_value")?;
-
-   // Create child namespace
-   let child1 = store.child("child1", Options::DEF)?;
-
-   // Set values in child namespace
-   child1.put(b"child1_key", b"child1_value")?;
-
-   // Create another child
-   let child2 = store.child("child2", Options::DEF)?;
-   child2.put(b"child2_key", b"child2_value")?;
-
-   // Values in each namespace should be isolated
-   assert_eq!(
-      store.get(b"parent_key")?.as_deref(),
-      Some(b"parent_value".as_ref())
-   );
-   assert_eq!(
-      child1.get(b"child1_key")?.as_deref(),
-      Some(b"child1_value".as_ref())
-   );
-   assert_eq!(
-      child2.get(b"child2_key")?.as_deref(),
-      Some(b"child2_value".as_ref())
-   );
-
-   // Child shouldn't see parent's keys
-   assert_eq!(child1.get(b"parent_key")?.as_deref(), None);
-
-   // Parent shouldn't see child's keys
-   assert_eq!(store.get(b"child1_key")?.as_deref(), None);
-
-   // Test clearing child namespace
-   child1.clear()?;
-   assert_eq!(child1.get(b"child1_key")?.as_deref(), None);
-
-   // But other namespaces should be unaffected
-   assert_eq!(
-      store.get(b"parent_key")?.as_deref(),
-      Some(b"parent_value".as_ref())
-   );
-   assert_eq!(
-      child2.get(b"child2_key")?.as_deref(),
-      Some(b"child2_value".as_ref())
-   );
-
-   // Test listing children
-   let children = store.children();
-   assert_eq!(children.len(), 2);
-   assert!(children.contains(&"child1".into()));
-   assert!(children.contains(&"child2".into()));
-
-   Ok(())
-}
-
-/// Test typed key-value store functionality
-fn test_typed_kv<S: Store + Clone>(store: S) -> Result<()> {
-   // Create typed store for storing strings
-   let typed_store = store.clone().into_typed::<str, str>();
-
-   // Test basic operations
-   typed_store.put("typed_key1", "typed_value1")?;
-   typed_store.put("typed_key2", "typed_value2")?;
-
-   assert_eq!(
-      typed_store.get("typed_key1")?,
-      Some("typed_value1".to_string())
-   );
-   assert_eq!(
-      typed_store.get("typed_key2")?,
-      Some("typed_value2".to_string())
-   );
-
-   // Test batch operations
-   let mut batch = typed_store.batch();
-   batch.put("batch_key1", "batch_value1");
-   batch.put("batch_key2", "batch_value2");
-   batch.write()?;
-
-   assert_eq!(
-      typed_store.get("batch_key1")?,
-      Some("batch_value1".to_string())
-   );
-
-   // Test get_many
-   let values = typed_store.get_many(&["typed_key1", "typed_key2", "nonexistent"])?;
-   assert_eq!(values.len(), 3);
-   assert_eq!(values.get(0)?, Some("typed_value1".to_string()));
-   assert_eq!(values.get(1)?, Some("typed_value2".to_string()));
-   assert_eq!(values.get(2)?, None);
-
-   // Test iteration
-   let mut iter_pairs = Vec::new();
-   for result in typed_store.iter(IterMode::forward()) {
-      let (k, v) = result?;
-      iter_pairs.push((k, v));
-   }
-
-   assert!(iter_pairs.contains(&("typed_key1".to_string(), "typed_value1".to_string())));
-   assert!(iter_pairs.contains(&("typed_key2".to_string(), "typed_value2".to_string())));
-
-   // Test with complex types
-   let complex_store = store.into_typed::<u32, AHashMap<String, Vec<i32>>>();
-
-   let mut map1 = AHashMap::new();
-   map1.insert("nums".to_string(), vec![1, 2, 3]);
-
-   let mut map2 = AHashMap::new();
-   map2.insert("chars".to_string(), vec![65, 66, 67]);
-
-   complex_store.put(&100, &map1)?;
-   complex_store.put(&200, &map2)?;
-
-   assert_eq!(complex_store.get(&100)?, Some(map1));
-   assert_eq!(complex_store.get(&200)?, Some(map2));
-
-   Ok(())
-}
-
-/// Test iterator seek edge cases to ensure correct inclusiveness
-///
-/// Both forward and backward iteration should include the seek key.
-fn test_iterator_one_offs<S: Store>(store: &S) -> Result<()> {
-   // Insert ordered keys
-   store.put(b"alpha", b"val_alpha")?;
-   store.put(b"beta", b"val_beta")?;
-   store.put(b"gamma", b"val_gamma")?;
-
-   // ------------------------------------------------------------
-   // Backward iteration starting AT the seek key must *include* the key
-   // ------------------------------------------------------------
-   let mut bw_iter = store.iter(IterMode::upper_bound(b"beta"));
-
-   // The first element yielded must be the seek key itself
-   let (first_k, _first_v) = bw_iter
-      .next()
-      .expect("iterator should yield at least one element")?;
-   assert_eq!(first_k.as_ref(), b"beta");
-
-   // The second element should be the previous key
-   let (second_k, _second_v) = bw_iter
-      .next()
-      .expect("iterator should yield at least two elements")?;
-   assert_eq!(second_k.as_ref(), b"alpha");
-
-   // ------------------------------------------------------------
-   // Forward iteration starting AT the seek key must *include* the key
-   // ------------------------------------------------------------
-   let mut fw_iter = store.iter(IterMode::lower_bound(b"beta"));
-   let (first_k_fw, _first_v_fw) = fw_iter
-      .next()
-      .expect("iterator should yield at least one element")?;
-   assert_eq!(first_k_fw.as_ref(), b"beta");
-
-   // The second element should be the next key
-   let (second_k_fw, _second_v_fw) = fw_iter
-      .next()
-      .expect("iterator should yield at least two elements")?;
-   assert_eq!(second_k_fw.as_ref(), b"gamma");
-
-   Ok(())
-}
-
-/// Test read-modify-write operator functionality (Append and CompareExchange)
-fn test_rmw<S: Store>(store: &S) -> Result<()> {
-   // ----- Append semantics -----
-   // Appending to a nonexistent key should create it.
-   store.update(b"append_key", &ops::Append(b"abc"))?;
-   assert_eq!(store.get(b"append_key")?.as_deref(), Some(b"abc".as_ref()));
-
-   // Subsequent appends should concatenate at the end.
-   store.update(b"append_key", &ops::Append(b"def"))?;
-   assert_eq!(
-      store.get(b"append_key")?.as_deref(),
-      Some(b"abcdef".as_ref())
-   );
-
-   // ----- CompareExchange semantics -----
-   // Successful CAS should update the value.
-   store.put(b"cas_key", b"old")?;
-   store.update(b"cas_key", &ops::CompareExchange {
-      expected: Some(b"old"),
-      desired: b"new",
-   })?;
-   assert_eq!(store.get(b"cas_key")?.as_deref(), Some(b"new".as_ref()));
-
-   // Failed CAS (mismatched expected) should leave the value unchanged.
-   store.update(b"cas_key", &ops::CompareExchange {
-      expected: Some(b"old"),
-      desired: b"should_not_apply",
-   })?;
-   assert_eq!(store.get(b"cas_key")?.as_deref(), Some(b"new".as_ref()));
-
-   // CAS from None to Some should succeed when key does not exist.
-   store.update(b"new_key", &ops::CompareExchange {
-      expected: None,
-      desired: b"value",
-   })?;
-   assert_eq!(store.get(b"new_key")?.as_deref(), Some(b"value".as_ref()));
-
-   // CAS expecting Some should fail when key is absent.
-   store.update(b"absent_key", &ops::CompareExchange {
-      expected: Some(b"whatever"),
-      desired: b"value",
-   })?;
-   assert_eq!(
-      store.get(b"absent_key")?.as_deref().unwrap_or_default(),
-      b""
-   );
-
-   // ----- Increment semantics -----
-   // Test basic increment operation
-   store.put(b"counter", &0u64.to_le_bytes())?;
-   store.update(b"counter", &ops::Inc(1))?;
-   assert_eq!(
-      u64::from_le_bytes(store.get(b"counter")?.unwrap().as_ref().try_into().unwrap()),
-      1
-   );
-
-   // Test multiple increments
-   store.update(b"counter", &ops::Inc(5))?;
-   assert_eq!(
-      u64::from_le_bytes(store.get(b"counter")?.unwrap().as_ref().try_into().unwrap()),
-      6
-   );
-
-   // Test increment on non-existent key (should create and initialize to the
-   // increment value)
-   store.update(b"new_counter", &ops::Inc(10))?;
-   assert_eq!(
-      u64::from_le_bytes(
-         store
-            .get(b"new_counter")?
-            .unwrap()
-            .as_ref()
-            .try_into()
-            .unwrap()
-      ),
-      10
-   );
-
-   // Test overflow behavior
-   store.put(b"max_counter", &u64::MAX.to_le_bytes())?;
-   store.update(b"max_counter", &ops::Inc(1))?;
-   let result = store.get(b"max_counter")?.unwrap();
-   assert_eq!(result.len(), 16); // Should now be 16 bytes (two u64s)
-   assert_eq!(u64::from_le_bytes(result[0..8].try_into().unwrap()), 0);
-   assert_eq!(u64::from_le_bytes(result[8..16].try_into().unwrap()), 1);
-
-   // ----- Decrement semantics -----
-   // Test basic decrement operation
-   store.put(b"counter", &10u64.to_le_bytes())?;
-   store.update(b"counter", &ops::SaturatingDec(1))?;
-   assert_eq!(
-      u64::from_le_bytes(store.get(b"counter")?.unwrap().as_ref().try_into().unwrap()),
-      9
-   );
-
-   // Test decrement on non-existent key (should create and initialize to 0)
-   store.update(b"new_counter", &ops::SaturatingDec(10))?;
-   assert_eq!(
-      u64::from_le_bytes(
-         store
-            .get(b"new_counter")?
-            .unwrap()
-            .as_ref()
-            .try_into()
-            .unwrap()
-      ),
-      0
-   );
-
-   // Test decrement saturation
-   store.put(b"saturate_counter", &1u64.to_le_bytes())?;
-   store.update(b"saturate_counter", &ops::SaturatingDec(2))?;
-   assert_eq!(
-      u64::from_le_bytes(
-         store
-            .get(b"saturate_counter")?
-            .unwrap()
-            .as_ref()
-            .try_into()
-            .unwrap()
-      ),
-      0
-   );
-
-   Ok(())
-}
-
-/// Test delete_range functionality
-fn test_delete_range<S: Store>(store: &S) -> Result<()> {
-   // Setup test data
-   store.put(b"a", b"value_a")?;
-   store.put(b"b", b"value_b")?;
-   store.put(b"c", b"value_c")?;
-   store.put(b"d", b"value_d")?;
-   store.put(b"e", b"value_e")?;
-
-   // Delete range [b, d) - should delete b and c but not a, d, or e
-   store.delete_range(b"b", b"d")?;
-
-   // Verify results
-   assert_eq!(store.get(b"a")?.as_deref(), Some(b"value_a".as_ref()));
-   assert_eq!(store.get(b"b")?.as_deref(), None);
-   assert_eq!(store.get(b"c")?.as_deref(), None);
-   assert_eq!(store.get(b"d")?.as_deref(), Some(b"value_d".as_ref()));
-   assert_eq!(store.get(b"e")?.as_deref(), Some(b"value_e".as_ref()));
-
-   // Test with batch
-   let batch = store.batch();
-   batch.put(b"f", b"value_f");
-   batch.put(b"g", b"value_g");
-   batch.put(b"h", b"value_h");
-   batch.commit()?;
-
-   // Delete range using batch
-   let batch = store.batch();
-   batch.delete_range(b"f", b"h");
-   batch.commit()?;
-
-   assert_eq!(store.get(b"f")?.as_deref(), None);
-   assert_eq!(store.get(b"g")?.as_deref(), None);
-   assert_eq!(store.get(b"h")?.as_deref(), Some(b"value_h".as_ref()));
-
-   // Test edge cases
-   // Empty range
-   store.delete_range(b"z", b"z")?;
-
-   // Range with no keys
-   store.delete_range(b"y", b"z")?;
-
-   Ok(())
-}
-
-macro_rules! run_test_suite_over {
-   ($ctor:expr) => {
-      #[test]
-      fn test_db_basic_ops() {
-         let db = $ctor;
-         super::test_basic_kv_ops(&db).expect("basic ops failed");
-      }
-
-      #[test]
-      fn test_db_snapshot() {
-         let db = $ctor;
-         super::test_snapshot(&db).expect("snapshot failed");
-      }
-
-      #[test]
-      fn test_db_prefix_scan() {
-         let db = $ctor;
-         super::test_prefix_scan(&db).expect("prefix scan failed");
-      }
-
-      #[test]
-      fn test_db_child_namespaces() {
-         let db = $ctor;
-         super::test_child_namespaces(&db).expect("child namespaces failed");
-      }
-
-      #[test]
-      fn test_db_typed_kv() {
-         let db = $ctor;
-         super::test_typed_kv(db).expect("typed kv failed");
-      }
-
-      #[test]
-      fn test_db_iterator_one_offs() {
-         let db = $ctor;
-         super::test_iterator_one_offs(&db).expect("iterator one offs failed");
-      }
-
-      #[test]
-      fn test_db_rmw() {
-         let db = $ctor;
-         super::test_rmw(&db).expect("rmw failed");
-      }
-
-      #[test]
-      fn test_db_delete_range() {
-         let db = $ctor;
-         super::test_delete_range(&db).expect("delete range failed");
-      }
-   };
-}
-
-#[cfg(test)]
-#[cfg(feature = "rocksdb")]
-mod rocksdb_tests {
-   run_test_suite_over! {
-      crate::rocksdb::RocksDb::temp().expect("failed to create rocksdb")
-   }
-}
-
-#[cfg(test)]
-mod memorydb_tests {
-   run_test_suite_over! {
-      crate::memorydb::MemoryDb::new()
-   }
-}
-
-#[cfg(test)]
-mod erased_tests {
-   run_test_suite_over! {
-      crate::erased::AnyDb::new(crate::memorydb::MemoryDb::new())
-   }
-}
-
-#[cfg(test)]
-mod prefix_tests {
-   use crate::prefixed::PrefixExt;
-
-   run_test_suite_over! {
-      crate::memorydb::MemoryDb::new().with_prefix(b"pfx_")
-   }
-}
-
-#[cfg(feature = "heed")]
-#[cfg(test)]
-mod heed_tests {
-   run_test_suite_over! {
-      crate::lmdb::Lmdb::temp().expect("failed to create heed db")
-   }
-}
diff --git a/attic/kv/src/traits.rs b/attic/kv/src/traits.rs
deleted file mode 100644
index e88f90092..000000000
--- a/attic/kv/src/traits.rs
+++ /dev/null
@@ -1,292 +0,0 @@
-use std::fmt;
-
-use bon::Builder;
-use bytes::Bytes;
-use smol_str::SmolStr;
-use tetra_core::alloc::quickbuf::{self, FmtTuple};
-
-use super::error::Result;
-use crate::{pfx_iter::PrefixIter, IVec, IVecs, Operator};
-
-#[derive(Copy, Clone, Debug, Builder)]
-pub struct Options {
-   /// Whether WAL is used for this namespace (if disabled, writes may not
-   /// persist across crashes)
-   #[builder(default = Options::DEF.wal)]
-   pub wal: bool,
-
-   /// Whether to sync writes to the database (unlesss enabled, writes may be
-   /// lost when the system crashes [not the process!])
-   #[builder(default = Options::DEF.sync)]
-   pub sync: bool,
-}
-
-impl Default for Options {
-   fn default() -> Self {
-      Self::DEF
-   }
-}
-
-impl Options {
-   pub const DEF: Self = Self {
-      wal: false,
-      sync: false,
-   };
-}
-
-/// Direction for database iteration.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum IterMode<'a> {
-   /// Iterate in forward direction (ascending keys), starting from the given
-   /// key.
-   Forward(Option<&'a [u8]>),
-   /// Iterate in backward direction (descending keys), starting from the given
-   /// key.
-   Reverse(Option<&'a [u8]>),
-}
-
-impl<'a> Default for IterMode<'a> {
-   fn default() -> Self {
-      Self::Forward(None)
-   }
-}
-
-impl<'a> IterMode<'a> {
-   /// Returns an iterator mode that iterates forward from the beginning
-   pub fn forward() -> Self {
-      Self::Forward(None)
-   }
-
-   /// Returns an iterator mode that iterates backward from the end
-   pub fn reverse() -> Self {
-      Self::Reverse(None)
-   }
-
-   /// Returns an iterator mode that iterates forward starting at >= key
-   pub fn lower_bound(key: &'a [u8]) -> Self {
-      Self::Forward(Some(key))
-   }
-
-   /// Returns an iterator mode that iterates backward starting at < key
-   pub fn upper_bound(key: &'a [u8]) -> Self {
-      Self::Reverse(Some(key))
-   }
-
-   /// Replaces the inner bound into another
-   pub fn replace_bound<'b>(self, other: Option<&'b [u8]>) -> IterMode<'b> {
-      match self {
-         Self::Forward(_key) => IterMode::Forward(other),
-         Self::Reverse(_key) => IterMode::Reverse(other),
-      }
-   }
-
-   /// Gets the inner bound
-   pub fn inner(&self) -> Option<&'a [u8]> {
-      match self {
-         Self::Forward(key) => *key,
-         Self::Reverse(key) => *key,
-      }
-   }
-
-   /// Returns true if the iterator mode is reverse
-   pub fn is_reverse(&self) -> bool {
-      matches!(self, Self::Reverse(_))
-   }
-
-   /// Returns the initial position for the iterator, if any
-   pub fn at(&self) -> Option<&'a [u8]> {
-      match self {
-         Self::Forward(key) => *key,
-         Self::Reverse(key) => *key,
-      }
-   }
-}
-
-pub trait Write {
-   type Result;
-
-   /// Sets the value for the given key
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result;
-
-   /// Deletes the value for the given key
-   fn delete(&self, key: &[u8]) -> Self::Result;
-
-   /// Applies the given atomic merge operation to the key
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result;
-
-   /// Deletes all keys in the range [from, to)
-   /// # Arguments
-   /// * `from` - The inclusive start of the range
-   /// * `to` - The exclusive end of the range
-   ///
-   /// # Implementation Note
-   /// Each implementation must provide its own delete_range logic. For
-   /// databases without native range deletion support, implementations
-   /// should iterate through the range and delete keys individually.
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result;
-}
-
-pub trait Writef: Write {
-   /// Sets the value for the given key using a displayable key
-   fn putf(&self, key: impl fmt::Display, value: &[u8]) -> Self::Result {
-      with_fmtbuf((&key,), |[key]| self.put(key, value))
-   }
-
-   /// Deletes the value for the given key using a displayable key
-   fn deletef(&self, key: impl fmt::Display) -> Self::Result {
-      with_fmtbuf((&key,), |[key]| self.delete(key))
-   }
-
-   /// Applies the given atomic merge operation to the key using a displayable
-   /// key
-   fn updatef(&self, key: impl fmt::Display, op: &dyn Operator) -> Self::Result {
-      with_fmtbuf((&key,), |[key]| self.update(key, op))
-   }
-
-   /// Deletes all keys in the range [from, to) using displayable keys
-   fn delete_rangef(&self, from: impl fmt::Display, to: impl fmt::Display) -> Self::Result {
-      with_fmtbuf((&from, &to), |[from, to]| self.delete_range(from, to))
-   }
-}
-impl<T: Write> Writef for T {}
-
-/// Trait for write batches that can be used to perform multiple operations
-/// atomically
-pub trait WriteBatch<'a>: Write<Result = ()> + Send + fmt::Debug + 'a {
-   /// Writes all batched operations to the database
-   fn commit(&self) -> Result<()>;
-
-   /// Clear the operations in this batch
-   fn reset(&mut self);
-}
-
-/// Trait for mutable key-value store operations
-pub trait Store:
-   Write<Result = Result<()>> + View + Clone + Send + Sync + fmt::Debug + 'static
-{
-   /// The type of write batch used by this key-value store
-   type WriteBatch<'a>: WriteBatch<'a>;
-
-   /// The type of snapshot used by this key-value store
-   type Snapshot<'a>: View + 'a;
-   /// Creates a new write batch for this key-value store
-   fn batch(&self) -> Self::WriteBatch<'_>;
-
-   /// Returns the namespace of this key-value store
-   fn namespace(&self) -> &str;
-
-   /// Creates a child key-value store with the given name
-   fn child(&self, name: &str, opts: Options) -> Result<Self>;
-
-   /// Returns an iterator over each child key-value store
-   fn children(&self) -> Vec<SmolStr>;
-
-   /// Clears all data in this key-value store
-   fn clear(&self) -> Result<()>;
-
-   /// Flushes all data in this key-value store to the underlying storage
-   fn flush(&self) -> Result<()>;
-
-   /// Creates a snapshot of the key-value store at the current point in time
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b>;
-
-   /// Returns the options for this key-value store
-   fn options(&self) -> &Options;
-
-   /// Estimate the size of the key-value store
-   fn estimate_size(&self) -> Option<u64> {
-      None
-   }
-}
-
-/// Trait for read-only key-value store operations
-pub trait View: fmt::Debug {
-   /// The type of iterator returned by this key-value store
-   type Iter<'a>: Iterator<Item = Result<(Bytes, Bytes)>> + 'a
-   where
-      Self: 'a;
-
-   /// Gets the value for the given key
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>>;
-
-   /// Gets the value for the given key using a displayable key
-   fn getf(&self, key: impl fmt::Display) -> Result<Option<IVec<'_>>> {
-      with_fmtbuf((&key,), |[key]| self.get(key))
-   }
-
-   /// Gets the values for multiple keys at once
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>>;
-
-   /// Returns true if the key exists in the key-value store
-   fn contains(&self, key: &[u8]) -> Result<bool>;
-
-   /// Returns true if the key exists in the key-value store using a displayable
-   /// key
-   fn containsf(&self, key: impl fmt::Display) -> Result<bool> {
-      with_fmtbuf((&key,), |[key]| self.contains(key))
-   }
-
-   /// Iterates over key-value pairs in the key-value store
-   fn iter<'a>(&'a self, mode: IterMode<'_>) -> Self::Iter<'a>;
-
-   /// Scans over a prefix
-   fn scan<'a>(
-      &'a self,
-      prefix: &[u8],
-   ) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'a, Self> {
-      self.prefix_scan(prefix, IterMode::forward())
-   }
-
-   /// Scans over a prefix using a displayable key
-   fn scanf<'a>(
-      &'a self,
-      prefix: &dyn fmt::Display,
-   ) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'a, Self> {
-      with_fmtbuf((&prefix,), |[prefix]| {
-         self.prefix_scan(prefix, IterMode::forward())
-      })
-   }
-
-   /// Scans all keys with the given prefix.
-   ///
-   /// This is a convenience method that uses `iter` to scan all keys with the
-   /// given prefix.
-   fn prefix_scan<'a>(
-      &'a self,
-      prefix: &[u8],
-      mode: IterMode<'_>,
-   ) -> impl Iterator<Item = Result<(Bytes, Bytes)>> + use<'a, Self> {
-      PrefixIter::new(self, prefix, mode)
-   }
-}
-
-/// Formats displayable values into byte slices using a type-safe tuple
-/// abstraction.
-///
-/// This function provides a zero-cost abstraction for formatting one or more
-/// `Display` values into byte slices, with compile-time optimization of buffer
-/// sizes. It uses the `FmtTuple` trait to handle different arities (1-tuple,
-/// 2-tuple, etc.) in a type-safe manner.
-///
-/// # Type Parameters
-/// - `R`: The return type of the callback function
-/// - `F`: A type implementing `FmtTuple` (typically a tuple of references to
-///   Display types)
-///
-/// # Arguments
-/// - `key`: A tuple of references to `Display` objects (e.g., `(&key,)` or
-///   `(&from, &to)`)
-/// - `f`: A callback that receives the formatted byte slices as a tuple
-///
-/// # Design
-///
-/// The function leverages Rust's type system to:
-/// 1. Automatically determine the appropriate buffer size via `F::StackHint`
-/// 2. Return the correct tuple type via `F::Output<'_>`
-/// 3. Ensure type safety without runtime overhead
-fn with_fmtbuf<R, F: FmtTuple>(key: F, f: impl FnOnce(F::Output<'_>) -> R) -> R {
-   // Create a stack buffer with size hint from the FmtTuple implementation
-   let mut buf = quickbuf::StackBufferN::<F::SizeHint>::new();
-   // Format the keys and pass the resulting byte slices to the callback
-   f(buf.fmt_within(key))
-}
diff --git a/attic/kv/src/ttl.rs b/attic/kv/src/ttl.rs
deleted file mode 100644
index 4e03ad5ed..000000000
--- a/attic/kv/src/ttl.rs
+++ /dev/null
@@ -1,459 +0,0 @@
-use std::{
-   collections::BTreeMap,
-   ops::DerefMut,
-   sync::{
-      Arc,
-      atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
-   },
-   time::{Duration, SystemTime, UNIX_EPOCH},
-};
-
-use bytes::Bytes;
-use futures::{FutureExt, future::BoxFuture};
-use parking_lot::Mutex;
-use smol_str::SmolStr;
-use tokio::sync::Notify;
-
-use super::{Operator, Options, error::Result, traits};
-use crate::{IVec, IVecs, Write, WriteBatch as _};
-
-/// Represents a key in the expiry database.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Default)]
-#[repr(C, packed)]
-struct ExpiryKey {
-   time: u64,
-   seq: u32,
-}
-
-impl ExpiryKey {
-   const LEN: usize = 12;
-
-   #[inline]
-   const fn new(time: u64, seq: u32) -> Self {
-      Self { time, seq }
-   }
-
-   #[inline]
-   fn to_bytes(self) -> [u8; Self::LEN] {
-      let mut out = [0u8; Self::LEN];
-      out[..8].copy_from_slice(&self.time.to_be_bytes());
-      out[8..].copy_from_slice(&self.seq.to_be_bytes());
-      out
-   }
-
-   #[inline]
-   fn from_bytes(b: &[u8]) -> Option<Self> {
-      (b.len() == Self::LEN).then(|| Self {
-         time: u64::from_be_bytes(*b.first_chunk().unwrap()),
-         seq: u32::from_be_bytes(*b.last_chunk().unwrap()),
-      })
-   }
-}
-
-struct GcTimer {
-   /// Timestamp (in millis since Unix epoch) for the next scheduled GC run.
-   time: AtomicU64,
-   /// Notifies the background GC task that the schedule has been updated and
-   /// it may need to wake up sooner than previously planned.
-   signal: Notify,
-}
-
-impl GcTimer {
-   fn new() -> Arc<Self> {
-      Arc::new(Self {
-         time: AtomicU64::new(u64::MAX),
-         signal: Notify::new(),
-      })
-   }
-}
-
-/// Internal structure managing TTL metadata.
-struct ExpiryDb<S: traits::Store> {
-   ttl_store: S,
-   dst_store: S,
-   sequence: AtomicU32,
-   mem_index: Arc<parking_lot::RwLock<BTreeMap<Bytes, ExpiryKey>>>,
-   timer: Arc<GcTimer>,
-   gc_started: AtomicBool,
-   gc_future: Mutex<Option<BoxFuture<'static, ()>>>,
-}
-
-impl<S: traits::Store> ExpiryDb<S> {
-   const MAX_GC_IDLE: Duration = Duration::from_secs(30);
-
-   fn new(ttl_store: S, dst_store: S) -> Arc<Self> {
-      let timer = GcTimer::new();
-      let mem_index = Arc::new(parking_lot::RwLock::new(BTreeMap::new()));
-      let now = Self::now();
-      {
-         let mut to_remove = Vec::new();
-         for item in ttl_store.iter(traits::IterMode::forward()) {
-            let (ttl_key, key) = item.expect("invalid expiry entry");
-            let exp = ExpiryKey::from_bytes(ttl_key.as_ref()).expect("invalid expiry key");
-            if exp.time < now {
-               to_remove.push((ttl_key, key));
-            } else {
-               mem_index.write().insert(key, exp);
-            }
-         }
-         for (ttl, key) in to_remove {
-            let _ = ttl_store.delete(&ttl);
-            let _ = dst_store.delete(&key);
-         }
-      }
-      let me = Arc::new(Self {
-         ttl_store,
-         dst_store,
-         sequence: AtomicU32::new(0),
-         timer,
-         mem_index,
-         gc_started: AtomicBool::new(false),
-         gc_future: Mutex::new(None),
-      });
-
-      *me.gc_future.lock() = Some({
-         let weak = Arc::downgrade(&me);
-         let notify = me.timer.clone();
-         async move {
-            loop {
-               tokio::task::yield_now().await;
-
-               // Wait until either the next GC deadline is reached or we are
-               // explicitly woken up because the deadline was moved closer.
-               loop {
-                  let now = Self::now();
-                  let t = notify.time.load(Ordering::Relaxed);
-
-                  // Compute how long we should sleep (never exceeding the
-                  // maximum idle window).
-                  let mut idle = Duration::from_millis(t.saturating_sub(now));
-                  if idle > Self::MAX_GC_IDLE {
-                     idle = Self::MAX_GC_IDLE;
-                  }
-
-                  _ = tokio::time::timeout(idle, notify.signal.notified()).await;
-
-                  // If the scheduled time has elapsed break so GC is run.
-                  if notify.time.load(Ordering::Relaxed) <= Self::now() {
-                     break;
-                  }
-               }
-
-               let Some(db) = weak.upgrade() else { break };
-               let _ = db.gc();
-            }
-         }
-         .boxed()
-      });
-
-      me
-   }
-
-   fn gc(&self) -> Result<usize> {
-      let now = Self::now();
-      let mut next = now + Self::MAX_GC_IDLE.as_millis() as u64;
-      let mut expired = Vec::new();
-      for item in self.ttl_store.iter(traits::IterMode::forward()) {
-         let (ttl_key, key): (Bytes, Bytes) = item?;
-         let exp = ExpiryKey::from_bytes(ttl_key.as_ref()).expect("invalid expiry key");
-         if exp.time > now {
-            next = if next < exp.time { next } else { exp.time };
-            break;
-         }
-         expired.push((ttl_key, key, exp));
-      }
-
-      let mut removed = 0;
-      {
-         let mut mem_index = self.mem_index.write();
-         for (ttl_key, key, exp) in &expired {
-            if let Some(entry) = mem_index.get(key) {
-               if *entry == *exp {
-                  mem_index.remove(key);
-               } else {
-                  continue;
-               }
-            }
-            self.dst_store.delete(key)?;
-            self.ttl_store.delete(ttl_key)?;
-            removed += 1;
-         }
-      }
-
-      let prev = self.timer.time.swap(next, Ordering::AcqRel);
-      if next < prev {
-         self.timer.signal.notify_one();
-      }
-      Ok(removed)
-   }
-
-   fn now() -> u64 {
-      SystemTime::now()
-         .duration_since(UNIX_EPOCH)
-         .unwrap_or(Duration::ZERO)
-         .as_millis() as u64
-   }
-
-   fn remove(&self, key: &[u8]) -> Result<()> {
-      if let Some(exp) = self.mem_index.write().remove(key) {
-         self.ttl_store.delete(&exp.to_bytes())?;
-      }
-      Ok(())
-   }
-
-   fn remove_range(&self, from: &[u8], to: &[u8]) -> Result<()> {
-      let mut keys = Vec::new();
-      {
-         let idx = self.mem_index.read();
-         let mut from = idx.lower_bound(std::ops::Bound::Included(from));
-         while let Some((k, exp)) = from.next() {
-            if k.as_ref() >= to {
-               break;
-            }
-            keys.push((k.clone(), *exp));
-         }
-      }
-
-      let mut idx = self.mem_index.write();
-      let batch = self.ttl_store.batch();
-      for (k, exp) in keys {
-         batch.delete(&exp.to_bytes());
-         idx.remove(k.as_ref());
-      }
-
-      batch.commit()?;
-
-      Ok(())
-   }
-
-   fn insert(&self, key: Bytes, ttl: u64, while_locked: impl FnOnce() -> Result<()>) -> Result<()> {
-      if !self.gc_started.load(Ordering::SeqCst) {
-         self.start_gc();
-      }
-      let exp_key = ExpiryKey::new(ttl, self.sequence.fetch_add(1, Ordering::SeqCst));
-      self.ttl_store.put(&exp_key.to_bytes(), &key)?;
-      while_locked()?;
-      self.mem_index.write().insert(key, exp_key);
-
-      let prev = self.timer.time.fetch_min(ttl, Ordering::AcqRel);
-      if ttl < prev {
-         self.timer.signal.notify_one();
-      }
-      Ok(())
-   }
-
-   #[cold]
-   fn start_gc(&self) {
-      if !self.gc_started.swap(true, Ordering::SeqCst) {
-         let mut lock = self.gc_future.lock();
-         let opt: &mut Option<_> = lock.deref_mut();
-         if let Some(task) = opt.take() {
-            tokio::spawn(task);
-         }
-      }
-   }
-
-   fn clear(&self) -> Result<()> {
-      self.ttl_store.clear()?;
-      self.mem_index.write().clear();
-      self.timer.time.store(u64::MAX, Ordering::Release);
-      self.timer.signal.notify_one();
-      Ok(())
-   }
-}
-
-/// TTL-enabled key-value store wrapper.
-#[derive(Clone, derive_more::Debug)]
-pub struct TtlDb<S: traits::Store> {
-   inner: S,
-   #[debug(skip)]
-   ttl: Arc<ExpiryDb<S>>,
-}
-
-impl<S: traits::Store> TtlDb<S> {
-   pub fn new(inner: S) -> Result<Self> {
-      let ttl_store = inner.child("$ttl", *inner.options())?;
-      let ttl = ExpiryDb::new(ttl_store, inner.clone());
-      Ok(Self { inner, ttl })
-   }
-
-   fn check_expiry(&self, key: &[u8]) -> Result<()> {
-      if let Some(exp) = self.ttl.mem_index.read().get(key).cloned()
-         && exp.time <= ExpiryDb::<S>::now()
-      {
-         self.inner.delete(key)?;
-         self.ttl.remove(key)?;
-      }
-      Ok(())
-   }
-
-   pub fn put_ttl(&self, key: &[u8], value: &[u8], ttl: Duration) -> Result<()> {
-      let expire = ExpiryDb::<S>::now() + ttl.as_millis() as u64;
-      self.ttl.insert(Bytes::copy_from_slice(key), expire, || {
-         self.inner.put(key, value)
-      })
-   }
-
-   pub fn purge_expired(&self) -> Result<usize> {
-      self.ttl.gc()
-   }
-}
-
-impl<S: traits::Store> traits::View for TtlDb<S> {
-   type Iter<'a>
-      = TtlIter<'a, S>
-   where
-      S: 'a;
-
-   fn get(&self, key: &[u8]) -> Result<Option<IVec<'_>>> {
-      self.check_expiry(key)?;
-      self.inner.get(key)
-   }
-
-   fn contains(&self, key: &[u8]) -> Result<bool> {
-      self.check_expiry(key)?;
-      self.inner.contains(key)
-   }
-
-   fn get_many(&self, keys: impl IntoIterator<Item: AsRef<[u8]>>) -> Result<IVecs<'_>> {
-      self.inner.get_many(keys)
-   }
-
-   fn iter<'a>(&'a self, mode: traits::IterMode<'_>) -> Self::Iter<'a> {
-      TtlIter {
-         inner: self.inner.iter(mode),
-         parent: self,
-      }
-   }
-}
-
-pub struct TtlIter<'a, S: traits::Store> {
-   inner: S::Iter<'a>,
-   parent: &'a TtlDb<S>,
-}
-
-impl<'a, S: traits::Store> Iterator for TtlIter<'a, S> {
-   type Item = Result<(Bytes, Bytes)>;
-   fn next(&mut self) -> Option<Self::Item> {
-      for item in self.inner.by_ref() {
-         match item {
-            Ok((k, v)) => {
-               if let Err(e) = self.parent.check_expiry(k.as_ref()) {
-                  return Some(Err(e));
-               }
-               if let Some(exp) = self.parent.ttl.mem_index.read().get(k.as_ref()).cloned()
-                  && exp.time <= ExpiryDb::<S>::now()
-               {
-                  continue;
-               }
-               return Some(Ok((k, v)));
-            },
-            Err(e) => return Some(Err(e)),
-         }
-      }
-      None
-   }
-}
-
-impl<S: traits::Store> traits::Write for TtlDb<S> {
-   type Result = Result<()>;
-
-   fn put(&self, key: &[u8], value: &[u8]) -> Self::Result {
-      self.ttl.remove(key)?;
-      self.inner.put(key, value)
-   }
-
-   fn delete(&self, key: &[u8]) -> Self::Result {
-      self.ttl.remove(key)?;
-      self.inner.delete(key)
-   }
-   fn update(&self, key: &[u8], op: &dyn Operator) -> Self::Result {
-      self.inner.update(key, op)
-   }
-   fn delete_range(&self, from: &[u8], to: &[u8]) -> Self::Result {
-      let batch = self.inner.batch();
-      batch.delete_range(from, to);
-      self.ttl.remove_range(from, to)?;
-      batch.commit()?;
-      Ok(())
-   }
-}
-
-impl<S: traits::Store> traits::Store for TtlDb<S> {
-   type WriteBatch<'a>
-      = S::WriteBatch<'a>
-   where
-      S: 'a;
-   type Snapshot<'a>
-      = S::Snapshot<'a>
-   where
-      S: 'a;
-
-   fn batch(&self) -> Self::WriteBatch<'_> {
-      self.inner.batch()
-   }
-
-   fn namespace(&self) -> &str {
-      self.inner.namespace()
-   }
-
-   fn child(&self, name: &str, opts: traits::Options) -> Result<Self> {
-      let child = self.inner.child(name, opts)?;
-      TtlDb::new(child)
-   }
-
-   fn children(&self) -> Vec<SmolStr> {
-      self.inner.children()
-   }
-
-   fn clear(&self) -> Result<()> {
-      self.ttl.clear()?;
-      self.inner.clear()
-   }
-
-   fn flush(&self) -> Result<()> {
-      self.inner.flush()
-   }
-
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-      self.inner.snapshot()
-   }
-
-   fn estimate_size(&self) -> Option<u64> {
-      self.inner.estimate_size()
-   }
-
-   fn options(&self) -> &Options {
-      self.inner.options()
-   }
-}
-
-/// Extension trait to add TTL functionality to any store.
-pub trait TtlExt: traits::Store + Sized {
-   fn with_ttl(self) -> Result<TtlDb<Self>> {
-      TtlDb::new(self)
-   }
-}
-
-impl<T: traits::Store> TtlExt for T {}
-
-#[cfg(test)]
-mod tests {
-   use super::*;
-   use crate::{Store, View, memorydb::MemoryDb};
-
-   fn test_ttl<S: Store>(store: &TtlDb<S>) -> Result<()> {
-      store.put_ttl(b"ephemeral", b"val", std::time::Duration::from_millis(10))?;
-      assert!(store.contains(b"ephemeral")?);
-      std::thread::sleep(std::time::Duration::from_millis(20));
-      store.purge_expired()?;
-      assert!(!store.contains(b"ephemeral")?);
-      Ok(())
-   }
-
-   #[tokio::test]
-   async fn test_ttl_memorydb() {
-      let store = MemoryDb::new().with_ttl().unwrap();
-      test_ttl(&store).unwrap();
-   }
-}
diff --git a/attic/kv/src/typed.rs b/attic/kv/src/typed.rs
deleted file mode 100644
index a499ef870..000000000
--- a/attic/kv/src/typed.rs
+++ /dev/null
@@ -1,746 +0,0 @@
-use std::borrow::Borrow;
-
-use smol_str::SmolStr;
-
-use super::{
-   error::{Error, Result},
-   traits, IterMode,
-};
-use crate::Options;
-
-pub trait TypedEntity {
-   /// The type of the underlying implementation
-   type Entity;
-
-   /// Converts to the underlying implementation
-   fn into_inner(self) -> Self::Entity;
-
-   /// Returns a reference to the underlying implementation
-   fn inner(&self) -> &Self::Entity;
-}
-
-pub trait TypedWriteBatch<'a, K: ?Sized, V: ?Sized>:
-   TypedEntity<Entity: traits::WriteBatch<'a>>
-{
-   /// Sets the value for the given key
-   fn put(&mut self, key: impl Borrow<K>, value: impl Borrow<V>) -> &mut Self;
-
-   /// Deletes the value for the given key
-   fn delete(&mut self, key: impl Borrow<K>) -> &mut Self;
-
-   /// Writes all batched operations to the database
-   fn write(&mut self) -> Result<()>;
-}
-
-pub trait TypedView<K: ToOwned + ?Sized, V: ToOwned + ?Sized>:
-   TypedEntity<Entity: traits::View>
-{
-   /// Gets the value for the given key
-   fn get(&self, key: impl Borrow<K>) -> Result<Option<V::Owned>>;
-
-   /// Gets the values for multiple keys at once
-   fn get_many<'a>(
-      &'a self,
-      keys: impl IntoIterator<Item: AsRef<K>>,
-   ) -> Result<ser::TypedIVecs<'a, V::Owned>>;
-
-   /// Returns true if the key exists in the key-value store
-   fn contains(&self, key: impl Borrow<K>) -> Result<bool>;
-
-   /// Iterates over key-value pairs in the key-value store
-   fn iter<'a>(&'a self, mode: IterMode)
-      -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a;
-
-   /// Scans all keys with the given prefix.
-   ///
-   /// This is a convenience method that uses `iter` to scan all keys with the
-   /// given prefix.
-   fn prefix_scan<'a>(
-      &'a self,
-      prefix: impl Borrow<K>,
-      mode: IterMode<'a>,
-   ) -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a;
-}
-
-pub trait TypedStore<K: ToOwned + ?Sized, V: ToOwned + ?Sized>:
-   TypedView<K, V> + Clone + Send + TypedEntity<Entity: traits::Store>
-{
-   /// The type of write batch used by this key-value store
-   type WriteBatch<'a>: TypedWriteBatch<'a, K, V>
-   where
-      Self: 'a,
-      K: 'a,
-      V: 'a;
-
-   /// The type of snapshot used by this key-value store
-   type Snapshot<'a>: TypedView<K, V> + 'a
-   where
-      Self: 'a,
-      K: 'a,
-      V: 'a;
-
-   /// Creates a new write batch for this key-value store
-   fn batch<'a>(&'a self) -> Self::WriteBatch<'a>;
-
-   /// Returns the namespace of this key-value store
-   fn namespace(&self) -> &str;
-
-   /// Creates a child key-value store with the given name
-   fn child(&self, name: &str, opts: Options) -> Result<Self>;
-
-   /// Returns an iterator over each child key-value store
-   fn children(&self) -> Vec<SmolStr>;
-
-   /// Sets the value for the given key
-   fn put(&self, key: impl Borrow<K>, value: impl Borrow<V>) -> Result<()>;
-
-   /// Deletes the value for the given key
-   fn delete(&self, key: impl Borrow<K>) -> Result<()>;
-
-   /// Clears all data in this key-value store
-   fn clear(&mut self) -> Result<()>;
-
-   /// Creates a snapshot of the key-value store at the current point in time
-   fn snapshot<'b>(&'b self) -> Self::Snapshot<'b>;
-}
-
-pub mod ser {
-   //! Module ser implements typed store interfaces using serde for
-   //! serialization and deserialization.
-
-   use std::{borrow::Borrow, fmt, marker::PhantomData};
-
-   use derive_where::derive_where;
-   use smol_str::SmolStr;
-   use tetra_core::alloc::{quickbuf, ranges::SmallRangeList};
-
-   use super::*;
-   use crate::{IVecs, IVecsIter, Options};
-
-   const SELF_DESCRIBING: bool = false;
-
-   pub fn encode<T: ?Sized + serde::Serialize>(
-      sbuf: &mut quickbuf::StackBuffer,
-      value: &T,
-   ) -> Result<std::ops::Range<usize>, Error> {
-      let beg = sbuf.len();
-      if SELF_DESCRIBING {
-         serde_cbor::to_writer(&mut *sbuf, &value)?;
-      } else {
-         postcard::to_extend(value, &mut *sbuf)?;
-      }
-      Ok(beg..sbuf.len())
-   }
-
-   pub fn decode<'de, T: serde::de::Deserialize<'de>>(data: &'de [u8]) -> Result<T, Error> {
-      if SELF_DESCRIBING {
-         Ok(serde_cbor::from_slice(data)?)
-      } else {
-         Ok(postcard::from_bytes(data)?)
-      }
-   }
-
-   // --- Into Traits ---
-
-   pub trait IntoTypedWriteBatch {
-      type Output<K, V>
-      where
-         K: serde::Serialize,
-         V: serde::Serialize;
-      fn into_typed<K: serde::Serialize, V: serde::Serialize>(self) -> Self::Output<K, V>;
-   }
-
-   impl<'a, T: traits::WriteBatch<'a>> IntoTypedWriteBatch for T {
-      type Output<K, V>
-         = WriteBatch<K, V, T>
-      where
-         K: serde::Serialize,
-         V: serde::Serialize;
-
-      fn into_typed<K: serde::Serialize, V: serde::Serialize>(self) -> Self::Output<K, V> {
-         WriteBatch {
-            inner: self,
-            err: None,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   pub trait IntoTypedView {
-      type Output<K, V>
-      where
-         K: serde::Serialize,
-         V: serde::Serialize;
-      fn into_typed<K: serde::Serialize, V: serde::Serialize>(self) -> Self::Output<K, V>;
-   }
-
-   impl<T: traits::View> IntoTypedView for T {
-      type Output<K, V>
-         = View<K, V, T>
-      where
-         K: serde::Serialize,
-         V: serde::Serialize;
-
-      fn into_typed<K: serde::Serialize, V: serde::Serialize>(self) -> Self::Output<K, V> {
-         View {
-            inner: self,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   pub trait IntoTypedStore {
-      type Output<K, V>
-      where
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized;
-      fn into_typed<
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-      >(
-         self,
-      ) -> Self::Output<K, V>;
-   }
-
-   impl<T: traits::Store> IntoTypedStore for T {
-      type Output<K, V>
-         = Store<K, V, T>
-      where
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized;
-
-      fn into_typed<
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-      >(
-         self,
-      ) -> Self::Output<K, V> {
-         Store {
-            inner: self,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   // --- Wrapper Structs Impls ---
-
-   pub struct WriteBatch<K: ?Sized, V: ?Sized, I> {
-      inner: I,
-      err: Option<Error>,
-      _marker: PhantomData<fn(K, V)>,
-   }
-
-   impl<K: ?Sized, V: ?Sized, I> From<I> for WriteBatch<K, V, I> {
-      fn from(inner: I) -> Self {
-         Self {
-            inner,
-            err: None,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   impl<'a, K: ?Sized, V: ?Sized, I: traits::WriteBatch<'a> + fmt::Debug> fmt::Debug
-      for WriteBatch<K, V, I>
-   {
-      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-         f.debug_struct(
-            format!(
-               "WriteBatch<{}, {}>",
-               std::any::type_name::<K>(),
-               std::any::type_name::<V>()
-            )
-            .as_str(),
-         )
-         .field("inner", &self.inner)
-         .finish()
-      }
-   }
-
-   /// A typed value slice wrapper for a key-value store
-   #[repr(transparent)]
-   pub struct TypedIVecs<'a, V: ?Sized> {
-      inner: IVecs<'a>,
-      _marker: PhantomData<fn(&'a ()) -> V>,
-   }
-
-   impl<'a, V: ?Sized> From<IVecs<'a>> for TypedIVecs<'a, V> {
-      fn from(inner: IVecs<'a>) -> Self {
-         Self {
-            inner,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   impl<'a, V: ?Sized + fmt::Debug> fmt::Debug for TypedIVecs<'a, V> {
-      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-         f.debug_struct(format!("TypedIVecs<{}>", std::any::type_name::<V>()).as_str())
-            .field("inner", &self.inner)
-            .finish()
-      }
-   }
-   impl<'a, V: serde::de::DeserializeOwned> TypedIVecs<'a, V> {
-      pub fn get(&self, index: usize) -> Result<Option<V>> {
-         match self.inner.get(index)? {
-            Some(bytes) => match decode(bytes) {
-               Ok(value) => Ok(Some(value)),
-               Err(err) => Err(err),
-            },
-            None => Ok(None),
-         }
-      }
-
-      pub fn len(&self) -> usize {
-         self.inner.len()
-      }
-
-      pub fn is_empty(&self) -> bool {
-         self.inner.is_empty()
-      }
-   }
-
-   impl<'a, V: serde::de::DeserializeOwned> IntoIterator for TypedIVecs<'a, V> {
-      type Item = Result<Option<V>>;
-      type IntoIter = TypedIVecsIter<'a, V>;
-
-      fn into_iter(self) -> Self::IntoIter {
-         TypedIVecsIter {
-            inner: self.inner.into_iter(),
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   /// Iterator for a typed value slice
-   #[derive(derive_more::From)]
-   #[repr(transparent)]
-   pub struct TypedIVecsIter<'a, V: ?Sized> {
-      inner: IVecsIter<'a>,
-      #[from(ignore)]
-      _marker: PhantomData<fn(&'a ()) -> V>,
-   }
-
-   impl<'a, V: ?Sized + fmt::Debug> fmt::Debug for TypedIVecsIter<'a, V> {
-      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-         f.debug_struct(format!("TypedIVecsIter<{}>", std::any::type_name::<V>()).as_str())
-            .field("inner", &self.inner)
-            .finish()
-      }
-   }
-
-   impl<'a, V: serde::de::DeserializeOwned> Iterator for TypedIVecsIter<'a, V> {
-      type Item = Result<Option<V>>;
-
-      fn next(&mut self) -> Option<Self::Item> {
-         let r = self.inner.next()?;
-         let b = match r {
-            Ok(Some(bytes)) => bytes,
-            Ok(None) => return Some(Ok(None)),
-            Err(e) => return Some(Err(e)),
-         };
-         let v = match decode(b.as_ref()) {
-            Ok(value) => Ok(Some(value)),
-            Err(err) => Err(err),
-         };
-         Some(v)
-      }
-   }
-
-   /// A typed view wrapper for a key-value store
-   #[derive_where(Clone; I: Clone)]
-   #[repr(transparent)]
-   pub struct View<K: ?Sized, V: ?Sized, I: traits::View> {
-      inner: I,
-      _marker: PhantomData<fn(K, V)>,
-   }
-
-   impl<K: ?Sized, V: ?Sized, I: traits::View> From<I> for View<K, V, I> {
-      fn from(inner: I) -> Self {
-         Self {
-            inner,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   impl<K: ?Sized, V: ?Sized, I: traits::View + fmt::Debug> fmt::Debug for View<K, V, I> {
-      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-         f.debug_struct(
-            format!(
-               "View<{}, {}>",
-               std::any::type_name::<K>(),
-               std::any::type_name::<V>()
-            )
-            .as_str(),
-         )
-         .field("inner", &self.inner)
-         .finish()
-      }
-   }
-
-   #[derive_where(Clone; I: Clone)]
-   #[repr(transparent)]
-   pub struct Store<K: ?Sized, V: ?Sized, I: traits::Store> {
-      inner: I,
-      _marker: PhantomData<fn(K, V)>,
-   }
-
-   impl<K: ?Sized, V: ?Sized, I: traits::Store> From<I> for Store<K, V, I> {
-      fn from(inner: I) -> Self {
-         Self {
-            inner,
-            _marker: PhantomData,
-         }
-      }
-   }
-
-   impl<K: ?Sized, V: ?Sized, I: traits::Store + fmt::Debug> fmt::Debug for Store<K, V, I> {
-      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-         f.debug_struct(
-            format!(
-               "Store<{}, {}>",
-               std::any::type_name::<K>(),
-               std::any::type_name::<V>()
-            )
-            .as_str(),
-         )
-         .field("inner", &self.inner)
-         .finish()
-      }
-   }
-
-   // --- Actual Trait Implementations ---
-
-   impl<'a, K: ?Sized, V: ?Sized, I: traits::WriteBatch<'a>> TypedEntity for WriteBatch<K, V, I> {
-      type Entity = I;
-      fn into_inner(self) -> Self::Entity {
-         self.inner
-      }
-      fn inner(&self) -> &Self::Entity {
-         &self.inner
-      }
-   }
-   impl<K: ?Sized, V: ?Sized, I: traits::View> TypedEntity for View<K, V, I> {
-      type Entity = I;
-      fn into_inner(self) -> Self::Entity {
-         self.inner
-      }
-      fn inner(&self) -> &Self::Entity {
-         &self.inner
-      }
-   }
-   impl<K: ?Sized, V: ?Sized, I: traits::Store> TypedEntity for Store<K, V, I> {
-      type Entity = I;
-      fn into_inner(self) -> Self::Entity {
-         self.inner
-      }
-      fn inner(&self) -> &Self::Entity {
-         &self.inner
-      }
-   }
-
-   impl<
-         'a,
-         K: serde::Serialize + ?Sized,
-         V: serde::Serialize + ?Sized,
-         I: traits::WriteBatch<'a>,
-      > TypedWriteBatch<'a, K, V> for WriteBatch<K, V, I>
-   {
-      fn put(&mut self, key: impl Borrow<K>, value: impl Borrow<V>) -> &mut Self {
-         if self.err.is_some() {
-            return self;
-         }
-         quickbuf::with(move |buf| {
-            let kv = encode(buf, key.borrow())
-               .and_then(|kr| encode(buf, value.borrow()).map(|vr| (kr, vr)));
-            let (kr, vr) = match kv {
-               Ok((kr, vr)) => (kr, vr),
-               Err(e) => {
-                  self.err = Some(e);
-                  return self;
-               },
-            };
-            self.inner.put(&buf[kr], &buf[vr]);
-            self
-         })
-      }
-      fn delete(&mut self, key: impl Borrow<K>) -> &mut Self {
-         if self.err.is_some() {
-            return self;
-         }
-         quickbuf::with(move |buf| {
-            let kr = match encode(buf, key.borrow()) {
-               Ok(kr) => kr,
-               Err(e) => {
-                  self.err = Some(e);
-                  return self;
-               },
-            };
-            self.inner.delete(&buf[kr]);
-            self
-         })
-      }
-      fn write(&mut self) -> Result<()> {
-         if let Some(err) = self.err.take() {
-            return Err(err);
-         }
-         self.inner.commit()
-      }
-   }
-
-   impl<
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         I: traits::View,
-      > TypedView<K, V> for View<K, V, I>
-   {
-      fn get(&self, key: impl Borrow<K>) -> Result<Option<V::Owned>> {
-         quickbuf::with(move |buf| -> Result<_> {
-            let kr = encode(buf, key.borrow())?;
-            self
-               .inner
-               .get(&buf[kr])?
-               .map(|v| decode(v.as_ref()))
-               .transpose()
-         })
-      }
-
-      fn contains(&self, key: impl Borrow<K>) -> Result<bool> {
-         quickbuf::with(move |buf| {
-            let kr = encode(buf, key.borrow())?;
-            self.inner.contains(&buf[kr])
-         })
-      }
-
-      fn get_many<'a>(
-         &'a self,
-         keys: impl IntoIterator<Item: AsRef<K>>,
-      ) -> Result<ser::TypedIVecs<'a, V::Owned>> {
-         Ok(ser::TypedIVecs {
-            _marker: PhantomData,
-            inner: quickbuf::with(move |buf| -> Result<_> {
-               self.inner.get_many(
-                  keys
-                     .into_iter()
-                     .map(|k| encode(buf, k.as_ref()))
-                     .collect::<Result<Vec<_>>>()?
-                     .into_iter()
-                     .map(|kr| &buf[kr]),
-               )
-            })?,
-         })
-      }
-
-      fn iter<'a>(
-         &'a self,
-         mode: traits::IterMode,
-      ) -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a {
-         self.inner.iter(mode).map(|result| {
-            result.and_then(|(k, v)| {
-               let key = decode(k.as_ref())?;
-               let value = decode(v.as_ref())?;
-               Ok((key, value))
-            })
-         })
-      }
-
-      fn prefix_scan<'a>(
-         &'a self,
-         prefix: impl Borrow<K>,
-         mode: traits::IterMode<'a>,
-      ) -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a {
-         enum MaybeErrIter<I> {
-            Ok(I),
-            Err(Option<Error>),
-         }
-         impl<I: Iterator<Item = Result<R>>, R> Iterator for MaybeErrIter<I> {
-            type Item = Result<R>;
-            fn next(&mut self) -> Option<Self::Item> {
-               match self {
-                  Self::Ok(iter) => iter.next(),
-                  Self::Err(e) => e.take().map(|e| Err(e)),
-               }
-            }
-         }
-
-         let kbuf = quickbuf::with(|buf| -> Result<Box<[u8]>> {
-            let kr = encode(buf, prefix.borrow())?;
-            Ok(buf[kr].into())
-         });
-
-         match kbuf {
-            Err(e) => MaybeErrIter::Err(Some(e)),
-            Ok(v) => MaybeErrIter::Ok(self.inner.prefix_scan(v.as_ref(), mode).map(
-               |r| -> Result<(K::Owned, V::Owned)> {
-                  let (k, v) = r?;
-                  let key = decode(k.as_ref())?;
-                  let value = decode(v.as_ref())?;
-                  Ok((key, value))
-               },
-            )),
-         }
-      }
-   }
-
-   impl<
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         I: traits::Store,
-      > TypedView<K, V> for Store<K, V, I>
-   {
-      fn get(&self, key: impl Borrow<K>) -> Result<Option<V::Owned>> {
-         quickbuf::with(move |buf| {
-            let kr = encode(buf, key.borrow())?;
-            self
-               .inner
-               .get(&buf[kr])?
-               .map(|v| decode(v.as_ref()))
-               .transpose()
-         })
-      }
-
-      fn contains(&self, key: impl Borrow<K>) -> Result<bool> {
-         quickbuf::with(move |buf| {
-            let kr = encode(buf, key.borrow())?;
-            self.inner.contains(&buf[kr])
-         })
-      }
-
-      fn get_many<'a>(
-         &'a self,
-         keys: impl IntoIterator<Item: AsRef<K>>,
-      ) -> Result<ser::TypedIVecs<'a, V::Owned>> {
-         Ok(ser::TypedIVecs {
-            _marker: PhantomData,
-            inner: quickbuf::with(move |buf| -> Result<_> {
-               let mut ranges = SmallRangeList::<32>::new();
-               for key in keys {
-                  let kr = encode(buf, key.as_ref())?;
-                  ranges.push_range(kr);
-               }
-               self.inner.get_many(ranges.into_ranges().deref(&buf[..]))
-            })?,
-         })
-      }
-
-      fn iter<'a>(
-         &'a self,
-         mode: traits::IterMode,
-      ) -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a {
-         self.inner.iter(mode).map(|result| {
-            result.and_then(|(k, v)| {
-               let key = decode(k.as_ref())?;
-               let value = decode(v.as_ref())?;
-               Ok((key, value))
-            })
-         })
-      }
-
-      fn prefix_scan<'a>(
-         &'a self,
-         prefix: impl Borrow<K>,
-         mode: traits::IterMode<'a>,
-      ) -> impl Iterator<Item = Result<(K::Owned, V::Owned)>> + 'a {
-         enum MaybeErrIter<I> {
-            Ok(I),
-            Err(Option<Error>),
-         }
-         impl<I: Iterator<Item = Result<R>>, R> Iterator for MaybeErrIter<I> {
-            type Item = Result<R>;
-            fn next(&mut self) -> Option<Self::Item> {
-               match self {
-                  Self::Ok(iter) => iter.next(),
-                  Self::Err(e) => e.take().map(|e| Err(e)),
-               }
-            }
-         }
-
-         let kbuf = quickbuf::with(|buf| -> Result<Box<[u8]>> {
-            let kr = encode(buf, prefix.borrow())?;
-            Ok(buf[kr].into())
-         });
-
-         match kbuf {
-            Err(e) => MaybeErrIter::Err(Some(e)),
-            Ok(v) => MaybeErrIter::Ok(self.inner.prefix_scan(v.as_ref(), mode).map(
-               |r| -> Result<(K::Owned, V::Owned)> {
-                  let (k, v) = r?;
-                  let key = decode(k.as_ref())?;
-                  let value = decode(v.as_ref())?;
-                  Ok((key, value))
-               },
-            )),
-         }
-      }
-   }
-
-   impl<
-         K: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         V: serde::Serialize + ToOwned<Owned: serde::de::DeserializeOwned> + ?Sized,
-         I: traits::Store,
-      > TypedStore<K, V> for Store<K, V, I>
-   {
-      type WriteBatch<'a>
-         = WriteBatch<K, V, I::WriteBatch<'a>>
-      where
-         Self: 'a,
-         K: 'a,
-         V: 'a;
-      type Snapshot<'a>
-         = View<K, V, I::Snapshot<'a>>
-      where
-         Self: 'a,
-         K: 'a,
-         V: 'a;
-
-      fn batch<'a>(&'a self) -> Self::WriteBatch<'a> {
-         WriteBatch {
-            inner: self.inner.batch(),
-            err: None,
-            _marker: PhantomData,
-         }
-      }
-
-      fn namespace(&self) -> &str {
-         self.inner.namespace()
-      }
-
-      fn child(&self, name: &str, opts: Options) -> Result<Self> {
-         Ok(Store {
-            inner: self.inner.child(name, opts)?,
-            _marker: PhantomData,
-         })
-      }
-
-      fn children(&self) -> Vec<SmolStr> {
-         self.inner.children()
-      }
-
-      fn put(&self, key: impl Borrow<K>, value: impl Borrow<V>) -> Result<()> {
-         quickbuf::with(move |buf| {
-            let kr = encode(buf, key.borrow())?;
-            let vr = encode(buf, value.borrow())?;
-            self.inner.put(&buf[kr], &buf[vr])
-         })
-      }
-
-      fn delete(&self, key: impl Borrow<K>) -> Result<()> {
-         quickbuf::with(move |buf| {
-            let kr = encode(buf, key.borrow())?;
-            self.inner.delete(&buf[kr])
-         })
-      }
-
-      fn clear(&mut self) -> Result<()> {
-         self.inner.clear()
-      }
-
-      fn snapshot<'b>(&'b self) -> Self::Snapshot<'b> {
-         View {
-            inner: self.inner.snapshot(),
-            _marker: PhantomData,
-         }
-      }
-   }
-}
diff --git a/attic/net/http/client.rs b/attic/net/http/client.rs
deleted file mode 100644
index c114a9653..000000000
--- a/attic/net/http/client.rs
+++ /dev/null
@@ -1,912 +0,0 @@
-use std::{
-   fmt::Display,
-   mem,
-   sync::LazyLock,
-   time::{Duration, Instant},
-};
-
-use http::{HeaderMap, HeaderName, HeaderValue, Version, header, header::CONTENT_TYPE};
-use reqwest::{IntoUrl, Method, Request, ResponseBuilderExt, multipart};
-use serde::Serialize;
-use smol_str::{SmolStr, ToSmolStr};
-use tower::ServiceExt;
-
-use super::{server::RouterTable, sse, upgrade, utils, ws};
-
-const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
-const MIN_TIMEOUT: Duration = Duration::from_millis(500);
-const MIN_RETRY_DELAY: Duration = Duration::from_millis(50);
-
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
-   /// Error when a request fails.
-   #[error(transparent)]
-   RequestFailed(#[from] reqwest::Error),
-   /// Error when a request times out.
-   #[error("Request timed out")]
-   LocalTimeout,
-   /// Error when the request built has already been constructed.
-   #[error("Request has already been constructed")]
-   RequestAlreadyBuilt,
-   /// Error when the request body cannot be serialized into a postcard.
-   #[error("Failed to serialize request body into postcard")]
-   Postcard(#[from] postcard::Error),
-   /// Error when the request body cannot be serialized into a JSON.
-   #[error("Failed to serialize request body into JSON")]
-   Json(#[from] serde_json::Error),
-   /// Error when a WebSocket connection fails.
-   #[error("WebSocket error: {0}")]
-   WebSocket(#[from] ws::Error),
-}
-pub type Result<T, E = Error> = std::result::Result<T, E>;
-
-/// [`Client`] is a wrapper around [`reqwest::Client`] which runs middleware on
-/// every request.
-#[derive(Clone, Debug, derive_more::From, derive_more::Into, derive_more::Constructor)]
-pub struct Client<'a> {
-   inner: reqwest::Client,
-   router: &'a RouterTable,
-}
-
-/// Default implementation for [`Client`] that clones from the global client.
-impl Default for Client<'_> {
-   fn default() -> Self {
-      Client::global().clone()
-   }
-}
-
-/// Static methods for accessing a global singleton [`Client`] instance.
-impl Client<'static> {
-   /// Returns a reference to the global [`Client`] instance.
-   ///
-   /// The global client is lazily initialized with default settings
-   /// and uses the global router table.
-   pub fn global() -> &'static Self {
-      static GLOBAL_CLIENT: LazyLock<Client<'static>> = LazyLock::new(|| Client {
-         inner: reqwest::Client::builder()
-            .build()
-            .unwrap_or_else(|_| reqwest::Client::new()),
-         router: RouterTable::global(),
-      });
-      &GLOBAL_CLIENT
-   }
-}
-
-impl<'a> Client<'a> {
-   /// Returns the inner [`reqwest::Client`].
-   pub const fn inner(&self) -> &reqwest::Client {
-      &self.inner
-   }
-
-   /// Replaces the inner [`reqwest::Client`] with a new one.
-   pub fn with_inner(mut self, inner: reqwest::Client) -> Self {
-      self.inner = inner;
-      self
-   }
-
-   /// Returns the [`RouterTable`] used by the client.
-   pub const fn router(&self) -> &RouterTable {
-      self.router
-   }
-
-   /// Replaces the [`RouterTable`] with a new one.
-   pub const fn with_router(mut self, router: &'a RouterTable) -> Self {
-      self.router = router;
-      self
-   }
-
-   /// Convenience method to make a [`Method::GET`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::GET, url)
-   }
-
-   /// Convenience method to make a [`Method::POST`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::POST, url)
-   }
-
-   /// Convenience method to make a [`Method::PUT`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::PUT, url)
-   }
-
-   /// Convenience method to make a [`Method::PATCH`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::PATCH, url)
-   }
-
-   /// Convenience method to make a [`Method::DELETE`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::DELETE, url)
-   }
-
-   /// Convenience method to make a [`Method::HEAD`] request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder<'a> {
-      self.request(Method::HEAD, url)
-   }
-
-   /// Convenience method to make a WebSocket request to a URL.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn websocket<U: IntoUrl>(&self, url: U) -> WebsocketBuilder<'a> {
-      self.request(Method::GET, url).into()
-   }
-
-   /// Convenience method to open a Server-Sent Events stream.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn sse<U: IntoUrl>(&self, url: U) -> SseBuilder<'a> {
-      self.request(Method::GET, url).into()
-   }
-
-   /// Start building a [`Request`] with the [`Method`] and [`reqwest::Url`].
-   ///
-   /// Returns a [`RequestBuilder`], which will allow setting headers and
-   /// the request body before sending.
-   ///
-   /// # Errors
-   ///
-   /// This method fails whenever the supplied [`reqwest::Url`] cannot be
-   /// parsed.
-   pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder<'a> {
-      RequestBuilder {
-         inner: Ok(self
-            .inner
-            .request(method, url)
-            .timeout(Duration::from_secs(10))),
-         extensions: http::Extensions::new(),
-         router: self.router,
-      }
-   }
-
-   /// Executes a [`Request`].
-   ///
-   /// A [`Request`] can be built manually with [`Request::new()`] or obtained
-   /// from a [`RequestBuilder`] with [`RequestBuilder::build()`].
-   ///
-   /// You should prefer to use the [`RequestBuilder`] and
-   /// [`RequestBuilder::send()`].
-   ///
-   /// # Errors
-   ///
-   /// This method fails if there was an error while sending request,
-   /// redirect loop was detected or redirect limit was exhausted.
-   pub async fn execute(&self, req: Request) -> Result<reqwest::Response> {
-      let mut ext = http::Extensions::new();
-      self.execute_with_extensions(req, &mut ext, false).await
-   }
-
-   /// Executes a [`Request`] with initial [`http::Extensions`].
-   ///
-   /// A [`Request`] can be built manually with [`Request::new()`] or obtained
-   /// from a [`RequestBuilder`] with [`RequestBuilder::build()`].
-   ///
-   /// You should prefer to use the [`RequestBuilder`] and
-   /// [`RequestBuilder::send()`].
-   ///
-   /// # Errors
-   ///
-   /// This method fails if there was an error while sending request,
-   /// redirect loop was detected or redirect limit was exhausted.
-   pub async fn execute_with_extensions(
-      &self,
-      mut req: Request,
-      ext: &mut http::Extensions,
-      is_streaming_response: bool,
-   ) -> Result<reqwest::Response> {
-      let timeout = *req.timeout().unwrap_or(&DEFAULT_TIMEOUT);
-      let deadline = Instant::now() + timeout;
-
-      // TODO: Implement P2P URL handling
-      // Check if this is a P2P URL
-      // if let Some(p2p) = &self.p2p {
-      //    if let Some(host) = req.url().host_str() {
-      //       if host.starts_with("p2p:") || iroh::NodeId::from_str(host).is_ok() {
-      //          // This is a P2P request
-      //          return self.execute_p2p(p2p, req, ext).await;
-      //       }
-      //    }
-      // }
-
-      let router = req
-         .url()
-         .host_str()
-         .and_then(|host| self.router.lookup(host));
-
-      if is_streaming_response {
-         *req.timeout_mut() = None;
-      }
-
-      let base_req = req.try_clone();
-      let base_ext = mem::take(ext);
-
-      let mut req = req;
-      loop {
-         let now = Instant::now();
-         let rem = deadline
-            .checked_duration_since(now)
-            .unwrap_or_default()
-            .max(MIN_TIMEOUT);
-
-         let mut cur_ext = base_ext.clone();
-         let mut resp = if let Some(router) = router.clone() {
-            passthrough_local(req, &mut cur_ext, router, rem).await?
-         } else {
-            if !is_streaming_response {
-               *req.timeout_mut() = Some(rem);
-            }
-            tokio::time::timeout(rem, self.inner.execute(req))
-               .await
-               .map_err(|_| Error::LocalTimeout)??
-         };
-
-         let status = resp.status();
-         if (status.is_client_error() || status.is_server_error())
-            && let Some(dur) = utils::retry_after(resp.headers())
-         {
-            let dur = dur.max(MIN_RETRY_DELAY);
-            if let Some(base) = &base_req
-               && Instant::now() + dur < deadline
-               && let Some(req_new) = base.try_clone()
-            {
-               req = req_new;
-               tokio::time::sleep(dur).await;
-               continue;
-            }
-            resp.extensions_mut().insert(utils::RetryAfter(dur));
-         }
-
-         *ext = cur_ext;
-         return Ok(resp);
-      }
-   }
-}
-
-pub trait ReqwestBuilder: Sized {
-   fn parts(&mut self) -> (&mut Result<reqwest::RequestBuilder>, &mut http::Extensions);
-
-   /// Returns a mutable reference to the internal set of extensions for this
-   /// request
-   fn extensions(&mut self) -> &mut http::Extensions {
-      let (_, ext) = self.parts();
-      ext
-   }
-
-   /// Inserts the extension into this request builder
-   fn extension<T: Send + Sync + Clone + 'static>(&mut self, extension: T) -> &mut Self {
-      self.extensions().insert(extension);
-      self
-   }
-
-   /// Updates the internal request builder with a new one
-   fn update(
-      &mut self,
-      f: impl FnOnce(reqwest::RequestBuilder) -> reqwest::RequestBuilder,
-   ) -> &mut Self {
-      self.try_update(|b| Ok(f(b)))
-   }
-
-   /// Updates the internal request builder with a new one, returning an error
-   /// if the update fails
-   fn try_update<F>(&mut self, f: F) -> &mut Self
-   where
-      F: FnOnce(reqwest::RequestBuilder) -> Result<reqwest::RequestBuilder>,
-   {
-      let (builder, _) = self.parts();
-      let inner = mem::replace(builder, Err(Error::RequestAlreadyBuilt));
-      *builder = inner.and_then(f);
-      self
-   }
-
-   /// Build a [`Request`], which can be inspected, modified and executed with
-   /// [`Client::execute()`].
-   fn build(&mut self) -> Result<Request> {
-      let (builder, _) = self.parts();
-      mem::replace(builder, Err(Error::RequestAlreadyBuilt))?
-         .build()
-         .map_err(Error::RequestFailed)
-   }
-
-   /// Add a header to this [`Request`].
-   fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
-   where
-      HeaderName: TryFrom<K>,
-      <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
-      HeaderValue: TryFrom<V>,
-      <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
-   {
-      self.update(|builder| builder.header(key, value))
-   }
-
-   /// Add a set of headers to the existing ones on this [`Request`].
-   ///
-   /// The headers will be merged in to any already set.
-   fn headers(&mut self, headers: HeaderMap) -> &mut Self {
-      self.update(|builder| builder.headers(headers))
-   }
-
-   /// Set the HTTP version of the request.
-   fn version(&mut self, version: reqwest::Version) -> &mut Self {
-      self.update(|builder| builder.version(version))
-   }
-
-   /// Enable HTTP basic authentication.
-   fn basic_auth<U, P>(&mut self, username: U, password: Option<P>) -> &mut Self
-   where
-      U: Display,
-      P: Display,
-   {
-      self.update(|builder| builder.basic_auth(username, password))
-   }
-
-   /// Enable HTTP bearer authentication.
-   fn bearer_auth<T>(&mut self, token: T) -> &mut Self
-   where
-      T: Display,
-   {
-      self.update(|builder| builder.bearer_auth(token))
-   }
-
-   /// Set the request body.
-   fn body<T: Into<reqwest::Body>>(&mut self, body: T) -> &mut Self {
-      self.update(|builder| builder.body(body))
-   }
-
-   /// Enables a request timeout.
-   ///
-   /// The timeout is applied from when the request starts connecting until the
-   /// response body has finished. It affects only this request and overrides
-   /// the timeout configured using [`reqwest::ClientBuilder::timeout()`].
-   #[cfg(not(target_arch = "wasm32"))]
-   fn timeout(&mut self, timeout: Duration) -> &mut Self {
-      self.update(|builder| builder.timeout(timeout))
-   }
-
-   /// Sends a multipart/form-data body.
-   ///
-   /// In additional the request's body, the Content-Type and Content-Length
-   /// fields are appropriately set.
-   fn multipart(&mut self, multipart: multipart::Form) -> &mut Self {
-      self.update(|builder| builder.multipart(multipart))
-   }
-
-   /// Modify the query string of the URL.
-   ///
-   /// Modifies the URL of this request, adding the parameters provided.
-   /// This method appends and does not overwrite. This means that it can
-   /// be called multiple times and that existing query parameters are not
-   /// overwritten if the same key is used. The key will simply show up
-   /// twice in the query string.
-   /// Calling `.query(&[("foo", "a"), ("foo", "b")])` gives `"foo=a&foo=b"`.
-   ///
-   /// # Note
-   /// This method does not support serializing a single key-value
-   /// pair. Instead of using `.query(("key", "val"))`, use a sequence, such
-   /// as `.query(&[("key", "val")])`. It's also possible to serialize structs
-   /// and maps into a key-value pair.
-   ///
-   /// # Errors
-   /// This method will fail if the object you provide cannot be serialized
-   /// into a query string.
-   fn query<T: serde::Serialize + ?Sized>(&mut self, query: &T) -> &mut Self {
-      self.update(|builder| builder.query(query))
-   }
-
-   /// Send a form body.
-   ///
-   /// Sets the body to the url encoded serialization of the passed value,
-   /// and also sets the `Content-Type: application/x-www-form-urlencoded`
-   /// header.
-   ///
-   /// # Errors
-   ///
-   /// This method fails if the passed value cannot be serialized into
-   /// url encoded format
-   fn form<T: Serialize + ?Sized>(&mut self, form: &T) -> &mut Self {
-      self.update(|builder| builder.form(form))
-   }
-
-   /// Send a JSON body.
-   ///
-   /// # Optional
-   ///
-   /// This requires the optional `json` feature enabled.
-   ///
-   /// # Errors
-   ///
-   /// Serialization can fail if `T`'s implementation of [`Serialize`] decides
-   /// to fail, or if `T` contains a map with non-string keys.
-   fn json<T: serde::Serialize + ?Sized>(&mut self, json: &T) -> &mut Self {
-      self.try_update(|builder| {
-         let (client, req) = builder.build_split();
-         let mut req = req?;
-         if !req.headers().contains_key(CONTENT_TYPE) {
-            req.headers_mut()
-               .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
-         }
-         *req.body_mut() = Some(serde_json::to_string(json).map_err(Error::Json)?.into());
-         Ok(reqwest::RequestBuilder::from_parts(client, req))
-      })
-   }
-
-   /// Send a Postcard body.
-   ///
-   /// # Errors
-   ///
-   /// This method fails if the passed value cannot be serialized into
-   /// postcard format
-   fn postcard<T: serde::Serialize + ?Sized>(&mut self, postcard: &T) -> &mut Self {
-      self.try_update(|builder| {
-         let (client, req) = builder.build_split();
-         let mut req = req?;
-         if !req.headers().contains_key(CONTENT_TYPE) {
-            req.headers_mut().insert(
-               CONTENT_TYPE,
-               HeaderValue::from_static("application/x-postcard"),
-            );
-         }
-
-         *req.body_mut() = Some(
-            postcard::to_allocvec(postcard)
-               .map_err(Error::Postcard)?
-               .into(),
-         );
-         Ok(reqwest::RequestBuilder::from_parts(client, req))
-      })
-   }
-}
-/// Merges two [`http::Extensions`] instances.
-///
-/// If the source extensions are empty, nothing happens.
-/// If the destination extensions are empty, they are replaced with the source.
-/// Otherwise, the source extensions are added to the destination.
-fn merge_extensions(dst: &mut http::Extensions, src: http::Extensions) {
-   if dst.is_empty() {
-      *dst = src;
-   } else {
-      dst.extend(src);
-   }
-}
-
-/// Handles a request locally using the provided router.
-///
-/// This function creates a local HTTP request from the given [`Request`] and
-/// processes it through the provided [`axum::Router`]. It handles WebSocket
-/// upgrades and properly manages extensions between the request and response.
-///
-/// # Arguments
-///
-/// * `req` - The request to be processed locally
-/// * `ext` - Extensions to be merged with the request
-/// * `router` - The Axum router that will handle the request
-/// * `timeout` - Maximum duration to wait for the router to process the request
-///
-/// # Returns
-///
-/// A [`reqwest::Response`] containing the response from the router
-///
-/// # Errors
-///
-/// Returns an error if:
-/// * The request conversion fails
-/// * The router times out while processing the request
-#[inline(never)]
-pub async fn passthrough_local(
-   req: Request,
-   ext: &mut http::Extensions,
-   router: axum::Router,
-   timeout: Duration,
-) -> Result<reqwest::Response> {
-   let url = req.url().clone();
-   let mut req: http::Request<_> = req.try_into()?;
-   merge_extensions(req.extensions_mut(), mem::take(ext));
-
-   let mut server_tx: Option<upgrade::Promise> = None;
-   if req.headers().contains_key(header::UPGRADE) {
-      server_tx = Some(upgrade::OnUpgrade::pending_at(req.extensions_mut()));
-   }
-
-   let (mut parts, body) = tokio::time::timeout(timeout, router.oneshot(req))
-      .await
-      .map_err(|_| Error::LocalTimeout)?
-      .expect("infallible")
-      .into_parts();
-
-   let mut builder = http::response::Builder::new();
-   {
-      *builder.headers_mut().unwrap() = mem::take(&mut parts.headers);
-
-      let ext = builder.extensions_mut().unwrap();
-      merge_extensions(ext, mem::take(&mut parts.extensions));
-
-      if let Some(server_tx) = server_tx {
-         let cli_tx = upgrade::OnUpgrade::pending_at(ext);
-         if parts.status == http::StatusCode::SWITCHING_PROTOCOLS {
-            let (client_io, server_io) = tokio::io::duplex(1024);
-            let _ = cli_tx.send(Ok(upgrade::Upgraded::custom(client_io)));
-            let _ = server_tx.send(Ok(upgrade::Upgraded::custom(server_io)));
-         } else {
-            let _ = cli_tx.send(Err(upgrade::UpgradeError::Cancelled));
-            let _ = server_tx.send(Err(upgrade::UpgradeError::Cancelled));
-         }
-      }
-   }
-
-   let response = builder
-      .status(parts.status)
-      .version(parts.version)
-      .url(url)
-      .body(reqwest::Body::wrap_stream(body.into_data_stream()))
-      .unwrap();
-   Ok(reqwest::Response::from(response))
-}
-
-/// This is a wrapper around [`reqwest::RequestBuilder`] exposing the same API.
-#[derive(Debug)]
-#[must_use = "RequestBuilder does nothing until you 'send' it"]
-pub struct RequestBuilder<'a> {
-   inner: Result<reqwest::RequestBuilder>,
-   extensions: http::Extensions,
-   router: &'a RouterTable,
-}
-
-impl ReqwestBuilder for RequestBuilder<'_> {
-   fn parts(&mut self) -> (&mut Result<reqwest::RequestBuilder>, &mut http::Extensions) {
-      (&mut self.inner, &mut self.extensions)
-   }
-}
-
-impl<'a> RequestBuilder<'a> {
-   /// Build a [`Request`], which can be inspected, modified and executed with
-   /// [`Client::execute()`].
-   ///
-   /// This is similar to [`RequestBuilder::build()`], but also returns the
-   /// embedded [`Client`].
-   pub fn build_split(&mut self) -> Result<(Client<'a>, Request)> {
-      let Self { inner, router, .. } = self;
-      let (inner, req) = mem::replace(inner, Err(Error::RequestAlreadyBuilt))?.build_split();
-      let client = Client { inner, router };
-      Ok((client, req?))
-   }
-
-   /// Constructs the Request and sends it to the target URL, returning a
-   /// future Response.
-   ///
-   /// # Errors
-   ///
-   /// This method fails if there was an error while sending request,
-   /// redirect loop was detected or redirect limit was exhausted.
-   pub async fn send(&mut self) -> Result<reqwest::Response> {
-      let (client, req) = self.build_split()?;
-      client
-         .execute_with_extensions(req, &mut self.extensions, false)
-         .await
-   }
-
-   /// Attempt to clone the [`RequestBuilder`].
-   ///
-   /// [`None`] is returned if the [`RequestBuilder`] can not be cloned,
-   /// i.e. if the request body is a stream.
-   pub fn try_clone(&self) -> Option<Self> {
-      self
-         .inner
-         .as_ref()
-         .ok()
-         .and_then(|i| i.try_clone())
-         .map(|inner| Self {
-            inner: Ok(inner),
-            extensions: self.extensions.clone(),
-            router: self.router,
-         })
-   }
-}
-
-/// This is a wrapper around [`reqwest::RequestBuilder`] building a
-/// [`Websocket`] instead.
-#[derive(Debug)]
-#[must_use = "WebsocketBuilder does nothing until you 'send' it"]
-pub struct WebsocketBuilder<'a> {
-   inner: Result<reqwest::RequestBuilder>,
-   extensions: http::Extensions,
-   websocket_config: ws::WebSocketConfig,
-   protocols: Vec<SmolStr>,
-   router: &'a RouterTable,
-}
-
-/// Wrapper around [`reqwest::RequestBuilder`] building a Server-Sent Events
-/// stream.
-#[derive(Debug)]
-#[must_use = "SseBuilder does nothing until you 'send' it"]
-pub struct SseBuilder<'a> {
-   inner: Result<reqwest::RequestBuilder>,
-   extensions: http::Extensions,
-   router: &'a RouterTable,
-}
-
-impl ReqwestBuilder for SseBuilder<'_> {
-   fn parts(&mut self) -> (&mut Result<reqwest::RequestBuilder>, &mut http::Extensions) {
-      (&mut self.inner, &mut self.extensions)
-   }
-}
-
-impl<'a> From<RequestBuilder<'a>> for SseBuilder<'a> {
-   fn from(req: RequestBuilder<'a>) -> Self {
-      Self {
-         inner: req.inner,
-         extensions: req.extensions,
-         router: req.router,
-      }
-   }
-}
-
-impl<'a> SseBuilder<'a> {
-   pub fn build_split(&mut self) -> Result<(Client<'a>, Request)> {
-      let Self { inner, router, .. } = self;
-      let (inner, req) = mem::replace(inner, Err(Error::RequestAlreadyBuilt))?.build_split();
-      let client = Client { inner, router };
-      Ok((client, req?))
-   }
-
-   pub async fn send(&mut self) -> Result<sse::Response> {
-      let (client, mut req) = self.build_split()?;
-
-      req.headers_mut().insert(
-         reqwest::header::ACCEPT,
-         HeaderValue::from_static(sse::EventFormat::accepted_mimes()),
-      );
-
-      let response = client
-         .execute_with_extensions(req, &mut self.extensions, true)
-         .await?;
-
-      Ok(sse::Response { response })
-   }
-
-   pub fn try_clone(&self) -> Option<Self> {
-      self
-         .inner
-         .as_ref()
-         .ok()
-         .and_then(|i| i.try_clone())
-         .map(|inner| Self {
-            inner: Ok(inner),
-            extensions: self.extensions.clone(),
-            router: self.router,
-         })
-   }
-}
-
-impl ReqwestBuilder for WebsocketBuilder<'_> {
-   fn parts(&mut self) -> (&mut Result<reqwest::RequestBuilder>, &mut http::Extensions) {
-      (&mut self.inner, &mut self.extensions)
-   }
-}
-
-impl<'a> From<RequestBuilder<'a>> for WebsocketBuilder<'a> {
-   fn from(req: RequestBuilder<'a>) -> Self {
-      Self {
-         inner: req.inner,
-         extensions: req.extensions,
-         websocket_config: ws::WebSocketConfig::default(),
-         protocols: Default::default(),
-         router: req.router,
-      }
-   }
-}
-
-impl ws::ConfigBuilder for WebsocketBuilder<'_> {
-   fn websocket_config(&mut self) -> &mut ws::WebSocketConfig {
-      &mut self.websocket_config
-   }
-   fn protocols(&mut self, extend: impl IntoIterator<Item: ToSmolStr>) -> &mut Self {
-      self
-         .protocols
-         .extend(extend.into_iter().map(|x| x.to_smolstr()));
-      self
-   }
-}
-
-impl<'a> WebsocketBuilder<'a> {
-   /// Build a [`Request`], which can be inspected, modified and executed with
-   /// [`Client::execute()`].
-   ///
-   /// This is similar to [`RequestBuilder::build()`], but also returns the
-   /// embedded [`Client`].
-   pub fn build_split(&mut self) -> Result<(Client<'a>, Request)> {
-      let Self { inner, router, .. } = self;
-      let (inner, req) = mem::replace(inner, Err(Error::RequestAlreadyBuilt))?.build_split();
-      let client = Client { inner, router };
-      Ok((client, req?))
-   }
-
-   /// Constructs the Request and sends it to the target URL, returning a
-   /// future Response.
-   ///
-   /// # Errors
-   ///
-   /// This method fails if there was an error while sending request,
-   /// redirect loop was detected or redirect limit was exhausted.
-   pub async fn send(&mut self) -> Result<ws::Response> {
-      let (client, mut req) = self.build_split()?;
-
-      // change the scheme from wss? to https?
-      let url = req.url_mut();
-      match url.scheme() {
-         "ws" => {
-            url.set_scheme("http")
-               .expect("url should accept http scheme");
-         },
-         "wss" => {
-            url.set_scheme("https")
-               .expect("url should accept https scheme");
-         },
-         _ => {},
-      }
-
-      let nonce = ws::Nonce::new();
-      *req.version_mut() = Version::HTTP_11;
-      let headers = req.headers_mut();
-      headers.insert(
-         reqwest::header::CONNECTION,
-         HeaderValue::from_static("upgrade"),
-      );
-      headers.insert(
-         reqwest::header::UPGRADE,
-         HeaderValue::from_static("websocket"),
-      );
-      headers.insert(
-         reqwest::header::SEC_WEBSOCKET_KEY,
-         HeaderValue::from_str(&nonce.key).expect("nonce is a invalid header value"),
-      );
-      headers.insert(
-         reqwest::header::SEC_WEBSOCKET_VERSION,
-         HeaderValue::from_static("13"),
-      );
-      if !self.protocols.is_empty() {
-         headers.insert(
-            reqwest::header::SEC_WEBSOCKET_PROTOCOL,
-            HeaderValue::from_str(&self.protocols.join(", "))
-               .expect("protocols is an invalid header value"),
-         );
-      }
-
-      let response = client
-         .execute_with_extensions(req, &mut self.extensions, true)
-         .await?;
-
-      Ok(ws::Response {
-         response,
-         nonce,
-         protocols: mem::take(&mut self.protocols),
-         websocket_config: Some(self.websocket_config),
-      })
-   }
-
-   /// Attempt to clone the [`RequestBuilder`].
-   ///
-   /// [`None`] is returned if the [`RequestBuilder`] can not be cloned,
-   /// i.e. if the request body is a stream.
-   pub fn try_clone(&self) -> Option<Self> {
-      self
-         .inner
-         .as_ref()
-         .ok()
-         .and_then(|i| i.try_clone())
-         .map(|inner| Self {
-            inner: Ok(inner),
-            extensions: self.extensions.clone(),
-            websocket_config: self.websocket_config,
-            protocols: self.protocols.clone(),
-            router: self.router,
-         })
-   }
-}
-
-#[cfg(test)]
-mod tests {
-   use std::{
-      sync::atomic::{AtomicUsize, Ordering},
-      time::Duration,
-   };
-
-   use axum::{Router, routing::get};
-
-   use super::*;
-   use crate::http::server::SharedRouter;
-
-   #[tokio::test]
-   async fn retry_after_extension_present() {
-      let app = SharedRouter::new(Router::new().route(
-         "/retry",
-         get(|| async {
-            axum::response::Response::builder()
-               .status(axum::http::StatusCode::TOO_MANY_REQUESTS)
-               .header("Retry-After", "3")
-               .body(axum::body::Body::empty())
-               .unwrap()
-         }),
-      ));
-      app.bind(["retry.local"]);
-
-      let resp = Client::global()
-         .get("https://retry.local/retry")
-         .send()
-         .await
-         .expect("request failed");
-
-      let ext = resp.extensions().get::<utils::RetryAfter>().copied();
-      assert_eq!(ext.map(|r| r.0), Some(Duration::from_secs(3)));
-   }
-
-   #[tokio::test]
-   async fn retry_after_auto_retries() {
-      static CALLS: AtomicUsize = AtomicUsize::new(0);
-
-      let app = SharedRouter::new(Router::new().route(
-         "/retry-auto",
-         get(|| async {
-            if CALLS.fetch_add(1, Ordering::SeqCst) == 0 {
-               axum::response::Response::builder()
-                  .status(axum::http::StatusCode::SERVICE_UNAVAILABLE)
-                  .header("Retry-After", "0")
-                  .body(axum::body::Body::empty())
-                  .unwrap()
-            } else {
-               axum::response::Response::builder()
-                  .status(axum::http::StatusCode::OK)
-                  .body(axum::body::Body::from("ok"))
-                  .unwrap()
-            }
-         }),
-      ));
-      app.bind(["retry-auto.local"]);
-
-      let body = Client::global()
-         .get("https://retry-auto.local/retry-auto")
-         .send()
-         .await
-         .expect("request failed")
-         .text()
-         .await
-         .expect("read body");
-
-      assert_eq!(body, "ok");
-      assert!(CALLS.load(Ordering::SeqCst) >= 2);
-   }
-}
diff --git a/attic/net/http/mod.rs b/attic/net/http/mod.rs
deleted file mode 100644
index d4491c9d8..000000000
--- a/attic/net/http/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-pub mod client;
-pub mod server;
-pub mod sse;
-pub mod upgrade;
-pub mod utils;
-pub mod ws;
diff --git a/attic/net/http/server.rs b/attic/net/http/server.rs
deleted file mode 100644
index 12b0c4e18..000000000
--- a/attic/net/http/server.rs
+++ /dev/null
@@ -1,407 +0,0 @@
-use std::{
-   borrow::{Borrow, ToOwned},
-   fmt, hash,
-   mem::MaybeUninit,
-   ptr,
-   sync::{Arc, LazyLock, Weak},
-};
-
-use ahash::{AHashMap, AHashSet};
-use axum::{
-   Router,
-   body::Body,
-   extract::{FromRequestParts, Request},
-   handler::{Handler, HandlerService, HandlerWithoutStateExt},
-   response::IntoResponse,
-   routing::IntoMakeService,
-   serve::Serve,
-};
-use axum_extra::extract::Host;
-use bon::Builder;
-use futures::FutureExt;
-use parking_lot::RwLock;
-use smallvec::SmallVec;
-use smol_str::ToSmolStr;
-use tower::ServiceExt;
-
-use crate::replica::Hostname;
-
-/// A case-insensitive string slice, used for case-insensitive host name
-/// lookups. This is a transparent wrapper around [`str`] that implements
-/// case-insensitive hashing and equality.
-#[repr(transparent)]
-pub struct IStr(str);
-
-impl fmt::Debug for IStr {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      f.debug_tuple("IStr").field(&self.as_str()).finish()
-   }
-}
-
-impl IStr {
-   /// Converts a string slice to an [`IStr`] reference.
-   ///
-   /// This is a zero-cost conversion since [`IStr`] is `repr(transparent)`.
-   #[inline]
-   const fn from_str(s: &str) -> &Self {
-      // SAFETY: IStr is repr(transparent) around str
-      unsafe { &*(ptr::from_ref::<str>(s) as *const Self) }
-   }
-
-   /// Converts an [`IStr`] reference back to a string slice.
-   ///
-   /// This is a zero-cost conversion since [`IStr`] is `repr(transparent)`.
-   #[inline]
-   const fn as_str(&self) -> &str {
-      // SAFETY: IStr is repr(transparent) around str
-      unsafe { &*(ptr::from_ref::<Self>(self) as *const str) }
-   }
-}
-
-impl hash::Hash for IStr {
-   /// Implements case-insensitive hashing by converting all ASCII characters
-   /// to lowercase during hashing.
-   fn hash<H: hash::Hasher>(&self, state: &mut H) {
-      let mut chunks = self.as_str().as_bytes();
-      while let Some((qc, rem)) = chunks.split_first_chunk() {
-         let q = u64::from_le_bytes(*qc);
-         state.write_u64(q | 0x2020202020202020);
-         chunks = rem;
-      }
-      for c in chunks {
-         state.write_u8(*c | 0x20);
-      }
-   }
-}
-impl Eq for IStr {}
-impl PartialEq for IStr {
-   /// Implements case-insensitive equality comparison.
-   fn eq(&self, other: &Self) -> bool {
-      self.as_str().eq_ignore_ascii_case(other.as_str())
-   }
-}
-
-impl ToOwned for IStr {
-   type Owned = IString;
-   fn to_owned(&self) -> Self::Owned {
-      IString(self.as_str().into())
-   }
-}
-
-/// An owned case-insensitive string, used for case-insensitive host name
-/// storage. This is a wrapper around [`String`] that implements
-/// case-insensitive hashing and equality.
-#[derive(Clone, derive_more::Debug, derive_more::From, derive_more::Into)]
-pub struct IString(Hostname);
-
-impl IString {
-   /// Returns a reference to the underlying [`IStr`].
-   fn as_istr(&self) -> &IStr {
-      IStr::from_str(&self.0)
-   }
-}
-
-impl hash::Hash for IString {
-   /// Delegates to the case-insensitive hashing implementation of [`IStr`].
-   fn hash<H: hash::Hasher>(&self, state: &mut H) {
-      self.as_istr().hash(state);
-   }
-}
-
-impl Eq for IString {}
-impl PartialEq for IString {
-   /// Implements case-insensitive equality comparison.
-   fn eq(&self, other: &Self) -> bool {
-      self.as_istr().eq(other.as_istr())
-   }
-}
-
-impl Borrow<IStr> for IString {
-   fn borrow(&self) -> &IStr {
-      self.as_istr()
-   }
-}
-
-/// A thread-safe reference-counted handle to an Axum [`Router`].
-///
-/// Internally the router is stored in an [`Arc`] wrapped [`RwLock`] so that it
-/// can be mutated in place while still being shared across threads. See the
-/// individual methods for the available operations.
-#[derive(Debug, Default, Clone)]
-#[repr(transparent)]
-pub struct SharedRouter(Arc<RwLock<Router>>);
-
-impl From<Router> for SharedRouter {
-   fn from(router: Router) -> Self {
-      Self::new(router)
-   }
-}
-
-impl From<Arc<RwLock<Router>>> for SharedRouter {
-   fn from(router: Arc<RwLock<Router>>) -> Self {
-      Self(router)
-   }
-}
-
-impl SharedRouter {
-   /// Creates a new [`SharedRouter`] from the given [`Router`].
-   ///
-   /// The router is wrapped in an [`Arc`] + [`RwLock`], making the returned
-   /// value cheap to clone and safe to use from multiple threads.
-   pub fn new(router: Router) -> Self {
-      Self(Arc::new(RwLock::new(router)))
-   }
-   /// Applies the provided closure to the inner [`Router`] while holding the
-   /// write-side of the [`RwLock`].
-   ///
-   /// This allows updating the router in place (e.g. adding routes) without
-   /// having to reconstruct the surrounding [`SharedRouter`].
-   pub fn update(&self, f: impl FnOnce(Router) -> Router) {
-      let mut write = self.0.write();
-      write.update(f);
-   }
-   /// Downgrades this [`SharedRouter`] to a [`WeakRouter`].
-   ///
-   /// The weak reference does not contribute to the [`Arc`] strong count and
-   /// can later be [`WeakRouter::upgrade`]d back to a strong reference.
-   pub fn downgrade(&self) -> WeakRouter {
-      WeakRouter(Arc::downgrade(&self.0))
-   }
-   /// Clones and returns the inner [`Router`].
-   ///
-   /// The read-side of the lock is taken to obtain a snapshot of the router.
-   pub fn read(&self) -> Router {
-      self.0.read().clone()
-   }
-
-   /// Registers the router for the given list of host names into the given
-   /// router table.
-   pub fn bind_in(&self, hosts: impl IntoIterator<Item: ToSmolStr>, table: &RouterTable) {
-      table.bind(hosts, self);
-   }
-
-   /// Removes the router from the given router table
-   pub fn unbind_in(&self, hosts: impl IntoIterator<Item: AsRef<str>>, table: &RouterTable) {
-      table.retain(hosts, |_, r| !Self::ptr_eq(&r, self));
-   }
-
-   /// Registers the router for the given list of host names into the global
-   /// router table.
-   pub fn bind(&self, hosts: impl IntoIterator<Item: ToSmolStr>) {
-      self.bind_in(hosts, RouterTable::global());
-   }
-
-   /// Removes the router from the global router table.
-   pub fn unbind(&self, hosts: impl IntoIterator<Item: AsRef<str>>) {
-      self.unbind_in(hosts, RouterTable::global());
-   }
-
-   /// Checks if two [`SharedRouter`] instances point to the same underlying
-   /// [`Router`].
-   #[inline]
-   pub fn ptr_eq(a: &Self, b: &Self) -> bool {
-      Arc::ptr_eq(&a.0, &b.0)
-   }
-}
-
-/// A non-owning weak reference to a [`SharedRouter`].
-///
-/// The reference can be upgraded back to a strong [`SharedRouter`] using
-/// [`WeakRouter::upgrade`]. It becomes invalid once the last strong reference
-/// is dropped.
-#[derive(Debug, Default, Clone)]
-pub struct WeakRouter(Weak<RwLock<Router>>);
-
-impl WeakRouter {
-   /// Attempts to upgrade the weak reference to a [`SharedRouter`].
-   ///
-   /// Returns `Some(shared)` if the router is still alive, or `None`
-   /// otherwise.
-   pub fn upgrade(&self) -> Option<SharedRouter> {
-      self.0.upgrade().map(SharedRouter)
-   }
-}
-
-/// A thread-safe table that maps host names to Axum routers.
-///
-/// This is used to route requests to the appropriate handler based on the host
-/// name. The host names are compared case-insensitively.
-#[derive(Debug, Default, Clone)]
-pub struct RouterTable {
-   routers: Arc<RwLock<AHashMap<IString, WeakRouter>>>,
-}
-
-impl RouterTable {
-   /// Returns the global router table singleton as an `Arc`.
-   pub fn global() -> &'static Self {
-      static GLOBAL_TABLE: LazyLock<RouterTable> = LazyLock::new(Default::default);
-      &GLOBAL_TABLE
-   }
-
-   /// Binds a router for the given host.
-   ///
-   /// If a router was already registered for this host, it will be replaced.
-   pub fn bind(&self, hosts: impl IntoIterator<Item: ToSmolStr>, router: &SharedRouter) {
-      for host in hosts {
-         self.routers.write().insert(
-            IString(host.to_smolstr()),
-            SharedRouter::downgrade(router),
-         );
-      }
-   }
-
-   /// Retains the router for the given host if the predicate returns `true`.
-   ///
-   /// If the predicate returns `false`, the router is removed from the table.
-   pub fn retain(
-      &self,
-      hosts: impl IntoIterator<Item: AsRef<str>>,
-      f: impl Fn(&str, SharedRouter) -> bool,
-   ) {
-      let mut write = self.routers.write();
-      for host in hosts {
-         let istr = IStr::from_str(host.as_ref());
-         let entry = write.get(istr);
-         if let Some(entry) = entry {
-            let retain = entry.upgrade().is_some_and(|r| f(istr.as_str(), r));
-            if !retain {
-               write.remove(istr);
-            }
-         }
-      }
-   }
-
-   /// Looks up a router by host name.
-   ///
-   /// The lookup is case-insensitive.
-   pub fn lookup(&self, host: &str) -> Option<Router> {
-      self
-         .routers
-         .read()
-         .get(IStr::from_str(host))
-         .and_then(|r| r.upgrade())
-         .map(|r| r.read())
-   }
-
-   /// Serves the router table on the given listener.
-   #[allow(clippy::type_complexity)]
-   pub fn serve<L>(
-      self,
-      listener: L,
-   ) -> Serve<L, IntoMakeService<HandlerService<Self, (), ()>>, HandlerService<Self, (), ()>>
-   where
-      L: axum::serve::Listener,
-   {
-      axum::serve(listener, self.into_make_service())
-   }
-}
-
-/// Implements an axum handler for the router table.
-impl Handler<(), ()> for RouterTable {
-   type Future = futures::future::BoxFuture<'static, http::Response<Body>>;
-   fn call(self, req: Request, state: ()) -> Self::Future {
-      async move {
-         let (mut parts, body) = req.into_parts();
-         let host = Host::from_request_parts(&mut parts, &state)
-            .await
-            .map(|h| h.0)
-            .unwrap_or_default();
-
-         // Split host and port if a port is specified
-         let host = if let Some(idx) = host.find(':') {
-            host.split_at(idx).0
-         } else {
-            host.as_str()
-         };
-
-         if let Some(router) = self.lookup(host) {
-            let req = Request::from_parts(parts, body);
-            router.oneshot(req).await.expect("infallible")
-         } else {
-            (http::StatusCode::NOT_FOUND, format!("Not found: {host}")).into_response()
-         }
-      }
-      .boxed()
-   }
-}
-
-/// Serves the global router table on the given listener.
-///
-/// This is a convenience function that delegates to
-/// `RouterTable::global().serve()`.
-#[allow(clippy::type_complexity)]
-pub fn serve<L>(
-   listener: L,
-) -> Serve<
-   L,
-   IntoMakeService<HandlerService<RouterTable, (), ()>>,
-   HandlerService<RouterTable, (), ()>,
->
-where
-   L: axum::serve::Listener,
-{
-   RouterTable::global().clone().serve(listener)
-}
-
-/// Convenience wrapper that owns a [`SharedRouter`] and manages its
-/// registration in one or more [`RouterTable`] instances.
-///
-/// The type tracks the set of host names the router should be reachable under
-/// and exposes ergonomic helper methods to mutate the router or extend the
-/// host list.
-#[derive(Debug, Clone, Builder)]
-pub struct Server {
-   #[builder(default = AHashSet::default())]
-   hosts: AHashSet<Hostname>,
-   #[builder(default = SmallVec::from_iter([RouterTable::global().clone()]))]
-   rtables: SmallVec<[RouterTable; 1]>,
-   #[builder(default = SharedRouter::new(Router::new()))]
-   router: SharedRouter,
-}
-
-impl Server {
-   /// Returns a reference to the inner [`SharedRouter`].
-   pub const fn router(&self) -> &SharedRouter {
-      &self.router
-   }
-
-   /// Mutates the inner [`Router`] by applying the given closure.
-   ///
-   /// This is delegated to [`SharedRouter::update`].
-   pub fn update(&mut self, f: impl FnOnce(Router) -> Router) {
-      self.router.update(f);
-   }
-
-   /// Nests the provided `router` under the given `path` on the inner router.
-   ///
-   /// Internally this calls [`Router::nest`].
-   pub fn nest(&mut self, path: &str, router: Router) {
-      self.router.update(|r| r.nest(path, router));
-   }
-
-   /// Registers an additional `host` for this server.
-   ///
-   /// The new host name is propagated to all known [`RouterTable`]s so that
-   /// the server becomes reachable under the added host name immediately.
-   pub fn add_host<H: ToSmolStr + ?Sized>(&mut self, host: &H) {
-      if self.hosts.insert(host.to_smolstr()) {
-         for table in &mut self.rtables {
-            table.bind(self.hosts.iter().cloned(), &self.router);
-         }
-      }
-   }
-}
-
-trait RouterExt {
-   fn update(&mut self, f: impl FnOnce(Self) -> Self) -> &mut Self
-   where
-      Self: Sized,
-   {
-      unsafe {
-         let tmp = &mut *ptr::from_mut::<Self>(self).cast::<MaybeUninit<Self>>();
-         tmp.write(f(tmp.assume_init_read()));
-      }
-      self
-   }
-}
-impl RouterExt for Router {}
diff --git a/attic/net/http/sse/mod.rs b/attic/net/http/sse/mod.rs
deleted file mode 100644
index ca693fc88..000000000
--- a/attic/net/http/sse/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-pub mod request;
-pub mod response;
-pub mod stream;
-pub mod types;
-
-pub use request::Request;
-pub use response::Response;
-pub use stream::{EventFormat, Incoming, Outgoing};
-pub use types::{Error, Event, Result, Value};
-
-#[cfg(test)]
-pub mod tests;
diff --git a/attic/net/http/sse/request.rs b/attic/net/http/sse/request.rs
deleted file mode 100644
index cd311b0f3..000000000
--- a/attic/net/http/sse/request.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use std::{
-   borrow::Borrow,
-   convert::Infallible,
-   future::{self, Future},
-   ops::Deref,
-};
-
-use futures::{Stream, StreamExt};
-use http::request::Parts;
-
-use super::Event;
-use crate::http::{sse, utils, utils::Result};
-
-#[derive(Debug)]
-pub struct Request {
-   pub request: Option<Parts>,
-}
-
-impl Request {
-   pub const fn new(request: Parts) -> Self {
-      Self {
-         request: Some(request),
-      }
-   }
-
-   pub fn stream<S>(
-      self,
-      events: S,
-   ) -> Result<
-      sse::Outgoing<impl Stream<Item = Result<impl Borrow<Event>, anyhow::Error>> + Send + 'static>,
-   >
-   where
-      S: Stream<Item: Borrow<Event>> + Send + 'static,
-   {
-      self.try_stream(events.map(anyhow::Ok))
-   }
-
-   pub fn try_stream<S, I, E>(mut self, events: S) -> Result<sse::Outgoing<S>>
-   where
-      S: Stream<Item = Result<I, E>> + Send + 'static,
-      I: Borrow<Event>,
-      E: Into<axum::BoxError>,
-   {
-      let parts = self.request.take().expect("request used after finalized");
-      let format = utils::negotiate_content_type(&parts.headers, &[
-         sse::EventFormat::NdJson,
-         sse::EventFormat::Dom,
-      ])?;
-      Ok(sse::Outgoing::new(events).with_format(format))
-   }
-
-   pub fn into_inner(self) -> Parts {
-      self.request.expect("request used after finalized")
-   }
-}
-
-impl<S> axum::extract::FromRequestParts<S> for Request {
-   type Rejection = Infallible;
-
-   fn from_request_parts(
-      parts: &mut Parts,
-      _state: &S,
-   ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send {
-      let result = Self::new(parts.clone());
-      future::ready(Ok(result))
-   }
-}
-
-impl Deref for Request {
-   type Target = Parts;
-   fn deref(&self) -> &Self::Target {
-      self.request.as_ref().expect("request used after finalized")
-   }
-}
diff --git a/attic/net/http/sse/response.rs b/attic/net/http/sse/response.rs
deleted file mode 100644
index e182610c3..000000000
--- a/attic/net/http/sse/response.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use http::StatusCode;
-
-use super::{Incoming, Result};
-use crate::http::{sse::EventFormat, utils};
-
-#[derive(Debug)]
-pub struct Response {
-   pub response: reqwest::Response,
-}
-
-impl Response {
-   pub async fn stream(
-      self,
-   ) -> Result<Incoming<impl futures::Stream<Item = reqwest::Result<bytes::Bytes>>>> {
-      if self.response.status() != StatusCode::OK {
-         return Err(utils::read_remote_error(self.response).await.into());
-      }
-
-      let format = utils::match_content_type(self.response.headers(), &[
-         EventFormat::NdJson,
-         EventFormat::Dom,
-      ])?;
-
-      let stream = self.response.bytes_stream();
-      Ok(Incoming::new(stream).with_format(format))
-   }
-
-   pub fn into_inner(self) -> reqwest::Response {
-      self.response
-   }
-}
diff --git a/attic/net/http/sse/stream.rs b/attic/net/http/sse/stream.rs
deleted file mode 100644
index 42e3a2d33..000000000
--- a/attic/net/http/sse/stream.rs
+++ /dev/null
@@ -1,252 +0,0 @@
-use std::{
-   borrow::Borrow,
-   pin::Pin,
-   task::{Context, Poll},
-   time::Duration,
-};
-
-use axum::response::IntoResponse;
-use bytes::{Bytes, BytesMut};
-use futures::Stream;
-use http_body::Frame;
-use pin_project_lite::pin_project;
-use tokio::time::{self, Instant};
-
-use super::{Error, Event, Result};
-use crate::http::utils::ToMime;
-
-#[derive(
-   Debug, Clone, Copy, PartialEq, Eq, Hash, strum::EnumString, strum::IntoStaticStr, strum::EnumIter,
-)]
-pub enum EventFormat {
-   #[strum(serialize = "text/event-stream")]
-   Dom,
-   #[strum(serialize = "application/x-ndjson")]
-   NdJson,
-}
-
-impl EventFormat {
-   pub const fn accepted_mimes() -> &'static str {
-      "application/x-ndjson, text/event-stream"
-   }
-}
-
-impl ToMime for EventFormat {
-   fn to_mime(&self) -> &'static str {
-      self.into()
-   }
-}
-
-pin_project! {
-   pub struct Incoming<S> {
-      #[pin]
-      inner: S,
-      buffer: BytesMut,
-      format: EventFormat,
-   }
-}
-
-impl<S> Incoming<S> {
-   pub fn new(stream: S) -> Self {
-      Self {
-         inner: stream,
-         buffer: BytesMut::new(),
-         format: EventFormat::Dom,
-      }
-   }
-   pub const fn with_format(mut self, format: EventFormat) -> Self {
-      self.format = format;
-      self
-   }
-}
-
-pin_project! {
-   struct Keepalive {
-      t0: Option<(Instant, Duration)>,
-      #[pin]
-      sleep: Option<tokio::time::Sleep>,
-   }
-}
-
-impl From<Option<Duration>> for Keepalive {
-   fn from(interval: Option<Duration>) -> Self {
-      Self {
-         t0: interval.map(|i| (Instant::now(), i)),
-         sleep: None,
-      }
-   }
-}
-
-impl Default for Keepalive {
-   fn default() -> Self {
-      Self {
-         t0: Some((Instant::now(), Self::DEFAULT_INTERVAL)),
-         sleep: None,
-      }
-   }
-}
-
-impl Keepalive {
-   const DEFAULT_INTERVAL: Duration = Duration::from_secs(30);
-
-   pub const fn enabled(&self) -> bool {
-      self.t0.is_some()
-   }
-
-   pub fn reset(self: Pin<&mut Self>) {
-      let Some((_, interval)) = self.t0 else {
-         return;
-      };
-
-      let mut this = self.project();
-      let now = Instant::now();
-      if this.sleep.is_none() {
-         *this.t0 = Some((now, interval));
-         this.sleep.set(Some(time::sleep_until(now + interval)));
-      } else {
-         this.sleep.as_pin_mut().unwrap().reset(now + interval);
-      }
-   }
-
-   pub fn poll_tick(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
-      let Some((t0, interval)) = self.t0 else {
-         panic!("keepalive is disabled, should not have called poll_tick");
-      };
-
-      let mut this = self.project();
-      let now = Instant::now();
-      if this.sleep.is_none() {
-         let elapsed = now.saturating_duration_since(t0);
-         if let Some(rem) = interval.checked_sub(elapsed) {
-            this.sleep.set(Some(time::sleep_until(now + rem)));
-            return Poll::Pending;
-         }
-         this.sleep.set(Some(time::sleep_until(now + interval)));
-         return Poll::Ready(());
-      }
-
-      let Some(mut sleep) = this.sleep.as_pin_mut() else {
-         unreachable!("sleep is not None");
-      };
-      match sleep.as_mut().poll(cx) {
-         Poll::Pending => Poll::Pending,
-         Poll::Ready(()) => {
-            sleep.reset(now + interval);
-            Poll::Ready(())
-         },
-      }
-   }
-}
-
-pin_project! {
-   pub struct Outgoing<S> {
-      #[pin]
-      inner: S,
-      format: EventFormat,
-      #[pin]
-      keepalive: Keepalive,
-   }
-}
-
-impl<S> Outgoing<S> {
-   pub fn new(stream: S) -> Self {
-      Self {
-         inner: stream,
-         format: EventFormat::Dom,
-         keepalive: Keepalive::default(),
-      }
-   }
-   pub const fn with_format(mut self, format: EventFormat) -> Self {
-      self.format = format;
-      self
-   }
-   pub fn with_keepalive(mut self, interval: Option<Duration>) -> Self {
-      self.keepalive = interval.into();
-      self
-   }
-}
-
-impl<S> IntoResponse for Outgoing<S>
-where
-   Self: http_body::Body<Data = Bytes, Error: Into<axum::BoxError>>,
-   S: Send + 'static,
-{
-   fn into_response(self) -> axum::response::Response {
-      (
-         [
-            (http::header::CONTENT_TYPE, self.format.to_mime()),
-            (http::header::CACHE_CONTROL, "no-cache"),
-         ],
-         axum::body::Body::new(self),
-      )
-         .into_response()
-   }
-}
-
-impl<S> Stream for Incoming<S>
-where
-   S: Stream<Item = reqwest::Result<Bytes>>,
-{
-   type Item = Result<Event>;
-
-   fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
-      let mut this = self.project();
-      loop {
-         match Event::parse_body(this.buffer, *this.format) {
-            Ok(Some(event)) => return Poll::Ready(Some(Ok(event))),
-            Err(e) => return Poll::Ready(Some(Err(e))),
-            Ok(None) => {},
-         }
-         match futures::ready!(this.inner.as_mut().poll_next(cx)) {
-            Some(Ok(chunk)) => this.buffer.extend_from_slice(&chunk),
-            Some(Err(e)) => return Poll::Ready(Some(Err(Error::Reqwest(e)))),
-            None => {
-               if this.buffer.is_empty() {
-                  return Poll::Ready(None);
-               }
-               match Event::parse_body(this.buffer, *this.format) {
-                  Ok(Some(event)) => return Poll::Ready(Some(Ok(event))),
-                  Ok(None) => return Poll::Ready(None),
-                  Err(e) => return Poll::Ready(Some(Err(e))),
-               }
-            },
-         }
-      }
-   }
-}
-
-impl<S, I, E> http_body::Body for Outgoing<S>
-where
-   I: Borrow<Event>,
-   S: Stream<Item = Result<I, E>>,
-   E: Into<axum::BoxError>,
-{
-   type Data = Bytes;
-   type Error = E;
-
-   fn poll_frame(
-      self: Pin<&mut Self>,
-      cx: &mut Context<'_>,
-   ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
-      let this = self.project();
-
-      match this.inner.poll_next(cx) {
-         Poll::Pending => {
-            if this.keepalive.enabled() {
-               this
-                  .keepalive
-                  .poll_tick(cx)
-                  .map(|()| Some(Ok(Frame::data(Event::EMPTY.to_body(*this.format)))))
-            } else {
-               Poll::Pending
-            }
-         },
-         Poll::Ready(Some(Ok(e))) => {
-            this.keepalive.reset();
-            Poll::Ready(Some(Ok(Frame::data(e.borrow().to_body(*this.format)))))
-         },
-         Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
-         Poll::Ready(None) => Poll::Ready(None),
-      }
-   }
-}
diff --git a/attic/net/http/sse/tests.rs b/attic/net/http/sse/tests.rs
deleted file mode 100644
index 603dcdfe5..000000000
--- a/attic/net/http/sse/tests.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use std::{
-   sync::atomic::{AtomicUsize, Ordering},
-   time::Duration,
-};
-
-use axum::{Router, response::IntoResponse, routing::get};
-use futures::StreamExt;
-use tokio::time::timeout;
-
-use crate::http::{client, server::SharedRouter, sse, utils};
-
-#[tokio::test]
-async fn test_sse_communication() {
-   let app = SharedRouter::new(Router::new().route("/sse", get(sse_handler)));
-   app.bind(["sse-example.local"]);
-
-   let mut stream = client::Client::global()
-      .sse("https://sse-example.local/sse")
-      .send()
-      .await
-      .expect("Failed to send SSE request")
-      .stream()
-      .await
-      .expect("Failed to open SSE stream");
-
-   let mut events = Vec::new();
-   for _ in 0..2 {
-      if let Ok(Some(evt)) = timeout(std::time::Duration::from_secs(1), stream.next()).await {
-         let evt = evt.expect("Failed to read event");
-         events.push(evt.text_data().unwrap_or_default().to_owned());
-      } else {
-         panic!("Timed out waiting for event");
-      }
-   }
-
-   assert_eq!(events, ["one", "two"]);
-}
-
-async fn sse_handler(req: sse::Request) -> impl IntoResponse {
-   let events = vec![
-      sse::Event::new().with_raw_data("one"),
-      sse::Event::new().with_raw_data("two"),
-   ];
-   let stream = tokio_stream::iter(events);
-   req.stream(stream)
-}
-
-#[tokio::test]
-async fn test_sse_retry_after_error() {
-   let app = SharedRouter::new(Router::new().route(
-      "/sse",
-      get(|| async {
-         axum::response::Response::builder()
-            .status(axum::http::StatusCode::SERVICE_UNAVAILABLE)
-            .header("Retry-After", "5")
-            .body(axum::body::Body::empty())
-            .unwrap()
-      }),
-   ));
-   app.bind(["sse-retry.local"]);
-
-   let response = client::Client::global()
-      .sse("https://sse-retry.local/sse")
-      .send()
-      .await
-      .expect("send should succeed");
-
-   let err = match response.stream().await {
-      Ok(_) => panic!("expected failure"),
-      Err(e) => e,
-   };
-
-   match err {
-      sse::Error::Remote(utils::Error::ServerError { retry_after, .. }) => {
-         assert_eq!(retry_after, Some(Duration::from_secs(5)));
-      },
-      other => panic!("unexpected error: {other:?}"),
-   }
-}
-
-#[tokio::test]
-async fn test_sse_retry_automatically() {
-   static CALLS: AtomicUsize = AtomicUsize::new(0);
-
-   async fn handler(req: sse::Request) -> impl IntoResponse {
-      if CALLS.fetch_add(1, Ordering::SeqCst) == 0 {
-         axum::response::Response::builder()
-            .status(axum::http::StatusCode::SERVICE_UNAVAILABLE)
-            .header("Retry-After", "0")
-            .body(axum::body::Body::empty())
-            .unwrap()
-      } else {
-         let events = vec![sse::Event::new().with_raw_data("retry")];
-         let stream = tokio_stream::iter(events);
-         req.stream(stream).into_response()
-      }
-   }
-
-   let app = SharedRouter::new(Router::new().route("/sse-auto", get(handler)));
-   app.bind(["sse-auto.local"]);
-
-   let mut stream = client::Client::global()
-      .sse("https://sse-auto.local/sse-auto")
-      .send()
-      .await
-      .expect("send")
-      .stream()
-      .await
-      .expect("stream");
-
-   let msg = timeout(Duration::from_secs(1), stream.next())
-      .await
-      .expect("timeout")
-      .expect("option")
-      .expect("event");
-
-   assert_eq!(msg.text_data().unwrap_or_default(), "retry");
-   assert!(CALLS.load(Ordering::SeqCst) >= 2);
-}
diff --git a/attic/net/http/sse/types.rs b/attic/net/http/sse/types.rs
deleted file mode 100644
index 0bc5b5662..000000000
--- a/attic/net/http/sse/types.rs
+++ /dev/null
@@ -1,789 +0,0 @@
-use std::{
-   borrow::Borrow,
-   collections::BTreeMap,
-   fmt, mem,
-   ops::Deref,
-   str::{self, FromStr},
-};
-
-use bytes::{BufMut, Bytes, BytesMut};
-use bytes_utils::Str;
-use serde::{Deserialize, Serialize, de::MapAccess, ser::SerializeMap};
-use strum::{EnumCount, IntoEnumIterator};
-use thiserror::Error;
-
-use crate::http::{sse::stream::EventFormat, utils};
-
-#[derive(Default, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
-#[serde(transparent)]
-pub struct Value {
-   inner: Str,
-}
-
-impl fmt::Debug for Value {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      let s: &str = &self.inner;
-      write!(f, "{s:?}")
-   }
-}
-
-impl From<String> for Value {
-   fn from(value: String) -> Self {
-      let bytes = Bytes::from_owner(value.into_bytes());
-      unsafe { Self::new_unchecked(bytes) }
-   }
-}
-impl From<Str> for Value {
-   fn from(value: Str) -> Self {
-      Self { inner: value }
-   }
-}
-impl Borrow<str> for Value {
-   fn borrow(&self) -> &str {
-      &self.inner
-   }
-}
-impl AsRef<str> for Value {
-   fn as_ref(&self) -> &str {
-      &self.inner
-   }
-}
-impl Deref for Value {
-   type Target = str;
-   fn deref(&self) -> &Self::Target {
-      &self.inner
-   }
-}
-
-impl Value {
-   /// Creates a new [`Value`] from a static string.
-   pub const fn from_static(data: &'static str) -> Self {
-      let bytes = Bytes::from_static(data.as_bytes());
-      unsafe { Self::new_unchecked(bytes) }
-   }
-
-   /// Creates a new [`Value`] from a [`Bytes`] instance without checking if
-   /// the bytes are valid UTF-8.
-   /// # Safety
-   /// This method is unsafe because it does not check if the bytes are valid
-   /// UTF-8. It is only safe to use if you are sure that the bytes are valid
-   /// UTF-8.
-   pub const unsafe fn new_unchecked(bytes: Bytes) -> Self {
-      Self {
-         inner: unsafe { Str::from_inner_unchecked(bytes) },
-      }
-   }
-
-   /// Creates a new [`Value`] from a [`fmt::Display`] instance by rendering it
-   /// to a [`Str`].
-   pub fn from_display<D: fmt::Display + ?Sized>(data: &D) -> Self {
-      use std::fmt::Write;
-      let mut buf = BytesMut::new();
-      write!(buf, "{data}").unwrap();
-      unsafe { Self::new_unchecked(buf.freeze()) }
-   }
-
-   /// Attempts to parse the [`Value`] as a [`FromStr`] instance.
-   pub fn parse_str<T: FromStr<Err: Into<anyhow::Error>>>(&self) -> Result<T> {
-      self
-         .as_non_empty_str()
-         .ok_or(Error::NoData)
-         .and_then(|s| T::from_str(s).map_err(Error::user_data_parse))
-   }
-
-   /// Creates a new [`Value`] from a [`serde::Serialize`] instance by
-   /// rendering it to a [`Str`].
-   pub fn from_json<J: serde::Serialize + ?Sized>(data: &J) -> Self {
-      let mut buf = BytesMut::new().writer();
-      serde_json::to_writer(&mut buf, data).unwrap();
-      unsafe { Self::new_unchecked(buf.into_inner().freeze()) }
-   }
-
-   /// Attempts to parse the [`Value`] as a [`serde::Deserialize`] instance
-   /// using [`serde_json`].
-   pub fn parse_json<'de, T: serde::de::Deserialize<'de>>(&'de self) -> Result<T> {
-      self
-         .as_non_empty_str()
-         .ok_or(Error::NoData)
-         .and_then(|s| serde_json::from_slice::<'de, T>(s.as_bytes()).map_err(Error::UserData))
-   }
-
-   /// Returns `true` when the [`Value`] is empty.
-   pub fn is_empty(&self) -> bool {
-      self.inner.is_empty()
-   }
-
-   /// Appends a [`Str`] to the [`Value`].
-   pub fn append_str(&mut self, line: Str) {
-      if self.is_empty() {
-         *self = Self::from(line);
-      } else {
-         let mut buf = mem::take(&mut self.inner)
-            .into_inner()
-            .try_into_mut()
-            .unwrap_or_default();
-         buf.reserve(1 + line.len());
-         buf.extend_from_slice(b"\n");
-         buf.extend_from_slice(line.as_bytes());
-         *self = unsafe { Self::new_unchecked(buf.freeze()) };
-      }
-   }
-
-   /// Appends a [`Bytes`] to the [`Value`] without checking if the bytes are
-   /// valid UTF-8.
-   /// # Safety
-   /// This method is unsafe because it does not check if the bytes are valid
-   /// UTF-8. It is only safe to use if you are sure that the bytes are valid
-   /// UTF-8.
-   pub unsafe fn append_unchecked(&mut self, line: Bytes) {
-      let line = unsafe { Str::from_inner_unchecked(line) };
-      self.append_str(line);
-   }
-
-   /// Returns the [`Value`] as a [`Str`].
-   pub fn as_str(&self) -> &str {
-      &self.inner
-   }
-
-   /// Returns the [`Value`] as a [`Str`].
-   pub const fn as_bstr(&self) -> &Str {
-      &self.inner
-   }
-
-   /// Returns the [`Value`] as a [`Bytes`].
-   pub fn as_bytes(&self) -> &Bytes {
-      self.inner.inner()
-   }
-
-   /// Returns the [`Value`] as a [`str`] if it is not empty.
-   pub fn as_non_empty_str(&self) -> Option<&str> {
-      if self.is_empty() {
-         None
-      } else {
-         Some(&self.inner)
-      }
-   }
-}
-
-#[derive(
-   Debug,
-   Clone,
-   Copy,
-   PartialEq,
-   Eq,
-   Hash,
-   strum::EnumString,
-   strum::EnumCount,
-   strum::IntoStaticStr,
-   strum::EnumIter,
-)]
-pub enum IntrinsicField {
-   #[strum(serialize = "id", ascii_case_insensitive)]
-   Id,
-   #[strum(serialize = "data", ascii_case_insensitive)]
-   Data,
-   #[strum(serialize = "event", ascii_case_insensitive)]
-   Event,
-}
-
-/// A single [Server-Sent Event](https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events)
-/// that can be sent **or** received through the [`crate::sse`] module.
-///
-/// The type is purposely minimal and is mainly a thin wrapper over the
-/// wire-format used by browsers and by the [`axum::response::sse`] primitives.
-/// It keeps the raw textual representation so that *unknown* or *vendor
-/// specific* fields are preserved during a round-trip.
-///
-/// Construction of an event follows the "builder" pattern so that calls can be
-/// chained fluently:
-///
-/// ```ignore
-/// use tetra_net::http::sse::Event;
-///
-/// let evt = Event::new()
-///     .with_id(&42)
-///     .with_event("tick")
-///     .with_raw_data("hello world");
-/// ```
-///
-/// # Parsing
-/// Instances are produced by the internal parser when a
-/// [`crate::http::sse::EventStream`] is consumed.  Consumers should use the
-/// high-level accessors such as [`Event::data`] or [`Event::field`] instead of
-/// inspecting the private fields directly.
-#[derive(Clone, Default)]
-pub struct Event {
-   int: [Value; IntrinsicField::COUNT],
-   aux: BTreeMap<Value, Value>,
-}
-
-impl fmt::Debug for Event {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      let mut map = f.debug_struct("Event");
-      for (k, v) in self.fields() {
-         map.field(k, &v.as_str());
-      }
-      map.finish()
-   }
-}
-
-impl serde::Serialize for Event {
-   fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
-   where
-      S: serde::Serializer,
-   {
-      let mut map = serializer.serialize_map(Some(self.len()))?;
-      for (k, v) in self.fields() {
-         map.serialize_entry(k, v)?;
-      }
-      map.end()
-   }
-}
-
-impl<'de> serde::Deserialize<'de> for Event {
-   fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
-   where
-      D: serde::Deserializer<'de>,
-   {
-      struct EventVisitor;
-      impl<'de> serde::de::Visitor<'de> for EventVisitor {
-         type Value = Event;
-         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-            formatter.write_str("an SSE event")
-         }
-         fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
-         where
-            A: MapAccess<'de>,
-         {
-            let mut event = Event::new();
-            while let Some((k, v)) = map.next_entry()? {
-               event.set_field_value(k, v);
-            }
-            Ok(event)
-         }
-      }
-      deserializer.deserialize_map(EventVisitor)
-   }
-}
-
-impl Event {
-   pub const EMPTY: Self = Self::new();
-
-   /// Creates an empty [`Event`].
-   ///
-   /// The returned value carries no field.  Use the builder helpers or the
-   /// individual setters such as [`Event::with_raw_data`] to populate it.
-   ///
-   /// # Examples
-   /// ```ignore
-   /// use tetra_net::http::sse::Event;
-   /// let heartbeat = Event::new();
-   /// assert!(heartbeat.is_empty());
-   /// ```
-   pub const fn new() -> Self {
-      Self {
-         int: [const { Value::from_static("") }; IntrinsicField::COUNT],
-         aux: BTreeMap::new(),
-      }
-   }
-
-   /// Returns an iterator over the fields in the event.
-   pub fn fields(&self) -> impl Iterator<Item = (&str, &Value)> {
-      IntrinsicField::iter()
-         .map(|field| (field.into(), &self.int[field as usize]))
-         .filter(|(_, v)| !v.is_empty())
-         .chain(self.aux.iter().map(|(k, v)| (k as &str, v)))
-   }
-
-   /// Returns the number of fields in the event.
-   pub fn len(&self) -> usize {
-      let mut n = 0;
-      for field in IntrinsicField::iter() {
-         if !self.int[field as usize].is_empty() {
-            n += 1;
-         }
-      }
-      n += self.aux.len(); // aux is guaranteed to be non-empty
-      n
-   }
-
-   /// Returns `true` when the event does not carry any field whatsoever.
-   ///
-   /// This can be useful to ignore *keep-alive* messages that some servers
-   /// periodically send configured with `:\n`.
-   pub fn is_empty(&self) -> bool {
-      IntrinsicField::iter().all(|field| self.int[field as usize].is_empty()) && self.aux.is_empty()
-   }
-
-   /// Sets the value of an intrinsic field.
-   pub fn with_intrinsic(mut self, field: IntrinsicField, value: Value) -> Self {
-      self.int[field as usize] = value;
-      self
-   }
-
-   /// Sets the `id:` field.
-   ///
-   /// The identifier will be converted to a string using [`fmt::Display`].
-   /// Although the *SSE* specification does not mandate any particular format,
-   /// using an increasing integer is a common pattern as it allows the browser
-   /// to resume the stream by sending the `Last-Event-ID` header.
-   pub fn with_id<D: fmt::Display + ?Sized>(self, id: &D) -> Self {
-      self.with_intrinsic(IntrinsicField::Id, Value::from_display(id))
-   }
-
-   /// Writes raw UTF-8 data into the `data:` field.
-   ///
-   /// The contents are **not** escaped or transformed in any way; make sure it
-   /// does not contain control characters other than **LF** (`\n`).  For JSON
-   /// payloads prefer [`Event::with_json_data`] which automatically serialises
-   /// the value for you.
-   pub fn with_raw_data<D: fmt::Display + ?Sized>(self, data: &D) -> Self {
-      self.with_intrinsic(IntrinsicField::Data, Value::from_display(data))
-   }
-
-   /// Serialises `data` into JSON and stores the resulting string in the
-   /// `data:` field.
-   ///
-   /// # Errors
-   /// The method panics if `serde_json` cannot serialise the value.  The panic
-   /// is not expected in practice — if it does occur it signals a bug in the
-   /// caller or during the derivation of [`serde::Serialize`].
-   pub fn with_json_data<J: serde::Serialize + ?Sized>(self, data: &J) -> Self {
-      self.with_intrinsic(IntrinsicField::Data, Value::from_json(data))
-   }
-
-   /// Explicitly sets the [`event`](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation)
-   /// name of the message.
-   ///
-   /// This is a convenience wrapper around writing to the `event:` field.
-   /// It exists because the field name collides with the [`Event::event`]
-   /// accessor.
-   pub fn with_event<D: fmt::Display + ?Sized>(self, name: &D) -> Self {
-      self.with_intrinsic(IntrinsicField::Event, Value::from_display(name))
-   }
-
-   /// Inserts an arbitrary, user-defined field.
-   ///
-   /// According to the _WHATWG_ specification any unrecognised field must be
-   /// forwarded to the client unchanged.  This method therefore gives you a
-   /// fully future-proof escape hatch.
-   ///
-   /// The provided key **must** already comply with the field-name grammar —
-   /// no validation is performed.
-   pub fn with_field(mut self, key: impl AsRef<str> + Into<Str>, value: impl Into<Value>) -> Self {
-      let kstr = key.as_ref();
-      if let Ok(field) = kstr.parse() {
-         return self.with_intrinsic(field, value.into());
-      }
-      if kstr.is_empty() {
-         return self;
-      }
-
-      let value: Value = value.into();
-      if value.is_empty() {
-         self.aux.remove(kstr);
-      } else {
-         let owned: Str = key.into();
-         self.aux.insert(owned.into(), value);
-      }
-      self
-   }
-   /// Returns a mutable reference to the value of the field identified by
-   /// `key`.
-   ///
-   /// If the field is an intrinsic field (like `data`, `id`, or `event`),
-   /// returns a reference to that field's value. Otherwise, looks up the
-   /// field in the map of custom fields.
-   ///
-   /// # Returns
-   /// - `Some(&mut Value)` if the field exists
-   /// - `None` if the field doesn't exist in custom fields
-   pub fn field_value_mut(&mut self, key: &str) -> Option<&mut Value> {
-      if let Ok(field) = key.parse::<IntrinsicField>() {
-         return Some(&mut self.int[field as usize]);
-      }
-      self.aux.get_mut(key)
-   }
-
-   /// Returns a reference to the value of the field identified by `key`.
-   ///
-   /// If the field is an intrinsic field (like `data`, `id`, or `event`),
-   /// returns a reference to that field's value. Otherwise, looks up the
-   /// field in the map of custom fields.
-   ///
-   /// # Returns
-   /// Returns the field's value, or an empty value if the field doesn't exist.
-   pub fn field_value(&self, key: &str) -> &Value {
-      if let Ok(field) = key.parse::<IntrinsicField>() {
-         return &self.int[field as usize];
-      }
-      static DEFAULT: Value = Value::from_static("");
-      self.aux.get(key).unwrap_or(&DEFAULT)
-   }
-
-   /// Sets the value of a field identified by `key`.
-   ///
-   /// If the field is an intrinsic field (like `data`, `id`, or `event`),
-   /// updates that field's value. Otherwise, inserts or updates the field in
-   /// the map of custom fields.
-   pub fn set_field_value(&mut self, key: Str, value: Value) {
-      if let Ok(field) = key.parse::<IntrinsicField>() {
-         self.int[field as usize] = value;
-      } else {
-         self.aux.insert(key.into(), value);
-      }
-   }
-
-   /// Returns the identifier carried by the `id:` field, if any.
-   ///
-   /// The caller **must not** assume any particular semantics: the value may
-   /// be a monotonic counter, a UUID or even a timestamp.  Its interpretation
-   /// is left to the application layer.
-   pub fn id(&self) -> Option<&str> {
-      self.int[IntrinsicField::Id as usize].as_non_empty_str()
-   }
-
-   /// Returns the raw payload as a UTF-8 string.
-   ///
-   /// Contrary to [`Event::json_data`], this accessor does **not** attempt to
-   /// parse the value as JSON — it simply exposes the bytes as text.  Use it
-   /// when you expect the `data:` field to hold arbitrary text or when
-   /// performance is critical.
-   pub fn text_data(&self) -> Option<&str> {
-      self.int[IntrinsicField::Data as usize].as_non_empty_str()
-   }
-
-   /// Returns the _event type_ (value of the `event:` field) if present.
-   pub fn event(&self) -> Option<&str> {
-      self.int[IntrinsicField::Event as usize].as_non_empty_str()
-   }
-
-   /// Attempts to deserialize the `data:` field from JSON into `J`.
-   pub fn json_data<'de, J: serde::de::Deserialize<'de>>(&'de self) -> Result<J> {
-      self.int[IntrinsicField::Data as usize].parse_json()
-   }
-
-   /// Attempts to deserialize the `data:` field from string into `T`.
-   pub fn fmt_data<T: FromStr<Err: Into<anyhow::Error>>>(&self) -> Result<T> {
-      self.int[IntrinsicField::Data as usize].parse_str()
-   }
-
-   /// Returns an arbitrary field previously added with [`Event::with_field`].
-   ///
-   /// The lookup is case-sensitive and uses the field name *as sent on the
-   /// wire*.
-   pub fn field(&self, key: &str) -> Option<&str> {
-      self.field_value(key).as_non_empty_str()
-   }
-
-   /// Appends a string value to an existing field or creates a new one.
-   ///
-   /// # Arguments
-   /// * `key` - The field name to append to
-   /// * `value` - The bytes value to append
-   ///
-   /// If the field is an intrinsic field (data, id, event), appends to that
-   /// field. Otherwise, inserts or replaces the custom field with the given
-   /// value.
-   pub(crate) fn append_field_value(&mut self, key: Str, value: Str) {
-      if value.is_empty() || key.is_empty() {
-         return;
-      }
-
-      if let Ok(field) = key.parse::<IntrinsicField>() {
-         self.int[field as usize].append_str(value);
-      } else {
-         self.aux.insert(key.into(), Value::from(value));
-      }
-   }
-
-   /// Converts this event to a chunk of bytes.
-   pub fn to_body(&self, format: EventFormat) -> Bytes {
-      match format {
-         EventFormat::Dom => self.to_dom_body(),
-         EventFormat::NdJson => self.to_ndjson_body(),
-      }
-   }
-
-   /// Converts this event to a chunk of bytes in DOM format.
-   pub fn to_dom_body(&self) -> Bytes {
-      if self.is_empty() {
-         return Bytes::from_static(b":\n\n");
-      }
-
-      let mut size_estimation = self
-         .fields()
-         .fold(0, |acc, (k, v)| acc + k.len() + v.len() + 3);
-      if size_estimation == 0 {
-         return Bytes::new();
-      }
-      size_estimation += 1;
-
-      let mut buf = BytesMut::with_capacity(size_estimation);
-      for (k, v) in self.fields() {
-         buf.extend_from_slice(k.as_bytes());
-         buf.extend_from_slice(b": ");
-         buf.extend_from_slice(v.as_bytes());
-         buf.put_u8(b'\n');
-      }
-      if !buf.is_empty() {
-         buf.put_u8(b'\n');
-      }
-      buf.freeze()
-   }
-
-   /// Converts this event to a chunk of bytes in NDJSON format.
-   pub fn to_ndjson_body(&self) -> Bytes {
-      if self.is_empty() {
-         return Bytes::from_static(b"{}\n");
-      }
-
-      let mut size_estimation = self
-         .fields()
-         .fold(0, |acc, (k, v)| acc + k.len() + v.len() + 8);
-      if size_estimation == 0 {
-         return Bytes::new();
-      }
-      size_estimation += 3;
-
-      let mut wr = BytesMut::with_capacity(size_estimation).writer();
-      serde_json::to_writer(&mut wr, self).expect("Failed to serialize event");
-      let mut buf = wr.into_inner();
-      buf.put_u8(b'\n');
-      buf.freeze()
-   }
-
-   /// Parses an event in DOM format from a buffer of bytes.
-   ///
-   /// The DOM format separates events with double newlines (`\n\n`).
-   ///
-   /// # Arguments
-   /// * `lines` - A mutable reference to a buffer containing SSE data
-   ///
-   /// # Returns
-   /// * `Ok(Some(Event))` - If an event was successfully parsed
-   /// * `Ok(None)` - If no complete event was found in the buffer
-   /// * `Err(Error)` - If an error occurred during parsing
-   pub fn parse_dom_body(lines: &mut BytesMut) -> Result<Option<Self>> {
-      // If there's no \n\n, nothing to read.
-      let lines = {
-         let Some(i) = memchr::memmem::find(lines.as_ref(), b"\n\n") else {
-            return Ok(None);
-         };
-         let mut cursor = lines.split_to(i + 2);
-         cursor.truncate(i);
-         Str::try_from(cursor.freeze()).map_err(|x| Error::Utf8(x.utf8_error()))?
-      };
-
-      // Parse the event.
-      let mut event = Self::default();
-      let mut seen_non_empty = false;
-      for line in lines.split('\n') {
-         // Ignore comments.
-         if line.starts_with(':') {
-            continue;
-         }
-
-         let Some(i) = line.find(": ") else {
-            // error?
-            continue;
-         };
-
-         let key = &line[..i];
-         let val = &line[i + 2..];
-         if key.is_empty() || val.is_empty() {
-            continue;
-         }
-         seen_non_empty = true;
-
-         let key = lines.slice_ref(key);
-         let val = lines.slice_ref(val);
-         event.append_field_value(key, val);
-      }
-
-      if seen_non_empty {
-         Ok(Some(event))
-      } else {
-         Ok(None)
-      }
-   }
-
-   /// Parses an event in NDJSON format from a buffer of bytes.
-   ///
-   /// The NDJSON format separates events with newlines (`\n`).
-   ///
-   /// # Arguments
-   /// * `lines` - A mutable reference to a buffer containing NDJSON data
-   ///
-   /// # Returns
-   /// * `Ok(Some(Event))` - If an event was successfully parsed
-   /// * `Ok(None)` - If no complete event was found in the buffer
-   /// * `Err(Error)` - If an error occurred during parsing
-   pub fn parse_ndjson_body(lines: &mut BytesMut) -> Result<Option<Self>> {
-      // If there's no \n, nothing to read.
-      let cursor = {
-         let Some(i) = memchr::memchr(b'\n', lines.as_ref()) else {
-            return Ok(None);
-         };
-         let mut cursor = lines.split_to(i + 1);
-         cursor.truncate(i);
-         cursor.freeze()
-      };
-
-      // Parse the event as JSON.
-      if cursor.as_ref() == b"{}" {
-         return Ok(Some(Self::EMPTY));
-      }
-      let event: Self = serde_json::from_slice(cursor.as_ref())?;
-      if event.is_empty() {
-         return Ok(None);
-      }
-      Ok(Some(event))
-   }
-
-   /// Parses an event from a buffer using the specified format.
-   ///
-   /// # Arguments
-   /// * `lines` - A mutable reference to a buffer containing event data
-   /// * `format` - The format of the events (DOM or NDJSON)
-   ///
-   /// # Returns
-   /// * `Ok(Some(Event))` - If an event was successfully parsed
-   /// * `Ok(None)` - If no complete event was found in the buffer
-   /// * `Err(Error)` - If an error occurred during parsing
-   pub fn parse_body(lines: &mut BytesMut, format: EventFormat) -> Result<Option<Self>> {
-      match format {
-         EventFormat::Dom => Self::parse_dom_body(lines),
-         EventFormat::NdJson => Self::parse_ndjson_body(lines),
-      }
-   }
-}
-
-/// Errors that can be emitted while parsing or streaming [`Event`]s.
-#[derive(Debug, Error)]
-pub enum Error {
-   #[error(transparent)]
-   Remote(#[from] utils::Error),
-   #[error("UTF-8 error: {0}")]
-   Utf8(#[from] str::Utf8Error),
-   /// Error from the HTTP client.
-   #[error(transparent)]
-   Reqwest(#[from] reqwest::Error),
-   /// Errors during deserialisation of the `data:` field.
-   #[error("Failed to parse user data using serde_json: {0}")]
-   UserData(#[from] serde_json::Error),
-   /// Error from the `FromStr` implementation.
-   #[error("Failed to parse user data using FromStr: {0}")]
-   UserDataParse(#[source] anyhow::Error),
-   #[error("Event has no associated data")]
-   NoData,
-}
-
-impl Error {
-   pub fn user_data_parse<E: Into<anyhow::Error>>(err: E) -> Self {
-      Self::UserDataParse(err.into())
-   }
-}
-
-/// Convenience alias over [`std::result::Result`] that defaults the error type
-/// to [`Error`].
-pub type Result<T, E = Error> = std::result::Result<T, E>;
-
-#[cfg(test)]
-mod tests {
-   use bytes::BytesMut;
-
-   use super::*;
-
-   /// Tests the roundtrip serialization and deserialization of Events in DOM
-   /// format.
-   #[test]
-   fn test_event_roundtrip_dom() {
-      // Create test events with different combinations of fields
-      let events = vec![
-         Event::new().with_raw_data("simple data"),
-         Event::new().with_raw_data("data with id").with_id("1234"),
-         Event::new()
-            .with_raw_data("complete event")
-            .with_id("5678")
-            .with_event("custom-event"),
-      ];
-
-      for original_event in events {
-         // Serialize the event to DOM format
-         let serialized = original_event.to_body(EventFormat::Dom);
-         // Parse the event back from the serialized bytes
-         let mut buffer = BytesMut::from(&serialized[..]);
-         let parsed_event = Event::parse_dom_body(&mut buffer)
-            .expect("Failed to parse event")
-            .expect("No event parsed");
-
-         // Verify the parsed event matches the original
-         assert_eq!(parsed_event.text_data(), original_event.text_data());
-         assert_eq!(parsed_event.id(), original_event.id());
-         assert_eq!(parsed_event.event(), original_event.event());
-      }
-   }
-
-   /// Tests the roundtrip serialization and deserialization of Events in
-   /// NDJSON format.
-   #[test]
-   fn test_event_roundtrip_ndjson() {
-      // Create test events with different combinations of fields
-      let events = vec![
-         Event::new().with_raw_data("simple data"),
-         Event::new().with_raw_data("data with id").with_id("1234"),
-         Event::new()
-            .with_raw_data("complete event")
-            .with_id("5678")
-            .with_event("custom-event"),
-      ];
-
-      for original_event in events {
-         // Serialize the event to NDJSON format
-         let serialized = original_event.to_body(EventFormat::NdJson);
-
-         // Parse the event back from the serialized bytes
-         let mut buffer = BytesMut::from(&serialized[..]);
-         let parsed_event = Event::parse_ndjson_body(&mut buffer)
-            .expect("Failed to parse event")
-            .expect("No event parsed");
-
-         // Verify the parsed event matches the original
-         assert_eq!(parsed_event.text_data(), original_event.text_data());
-         assert_eq!(parsed_event.id(), original_event.id());
-         assert_eq!(parsed_event.event(), original_event.event());
-      }
-   }
-
-   /// Tests the generic `parse_as` method with both formats.
-   #[test]
-   fn test_event_parse_as() {
-      let event = Event::new()
-         .with_raw_data("test data")
-         .with_id("123")
-         .with_event("test");
-
-      // Test DOM format
-      let dom_bytes = event.to_body(EventFormat::Dom);
-      let mut dom_buffer = BytesMut::from(&dom_bytes[..]);
-      let parsed_dom = Event::parse_body(&mut dom_buffer, EventFormat::Dom)
-         .expect("Failed to parse DOM format")
-         .expect("No DOM event parsed");
-
-      assert_eq!(parsed_dom.text_data(), event.text_data());
-      assert_eq!(parsed_dom.id(), event.id());
-      assert_eq!(parsed_dom.event(), event.event());
-
-      // Test NDJSON format
-      let ndjson_bytes = event.to_body(EventFormat::NdJson);
-      let mut ndjson_buffer = BytesMut::from(&ndjson_bytes[..]);
-      let parsed_ndjson = Event::parse_body(&mut ndjson_buffer, EventFormat::NdJson)
-         .expect("Failed to parse NDJSON format")
-         .expect("No NDJSON event parsed");
-
-      assert_eq!(parsed_ndjson.text_data(), event.text_data());
-      assert_eq!(parsed_ndjson.id(), event.id());
-      assert_eq!(parsed_ndjson.event(), event.event());
-   }
-}
diff --git a/attic/net/http/upgrade.rs b/attic/net/http/upgrade.rs
deleted file mode 100644
index 921bbbff6..000000000
--- a/attic/net/http/upgrade.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-use std::{
-   fmt,
-   future::Future,
-   io, mem,
-   pin::Pin,
-   sync::Arc,
-   task,
-   task::{Context, Poll},
-};
-
-use futures::FutureExt;
-use hyper::upgrade::OnUpgrade as HyperOnUpgrade;
-use parking_lot::Mutex;
-use tokio::{
-   io::{AsyncRead, AsyncWrite, ReadBuf},
-   sync::oneshot,
-};
-
-#[derive(Debug, thiserror::Error)]
-pub enum UpgradeError {
-   #[error("hyper error: {0}")]
-   Hyper(hyper::Error),
-   #[error("timeout")]
-   Timeout,
-   #[error("cancelled")]
-   Cancelled,
-   #[error("use after lifetime")]
-   UseAfterLifetime,
-   #[error("connection not upgradable")]
-   ConnectionNotUpgradable,
-}
-
-pub trait UpgradedDuplex: AsyncRead + AsyncWrite + Send + Sync + 'static {}
-impl<T: AsyncRead + AsyncWrite + Send + Sync + 'static> UpgradedDuplex for T {}
-
-pub enum Upgraded {
-   Hyper(reqwest::Upgraded), // nice wrapper around it with TokioIo
-   Custom(Pin<Box<dyn UpgradedDuplex>>),
-}
-
-impl From<hyper::upgrade::Upgraded> for Upgraded {
-   fn from(value: hyper::upgrade::Upgraded) -> Self {
-      Self::Hyper(value.into())
-   }
-}
-
-impl Upgraded {
-   pub fn custom<T: UpgradedDuplex>(dup: T) -> Self {
-      Self::Custom(Box::pin(dup))
-   }
-}
-
-impl AsyncRead for Upgraded {
-   fn poll_read(
-      mut self: Pin<&mut Self>,
-      cx: &mut task::Context<'_>,
-      buf: &mut ReadBuf<'_>,
-   ) -> Poll<io::Result<()>> {
-      match &mut *self {
-         Self::Hyper(h) => Pin::new(h).poll_read(cx, buf),
-         Self::Custom(c) => Pin::new(c).poll_read(cx, buf),
-      }
-   }
-}
-
-impl AsyncWrite for Upgraded {
-   fn poll_write(
-      mut self: Pin<&mut Self>,
-      cx: &mut task::Context<'_>,
-      buf: &[u8],
-   ) -> Poll<io::Result<usize>> {
-      match &mut *self {
-         Self::Hyper(h) => Pin::new(h).poll_write(cx, buf),
-         Self::Custom(c) => Pin::new(c).poll_write(cx, buf),
-      }
-   }
-
-   fn poll_write_vectored(
-      mut self: Pin<&mut Self>,
-      cx: &mut task::Context<'_>,
-      bufs: &[io::IoSlice<'_>],
-   ) -> Poll<io::Result<usize>> {
-      match &mut *self {
-         Self::Hyper(h) => Pin::new(h).poll_write_vectored(cx, bufs),
-         Self::Custom(c) => Pin::new(c).poll_write_vectored(cx, bufs),
-      }
-   }
-
-   fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
-      match &mut *self {
-         Self::Hyper(h) => Pin::new(h).poll_flush(cx),
-         Self::Custom(c) => Pin::new(c).poll_flush(cx),
-      }
-   }
-
-   fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
-      match &mut *self {
-         Self::Hyper(h) => Pin::new(h).poll_shutdown(cx),
-         Self::Custom(c) => Pin::new(c).poll_shutdown(cx),
-      }
-   }
-
-   fn is_write_vectored(&self) -> bool {
-      match self {
-         Self::Hyper(h) => h.is_write_vectored(),
-         Self::Custom(c) => c.is_write_vectored(),
-      }
-   }
-}
-
-impl fmt::Debug for Upgraded {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      if let Self::Hyper(h) = self {
-         f.debug_struct("Upgraded").field("hyper", &h).finish()
-      } else {
-         f.debug_struct("Upgraded").field("custom", &self).finish()
-      }
-   }
-}
-
-/// A custom upgrade future for mock transports.
-///
-/// This can be used in place of [`hyper::upgrade::OnUpgrade`] when
-/// constructing HTTP requests manually.
-#[derive(Clone, Debug)]
-pub enum OnUpgrade {
-   None,
-   Custom(Arc<Mutex<oneshot::Receiver<Result<Upgraded, UpgradeError>>>>),
-   Hyper(HyperOnUpgrade),
-}
-
-pub type Promise = oneshot::Sender<Result<Upgraded, UpgradeError>>;
-
-impl OnUpgrade {
-   /// Returns a sender paired with a new `OnUpgrade` future.
-   pub fn pending() -> (Promise, Self) {
-      let (tx, rx) = oneshot::channel();
-      (tx, Self::Custom(Arc::new(Mutex::new(rx))))
-   }
-
-   /// Returns a sender paired with a new `OnUpgrade` future.
-   pub fn pending_at(ext: &mut http::Extensions) -> Promise {
-      let (pr, up) = Self::pending();
-      ext.insert(up);
-      pr
-   }
-
-   /// Extracts an `OnUpgrade` from the extensions.
-   pub fn extract(ext: &mut http::Extensions) -> Result<Self, UpgradeError> {
-      if let Some(on_upgrade) = ext.remove::<hyper::upgrade::OnUpgrade>() {
-         Ok(Self::Hyper(on_upgrade))
-      } else if let Some(on_upgrade) = ext.remove::<Self>() {
-         Ok(on_upgrade)
-      } else {
-         Err(UpgradeError::ConnectionNotUpgradable)
-      }
-   }
-
-   pub const fn take(&mut self) -> Self {
-      mem::replace(self, Self::None)
-   }
-}
-
-impl Future for OnUpgrade {
-   type Output = Result<Upgraded, UpgradeError>;
-
-   fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-      match self.take() {
-         Self::Custom(rx) => {
-            if let Poll::Ready(res) = rx.lock().poll_unpin(cx) {
-               return Poll::Ready(res.map_err(|_| UpgradeError::Cancelled).flatten());
-            }
-            *self = Self::Custom(rx);
-            Poll::Pending
-         },
-         Self::Hyper(mut up) => {
-            if let Poll::Ready(res) = up.poll_unpin(cx) {
-               return Poll::Ready(res.map_err(UpgradeError::Hyper).map(Upgraded::from));
-            }
-            *self = Self::Hyper(up);
-            Poll::Pending
-         },
-         Self::None => Poll::Ready(Err(UpgradeError::UseAfterLifetime)),
-      }
-   }
-}
-
-impl From<HyperOnUpgrade> for OnUpgrade {
-   fn from(up: HyperOnUpgrade) -> Self {
-      Self::Hyper(up)
-   }
-}
diff --git a/attic/net/http/utils.rs b/attic/net/http/utils.rs
deleted file mode 100644
index b83c9e547..000000000
--- a/attic/net/http/utils.rs
+++ /dev/null
@@ -1,534 +0,0 @@
-use std::{
-   borrow::Cow,
-   mem,
-   time::{Duration, SystemTime},
-};
-
-use axum::response::IntoResponse;
-use futures::StreamExt;
-use http::{HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
-use httpdate::parse_http_date;
-use smol_str::{SmolStr, ToSmolStr};
-use tokio::{pin, select};
-
-#[derive(derive_more::Debug)]
-pub enum ErrorBody {
-   #[debug("{:?}", 0)]
-   Read(Cow<'static, str>),
-   #[debug("{:?}... (truncated)", 1)]
-   Trunc(Cow<'static, str>),
-   #[debug("<Io error: {:?}>", 2)]
-   Errored(anyhow::Error),
-   #[debug("<Io timeout>")]
-   Timeout,
-}
-
-/// Extension type inserted into [`reqwest::Response`] when the server returns
-/// a `Retry-After` header.
-#[derive(Debug, Clone, Copy)]
-pub struct RetryAfter(pub Duration);
-
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
-   /// The server did not respond with the expected status code.
-   #[error("unexpected status code {code}. response: {body:?}")]
-   UnexpectedStatus {
-      code: StatusCode,
-      body: ErrorBody,
-      retry_after: Option<Duration>,
-   },
-
-   /// The server responded with a client error status code (400-499).
-   #[error("client error {code}. response: {body:?}")]
-   ClientError {
-      code: StatusCode,
-      body: ErrorBody,
-      retry_after: Option<Duration>,
-   },
-
-   /// The server responded with a server error status code (500-599).
-   #[error("server error {code}. response: {body:?}")]
-   ServerError {
-      code: StatusCode,
-      body: ErrorBody,
-      retry_after: Option<Duration>,
-   },
-
-   /// A required header was missing.
-   #[error("missing header {0}")]
-   MissingHeader(&'static str),
-
-   /// The server did not respond with the expected method.
-   #[error("unexpected method. got {got:?}, expected {expected}")]
-   UnexpectedMethod {
-      got: Method,
-      expected: &'static Method,
-   },
-
-   /// The server did not respond with the expected header value.
-   #[error("unexpected header value for {header}. got {got:?}, expected {expected}")]
-   UnexpectedHeaderValue {
-      header: &'static str,
-      got: Option<HeaderValue>,
-      expected: SmolStr,
-   },
-
-   /// The content-type header does not match the expected value.
-   #[error("unexpected content-type. server sent {got:?}, client expected {expected:?}")]
-   UnexpectedContentType {
-      got: SmolStr,
-      expected: Vec<&'static str>,
-   },
-
-   /// Content-type negotiation failed.
-   #[error("content-type negotiation failed. client accepts {got:?}, server supports {expected:?}")]
-   ContentTypeNegotiationFailed {
-      got: SmolStr,
-      expected: Vec<&'static str>,
-   },
-
-   /// Wrapped error
-   #[error(transparent)]
-   Wrapped(anyhow::Error),
-}
-
-impl Error {
-   pub const fn code(&self) -> StatusCode {
-      match self {
-         Self::UnexpectedStatus { .. } => StatusCode::UNPROCESSABLE_ENTITY,
-         &Self::ClientError { code, .. } => code,
-         &Self::ServerError { code, .. } => code,
-         Self::MissingHeader(_) => StatusCode::BAD_REQUEST,
-         Self::UnexpectedMethod { .. } => StatusCode::METHOD_NOT_ALLOWED,
-         Self::UnexpectedHeaderValue { .. } => StatusCode::PRECONDITION_FAILED,
-         Self::UnexpectedContentType { .. } => StatusCode::UNSUPPORTED_MEDIA_TYPE,
-         Self::ContentTypeNegotiationFailed { .. } => StatusCode::NOT_ACCEPTABLE,
-         Self::Wrapped(_) => StatusCode::INTERNAL_SERVER_ERROR,
-      }
-   }
-
-   pub fn wrap(e: impl Into<anyhow::Error>) -> Self {
-      Self::Wrapped(e.into())
-   }
-}
-
-impl IntoResponse for Error {
-   fn into_response(self) -> axum::response::Response {
-      axum::response::Response::builder()
-         .status(self.code())
-         .body(axum::body::Body::from(self.to_string()))
-         .unwrap()
-   }
-}
-
-pub type Result<T, E = Error> = std::result::Result<T, E>;
-
-const ERROR_TIMEOUT: Duration = Duration::from_secs(4);
-const MAX_ERROR_BODY: usize = 1024;
-
-/// Parses the `Retry-After` header from the given set of headers.
-pub fn retry_after(headers: &HeaderMap) -> Option<Duration> {
-   headers
-      .get("Retry-After")
-      .and_then(|v| v.to_str().ok())
-      .and_then(|s| {
-         s.trim()
-            .parse::<u64>()
-            .map(Duration::from_secs)
-            .ok()
-            .or_else(|| {
-               parse_http_date(s)
-                  .ok()
-                  .and_then(|t| t.duration_since(SystemTime::now()).ok())
-            })
-      })
-}
-
-/// Helper function to read the error body of a response.
-pub async fn read_remote_error(response: reqwest::Response) -> Error {
-   let status = response.status();
-   let retry = retry_after(response.headers());
-
-   let mut buffer: Vec<u8> = Vec::new();
-   let mut stream = response.bytes_stream();
-
-   let mut body = ErrorBody::Read(Cow::Borrowed(""));
-   let timeout = tokio::time::sleep(ERROR_TIMEOUT);
-   pin!(timeout);
-   while buffer.len() < MAX_ERROR_BODY {
-      select! {
-         biased;
-         res = stream.next() => {
-            match res {
-               Some(Ok(bytes)) => {
-                  let max_read = MAX_ERROR_BODY - buffer.len();
-                  if bytes.len() > max_read {
-                     buffer.extend_from_slice(&bytes[..max_read]);
-                     body = ErrorBody::Trunc(String::from_utf8_lossy_owned(mem::take(&mut buffer)).into());
-                     break;
-                  }
-                  buffer.extend_from_slice(&bytes);
-               },
-               Some(Err(e)) => {
-                  body = ErrorBody::Errored(e.into());
-                  break;
-               },
-               None => {
-                  if !buffer.is_empty() {
-                     body = ErrorBody::Read(String::from_utf8_lossy_owned(mem::take(&mut buffer)).into());
-                  }
-                  break;
-               }
-            }
-         },
-         () = &mut timeout => {
-            if buffer.is_empty() {
-               body = ErrorBody::Timeout;
-            }
-            break;
-         },
-      }
-   }
-
-   if status.is_client_error() {
-      Error::ClientError {
-         code: status,
-         body,
-         retry_after: retry,
-      }
-   } else if status.is_server_error() {
-      Error::ServerError {
-         code: status,
-         body,
-         retry_after: retry,
-      }
-   } else {
-      Error::UnexpectedStatus {
-         code: status,
-         body,
-         retry_after: retry,
-      }
-   }
-}
-
-/// Helper function to get a header as a string.
-pub fn header_as_str<'a>(
-   headers: &'a HeaderMap,
-   header: &'static HeaderName,
-) -> Result<&'a str, Error> {
-   headers
-      .get(header)
-      .and_then(|h| h.to_str().ok())
-      .ok_or(Error::MissingHeader(header.as_str()))
-}
-
-/// Helper function to check if a header matches an expected value.
-pub fn header_must_eq(
-   headers: &HeaderMap,
-   header: &'static HeaderName,
-   expected: &str,
-) -> Result<(), Error> {
-   let value = header_as_str(headers, header)?;
-   if !value.eq_ignore_ascii_case(expected) {
-      return Err(Error::UnexpectedHeaderValue {
-         header: header.as_str(),
-         got: headers.get(header).cloned(),
-         expected: expected.to_smolstr(),
-      });
-   }
-   Ok(())
-}
-
-pub trait ToMime: Clone + PartialEq + Eq {
-   fn to_mime(&self) -> &'static str;
-}
-
-impl ToMime for &'static str {
-   fn to_mime(&self) -> &'static str {
-      self
-   }
-}
-
-/// Performs content negotiation to select the best MIME type from
-/// server-supported types.
-///
-/// This function compares the client's `Accept` header against a list of
-/// server-supported MIME types, selecting the best match according to HTTP
-/// content negotiation rules. It handles wildcards (e.g. `*/*`), quality
-/// values, and character set extensions.
-///
-/// # Examples
-/// ```
-/// # use http::HeaderMap;
-/// # use tetra_net::http::utils::negotiate_content_type;
-/// let mut headers = HeaderMap::new();
-/// headers.insert(
-///    "Accept",
-///    "text/html, application/json;q=0.8, */*;q=0.1"
-///       .parse()
-///       .unwrap(),
-/// );
-///
-/// // Server supports these formats
-/// let supported = &["application/json", "text/plain"];
-///
-/// assert_eq!(
-///    negotiate_content_type(&headers, supported).ok(),
-///    Some("application/json")
-/// );
-/// ```
-///
-/// # Return value
-///
-/// Returns the best matching MIME type from the supported list, or `None` if
-/// no acceptable match could be found.
-pub fn negotiate_content_type<T: ToMime>(headers: &HeaderMap, supported_types: &[T]) -> Result<T> {
-   // If no supported types, return None
-   let Some(preferred) = supported_types.first() else {
-      return Err(Error::ContentTypeNegotiationFailed {
-         got: header_as_str(headers, &http::header::ACCEPT)?.to_smolstr(),
-         expected: Vec::new(),
-      });
-   };
-
-   // If no Accept header present, return first supported type
-   let accept_header = match headers.get(http::header::ACCEPT) {
-      Some(value) => match value.to_str() {
-         Ok(v) => v,
-         Err(_) => return Ok(preferred.clone()),
-      },
-      None => return Ok(preferred.clone()),
-   };
-
-   accept_header
-      // Split the Accept header into parts
-      .split(',')
-      // Parse the Accept header into (mime, quality) pairs
-      .filter_map(|part| {
-         let part = part.trim();
-         if part.is_empty() {
-            return None;
-         }
-
-         // Split into mime and params
-         let mut parts = part.split(';');
-         let mime = parts.next()?.trim();
-
-         // Default quality is 1.0
-         let mut quality = 100;
-
-         // Parse quality value if present
-         for param in parts {
-            let param = param.trim();
-            if let Some(q_val) = param.strip_prefix("q=")
-               && let Ok(q) = q_val.parse::<f32>()
-            {
-               // Skip if quality is zero
-               if q <= f32::EPSILON {
-                  return None;
-               }
-               quality = (q.min(1.0) * 100.0) as u8;
-               break;
-            }
-         }
-         Some((mime, quality))
-      })
-      // Skip those that are not supported
-      .filter_map(|(accept_mime, q)| {
-         // Handle wildcard
-         if accept_mime == "*/*" {
-            return Some((preferred.clone(), q));
-         }
-
-         // Handle type wildcards like "text/*"
-         if let Some(prefix) = accept_mime.strip_suffix("/*") {
-            for supported in supported_types {
-               let mime = supported.to_mime();
-               if mime.starts_with(prefix)
-                  && mime.len() > prefix.len()
-                  && mime.as_bytes()[prefix.len()] == b'/'
-               {
-                  return Some((supported.clone(), q));
-               }
-            }
-         }
-
-         // Strip charset and other parameters from mime for comparison
-         let base_mime = accept_mime.split(';').next().unwrap_or(accept_mime).trim();
-
-         // Direct match
-         for supported in supported_types {
-            let mime = supported.to_mime();
-            if base_mime.eq_ignore_ascii_case(mime) {
-               return Some((supported.clone(), q));
-            }
-         }
-
-         None
-      })
-      // Find the best match
-      .max_by_key(|&(_, quality)| quality)
-      // Return the best match
-      .map(|(mime, _)| mime)
-      .ok_or_else(|| Error::ContentTypeNegotiationFailed {
-         got: accept_header.to_smolstr(),
-         expected: supported_types.iter().map(|t| t.to_mime()).collect(),
-      })
-}
-
-/// Matches a Content-Type header against a list of supported MIME types.
-///
-/// This function checks if the Content-Type header of a request or response
-/// matches any of the provided supported MIME types. It handles parameters
-/// in the Content-Type header (like charset) by comparing only the base MIME
-/// type.
-///
-/// # Examples
-/// ```
-/// # use http::HeaderMap;
-/// # use tetra_net::http::utils::match_content_type;
-/// let mut headers = HeaderMap::new();
-/// headers.insert(
-///    "Content-Type",
-///    "application/json; charset=utf-8".parse().unwrap(),
-/// );
-///
-/// // Server supports these formats
-/// let supported = &["application/json", "text/plain"];
-///
-/// assert_eq!(
-///    match_content_type(&headers, supported).ok(),
-///    Some("application/json")
-/// );
-/// ```
-///
-/// # Return value
-///
-/// Returns the matching MIME type from the supported list, or an error if
-/// the Content-Type header is missing or no match could be found.
-pub fn match_content_type<T: ToMime>(headers: &HeaderMap, supported_types: &[T]) -> Result<T> {
-   // If no supported types, return error
-   let Some(preferred) = supported_types.first() else {
-      return Err(Error::ContentTypeNegotiationFailed {
-         got: header_as_str(headers, &http::header::CONTENT_TYPE)?.to_smolstr(),
-         expected: Vec::new(),
-      });
-   };
-
-   // If no Content-Type header present, return first supported type
-   let content_type_header = match headers.get(http::header::CONTENT_TYPE) {
-      Some(value) => match value.to_str() {
-         Ok(v) => v,
-         Err(_) => return Ok(preferred.clone()),
-      },
-      None => return Ok(preferred.clone()),
-   };
-
-   // Get base MIME type without parameters
-   let base_mime = content_type_header
-      .split(';')
-      .next()
-      .unwrap_or(content_type_header)
-      .trim();
-
-   // Find first matching MIME type
-   for supported in supported_types {
-      if base_mime.eq_ignore_ascii_case(supported.to_mime()) {
-         return Ok(supported.clone());
-      }
-   }
-
-   // No match found
-   Err(Error::UnexpectedContentType {
-      got: content_type_header.to_smolstr(),
-      expected: supported_types.iter().map(|t| t.to_mime()).collect(),
-   })
-}
-
-/// Helper method to ensure the method.
-pub fn method_must_eq(method: &Method, expected: &'static Method) -> Result<()> {
-   if method != expected {
-      return Err(Error::UnexpectedMethod {
-         got: method.clone(),
-         expected,
-      });
-   }
-   Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-   use http::HeaderMap;
-
-   use super::*;
-
-   #[test]
-   fn test_negotiate_content_type() {
-      fn to_accept(accept: &str) -> HeaderMap {
-         let mut headers = HeaderMap::new();
-         headers.insert("Accept", accept.parse().unwrap());
-         headers
-      }
-
-      // Test with simple direct match
-      let accept = "text/plain";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("text/plain")
-      );
-
-      // Test with multiple accept values
-      let accept = "application/xml, application/json";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("application/json")
-      );
-
-      // Test with quality values
-      let accept = "text/html;q=0.8, application/json;q=0.9, */*;q=0.1";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("application/json")
-      );
-
-      // Test with wildcards
-      let accept = "text/*";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("text/plain")
-      );
-
-      // Test with global wildcard
-      let accept = "*/*";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("text/plain")
-      );
-
-      // Test with no match
-      let accept = "application/xml";
-      let supported = &["text/plain", "application/json"];
-      assert!(negotiate_content_type(&to_accept(accept), supported).is_err());
-
-      // Test with charset and other parameters
-      let accept = "text/plain; charset=utf-8";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("text/plain")
-      );
-
-      // Test case insensitivity
-      let accept = "TEXT/PLAIN";
-      let supported = &["text/plain", "application/json"];
-      assert_eq!(
-         negotiate_content_type(&to_accept(accept), supported).ok(),
-         Some("text/plain")
-      );
-   }
-}
diff --git a/attic/net/http/ws/config.rs b/attic/net/http/ws/config.rs
deleted file mode 100644
index 8eeca740c..000000000
--- a/attic/net/http/ws/config.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use smol_str::ToSmolStr;
-use tokio_tungstenite::tungstenite::protocol::WebSocketConfig;
-
-/// Trait for configuring WebSocket parameters.
-pub trait ConfigBuilder {
-   /// Returns a mutable reference to the `WebSocketConfig`.
-   fn websocket_config(&mut self) -> &mut WebSocketConfig;
-
-   /// Adds supported protocols to the configuration.
-   fn protocols(&mut self, extend: impl IntoIterator<Item: ToSmolStr>) -> &mut Self;
-
-   /// Read buffer capacity. This buffer is eagerly allocated and used for
-   /// receiving messages.
-   ///
-   /// For high read load scenarios a larger buffer, e.g. 128 KiB, improves
-   /// performance.
-   ///
-   /// For scenarios where you expect a lot of connections and don't need high
-   /// read load performance a smaller buffer, e.g. 4 KiB, would be
-   /// appropriate to lower total memory usage.
-   ///
-   /// The default value is 128 KiB.
-   fn read_buffer_size(&mut self, read_buffer_size: usize) -> &mut Self {
-      self.websocket_config().read_buffer_size = read_buffer_size;
-      self
-   }
-
-   /// The target minimum size of the write buffer to reach before writing the
-   /// data to the underlying stream.
-   /// The default value is 128 KiB.
-   ///
-   /// If set to `0` each message will be eagerly written to the underlying
-   /// stream. It is often more optimal to allow them to buffer a little,
-   /// hence the default value.
-   ///
-   /// Note: [`flush`](WebSocket::flush) will always fully write the buffer
-   /// regardless.
-   fn write_buffer_size(&mut self, write_buffer_size: usize) -> &mut Self {
-      self.websocket_config().write_buffer_size = write_buffer_size;
-      self
-   }
-
-   /// The max size of the write buffer in bytes. Setting this can provide
-   /// backpressure in the case the write buffer is filling up due to write
-   /// errors. The default value is unlimited.
-   ///
-   /// Note: The write buffer only builds up past
-   /// [`write_buffer_size`](Self::write_buffer_size) when writes to the
-   /// underlying stream are failing. So the **write buffer can not
-   /// fill up if you are not observing write errors even if not flushing**.
-   ///
-   /// Note: Should always be at least [`write_buffer_size + 1
-   /// message`](Self::write_buffer_size) and probably a little more
-   /// depending on error handling strategy.
-   fn max_write_buffer_size(&mut self, max_write_buffer_size: usize) -> &mut Self {
-      self.websocket_config().max_write_buffer_size = max_write_buffer_size;
-      self
-   }
-
-   /// The maximum size of an incoming message. `None` means no size limit. The
-   /// default value is 64 MiB which should be reasonably big for all normal
-   /// use-cases but small enough to prevent memory eating by a malicious
-   /// user.
-   fn max_message_size(&mut self, max_message_size: Option<usize>) -> &mut Self {
-      self.websocket_config().max_message_size = max_message_size;
-      self
-   }
-
-   /// The maximum size of a single incoming message frame. `None` means no
-   /// size limit. The limit is for frame payload NOT including the frame
-   /// header. The default value is 16 MiB which should be reasonably big
-   /// for all normal use-cases but small enough to prevent memory eating
-   /// by a malicious user.
-   fn max_frame_size(&mut self, max_frame_size: Option<usize>) -> &mut Self {
-      self.websocket_config().max_frame_size = max_frame_size;
-      self
-   }
-
-   /// When set to `true`, the server will accept and handle unmasked frames
-   /// from the client. According to the RFC 6455, the server must close the
-   /// connection to the client in such cases, however it seems like there are
-   /// some popular libraries that are sending unmasked frames, ignoring the
-   /// RFC. By default this option is set to `false`, i.e. according to RFC
-   /// 6455.
-   fn accept_unmasked_frames(&mut self, accept_unmasked_frames: bool) -> &mut Self {
-      self.websocket_config().accept_unmasked_frames = accept_unmasked_frames;
-      self
-   }
-}
diff --git a/attic/net/http/ws/mod.rs b/attic/net/http/ws/mod.rs
deleted file mode 100644
index 6caeb29f8..000000000
--- a/attic/net/http/ws/mod.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-pub mod config;
-pub mod request;
-pub mod response;
-pub mod security;
-pub mod socket;
-pub mod types;
-
-pub use config::ConfigBuilder;
-pub use request::Request;
-pub use response::Response;
-pub use security::Nonce;
-pub use socket::WebSocket;
-// Re-export WebSocketConfig from tungstenite
-pub use tokio_tungstenite::tungstenite::protocol::WebSocketConfig;
-pub use types::{Code, Error, Message, Result};
-
-#[cfg(test)]
-pub mod tests;
diff --git a/attic/net/http/ws/request.rs b/attic/net/http/ws/request.rs
deleted file mode 100644
index da144f7d9..000000000
--- a/attic/net/http/ws/request.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-use std::{convert::Infallible, future, future::Future, mem, ops::Deref};
-
-use axum::response::IntoResponse;
-use http::{HeaderValue, Method, StatusCode, Version, header, request::Parts};
-use smol_str::{SmolStr, ToSmolStr};
-use tokio_tungstenite::tungstenite::protocol::{Role, WebSocketConfig};
-
-use super::{
-   config::ConfigBuilder,
-   security::Nonce,
-   socket::WebSocket,
-   types::{Error, Result},
-};
-use crate::http::{upgrade::OnUpgrade, utils};
-
-/// Represents a WebSocket upgrade request on the server side.
-#[derive(Debug)]
-pub struct Request {
-   /// The HTTP request parts.
-   pub request: Option<Parts>,
-   /// The supported WebSocket protocols.
-   pub protocols: Vec<SmolStr>,
-   /// The WebSocket configuration.
-   pub websocket_config: Option<WebSocketConfig>,
-}
-
-impl ConfigBuilder for Request {
-   fn websocket_config(&mut self) -> &mut WebSocketConfig {
-      self.websocket_config.get_or_insert_default()
-   }
-   fn protocols(&mut self, extend: impl IntoIterator<Item: ToSmolStr>) -> &mut Self {
-      self
-         .protocols
-         .extend(extend.into_iter().map(|s| s.to_smolstr()));
-      self
-   }
-}
-
-impl Request {
-   /// Creates a new WebSocket upgrade request from HTTP request parts.
-   pub const fn new(request: Parts) -> Self {
-      Self {
-         request: Some(request),
-         protocols: Vec::new(),
-         websocket_config: None,
-      }
-   }
-
-   /// Attempts to upgrade an HTTP connection to a WebSocket connection.
-   /// Handles errors by returning an appropriate HTTP response.
-   pub fn upgrade<F, Fut>(&mut self, callback: F) -> axum::response::Response
-   where
-      F: FnOnce(WebSocket) -> Fut + Send + 'static,
-      Fut: Future<Output = ()> + Send,
-   {
-      let response = self.try_upgrade(callback);
-      match response {
-         Ok(response) => response,
-         Err(error) => (StatusCode::BAD_REQUEST, error.to_string()).into_response(),
-      }
-   }
-
-   /// Attempts to upgrade an HTTP connection to a WebSocket connection.
-   /// Returns a Result with either the response for a successful upgrade or an
-   /// error.
-   fn try_upgrade<F, Fut>(&mut self, callback: F) -> Result<axum::response::Response>
-   where
-      F: FnOnce(WebSocket) -> Fut + Send + 'static,
-      Fut: Future<Output = ()> + Send,
-   {
-      let mut req = self.request.take().ok_or(Error::RequestAlreadyBuilt)?;
-      let protocols = mem::take(&mut self.protocols);
-      let websocket_config = mem::take(&mut self.websocket_config);
-
-      let on_upgrade = OnUpgrade::extract(&mut req.extensions).map_err(Error::Upgrade)?;
-
-      utils::header_must_eq(&req.headers, &header::SEC_WEBSOCKET_VERSION, "13")?;
-
-      let sec_websocket_key = if req.version <= Version::HTTP_11 {
-         utils::method_must_eq(&req.method, &Method::GET)?;
-         utils::header_must_eq(&req.headers, &header::CONNECTION, "upgrade")?;
-         utils::header_must_eq(&req.headers, &header::UPGRADE, "websocket")?;
-         let sec_websocket_key = utils::header_as_str(&req.headers, &header::SEC_WEBSOCKET_KEY)?;
-         Some(sec_websocket_key)
-      } else {
-         None
-      };
-
-      let protocol = if protocols.is_empty() {
-         None
-      } else {
-         let protocol = req
-            .headers
-            .get(header::SEC_WEBSOCKET_PROTOCOL)
-            .map(|h| h.to_str().unwrap_or_default())
-            .unwrap_or_default();
-         protocols.into_iter().find(|p| p == protocol)
-      };
-
-      tokio::spawn({
-         let protocol = protocol.clone();
-         async move {
-            let upgraded = match on_upgrade.await {
-               Ok(upgraded) => upgraded,
-               Err(_) => return,
-            };
-            callback(WebSocket::create(upgraded, protocol, Role::Server, websocket_config).await)
-               .await;
-         }
-      });
-
-      let mut response = if let Some(sec_websocket_key) = sec_websocket_key {
-         // If `sec_websocket_key` was `Some`, we are using HTTP/1.1.
-         axum::response::Response::builder()
-            .status(StatusCode::SWITCHING_PROTOCOLS)
-            .header(header::CONNECTION, HeaderValue::from_static("upgrade"))
-            .header(header::UPGRADE, HeaderValue::from_static("websocket"))
-            .header(
-               header::SEC_WEBSOCKET_ACCEPT,
-               Nonce::accept(sec_websocket_key).as_str(),
-            )
-            .body(axum::body::Body::empty())
-            .unwrap()
-      } else {
-         // Otherwise, we are HTTP/2+. As established in RFC 9113 section 8.5, we just
-         // respond with a 2XX with an empty body:
-         // <https://datatracker.ietf.org/doc/html/rfc9113#name-the-connect-method>.
-         axum::response::Response::new(axum::body::Body::empty())
-      };
-
-      if let Some(protocol) = protocol {
-         response.headers_mut().insert(
-            header::SEC_WEBSOCKET_PROTOCOL,
-            HeaderValue::from_str(protocol.as_str()).unwrap(),
-         );
-      }
-
-      Ok(response)
-   }
-
-   /// Consumes the request and returns the [`Parts`] of the request.
-   pub fn into_inner(self) -> Parts {
-      self.request.expect("request used after finalized")
-   }
-}
-
-impl<S> axum::extract::FromRequestParts<S> for Request {
-   type Rejection = Infallible;
-
-   fn from_request_parts(
-      parts: &mut Parts,
-      _state: &S,
-   ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send {
-      let result = Self::new(parts.clone());
-      future::ready(Ok(result))
-   }
-}
-
-impl Deref for Request {
-   type Target = Parts;
-   fn deref(&self) -> &Self::Target {
-      self.request.as_ref().expect("request used after finalized")
-   }
-}
diff --git a/attic/net/http/ws/response.rs b/attic/net/http/ws/response.rs
deleted file mode 100644
index 2874a538a..000000000
--- a/attic/net/http/ws/response.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use std::ops::Deref;
-
-use http::{StatusCode, header};
-use smol_str::SmolStr;
-use tokio_tungstenite::tungstenite::protocol::{Role, WebSocketConfig};
-
-use super::{
-   security::Nonce,
-   socket::WebSocket,
-   types::{Error, Result},
-};
-use crate::http::{upgrade::OnUpgrade, utils};
-
-/// The server's response to the WebSocket upgrade request.
-#[derive(Debug)]
-pub struct Response {
-   /// The HTTP response from the server.
-   pub response: reqwest::Response,
-   /// The security nonce used during the handshake.
-   pub nonce: Nonce,
-   /// The supported WebSocket protocols.
-   pub protocols: Vec<SmolStr>,
-   /// The WebSocket configuration.
-   pub websocket_config: Option<WebSocketConfig>,
-}
-
-impl Response {
-   /// Attempts to upgrade the HTTP connection to a WebSocket connection based
-   /// on the server's response.
-   pub async fn upgrade(mut self) -> Result<WebSocket> {
-      let headers = self.response.headers();
-
-      if self.response.status() != StatusCode::SWITCHING_PROTOCOLS {
-         return Err(utils::read_remote_error(self.response).await.into());
-      }
-
-      utils::header_must_eq(headers, &header::CONNECTION, "upgrade")?;
-      utils::header_must_eq(headers, &header::UPGRADE, "websocket")?;
-      if !self.nonce.accept.is_empty() {
-         utils::header_must_eq(headers, &header::SEC_WEBSOCKET_ACCEPT, &self.nonce.accept)?;
-      }
-
-      let protocol = if self.protocols.is_empty() {
-         None
-      } else {
-         let protocol = utils::header_as_str(headers, &header::SEC_WEBSOCKET_PROTOCOL)
-            .map_err(|_| Error::ExpectedAProtocol)?;
-         Some(
-            self
-               .protocols
-               .into_iter()
-               .find(|p| p == protocol)
-               .ok_or_else(|| Error::UnexpectedProtocol(protocol.to_string()))?,
-         )
-      };
-
-      let upgraded = OnUpgrade::extract(self.response.extensions_mut())?.await?;
-      Ok(WebSocket::create(upgraded, protocol, Role::Client, self.websocket_config).await)
-   }
-
-   /// Consumes the response and returns the inner [`reqwest::Response`].
-   #[must_use]
-   pub fn into_inner(self) -> reqwest::Response {
-      self.response
-   }
-}
-
-impl Deref for Response {
-   type Target = reqwest::Response;
-   fn deref(&self) -> &Self::Target {
-      &self.response
-   }
-}
diff --git a/attic/net/http/ws/security.rs b/attic/net/http/ws/security.rs
deleted file mode 100644
index 18f824129..000000000
--- a/attic/net/http/ws/security.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use data_encoding::BASE64;
-use sha1::{digest::Update, Digest, Sha1};
-
-/// Represents a WebSocket security key pair used during the handshake process.
-#[derive(Debug)]
-pub struct Nonce {
-   /// The security key sent to the server.
-   pub key: heapless::String<32>,
-   /// The expected accept value that should be returned by the server.
-   pub accept: heapless::String<32>,
-}
-
-impl Default for Nonce {
-   fn default() -> Self {
-      Self::new()
-   }
-}
-
-impl Nonce {
-   /// Computes the accept value for a given security key according to the
-   /// WebSocket protocol.
-   pub fn accept(key: &str) -> heapless::String<32> {
-      use std::fmt::Write;
-
-      let hash = Sha1::new()
-         .chain(key.as_bytes())
-         .chain(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
-         .finalize();
-
-      let mut accept = heapless::String::new();
-      BASE64.encode_write(&hash, &mut accept).unwrap();
-      accept
-   }
-
-   /// Creates a new security key pair with a randomly generated key.
-   pub fn new() -> Self {
-      use std::fmt::Write;
-
-      let seed: [u8; 16] = rand::random();
-      let mut key = heapless::String::new();
-      BASE64.encode_write(&seed, &mut key).unwrap();
-
-      Self {
-         accept: Self::accept(&key),
-         key,
-      }
-   }
-}
diff --git a/attic/net/http/ws/socket.rs b/attic/net/http/ws/socket.rs
deleted file mode 100644
index 6d7858e3d..000000000
--- a/attic/net/http/ws/socket.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use std::{
-   pin::Pin,
-   task::{Context, Poll},
-};
-
-use futures::{Sink, SinkExt, Stream, StreamExt};
-use smol_str::SmolStr;
-use tokio_tungstenite::{
-   WebSocketStream,
-   tungstenite::protocol::{CloseFrame, Role, WebSocketConfig},
-};
-
-use super::types::{Code, Error, Message, Result};
-use crate::http::upgrade::Upgraded;
-
-/// A WebSocket connection. Implements [`futures::Stream`] and
-/// [`futures::Sink`].
-#[derive(Debug)]
-pub struct WebSocket {
-   /// The underlying WebSocket stream.
-   inner: WebSocketStream<Upgraded>,
-   /// The negotiated protocol, if any.
-   protocol: Option<SmolStr>,
-}
-
-impl WebSocket {
-   /// Creates a new WebSocket from a upgraded HTTP connection, a protocol, the
-   /// client/server role, and a configuration.
-   pub async fn create(
-      upgraded: Upgraded,
-      protocol: Option<SmolStr>,
-      role: Role,
-      config: Option<WebSocketConfig>,
-   ) -> Self {
-      Self {
-         inner: WebSocketStream::from_raw_socket(upgraded, role, config).await,
-         protocol,
-      }
-   }
-
-   /// Returns the protocol negotiated during the handshake.
-   pub fn protocol(&self) -> Option<&str> {
-      self.protocol.as_deref()
-   }
-
-   /// Closes the connection with a given code and (optional) reason.
-   pub async fn close(self, code: Code, reason: Option<&str>) -> Result<()> {
-      let mut inner = self.inner;
-      inner
-         .close(Some(CloseFrame {
-            code,
-            reason: reason.unwrap_or_default().into(),
-         }))
-         .await?;
-      Ok(())
-   }
-}
-
-impl Stream for WebSocket {
-   type Item = Result<Message>;
-
-   fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
-      match self.inner.poll_next_unpin(cx) {
-         Poll::Ready(None) => Poll::Ready(None),
-         Poll::Ready(Some(Err(error))) => Poll::Ready(Some(Err(error.into()))),
-         Poll::Ready(Some(Ok(message))) => Poll::Ready(Some(Ok(message.into()))),
-         Poll::Pending => Poll::Pending,
-      }
-   }
-}
-
-impl Sink<Message> for WebSocket {
-   type Error = Error;
-
-   fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
-      self.inner.poll_ready_unpin(cx).map_err(Into::into)
-   }
-
-   fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<()> {
-      self.inner.start_send_unpin(item.into()).map_err(Into::into)
-   }
-
-   fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
-      self.inner.poll_flush_unpin(cx).map_err(Into::into)
-   }
-
-   fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
-      self.inner.poll_close_unpin(cx).map_err(Into::into)
-   }
-}
diff --git a/attic/net/http/ws/tests.rs b/attic/net/http/ws/tests.rs
deleted file mode 100644
index e2b1d15d8..000000000
--- a/attic/net/http/ws/tests.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-use std::{
-   sync::atomic::{AtomicUsize, Ordering},
-   time::Duration,
-};
-
-use axum::{Router, response::IntoResponse, routing::get};
-use futures::{SinkExt, StreamExt};
-use tokio::time::timeout;
-
-use super::ConfigBuilder;
-use crate::http::{client, server::SharedRouter, utils, ws};
-
-/// Tests the WebSocket functionality by setting up a server and client,
-/// exchanging messages, and verifying proper connection handling.
-#[tokio::test]
-async fn test_websocket_communication() {
-   // Create axum router with WebSocket support
-   let app = SharedRouter::new(Router::new().route("/ws", get(websocket_handler)));
-   app.bind(["ws-example.local"]);
-
-   // Connect to WebSocket server
-   let mut websocket = client::Client::global()
-      .websocket("wss://ws-example.local/ws")
-      .protocols(["tetra-protocol"])
-      .read_buffer_size(64 * 1024)
-      .max_message_size(Some(10 * 1024 * 1024))
-      .send()
-      .await
-      .expect("Failed to send WebSocket request")
-      .upgrade()
-      .await
-      .expect("Failed to upgrade to WebSocket");
-
-   assert_eq!(
-      websocket.protocol(),
-      Some("tetra-protocol"),
-      "WebSocket should connect with the expected protocol"
-   );
-
-   // Send a text message
-   let text_message = "Hello from WebSocket client!";
-   websocket
-      .send(ws::Message::Text(text_message.to_string()))
-      .await
-      .expect("Failed to send text message");
-
-   // Send a binary message
-   let binary_data = b"Binary data example";
-   websocket
-      .send(ws::Message::Binary(binary_data.to_vec().into()))
-      .await
-      .expect("Failed to send binary message");
-
-   // Read messages from server (with timeout to avoid blocking)
-   let mut received_messages = Vec::new();
-   for _ in 0..2 {
-      if let Ok(Some(msg)) = timeout(std::time::Duration::from_secs(1), websocket.next()).await {
-         let msg = msg.expect("Failed to receive message");
-         received_messages.push(msg);
-      } else {
-         panic!("Timed out waiting for message");
-      }
-   }
-
-   // Verify received messages
-   assert_eq!(received_messages.len(), 2, "Should receive two messages");
-
-   match &received_messages[0] {
-      ws::Message::Text(text) => assert_eq!(
-         text, text_message,
-         "Text message should echo back correctly"
-      ),
-      _ => panic!("First message should be text"),
-   }
-
-   match &received_messages[1] {
-      ws::Message::Binary(bin) => assert_eq!(
-         bin.as_ref(),
-         binary_data,
-         "Binary message should echo back correctly"
-      ),
-      _ => panic!("Second message should be binary"),
-   }
-
-   // Close the WebSocket connection
-   websocket
-      .close(ws::Code::Normal, Some("Test complete"))
-      .await
-      .expect("Failed to close WebSocket connection");
-}
-
-async fn websocket_handler(mut ws: ws::Request) -> impl IntoResponse {
-   ws.protocols(["tetra-protocol"]).upgrade(handle_socket)
-}
-
-/// Handles the WebSocket connection by echoing back any received messages.
-async fn handle_socket(mut socket: ws::WebSocket) {
-   while let Some(msg) = socket.next().await {
-      if let Ok(msg) = msg {
-         // Echo the message back
-         if socket.send(msg).await.is_err() {
-            break;
-         }
-      } else {
-         // Client disconnected or error occurred
-         break;
-      }
-   }
-}
-
-#[tokio::test]
-async fn websocket_retry_after_error() {
-   let app = SharedRouter::new(Router::new().route(
-      "/ws",
-      get(|| async {
-         axum::response::Response::builder()
-            .status(axum::http::StatusCode::SERVICE_UNAVAILABLE)
-            .header("Retry-After", "7")
-            .body(axum::body::Body::empty())
-            .unwrap()
-      }),
-   ));
-   app.bind(["ws-retry.local"]);
-
-   let err = client::Client::global()
-      .websocket("wss://ws-retry.local/ws")
-      .send()
-      .await
-      .expect("send should succeed")
-      .upgrade()
-      .await
-      .unwrap_err();
-
-   match err {
-      ws::Error::Remote(utils::Error::ServerError { retry_after, .. }) => {
-         assert_eq!(retry_after, Some(Duration::from_secs(7)));
-      },
-      other => panic!("unexpected error: {other:?}"),
-   }
-}
-
-#[tokio::test]
-async fn websocket_retry_automatically() {
-   static CALLS: AtomicUsize = AtomicUsize::new(0);
-
-   async fn handler(mut ws: ws::Request) -> impl IntoResponse {
-      if CALLS.fetch_add(1, Ordering::SeqCst) == 0 {
-         axum::response::Response::builder()
-            .status(axum::http::StatusCode::SERVICE_UNAVAILABLE)
-            .header("Retry-After", "0")
-            .body(axum::body::Body::empty())
-            .unwrap()
-      } else {
-         ws.protocols(["tetra-protocol"]).upgrade(handle_socket)
-      }
-   }
-
-   let app = SharedRouter::new(Router::new().route("/ws-auto", get(handler)));
-   app.bind(["ws-auto.local"]);
-
-   let mut socket = client::Client::global()
-      .websocket("wss://ws-auto.local/ws-auto")
-      .protocols(["tetra-protocol"])
-      .send()
-      .await
-      .expect("send")
-      .upgrade()
-      .await
-      .expect("upgrade");
-
-   socket
-      .send(ws::Message::Text("ping".into()))
-      .await
-      .expect("send ping");
-
-   let msg = timeout(Duration::from_secs(1), socket.next())
-      .await
-      .expect("timeout")
-      .expect("option")
-      .expect("msg");
-
-   assert!(matches!(msg, ws::Message::Text(_)));
-   assert!(CALLS.load(Ordering::SeqCst) >= 2);
-}
diff --git a/attic/net/http/ws/types.rs b/attic/net/http/ws/types.rs
deleted file mode 100644
index 60923353c..000000000
--- a/attic/net/http/ws/types.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use bytes::Bytes;
-use tokio_tungstenite::tungstenite;
-pub use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode as Code;
-
-use crate::http::{upgrade, utils};
-
-/// Represents different types of WebSocket messages that can be sent or
-/// received.
-#[derive(Clone, Debug)]
-pub enum Message {
-   /// A text message containing UTF-8 encoded data.
-   Text(String),
-   /// A binary message.
-   Binary(Bytes),
-   /// A ping message used for keep-alive and latency measurement.
-   Ping(Bytes),
-   /// A pong message sent in response to a ping.
-   Pong(Bytes),
-   /// A close message indicating the connection is being terminated.
-   Close {
-      /// The close code indicating the reason for closing.
-      code: Code,
-      /// A human-readable explanation for the close.
-      reason: String,
-   },
-}
-
-impl From<String> for Message {
-   #[inline]
-   fn from(value: String) -> Self {
-      Self::Text(value)
-   }
-}
-
-impl From<&str> for Message {
-   #[inline]
-   fn from(value: &str) -> Self {
-      Self::from(value.to_owned())
-   }
-}
-
-impl From<Bytes> for Message {
-   #[inline]
-   fn from(value: Bytes) -> Self {
-      Self::Binary(value)
-   }
-}
-
-impl From<Vec<u8>> for Message {
-   #[inline]
-   fn from(value: Vec<u8>) -> Self {
-      Self::from(Bytes::from(value))
-   }
-}
-
-impl From<&[u8]> for Message {
-   #[inline]
-   fn from(value: &[u8]) -> Self {
-      Self::from(Bytes::copy_from_slice(value))
-   }
-}
-
-impl From<tungstenite::Message> for Message {
-   fn from(value: tungstenite::Message) -> Self {
-      match value {
-         tungstenite::Message::Text(text) => Self::Text(text.as_str().to_owned()),
-         tungstenite::Message::Binary(data) => Self::Binary(data),
-         tungstenite::Message::Ping(data) => Self::Ping(data),
-         tungstenite::Message::Pong(data) => Self::Pong(data),
-         tungstenite::Message::Close(Some(tungstenite::protocol::CloseFrame { code, reason })) => {
-            Self::Close {
-               code,
-               reason: reason.as_str().to_owned(),
-            }
-         },
-         tungstenite::Message::Close(None) => Self::Close {
-            code: Code::Normal,
-            reason: String::new(),
-         },
-         tungstenite::Message::Frame(value) => panic!("unexpected frame: {value:?}"),
-      }
-   }
-}
-
-impl From<Message> for tungstenite::Message {
-   fn from(value: Message) -> Self {
-      match value {
-         Message::Text(text) => Self::Text(tungstenite::Utf8Bytes::from(text)),
-         Message::Binary(data) => Self::Binary(data),
-         Message::Ping(data) => Self::Ping(data),
-         Message::Pong(data) => Self::Pong(data),
-         Message::Close { code, reason } => Self::Close(Some(tungstenite::protocol::CloseFrame {
-            code,
-            reason: reason.into(),
-         })),
-      }
-   }
-}
-
-/// Error during `Websocket` handshake.
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
-   #[error(transparent)]
-   Remote(#[from] utils::Error),
-
-   /// Error when the connection cannot be upgraded to a WebSocket.
-   #[error("connection not upgradable")]
-   ConnectionNotUpgradable,
-
-   /// Error when the server didn't select a protocol when one was expected.
-   #[error("expected the server to select a protocol.")]
-   ExpectedAProtocol,
-
-   /// Error when the server selected an unexpected protocol.
-   #[error("unexpected protocol: {0}")]
-   UnexpectedProtocol(String),
-
-   /// Error during the upgrade process.
-   #[error("upgrade error: {0}")]
-   Upgrade(#[from] upgrade::UpgradeError),
-
-   /// Error when trying to use a request that has already been built.
-   #[error("request already built")]
-   RequestAlreadyBuilt,
-
-   /// Error from the underlying WebSocket implementation.
-   #[error("socket error: {0}")]
-   Socket(Box<tungstenite::Error>),
-
-   /// Error from the HTTP client.
-   #[error("server error: {0}")]
-   Server(#[from] reqwest::Error),
-}
-
-impl From<tungstenite::Error> for Error {
-   fn from(value: tungstenite::Error) -> Self {
-      Self::Socket(Box::new(value))
-   }
-}
-
-/// A specialized Result type for WebSocket operations.
-pub type Result<T, E = Error> = std::result::Result<T, E>;
diff --git a/attic/net/identity_service.rs b/attic/net/identity_service.rs
deleted file mode 100644
index 5eeb02c79..000000000
--- a/attic/net/identity_service.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-use std::borrow::Cow;
-
-use axum::{
-   Json, Router,
-   body::Body,
-   extract::{Request, State},
-   response::{IntoResponse, Response},
-   routing::get,
-};
-use bytes::Bytes;
-use chrono::DurationRound;
-use futures::FutureExt;
-use http::StatusCode;
-
-use super::{Hostname, Identifiable, Identity, id};
-use crate::http::client;
-
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, derive_more::Display)]
-#[display("BuildInfo {{ time: {time}, commit: {commit} }}")]
-pub struct BuildInfo {
-   pub time: Cow<'static, str>,
-   pub commit: Cow<'static, str>,
-}
-
-impl Default for BuildInfo {
-   fn default() -> Self {
-      Self {
-         //time: env!("BUILD_TIMESTAMP").into(),
-         //commit: env!("GIT_COMMIT", "unknown").into(),
-         time: "TODO: 2025-06-30T12:00:00Z".into(),
-         commit: "TODO: Python script for 1234567890".into(),
-      }
-   }
-}
-
-#[derive(Debug, thiserror::Error)]
-pub enum IdentityServiceError {
-   #[error("Failed to fetch identity")]
-   Fetch(#[from] client::Error),
-   #[error("Failed to validate identity")]
-   Validate(#[from] id::Error),
-   #[error("Fetched identity belongs to a different host {host:?}, expected {expected:?}")]
-   Host { host: Hostname, expected: String },
-}
-
-impl From<reqwest::Error> for IdentityServiceError {
-   fn from(err: reqwest::Error) -> Self {
-      Self::Fetch(client::Error::RequestFailed(err))
-   }
-}
-
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, derive_more::Display)]
-#[display("{{ identity: {identity}, build: {build} }}")]
-pub struct IdentityResponse {
-   pub identity: Identity,
-   pub build: BuildInfo,
-}
-
-#[derive(Clone, Debug)]
-pub struct IdentityService {
-   prerender: Response<Bytes>,
-   init_time: chrono::DateTime<chrono::Utc>,
-}
-
-impl IdentityService {
-   pub const ROOT: &'static str = "/.well-known/tetra-id";
-
-   pub fn new(identity: Identity) -> Self {
-      let data = IdentityResponse {
-         identity,
-         build: BuildInfo::default(),
-      };
-
-      let (mut parts, body) = (StatusCode::OK, Json(data)).into_response().into_parts();
-
-      // Convert body to bytes for caching
-      let body = axum::body::to_bytes(body, usize::MAX)
-         .now_or_never()
-         .expect("Non-async body should not block")
-         .expect("Failed to convert body to bytes");
-
-      // Generate ETag from body content
-      let etag = blake3::hash(&body[..]).to_hex();
-
-      // Add caching headers
-      parts
-         .headers
-         .insert(http::header::ETAG, etag.parse().unwrap());
-      parts.headers.insert(
-         http::header::CACHE_CONTROL,
-         "public, max-age=31536000, immutable".parse().unwrap(),
-      );
-      parts.headers.insert(
-         http::header::EXPIRES,
-         "Thu, 31 Dec 2099 23:59:59 GMT".parse().unwrap(),
-      );
-      parts.headers.insert(
-         http::header::CONTENT_TYPE,
-         "application/json; charset=utf-8".parse().unwrap(),
-      );
-
-      let init_time = chrono::Utc::now()
-         .duration_trunc(chrono::Duration::seconds(1))
-         .unwrap();
-      parts.headers.insert(
-         http::header::LAST_MODIFIED,
-         init_time.to_rfc3339().parse().unwrap(),
-      );
-
-      Self {
-         prerender: Response::from_parts(parts, body),
-         init_time,
-      }
-   }
-
-   pub async fn fetch(host: &str) -> Result<IdentityResponse, IdentityServiceError> {
-      let url = format!("https://{host}{}/data.json", Self::ROOT);
-      let id: IdentityResponse = client::Client::global()
-         .get(url)
-         .send()
-         .await?
-         .error_for_status()?
-         .json()
-         .await?;
-
-      if id.identity.host() != host {
-         return Err(IdentityServiceError::Host {
-            host: id.identity.host().clone(),
-            expected: host.into(),
-         });
-      }
-      Ok(id)
-   }
-
-   pub fn router(&self) -> Router {
-      Router::new()
-         .route("/data.json", get(Self::handler))
-         .with_state(self.clone())
-   }
-
-   pub async fn handler(State(node): State<Self>, req: Request) -> impl IntoResponse {
-      // Check If-None-Match header
-      if let Some(etag) = node.prerender.headers().get(http::header::ETAG) {
-         for if_none_match in req.headers().get_all(http::header::IF_NONE_MATCH) {
-            if if_none_match == etag {
-               return StatusCode::NOT_MODIFIED.into_response();
-            }
-         }
-      }
-
-      // Check If-Modified-Since header
-      if let Some(tm) = req.headers().get(http::header::IF_MODIFIED_SINCE)
-         && let Ok(tm) = chrono::DateTime::parse_from_rfc3339(tm.to_str().unwrap_or_default())
-         && tm >= node.init_time
-      {
-         return StatusCode::NOT_MODIFIED.into_response();
-      }
-
-      // Otherwise return the full response
-      let (parts, body) = node.prerender.into_parts();
-      let body = Body::from(body);
-      Response::from_parts(parts, body)
-   }
-}
diff --git a/attic/net/netsim.rs b/attic/net/netsim.rs
deleted file mode 100644
index 7bb2167a8..000000000
--- a/attic/net/netsim.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use std::{iter, time::Duration};
-
-use rand::{Rng, prelude::Distribution};
-
-#[derive(Debug, Clone, Copy)]
-enum Distr {
-   Fixed(f64),
-   Uniform(rand_distr::Uniform<f64>),
-   Normal(rand_distr::Normal<f64>),
-   LogNormal(rand_distr::LogNormal<f64>),
-}
-
-impl Distr {
-   pub fn normal(mean: f64, cv: f64) -> Self {
-      Self::Normal(rand_distr::Normal::from_mean_cv(mean, cv).unwrap())
-   }
-
-   pub fn lognormal(mean: f64, cv: f64) -> Self {
-      Self::LogNormal(rand_distr::LogNormal::from_mean_cv(mean, cv).unwrap())
-   }
-
-   pub fn uniform(min: f64, max: f64) -> Self {
-      if (max - min) < 2.0 * f64::EPSILON {
-         return Self::fixed(min);
-      }
-      Self::Uniform(rand_distr::Uniform::new(min, max).unwrap())
-   }
-   pub const fn fixed(val: f64) -> Self {
-      Self::Fixed(val)
-   }
-
-   pub fn next(&self, r: &mut impl Rng) -> f64 {
-      match self {
-         Self::Normal(d) => d.sample(r),
-         Self::LogNormal(d) => d.sample(r),
-         Self::Uniform(d) => d.sample(r),
-         &Self::Fixed(d) => d,
-      }
-   }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct LatencyModel(Distr);
-
-impl LatencyModel {
-   pub const MIN: Duration = Duration::from_secs(0);
-   pub const MAX: Duration = Duration::from_secs(10);
-
-   pub fn normal(mean: Duration, cv: f64) -> Self {
-      let mean = mean.clamp(Self::MIN, Self::MAX);
-      Self(Distr::normal(mean.as_secs_f64(), cv))
-   }
-
-   pub fn lognormal(mean: Duration, cv: f64) -> Self {
-      let mean = mean.clamp(Self::MIN, Self::MAX);
-      Self(Distr::lognormal(mean.as_secs_f64(), cv))
-   }
-
-   pub fn uniform(min: Duration, max: Duration) -> Self {
-      let min = min.clamp(Self::MIN, Self::MAX);
-      let max = max.clamp(min, Self::MAX);
-      Self(Distr::uniform(min.as_secs_f64(), max.as_secs_f64()))
-   }
-   pub fn fixed(val: Duration) -> Self {
-      let val = val.clamp(Self::MIN, Self::MAX);
-      Self(Distr::fixed(val.as_secs_f64()))
-   }
-
-   pub fn next(&self, r: &mut impl Rng) -> Duration {
-      Duration::from_secs_f64(
-         self
-            .0
-            .next(r)
-            .clamp(Self::MIN.as_secs_f64(), Self::MAX.as_secs_f64()),
-      )
-   }
-
-   pub fn build(self, n: usize, r: &mut impl Rng) -> LatencySim {
-      LatencySim::new(n, self, r)
-   }
-}
-
-impl Default for LatencyModel {
-   fn default() -> Self {
-      Self::normal(Duration::from_millis(100), 0.2)
-   }
-}
-
-#[derive(Debug, Clone)]
-pub struct LatencySim {
-   e2e_latency: Box<[Duration]>,
-}
-
-impl LatencySim {
-   pub fn basic(n: usize) -> Self {
-      Self::new(n, LatencyModel::default(), &mut rand::rng())
-   }
-   pub fn with_rng<R: Rng>(n: usize, r: &mut R) -> Self {
-      Self::new(n, LatencyModel::default(), r)
-   }
-   pub fn with_model(n: usize, latency: LatencyModel) -> Self {
-      Self::new(n, latency, &mut rand::rng())
-   }
-   pub fn new(n: usize, latency: LatencyModel, r: &mut impl Rng) -> Self {
-      let k = Self::locate(n, 0).unwrap_or_default();
-      let lat_vec = iter::repeat_with(|| latency.next(r))
-         .take(k)
-         .collect::<Vec<_>>();
-      Self {
-         e2e_latency: lat_vec.into_boxed_slice(),
-      }
-   }
-
-   pub const fn locate(i: usize, j: usize) -> Option<usize> {
-      if i == j {
-         None
-      } else {
-         let (i, j) = if i < j { (j, i) } else { (i, j) };
-         Some(i * (i - 1) / 2 + j)
-      }
-   }
-
-   pub fn get_base(&self, i: usize, j: usize) -> &Duration {
-      if let Some(idx) = Self::locate(i, j) {
-         &self.e2e_latency[idx]
-      } else {
-         &const { Duration::from_secs(0) }
-      }
-   }
-
-   pub fn get_jitter(&self, i: usize, j: usize, jitter: f64, r: &mut impl Rng) -> Duration {
-      let base = *self.get_base(i, j);
-      if base <= Duration::from_millis(1) {
-         return base;
-      }
-      let jitter = LatencyModel::normal(base, jitter).next(r);
-      base + jitter
-   }
-
-   pub fn set(&mut self, i: usize, j: usize, val: Duration) {
-      if let Some(idx) = Self::locate(i, j) {
-         self.e2e_latency[idx] = val;
-      }
-   }
-}
diff --git a/attic/vm/Cargo.toml b/attic/vm/Cargo.toml
deleted file mode 100644
index 1c96fc37a..000000000
--- a/attic/vm/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "vm"
-publish = false
-version.workspace = true
-edition.workspace = true
-authors.workspace = true
-homepage.workspace = true
-description = "Tetra VM: tree-sitter based exploration"
-repository.workspace = true
-
-[lints]
-workspace = true
-
-[dependencies]
-tree-sitter = "0.25.3"
-tree-sitter-javascript = "0.23.1"
-anyhow.workspace = true
diff --git a/attic/vm/README.md b/attic/vm/README.md
deleted file mode 100644
index eb14f70c9..000000000
--- a/attic/vm/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# vm
-
-Early experiments with JavaScript parsing and virtual machine concepts using
-Tree‑sitter.
diff --git a/attic/vm/src/main.rs b/attic/vm/src/main.rs
deleted file mode 100644
index 71fd8cc0c..000000000
--- a/attic/vm/src/main.rs
+++ /dev/null
@@ -1,482 +0,0 @@
-// A *very* small JavaScript engine prototype written in Rust.
-// -----------------------------------------------------------
-// Supported features (MVP)
-//  - Numeric literals (e.g., 42, 3.14)
-//  - Identifiers & immutable const bindings
-//  - Binary expressions with +, -, *, /
-//  - console.log(<expr>); for side‑effect output
-//  - Function declarations and calls
-//  - Return statements
-//
-// This is intentionally tiny so you can flesh out additional
-// language features incrementally (conditionals, etc.).
-//
-// Build & run (requires Rust 1.77+):
-//   $ cargo add tree-sitter tree-sitter-javascript anyhow
-//   $ cargo run --release -- <file.js>
-// If no file is provided, an inline sample is executed.
-// -----------------------------------------------------------
-use std::{collections::HashMap, fmt, fs, path::Path};
-
-use anyhow::{Context, Result, anyhow};
-use tree_sitter::{Node, Parser};
-
-// ──────────────────────────────────────────────────────────────
-// AST definitions (greatly simplified)
-// ──────────────────────────────────────────────────────────────
-#[derive(Debug, Clone)]
-enum BinOp {
-   Add,
-   Sub,
-   Mul,
-   Div,
-}
-
-#[derive(Debug, Clone)]
-enum Expr {
-   Number(f64),
-   Ident(String),
-   Str(String),
-   Binary(Box<Expr>, BinOp, Box<Expr>),
-   Call { callee: String, args: Vec<Expr> },
-}
-
-#[derive(Debug, Clone)]
-enum Stmt {
-   VarDecl(String, Expr),
-   Expr(Expr),
-   FuncDecl {
-      name: String,
-      params: Vec<String>,
-      body: Vec<Stmt>,
-   },
-   Return(Option<Expr>),
-}
-
-#[derive(Debug, Clone)]
-struct Program {
-   body: Vec<Stmt>,
-}
-
-// ──────────────────────────────────────────────────────────────
-// Simple interpreter ‑ NOT spec‑compliant, just good enough ☺
-// ──────────────────────────────────────────────────────────────
-#[derive(Debug, Clone)]
-enum Value {
-   Number(f64),
-   Str(String),
-   Function {
-      params: Vec<String>,
-      body: Vec<Stmt>,
-      closure: HashMap<String, Value>,
-   },
-   Undefined,
-}
-
-impl fmt::Display for Value {
-   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-      match self {
-         Self::Number(n) => write!(f, "{n}"),
-         Self::Str(s) => write!(f, "{s}"),
-         Self::Function { .. } => write!(f, "[Function]"),
-         Self::Undefined => write!(f, "undefined"),
-      }
-   }
-}
-
-// Control flow for returns
-#[derive(Debug)]
-enum ControlFlow {
-   Normal(Value),
-   Return(Value),
-}
-
-#[derive(Clone, Default)]
-struct Interpreter {
-   env: HashMap<String, Value>,
-}
-
-impl Interpreter {
-   fn run(&mut self, program: &Program) {
-      for stmt in &program.body {
-         match self.exec_stmt(stmt) {
-            Ok(ControlFlow::Return(_)) => {
-               eprintln!("Runtime error: Return outside function");
-               return;
-            },
-            Err(e) => eprintln!("Runtime error: {e}"),
-            _ => {},
-         }
-      }
-   }
-
-   fn exec_stmt(&mut self, stmt: &Stmt) -> Result<ControlFlow> {
-      match stmt {
-         Stmt::VarDecl(name, init) => {
-            let val = self.eval_expr(init)?;
-            self.env.insert(name.clone(), val.clone());
-            Ok(ControlFlow::Normal(val))
-         },
-         Stmt::Expr(expr) => {
-            let val = self.eval_expr(expr)?;
-            Ok(ControlFlow::Normal(val))
-         },
-         Stmt::FuncDecl { name, params, body } => {
-            // Capture current environment as closure
-            let func = Value::Function {
-               params: params.clone(),
-               body: body.clone(),
-               closure: self.env.clone(),
-            };
-            self.env.insert(name.clone(), func);
-            Ok(ControlFlow::Normal(Value::Undefined))
-         },
-         Stmt::Return(expr) => {
-            let val = match expr {
-               Some(e) => self.eval_expr(e)?,
-               None => Value::Undefined,
-            };
-            Ok(ControlFlow::Return(val))
-         },
-      }
-   }
-
-   fn eval_expr(&mut self, expr: &Expr) -> Result<Value> {
-      match expr {
-         Expr::Number(n) => Ok(Value::Number(*n)),
-         Expr::Str(s) => Ok(Value::Str(s.clone())),
-         Expr::Ident(name) => self
-            .env
-            .get(name)
-            .cloned()
-            .ok_or_else(|| anyhow!("ReferenceError: {name} is not defined")),
-         Expr::Binary(lhs, op, rhs) => {
-            let l = self.eval_expr(lhs)?;
-            let r = self.eval_expr(rhs)?;
-            self.apply_bin_op(op, l, r)
-         },
-         Expr::Call { callee, args } => {
-            // Check for built-ins first
-            if callee == "console.log" {
-               let printed: Vec<String> = args
-                  .iter()
-                  .map(|a| self.eval_expr(a))
-                  .collect::<Result<Vec<_>>>()?
-                  .into_iter()
-                  .map(|v| v.to_string())
-                  .collect();
-               println!("{}", printed.join(" "));
-               return Ok(Value::Undefined);
-            }
-
-            // Otherwise, look up the function
-            let func = self
-               .env
-               .get(callee)
-               .ok_or_else(|| anyhow!("ReferenceError: {callee} is not defined"))?
-               .clone();
-
-            match func {
-               Value::Function {
-                  params,
-                  body,
-                  closure,
-               } => {
-                  // Evaluate arguments
-                  let arg_vals: Vec<Value> = args
-                     .iter()
-                     .map(|a| self.eval_expr(a))
-                     .collect::<Result<Vec<_>>>()?;
-
-                  // Check arity
-                  if params.len() != arg_vals.len() {
-                     return Err(anyhow!(
-                        "TypeError: {callee} expects {} arguments, got {}",
-                        params.len(),
-                        arg_vals.len()
-                     ));
-                  }
-
-                  // Create new environment for function execution
-                  let saved_env = self.env.clone();
-                  self.env = closure; // Start with closure
-
-                  // Bind parameters
-                  for (param, arg_val) in params.iter().zip(arg_vals.iter()) {
-                     self.env.insert(param.clone(), arg_val.clone());
-                  }
-
-                  // Execute function body
-                  let mut result = Value::Undefined;
-                  for stmt in &body {
-                     match self.exec_stmt(stmt)? {
-                        ControlFlow::Return(val) => {
-                           result = val;
-                           break;
-                        },
-                        ControlFlow::Normal(val) => {
-                           result = val;
-                        },
-                     }
-                  }
-
-                  // Restore environment
-                  self.env = saved_env;
-                  Ok(result)
-               },
-               _ => Err(anyhow!("TypeError: {callee} is not a function")),
-            }
-         },
-      }
-   }
-
-   fn apply_bin_op(&self, op: &BinOp, l: Value, r: Value) -> Result<Value> {
-      match (l, r) {
-         (Value::Number(a), Value::Number(b)) => {
-            let res = match op {
-               BinOp::Add => a + b,
-               BinOp::Sub => a - b,
-               BinOp::Mul => a * b,
-               BinOp::Div => a / b,
-            };
-            Ok(Value::Number(res))
-         },
-         _ => Err(anyhow!("TypeError: binary operands must be numbers")),
-      }
-   }
-}
-
-// ──────────────────────────────────────────────────────────────
-// Entry point & plumbing
-// ──────────────────────────────────────────────────────────────
-fn main() -> Result<()> {
-   // 1) Load source (file or sample)
-   let source_code = if let Some(path) = std::env::args().nth(1) {
-      fs::read_to_string(Path::new(&path)).with_context(|| format!("Could not read {path}"))?
-   } else {
-      r"// demo snippet with functions
-      function add(a, b) {
-         return a + b;
-      }
-      
-      function multiply(x, y) {
-         const result = x * y;
-         return result;
-      }
-      
-      const sum = add(5, 3);
-      console.log('5 + 3 =', sum);
-      
-      const product = multiply(4, 7);
-      console.log('4 * 7 =', product);
-      
-      // Nested function calls
-      console.log('add(10, multiply(2, 3)) =', add(10, multiply(2, 3)));
-      "
-      .into()
-   };
-
-   // 2) Parse with tree‑sitter‑javascript
-   let mut parser = Parser::new();
-   parser
-      .set_language(&tree_sitter_javascript::LANGUAGE.into())
-      .expect("Loading JS grammar failed");
-   let tree = parser
-      .parse(&source_code, None)
-      .ok_or_else(|| anyhow!("Parse failure"))?;
-
-   // 2.1) Print the tree
-   // println!("tree: {:?}", tree.root_node());
-   // fn rec_print(node: Node, indent: usize) {
-   //    println!("{:indent$}{:?}", "", node.kind(), indent = indent);
-   //    let mut cursor = node.walk();
-   //    for child in node.children(&mut cursor) {
-   //       rec_print(child, indent + 2);
-   //    }
-   // }
-   // rec_print(tree.root_node(), 0);
-
-   // 3) Convert to *our* tiny AST subset
-   let program = build_ast(tree.root_node(), &source_code)?;
-
-   // 4) Run interpreter
-   Interpreter::default().run(&program);
-
-   Ok(())
-}
-
-// ──────────────────────────────────────────────────────────────
-// AST builder helpers (subset only!)
-// ──────────────────────────────────────────────────────────────
-fn build_ast(root: Node, src: &str) -> Result<Program> {
-   let mut body = Vec::new();
-   let mut cursor = root.walk();
-   for child in root.children(&mut cursor) {
-      match child.kind() {
-         "lexical_declaration" => body.extend(parse_lexical_decl(child, src)?),
-         "expression_statement" => {
-            let expr_node = child
-               .named_child(0)
-               .ok_or_else(|| anyhow!("Malformed expression statement"))?;
-            body.push(Stmt::Expr(parse_expr(expr_node, src)?));
-         },
-         "function_declaration" => {
-            body.push(parse_function_decl(child, src)?);
-         },
-         "comment" | ";" => {}, // ignore
-         other => eprintln!("⚠️  Unhandled top‑level node: {other} (ignored)"),
-      }
-   }
-   Ok(Program { body })
-}
-
-fn parse_function_decl(node: Node, src: &str) -> Result<Stmt> {
-   let name_node = node
-      .child_by_field_name("name")
-      .ok_or_else(|| anyhow!("Missing function name"))?;
-   let name = src[name_node.byte_range()].to_string();
-
-   let params_node = node
-      .child_by_field_name("parameters")
-      .ok_or_else(|| anyhow!("Missing function parameters"))?;
-   let params = parse_params(params_node, src)?;
-
-   let body_node = node
-      .child_by_field_name("body")
-      .ok_or_else(|| anyhow!("Missing function body"))?;
-   let body = parse_block_stmt(body_node, src)?;
-
-   Ok(Stmt::FuncDecl { name, params, body })
-}
-
-fn parse_params(node: Node, src: &str) -> Result<Vec<String>> {
-   let mut params = Vec::new();
-   let mut cursor = node.walk();
-   for child in node.named_children(&mut cursor) {
-      if child.kind() == "identifier" {
-         params.push(src[child.byte_range()].to_string());
-      }
-   }
-   Ok(params)
-}
-
-fn parse_block_stmt(node: Node, src: &str) -> Result<Vec<Stmt>> {
-   let mut stmts = Vec::new();
-   let mut cursor = node.walk();
-   for child in node.children(&mut cursor) {
-      match child.kind() {
-         "lexical_declaration" => stmts.extend(parse_lexical_decl(child, src)?),
-         "expression_statement" => {
-            let expr_node = child
-               .named_child(0)
-               .ok_or_else(|| anyhow!("Malformed expression statement"))?;
-            stmts.push(Stmt::Expr(parse_expr(expr_node, src)?));
-         },
-         "return_statement" => {
-            stmts.push(parse_return_stmt(child, src)?);
-         },
-         "{" | "}" | "comment" => {}, // ignore
-         other => eprintln!("⚠️  Unhandled block node: {other} (ignored)"),
-      }
-   }
-   Ok(stmts)
-}
-
-fn parse_return_stmt(node: Node, src: &str) -> Result<Stmt> {
-   // Check if there's an expression after 'return'
-   let expr = if let Some(expr_node) = node.named_child(0) {
-      Some(parse_expr(expr_node, src)?)
-   } else {
-      None
-   };
-   Ok(Stmt::Return(expr))
-}
-
-fn parse_lexical_decl(node: Node, src: &str) -> Result<Vec<Stmt>> {
-   let mut stmts = Vec::new();
-   let mut cursor = node.walk();
-   for child in node.children(&mut cursor) {
-      if child.kind() == "variable_declarator" {
-         let id = child
-            .child_by_field_name("name")
-            .ok_or_else(|| anyhow!("Missing declarator name"))?;
-         let init = child
-            .child_by_field_name("value")
-            .ok_or_else(|| anyhow!("Missing initializer"))?;
-         let name = src[id.byte_range()].to_string();
-         let expr = parse_expr(init, src)?;
-         stmts.push(Stmt::VarDecl(name, expr));
-      }
-   }
-   Ok(stmts)
-}
-
-fn parse_expr(node: Node, src: &str) -> Result<Expr> {
-   match node.kind() {
-      "number" => Ok(Expr::Number(src[node.byte_range()].parse()?)),
-      "identifier" => Ok(Expr::Ident(src[node.byte_range()].into())),
-      "string" | "string_fragment" => {
-         let raw = &src[node.byte_range()];
-         let unquoted = raw.trim_matches('\'').trim_matches('"').to_string();
-         Ok(Expr::Str(unquoted))
-      },
-      "binary_expression" => {
-         let left = node
-            .child_by_field_name("left")
-            .ok_or_else(|| anyhow!("Missing lhs"))?;
-         let right = node
-            .child_by_field_name("right")
-            .ok_or_else(|| anyhow!("Missing rhs"))?;
-         let op_node = node
-            .child_by_field_name("operator")
-            .or_else(|| node.child(1))
-            .ok_or_else(|| anyhow!("Missing operator"))?;
-         let op_char = src[op_node.byte_range()].trim();
-         let op = match op_char {
-            "+" => BinOp::Add,
-            "-" => BinOp::Sub,
-            "*" => BinOp::Mul,
-            "/" => BinOp::Div,
-            _ => return Err(anyhow!("Unsupported operator {op_char}")),
-         };
-         Ok(Expr::Binary(
-            Box::new(parse_expr(left, src)?),
-            op,
-            Box::new(parse_expr(right, src)?),
-         ))
-      },
-      "call_expression" => {
-         let callee_node = node
-            .child_by_field_name("function")
-            .ok_or_else(|| anyhow!("Malformed call expression"))?;
-         let callee = match callee_node.kind() {
-            "member_expression" => {
-               let obj = callee_node
-                  .child_by_field_name("object")
-                  .ok_or_else(|| anyhow!("Malformed member expression"))?;
-               let prop = callee_node
-                  .child_by_field_name("property")
-                  .ok_or_else(|| anyhow!("Malformed member expression"))?;
-               format!(
-                  "{}.{}",
-                  src[obj.byte_range()].trim(),
-                  src[prop.byte_range()].trim()
-               )
-            },
-            "identifier" => src[callee_node.byte_range()].trim().into(),
-            other => return Err(anyhow!("Unsupported callee type: {other}")),
-         };
-         // Arguments
-         let args_node = node
-            .child_by_field_name("arguments")
-            .ok_or_else(|| anyhow!("Missing arguments"))?;
-         let mut args = Vec::<Expr>::new();
-         let mut cur = args_node.walk();
-         for arg in args_node.named_children(&mut cur) {
-            args.push(parse_expr(arg, src)?);
-         }
-         Ok(Expr::Call { callee, args })
-      },
-      other => Err(anyhow!("Unhandled expr kind: {other}")),
-   }
-}
diff --git a/attic/vmi-precompile/.gitignore b/attic/vmi-precompile/.gitignore
deleted file mode 100644
index 3bbc62499..000000000
--- a/attic/vmi-precompile/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-rsrc/
-src/wasm_modules.rs
\ No newline at end of file
diff --git a/attic/vmi-precompile/Cargo.toml b/attic/vmi-precompile/Cargo.toml
deleted file mode 100644
index 8ebc044c8..000000000
--- a/attic/vmi-precompile/Cargo.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-[package]
-name = "tetra-vmi-precompile"
-version.workspace = true
-edition.workspace = true
-authors.workspace = true
-homepage.workspace = true
-description = "Tetra VMI precompile: bundled Wasm modules"
-repository.workspace = true
-
-[lints]
-workspace = true
-
-[dependencies]
-serde_json.workspace = true
-serde.workspace = true
-
-[build-dependencies]
-pathdiff = "0.2.3"
-cargo_metadata = "0.19.2"
-serde_json.workspace = true
-serde.workspace = true
-blake3.workspace = true
-
-[[package.metadata.wasm-bundle.projects]]
-name = "scripthost"
-crate = "tetra-scripthost"
-
-[[package.metadata.wasm-bundle.projects]]
-name = "swcbundler"
-crate = "tetra-swcbundler"
diff --git a/attic/vmi-precompile/README.md b/attic/vmi-precompile/README.md
deleted file mode 100644
index 3a5e4c352..000000000
--- a/attic/vmi-precompile/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# tetra-vmi-precompile
-
-Collection of prebuilt WebAssembly modules bundled for use by the script host.
diff --git a/attic/vmi-precompile/build.rs b/attic/vmi-precompile/build.rs
deleted file mode 100644
index 4ebf9ab8e..000000000
--- a/attic/vmi-precompile/build.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-use std::{
-   env, fs,
-   path::{Path, PathBuf},
-   sync::LazyLock,
-};
-
-use cargo_metadata::{CargoOpt, MetadataCommand};
-use pathdiff::diff_paths;
-use serde::Deserialize;
-
-#[derive(Deserialize)]
-struct Project {
-   name: String,
-   //#[serde(rename = "crate")]
-   // crate_name: String,
-   #[serde(default)]
-   metadata: serde_json::Value,
-}
-
-#[derive(Deserialize)]
-struct Metadata {
-   projects: Vec<Project>,
-}
-
-static METADATA: LazyLock<Metadata> = LazyLock::new(|| {
-   let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap() + "/Cargo.toml";
-   let metadata = MetadataCommand::new()
-      .manifest_path(&manifest_path)
-      .features(CargoOpt::AllFeatures)
-      .exec()
-      .expect("Failed to get cargo metadata");
-
-   let pkg = metadata
-      .packages
-      .iter()
-      .find(|p| p.name == env!("CARGO_PKG_NAME"))
-      .expect(concat!(
-         "Could not find ",
-         env!("CARGO_PKG_NAME"),
-         " package"
-      ));
-
-   serde_json::from_value(
-      pkg.metadata
-         .get("wasm-bundle")
-         .expect("Failed to get wasm-bundle metadata")
-         .clone(),
-   )
-   .expect("Failed to parse wasm-bundle metadata")
-});
-
-fn main() {
-   // Find the workspace root directory (where your project is located)
-   println!("cargo:rerun-if-changed=build.rs"); // Rerun if this script changes
-
-   // Check if rsrc directory exists and contains WASM files
-   let src_dir = "./src/";
-   let wasm_dir = Path::new("./rsrc/");
-
-   if !wasm_dir.exists() {
-      println!("cargo:warning=WASM directory not found. Run scripts/build_wasm.py first.");
-      fs::create_dir_all(wasm_dir).unwrap();
-      return;
-   }
-
-   // Mark all WASM files as dependencies for the build
-   if let Ok(entries) = fs::read_dir(wasm_dir) {
-      for entry in entries.flatten() {
-         let path = entry.path();
-         if path.extension().is_some_and(|ext| ext == "wasm") {
-            println!("cargo:rerun-if-changed={}", path.display());
-         }
-      }
-   }
-
-   let mut projects = Vec::new();
-
-   for project in &METADATA.projects {
-      let wasm_path = wasm_dir.join(format!("{}.wasm", project.name));
-      if wasm_path.exists() {
-         projects.push((project, wasm_path));
-      } else {
-         println!(
-            "cargo:warning=WASM file for {} not found at {}. Run scripts/build_wasm.py.",
-            project.name,
-            wasm_path.display()
-         );
-      }
-   }
-
-   if projects.is_empty() {
-      println!("cargo:warning=No WASM files found. Run scripts/build_wasm.py first.");
-      return;
-   }
-
-   // Generate a Rust module that embeds the WASM files
-   generate_wasm_module(&projects, Path::new(&src_dir));
-}
-
-fn generate_wasm_module(projects: &Vec<(&'static Project, PathBuf)>, src_dir: &Path) {
-   let mut mod_content = String::from(
-      r"//! WASM Modules generated during build
-//! This file is auto-generated. Do not edit.
-
-#[derive(Debug, Clone, Copy)]
-pub struct WasmModule<'a> {
-    pub name: &'a str,
-    pub bytes: &'a [u8],
-    pub metadata: &'a str,
-    pub sum: [u8; 32],
-}
-
-// Use a static array for direct access if needed
-pub static ALL_MODULES: &[WasmModule<'static>] = & [
-",
-   );
-
-   for (project, path) in projects {
-      let relative_path =
-         diff_paths(path, src_dir).expect("Could not create relative path for include_bytes!");
-      let include_path = relative_path.to_str().unwrap().replace('\\', "/");
-      mod_content.push_str("\tWasmModule {\n");
-      mod_content.push_str(&format!("\t\tname: {:?},\n", project.name));
-      mod_content.push_str(&format!("\t\tbytes: include_bytes!({include_path:?}),\n"));
-      mod_content.push_str(&format!(
-         "\t\tmetadata: {:?},\n",
-         project.metadata.to_string()
-      ));
-      let bin = fs::read(path).unwrap();
-      let sum = blake3::hash(&bin);
-      mod_content.push_str(&format!("\t\tsum: {:?},\n", sum.as_bytes()));
-      mod_content.push_str("\t},\n");
-   }
-
-   mod_content.push_str("];\n\n");
-
-   let mod_path = src_dir.join("wasm_modules.rs");
-   fs::write(&mod_path, &mod_content).expect("Failed to write generated wasm_modules.rs");
-   println!("Generated module at: {}", mod_path.display());
-}
diff --git a/attic/vmi-precompile/src/lib.rs b/attic/vmi-precompile/src/lib.rs
deleted file mode 100644
index a9da061d1..000000000
--- a/attic/vmi-precompile/src/lib.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-mod wasm_modules;
-pub use wasm_modules::*;
-
-impl WasmModule<'_> {
-   pub fn metadata<'b, T: serde::de::Deserialize<'b>>(&'b self) -> T {
-      serde_json::from_str(self.metadata).unwrap()
-   }
-
-   pub const fn hash(&self) -> [u8; 32] {
-      self.sum
-   }
-}
-
-pub fn lookup_module(name: &str) -> Option<WasmModule<'static>> {
-   ALL_MODULES.iter().find(|m| m.name == name).copied()
-}
diff --git a/lib/services/examples/graphql.rs b/lib/services/examples/graphql.rs
index 97111e48d..ca1c9534b 100644
--- a/lib/services/examples/graphql.rs
+++ b/lib/services/examples/graphql.rs
@@ -144,14 +144,14 @@ impl MutationRoot {
 
       let user = users
          .get_mut(&id)
-         .ok_or_else(|| async_graphql::Error::new(format!("User with id {id} not found")))?;
+         .ok_or_else(|| async_graphql::Error::from(format!("User with id {id} not found")))?;
 
       if let Some(name) = input.name {
          user.name = name;
       }
       if let Some(email) = input.email {
          if !email.contains('@') {
-            return Err(async_graphql::Error::new("Invalid email format"));
+            return Err("Invalid email format".into());
          }
          user.email = email;
       }
diff --git a/package.json b/package.json
index 649af38b3..1a673ca6e 100644
--- a/package.json
+++ b/package.json
@@ -21,13 +21,13 @@
       "lint:fix": "bun scripts/lint.ts --fix",
       "lint:fmt": "bun scripts/lint.ts --fmt",
       "lint:sync-deps": "bun scripts/lint.ts --sync-deps",
-      "py:build": "cd bin/py && maturin build --release",
+      "py:build": "cd bin/py && VIRTUAL_ENV=$PWD/../../.venv maturin build --release",
       "py:clean": "rm -rf target/wheels/tetra-* bin/py/build/ bin/py/dist/",
       "py:dev": "bun run py:stubs && bun run py:develop",
-      "py:develop": "cd bin/py && maturin develop",
-      "py:install": "pip install --force-reinstall $(ls target/wheels/tetra-*.whl | head -1)",
+      "py:develop": "cd bin/py && VIRTUAL_ENV=$PWD/../../.venv maturin develop",
+      "py:install": "uv run --project . pip install --force-reinstall $(ls target/wheels/tetra-*.whl | head -1)",
       "py:stubs": "cd bin/py && cargo run --bin stub_gen --no-default-features --features stub-gen",
-      "py:test": "python3 bin/py/examples/simple_demo.py",
+      "py:test": "uv run --project . python bin/py/examples/simple_demo.py",
       "sim:tpm": "bun scripts/tpm-sim.ts",
       "test": "cargo nextest run",
       "test:actor": "cargo nextest run -p tetra-actor",
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 000000000..39a7f3a59
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,8 @@
+[project]
+name = "tetra-workspace"
+version = "0.1.0"
+requires-python = ">=3.11"
+description = "Tetra workspace Python environment"
+
+[tool.uv.workspace]
+members = ["bin/py"]
