Skip to content

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

Merged
bmc08gt merged 3 commits into
mainfrom
feat/push-preload-groundwork
Sep 11, 2026
Merged

bmc08gt merged 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.
@bmc08gt bmc08gt self-assigned this Sep 10, 2026
@bmc08gt
bmc08gt merged commit ea4043e into main Sep 11, 2026
1 check passed
bmc08gt added a commit that referenced this pull request Sep 11, 2026
…discrete-curve

* origin/main: (27 commits)
  fix(database): share one SQLite writer per owner and take write locks up front (#759)
  feat(chat): declare the payment action on tip DM payments (#752)
  refactor(chat): drop the deprecated new_messages overlay (#757)
  feat(notifications): write prefetched messages into the shared store (#756)
  refactor(store): move the persistence layer into a shared FlipcashStore package (#755)
  feat(database): move the SQLite store into the App Group container (#754)
  feat(database): open the store on demand, close it on background (#753)
  feat(nse): extension crash reporting, a WAL checkpoint, and on-device push hooks (#751)
  feat(home): long-press the You tab to open the account switcher (#749)
  fix(tests): reset Photos access before the previous app instance lingers (#746)
  chore: bump version to 2026.9.2 (#745)
  revert: back out the Coinbase Stable Swapper authority migration (#747) (#750)
  fix(swap): follow the Coinbase Stable Swapper authority migration (#747)
  fix(tests): cancel a cash link through the details screen (#744)
  fix(chat): make the whole Send Cash pill tappable while it stands alone (#743)
  fix(username): drop a leading @ in the validator (#742)
  fix(chat): scope the send-button spring to the button (#741)
  fix(transactions): tighten the details card stack and drop the header badge (#740)
  fix(transactions): draw View in Chat as a card, not the primary action (#739)
  feat(chat): flash the message a reply-quote jump lands on (#738)
  ...

# Conflicts:
#	Code.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
#	FlipcashCore/Package.swift
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