Skip to content

Bound persistentIds in their own store and mirror the client's clears - #9

Draft
cassiostp wants to merge 1 commit into
masterfrom
cs/bounded-persistent-ids
Draft

Bound persistentIds in their own store and mirror the client's clears#9
cassiostp wants to merge 1 commit into
masterfrom
cs/bounded-persistent-ids

Conversation

@cassiostp

@cassiostp cassiostp commented Aug 13, 2026

Copy link
Copy Markdown

persistentIds in the shared config.json only ever grow: the client clears its in-memory copy when the MCS login response acks the ids, but the disk copy was append-only, and every notification rewrote the whole 35MB+ file synchronously (~200ms main-process block; superhuman/desktop CLI-2311, ~54k desktop devices receive >100 pushes/day).

The renderer payload is the only switch: when fcmConfig.persistentIds on START_NOTIFICATION_SERVICE says storage: 'v2', persistence becomes a dumb mirror of the client's persistentIds snapshot event (push-receiver 2.1.8, superhuman/push-receiver#16 must merge and publish first) in its own file, push-receiver.json, capped (maxPersistedIds, default 5000; desktop will pass 20000 from a LaunchDarkly flag). The first v2 start runs a has()-guarded idempotent migration that trims the shared list into the new file and deletes the old key. With no payload, behavior is byte-for-byte today's legacy append — a bare package bump changes nothing, activation and same-day revert are both a flag flip, and setup()'s signature is unchanged from master.

Worth a close look: the module-scope new Config() is now lazy (electron-config's constructor rewrites the entire file — a full 35MB write at require() time on bloated configs); webContents.send goes through one isDestroyed()-guarded helper; the started short-circuit tolerates missing credentials. Worst-case failure of the cap is redelivery of ids beyond the newest entries — duplicate notifications after a restart, never missed ones; desktop is adding a log.duplicate_notification metric to watch exactly that. yarn.lock intentionally untouched — it regenerates once push-receiver 2.1.8 is on the registry. Tests: yarn jest (new; the repo had no test setup).

🤖 Generated with Claude Code

@cassiostp
cassiostp force-pushed the cs/bounded-persistent-ids branch from 4b71837 to e3dbea4 Compare August 13, 2026 21:28
The persistentIds list in the shared config.json only ever grows: the
client clears its in-memory copy when the MCS login response acks the
ids, but the disk copy was append-only. Field reports show 35MB+
config files rewritten synchronously on every notification (~200ms
main-process block each) and the full list uploaded to Google on
every connect.

Persistence is now a mirror of the client's 'persistentIds' snapshot
event (push-receiver 2.1.8) in its own config file, push-receiver.json,
capped at the most recent 5000 entries, so notification writes stop
rewriting the host app's shared config and the file cannot regrow.
A one-time idempotent migration trims the shared list into the new
file and deletes the old key; hosts can run it early via the exported
migratePersistentIds() before their own config traffic starts.

The legacy behavior remains selectable per START_NOTIFICATION_SERVICE
via fcmConfig.persistentIds (renderer payload wins over the static
setup option), so a host can revert storage modes with a web deploy.
The module-scope Config was made lazy: its constructor rewrites the
whole config file, which cost a full-file write at require() time.
Also guards webContents.send calls with isDestroyed() and tolerates
missing credentials on the started short-circuit.
@cassiostp
cassiostp force-pushed the cs/bounded-persistent-ids branch from e3dbea4 to 3c1ccfe Compare August 17, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant