* 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>
* Parse workflow experiment enrollment from the config item combo_key
The workflows topic serves each workflow item with a combo_key that
encodes the experiment variants the user was bucketed into
(experiment_id=variant_key pairs joined by ;, or default). Parse it
into WorkflowDataResult.enrolledVariants on every read path so steps
can report experiment exposure in a follow-up. Workflows without an
experiment keep enrolledVariants nil.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Tighten combo_key parsing after review
Drop the redundant default sentinel guard (no pair parses out of it
anyway), keep the moved helpers private, pin that = inside a variant
key is kept, and trim the doc comments.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Echo the step's experiment params on workflow step events
Khepri bakes experiment_id and experiment_variant into the steps of the
enrolled variant (khepri #24946, one experiment per screen) and enrolls
the subscriber on the first step_started that echoes them. Read both
from the step's param_values and put them on every step event.
Drops the combo_key parsing from the previous commits: enrollment must
not be derived from what the config endpoint served, only from exposure.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Trim comments to the ones that carry information
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Reword the experiment param comments
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Plainer wording on the experiment param comments
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Address review: plainer param docs and wire coverage for close
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Delete isLastVariantStep from the SDK
Khepri computes it server side and never puts it in the workflow blob,
so the SDK has nothing to read or send.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Report the workflow blob ref on step events
Khepri needs the blob the client rendered to validate the experiment
params it reports, instead of trusting them. Carry the config item's
blob_ref from the workflows topic through to every step event.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Group the experiment fields and name the ref workflowBlobRef
Per the thread: the blob ref only means something as proof of an
experiment claim, so it travels with the experiment instead of riding
on every workflow event. SDK-level naming is workflowBlobRef so it
does not read as a bare config-layer concept; the wire keys stay
experiment_id, experiment_variant and blob_ref.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Drop comments that restate the code
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Require the workflow blob ref alongside the experiment params
A workflow can only be read through a blob, so a rendered step that has
experiment params always has a ref. Making it required means khepri
never receives a claim it cannot validate.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Carry the blob ref through the checkpoint presentation path
Checkpoint workflows build their context through WorkflowPreview, which
left the ref nil, so a checkpoint-presented experiment step reported
nothing once the ref became required. Thread it from the resolved
workflow. Injected dashboard previews still pass none.
ResolvedCheckpointWorkflow moves to its own file, unchanged, to keep the
resolver under the file length limit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Register ResolvedCheckpointWorkflow.swift in RevenueCat.xcodeproj
The legacy project enumerates sources by hand, so a file added outside
Xcode is invisible to it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Name the request property workflowBlobRef
Matches the Android rename; wire name stays blob_ref.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>