Skip to content

feat(ios): report game reminder lifecycle to Sentry - #1678

Open
EnderOfWorlds007 wants to merge 23 commits into
mainfrom
claude/ios-reminder-telemetry
Open

EnderOfWorlds007 wants to merge 23 commits into
mainfrom
claude/ios-reminder-telemetry

Conversation

@EnderOfWorlds007

@EnderOfWorlds007 EnderOfWorlds007 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What

The iOS host records the full product game-reminder troubleshooting trail: scheduled, not_scheduled, fired, tapped, product_opened, missed, and cancelled.

These are troubleshooting telemetry events, not error reporting.

This PR now depends on #1571 and builds on its HostEvent and HostEventRecording types. Reminder events use that single typed Sentry path instead of adding feature-specific methods to generic IssueReporting.

How

  • GameReminderEvent and GameReminderDiagnostics live in the Products feature package, alongside the product reminder behavior they describe.
  • Values that are conceptually numeric or boolean remain typed HostEventValue values, including start/delay milliseconds, app build, and whether opening navigated.
  • AlarmKit and local-notification delivery report successful and skipped scheduling.
  • The reminder center records cancellation, auto-open, missed starts, and AlarmKit fired state. An already-alerting alarm is recorded before refresh can drop its past reminder slot.
  • A request whose rounded start is already past emits one not_scheduled(start_in_past) event and is not handed to either delivery service.
  • The Alarm Play action retains its original behavior: it directly opens the product and then stops the alarm. The ProductOpener Boolean return only records whether navigation occurred; it does not route the tap through or mutate ProductGameReminderCenter.
  • Open counts must filter or group by reminder.open_source: alarm and auto_open are distinct observations around one tap, so both can be present for the same user action.
  • The Play intent carries the optional scheduled start for correlation. Alarms created before this change omit it.

Every reminder event carries the product identifier and canonical host metadata. When available, it also carries the scheduled start, delay from start, delivery, skip reason, open source, app state, and navigation result.

AlarmKit limits

  • fired is observable only while the app process is running; the synchronous alerting-state check closes the refresh/drop race but cannot reconstruct a ring that happened entirely while the app was absent.
  • Alarm dismissal is not observable without adding a stopIntent, which would change Stop behavior and is intentionally out of scope.
  • Local-notification reminders do not currently expose equivalent fired/tapped attribution.

Verification

Local validation used Xcode 26.6 and an iPhone 17 Pro simulator:

  • Products package tests: passed with xcodebuild test -scheme Products.
  • Focused app tests: GameReminderEventTests, GameReminderDeliveryDiagnosticsTests, and ProductGameReminderCenterTests passed, including fired-before-drop, single past-start, and held-future-reminder replacement regressions.
  • Direct feat(ios): expose native host telemetry to products #1571 contract tests: HostEventTests passed.
  • Debug app build: passed with xcodebuild build -scheme polkadot-app.
  • SwiftFormat on the changed files and both iOS review checklists: passed; git diff --check is clean.

Dependency

Depends on #1571. Merge commit cfade2bd31a0caad499f2f7b2c83a7edc64f29be has the exact #1571 head ab88afef3808ac5f47bf3c46dd226dcd3ef1ba43 as a parent, so this branch can be reviewed against that parent to isolate the reminder work.

Adds host.reminder.* events through the IssueMonitoring seam (no-op in
Release): scheduled / not_scheduled (alarm or notification, with the
skip reason), fired (AlarmKit alerting seen while the app runs), tapped
and product_opened from the alarm's Play intent, product_opened on the
auto-open at the start, missed when the start is reached past the open
grace, and cancelled when the product cancels. Each carries the product,
the game start and the delay after the start in ms as numbers, plus the
host platform, OS version, app version/build and launch id.
@EnderOfWorlds007
EnderOfWorlds007 requested a review from a team October 24, 2026 08:04
@github-actions

Copy link
Copy Markdown
Contributor

