fix all cross-Io heap corruption: dual pg.Pool + Threaded service paths
the relay SIGSEGV'd at ~396 hosts during startup — DiskPersist's pg.Pool
was created on Threaded Io, but ~40 call sites across slurper, API handlers,
broadcaster, backfiller, and cleaner called it from Evented fibers, triggering
Thread.current() on a NULL threadlocal.
Part A — dual pg.Pool:
add ev_db (Evented pg.Pool) to DiskPersist. pure DB methods get *Impl(db)
internal implementations + thin *Ev wrappers. Evented callers use ev_db;
pool_io callers keep using self.db. 13 methods refactored.
Part B — Threaded service paths:
- admin ban: uidForDidEv on Evented side, takedown routed through host_ops
queue (fire-and-forget). worker executes takeDownUser + persist + broadcast
on pool_io under persist_order.
- playback: cross-Io request/reply via MPSC Treiber stack. Evented fiber
posts PlaybackRequest, pool_io worker executes playback() under mutex,
sets done atomic. fiber spin-waits on failure to prevent use-after-free
on stack-local request.
persist_order held through full persist → resequence → broadcast_queue.push()
to guarantee insertion order matches seq assignment order.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>