* Add trace_id to the checkpoint hit event
The id is created when the checkpoint is evaluated and handed to the workflow it
starts, so the hit, the workflow's step and paywall events and the receipt's
paywall trace_id all share it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Drop Android references from trace id comments
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Remove remaining Android references in workflow event comments
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: report what a checkpoint resolved to on the hit event
The hit only carried the identifier, so nothing downstream could tell a
checkpoint that presented a paywall from one that matched nothing. It now
carries checkpoint_type, result, and the workflow, offering and rule ids.
The hit moves to after resolution so it has an outcome to report. A resolution
that throws now reports nothing, which is the one case where registering the
identifier is lost.
Picks up cesar's #7563 while he is out. Outcome fields are optional so hits
stored by an older SDK version still decode off disk.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAMocQ6tct3P2rexywxjLu
* refactor: require the checkpoint outcome and trim comments
Checkpoint hits have not shipped, so there are no stored events with the old
shape and checkpoint_type and result do not need to be optional. The three ids
stay optional because they only exist when the checkpoint resolved to them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAMocQ6tct3P2rexywxjLu
* fix: date the checkpoint hit before resolving it
Resolution awaits rules, audiences, workflow data and offerings, so taking the
date afterwards reported resolution-completion time as the hit time. On a cold
start that drifts by a full network round trip.
Adds coverage for the resolution to event mapping, which nothing exercised:
present_ui with its workflow id, return_data with its offering id, and each
no-action reason.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAMocQ6tct3P2rexywxjLu
* chore: register the new test file in RevenueCat.xcodeproj
The CI test plans point at container:RevenueCat.xcodeproj, which lists test
files explicitly, so without this the new tests never run on CI.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAMocQ6tct3P2rexywxjLu
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(checkpoints): rename the checkpoint event's session_id to app_session_id
khepri renamed the field on the checkpoint hit ingest model in
RevenueCat/khepri#24141, aligning it with every other analytics event. The
field has no validation alias and the model ignores extra keys, so an SDK
still sending `session_id` loses the app session silently.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(checkpoints): require app_session_id on the checkpoint event
Matches Android's `BackendEvent.Checkpoint`, which types it non-null, and the
existing `CustomerCenterEventBaseRequest` pattern of dropping an event whose
stored app session is missing rather than posting a partial one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(checkpoints): send checkpoint hits through the analytics events pipeline
Hitting a checkpoint now emits a `checkpoint_hit` feature event, which is
also how khepri learns the checkpoint exists (registration is a side effect
of the hit, there is no separate endpoint).
The event is tracked before resolution and regardless of its outcome, so a
checkpoint reaches the dashboard even when nothing is configured for it yet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: register the new checkpoint event files in RevenueCat.xcodeproj
The Tuist workspace generates its own project, so the committed one needs
the files added by hand. Verified with a RevenueCat target build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(checkpoints): model CheckpointEvent as an enum with a single hit case
Follows PaywallEvent, WorkflowEvent and CustomPaywallEvent, and replaces the
two hardcoded "checkpoint_hit" literals with one exhaustive switch. Adding a
future case (checkpoint results) now fails to compile until both the wire
format and toMap() account for it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNpP9VnvEwrMckgbFWxnRB
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>