···78787979on a shared CPU with fractional allocation, all these threads compete. the BatchSpanProcessor's 500ms TLS flush is particularly suspect — TLS is CPU-intensive.
80808181+> **note (april 2026):** the backend now runs on zig 0.16 with thread-per-connection (Thread.Pool was removed). the thread count listed above is from the 0.15 era but the contention analysis still applies.
8282+8183## possible next steps
828483851. **upgrade VM**: move to `performance-1x` (dedicated CPU) — this is the real fix
···88908991```
9092client → fly proxy (TLS termination) → app (port 3000)
9191- ├── HTTP thread pool (16 workers)
9393+ ├── thread-per-connection (accept loop spawns threads)
9294 ├── local SQLite (read_conn for search, conn+mutex for writes)
9395 ├── turso client (fallback for unsupported queries)
9496 ├── sync thread (turso → local, full on startup + periodic incremental)
+1-1
docs/reconciliation.md
···4141| file | role |
4242|------|------|
4343| `backend/src/ingest/reconciler.zig` | background worker (~250 lines) |
4444-| `backend/src/main.zig` | wires up `ingest.reconciler.start(allocator)` after `tpuf.init()` |
4444+| `backend/src/main.zig` | wires up `ingest.reconciler.start(allocator, io)` after `tpuf.init()` |
4545| `backend/src/db/schema.zig` | `verified_at TEXT` column migration |
4646| `backend/src/ingest/tap.zig` | `tpuf.delete()` after `indexer.deleteDocument()` |
4747