port I/O-bound thread spawns to io.concurrent
phase 2 of the 0.16 migration — long-lived I/O loops now run as
std.Io concurrent tasks instead of OS threads. CPU-bound frame
worker pool stays on std.Thread.
- subscriber.zig: ping thread → ping future
- slurper.zig: per-host workers, startup, crawl queue → futures
- broadcaster.zig: per-consumer write loop → future
- validator.zig: resolver threads → resolver futures
- event_log.zig: flush thread → flush future
- main.zig: GC loop, metrics server → futures
- backfill.zig, resync.zig, cleaner.zig: thread → future
- all shutdown paths: thread.join() → future.cancel(io)
remaining std.Thread.spawn (intentional):
- thread_pool.zig: CPU-bound keyed frame workers
- broadcaster.zig: fire-and-forget slow consumer cleanup (detached)
- broadcaster.zig: test helper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>