Skip to content

feat(nse): extension crash reporting, a WAL checkpoint, and on-device push hooks - #751

Open
bmc08gt wants to merge 3 commits into
mainfrom
feat/push-preload-groundwork
Open

feat(nse): extension crash reporting, a WAL checkpoint, and on-device push hooks#751
bmc08gt wants to merge 3 commits into
mainfrom
feat/push-preload-groundwork

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Groundwork for moving the SQLite store into group.com.flipcash.shared, split out so the App Group move lands on top of it rather than tangled into it. Each piece stands on its own; none of them change app behaviour.

Crash reporting for the notification service extension

The extension is a separate process and ErrorReporting lives in the app target, so today an NSE crash produces no report at all. ExtensionReporting starts Bugsnag once per extension process and tags events with process = notification-service, which is what makes them separable from the app's in the dashboard — both report under the same app id otherwise.

It is deliberately not hoisted into FlipcashCore. That would put Bugsnag into the dependency graph of the core package, including its macOS vector test plans.

Three call sites: the start and a didReceive breadcrumb at the top of the entry point, and a capture on the prefetch failure path, which currently swallows its error.

One limit worth stating, because silence here will otherwise read as health: a jetsam kill for exceeding the extension's memory limit terminates the process without an exception, so it produces no report. Extension memory headroom still has to be measured.

Database.checkpoint()

PRAGMA wal_checkpoint(TRUNCATE). TRUNCATE rather than PASSIVE because a passive checkpoint gives up silently when any reader is mid-transaction, which is precisely the case that leaves the WAL growing without bound. This one blocks up to busyTimeout and throws when it cannot finish.

It has no production caller yet — it gains one in the next PR, which wires close() to app lifecycle. Landing the pragma and its tests separately keeps that PR to the connection-lifecycle change, which is the part with real blast radius.

Device harness hooks

Three CommandLine.arguments gates in AppDelegate, plus PushController.copyTokenToPasteboard(). None can run for a user.

They are here because 0xdead10cc — the watchdog kill for holding a lock on shared storage while suspended — is the one risk in this workstream a simulator cannot reproduce. The App Group move therefore has to be re-checked on hardware, and the spike that cleared it was bounded by one device and one OS, so that is standing advice rather than a one-off.

On a physical device there is otherwise no way to set a beta flag (Maestro does not support physical iOS devices, and devicectl cannot inject touches), no way to reach .authorized (the notification prompt is reachable only from onboarding or a money flow, so a device that skipped onboarding cannot get there, and without it there is no APNs token and no way to push the extension at all), and no way to read the FCM token (the log redactor strips it, correctly).

--beta-flags= sits outside the --ui-testing branch on purpose: that flag also suppresses keychain auto-login, so a launch that set flags through it would have no session and no open database.

The extension runs in its own process and `ErrorReporting` lives in the
app target, so an NSE crash currently produces no report at all.

`ExtensionReporting` starts Bugsnag once per extension process and tags
events with `process = notification-service`. Without that tag both
processes report under the same app id and the extension's crashes are
indistinguishable from the app's.

It stays in the extension target rather than moving into FlipcashCore,
which would put Bugsnag into the core package's dependency graph and its
macOS vector test plans.

A jetsam kill for exceeding the extension's memory limit terminates the
process without an exception, so it still produces nothing here. Memory
headroom has to be measured, not inferred from silence.
`PRAGMA wal_checkpoint(TRUNCATE)` rather than PASSIVE: a passive
checkpoint gives up silently when any reader is mid-transaction, which
is the case that leaves the WAL growing without bound. TRUNCATE blocks
up to `busyTimeout` and throws when it cannot finish.

No production caller yet. It gains one in the follow-up that wires
`close()` to app lifecycle; landing the pragma and its tests separately
keeps that change to connection lifecycle alone, which is the part with
real blast radius.
`0xdead10cc`, the watchdog kill for holding a lock on shared storage
while suspended, is the one risk in the App Group migration a simulator
cannot reproduce, so the store move has to be re-checked on hardware.

On a physical device there is otherwise no way to set a beta flag
(Maestro does not support physical iOS devices, and devicectl cannot
inject touches), no way to reach `.authorized` (the notification prompt
is reachable only from onboarding or a money flow, and without it there
is no APNs token at all), and no way to read the FCM token (the log
redactor strips it).

All three are gated on `CommandLine.arguments`, so none can run for a
user. `--beta-flags=` sits outside the `--ui-testing` branch because
that flag also suppresses keychain auto-login, which would leave the
launch with no session and no open database.
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