This pull request touches an app, which is not built by default. Add a label for each build you want:

  • iOS simulator build, ios-simulator-build: builds the iOS app and attaches a build for the iOS Simulator on a Mac; its unit tests run on every pull request.
  • iOS device build, ios-device-build: attaches a signed build that installs on a registered iPhone or iPad.

Each starts as soon as it is added and follows the branch from then on.

@github-actions github-actions Bot added the host-ios Touches the iOS host tree label Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Bundle size report

Compared with main at ff34f26.

Raw Gzip Brotli
truapi-host 8.23 MiB 5.77 MiB 5.46 MiB
truapi-provider 4.03 MiB 1.27 MiB 960.2 KiB
truapi 6.72 MiB 951.5 KiB 777.8 KiB
trinity-stack 562.4 KiB 225.5 KiB 186.6 KiB
Total 19.53 MiB 8.19 MiB 7.34 MiB

WebAssembly modules

Raw Gzip Brotli
truapi-host/wasm/web/truapi_server_bg.wasm 3.12 MiB 1.08 MiB 825.7 KiB
truapi-host/wasm/web/truapi_verifiable_bg.wasm 4.89 MiB 4.64 MiB 4.61 MiB
truapi-provider/truapi_provider_bg.wasm 3.99 MiB 1.26 MiB 952.5 KiB
trinity-stack/wasm/trinity_stack_bg.wasm 525.1 KiB 217.1 KiB 179.3 KiB

No file changed size.

Commit: f0f9db6

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

CI Status: not green, 1 item needs attention.

  • ios-app: failure
All job results
job result
android-app skipped
android-bindings skipped
bundle-size success
changes success
changeset-guard skipped
cli-package skipped
codegen success
e2e skipped
explorer success
headless-install success
host-wasm success
ios-app failure
ios-bindings success
licenses success
playground success
provider-android-bindings skipped
release-guard success
rust success
ts-client success
ts-debugger success
ts-host success
ts-trinity-stack success
wasm-provider success
workflow-lint skipped

Signing credentials: valid as of 2026-10-27

Commit f0f9db6b · run log

…elds

The alarm's Play button now goes through ProductGameReminderCenter, which
drops the held reminder before opening, so a tap is never followed by a
second product_opened or by missed. Every event carries logger
host.telemetry, and reminder.delivery is set only on scheduled and fired,
as on Android. A GameAlarmManaging seam over AlarmManager lets the alarm
reminder's scheduled and not_scheduled be tested, alongside the
notification reminder's.
drop(slot.productId)
if !isLate, !opened {
if isLate {
record(.missed, for: slot)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scheduling a start already in the past lands here as missed, same on Android.

let sentryEvent = Event(level: .info)
sentryEvent.message = SentryMessage(formatted: event.name)
sentryEvent.logger = GameReminderEvent.logger
SentrySDK.capture(event: sentryEvent) { scope in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we already have proper abstraction in the IssueMonitoring package. For example, one can follow NotificationSlotIssueDiagnostics as an example to add GameReminderDiagnostics. What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 15331dd: replaced the dedicated Sentry telemetry type with GameReminderDiagnostics over the shared IssueReporting abstraction, preserving the reminder event fields, fingerprint, level, and no-op behavior.

@EnderOfWorlds007

Copy link
Copy Markdown
Contributor Author

Good call, thanks. We'll rework it as GameReminderDiagnostics following NotificationSlotIssueDiagnostics.

@EnderOfWorlds007

Copy link
Copy Markdown
Contributor Author

Reworked as you suggested. GameReminderEvent and GameReminderDiagnostics now live in the Products package, following NotificationSlotIssueDiagnostics, and IssueReporting is unchanged. The events go through the HostEvent/HostEventRecording path from #1571, so this PR now depends on #1571. Ready for another look.

@EnderOfWorlds007

Copy link
Copy Markdown
Contributor Author

Refreshed onto current main (merge, no force-push). The only change beyond the merge is the test recorder adopting the new @autoclosure record() signature. A local iPhone 17 Pro run passes: Debug build, plus the 28 reminder tests and the full suite of 1,540 tests, with 0 failures. Ready for another look.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

host-ios Touches the iOS host tree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants