After each recompute, cmd/recompute sends a silent refresh push to every device with a registered token, whether or not that device's blocklist actually changed. The code says so plainly:
// This is a simple broadcast-to-all: every device with a registered token
// gets pinged regardless of whether its own blocklist actually changed.
// Per-device relevance targeting is deferred to Spec 4.
At one device this is free. At scale it is a recompute every 15 minutes waking every installed app, which burns battery for no reason and is the kind of thing that gets an app characterised as badly behaved.
Why it is not trivial
Each device syncs with its own cursor, so "did anything change for this device" means "did anything change after the cursor it last acknowledged". The server does not currently track per-device cursors — the cursor lives on the client. So this needs either:
- Recording each device's last-acknowledged cursor server-side (a schema addition, and a write on every blocklist fetch), or
- A coarser but cheaper signal — e.g. skip the broadcast entirely when a recompute produced no status changes at all, which is the common case in steady state
Option 2 is far less work and captures most of the benefit. Worth measuring before building option 1.
Where to look
cmd/recompute/main.go — runCycle, the notify branch
internal/store.RecomputeAll — already returns counts; does it distinguish "changed" from "examined"?
internal/store.ListPushTargets
internal/push.BroadcastRefresh
The broadcast path is covered by tests using an injectable notifier (cmd/recompute/broadcast_test.go), so you have a harness to work against without APNs credentials.
After each recompute,
cmd/recomputesends a silent refresh push to every device with a registered token, whether or not that device's blocklist actually changed. The code says so plainly:At one device this is free. At scale it is a recompute every 15 minutes waking every installed app, which burns battery for no reason and is the kind of thing that gets an app characterised as badly behaved.
Why it is not trivial
Each device syncs with its own cursor, so "did anything change for this device" means "did anything change after the cursor it last acknowledged". The server does not currently track per-device cursors — the cursor lives on the client. So this needs either:
Option 2 is far less work and captures most of the benefit. Worth measuring before building option 1.
Where to look
cmd/recompute/main.go—runCycle, thenotifybranchinternal/store.RecomputeAll— already returns counts; does it distinguish "changed" from "examined"?internal/store.ListPushTargetsinternal/push.BroadcastRefreshThe broadcast path is covered by tests using an injectable notifier (
cmd/recompute/broadcast_test.go), so you have a harness to work against without APNs credentials.