fix(workflows): compute intro eligibility for inherited packages on packageless workflow screens#6978
Merged
facumenzella merged 3 commits intoJun 11, 2026
Conversation
…ackageless workflow screens Intro-offer (`intro_offer_condition`) overrides never fired on a workflow step that has no package components, because intro eligibility was computed only over the screen's own package components (empty on such a step). Compute it over the inherited workflow package context as well, so a step that inherits a selected package from another step can resolve the rule. Standalone paywalls are unaffected: `workflowPackages` is nil there, so the helper returns the on-screen packages unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
99701ac to
e4caa9c
Compare
vegaro
reviewed
Jun 11, 2026
Mirror the intro-offer fix for `promo_offer_condition`: carry each inherited package's Apple promo offer product code through the workflow package context (`WorkflowPackageContext.promoOfferCodesByPackageId`) and union it into the promo eligibility computation, so promos and intros behave the same on a packageless workflow step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Member
Author
|
@vegaro this was indeed a bug, however, I am also adding some changes to the rc mobile app. |
vegaro
approved these changes
Jun 11, 2026
vegaro
left a comment
Member
There was a problem hiding this comment.
this looks good but I made a suggestion to prevent duplicated packages in cesar/facu-suggestion
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist
purchases-androidand hybridsMotivation
On Paywalls V2 workflows,
intro_offer_condition/promo_offer_conditionoverrides on a workflow step that has no package components never fire, even when the user is eligible and the step inherits a selected package from another step. Eligibility is computed only over the screen's own package components, which is empty on such a step, so the rules can't resolve.Description
Compute eligibility over the inherited workflow package context (
workflowPackages) in addition to the screen's own packages:introEligibilityPackages(...)unions the on-screen and inherited packages (order-preserving, deduped).WorkflowPackageContext.promoOfferCodesByPackageId, populated from each package component'sapplePromoOfferProductCode) and unioned into the promo eligibility computation, so promos and intros behave the same.Standalone paywalls are unaffected:
workflowPackagesisnilthere, so both helpers return the on-screen packages unchanged.Note: a screen that already hosts its package components (e.g. packages in a sticky footer) was never affected, it always computed eligibility over those packages.
Verification
A/B in PaywallsTester on the packageless first step, with the user genuinely intro-eligible:
compute for=[] -> []→ the step's tabs stay visible (rule can't fire).compute for=[$rc_annual,$rc_monthly] -> true→ tabs hide as intended.AI session context
Generated with Claude Code. Evidence-first decision log; no secrets included.
Task. Investigate a suspected bug on an iOS Paywalls V2 workflow where an intro-eligibility rule didn't take effect, then fix it.
Investigation (decision log).
mafdet workflow content). Foundintro_offer_conditionoverrides (hide-when-eligible): a carousel on a screen with packages, and tabs on a screen without package components. Onlyintro_offer_condition+selectedconditions exist, so the globaldiscardRulestrap is not triggered.PaywallsV2View.taskoverpaywallState.packages, populated byPackageValidator, which only collects package components present on the screen (ViewModelFactory.swift). A packageless screen => empty list =>isEligible(_:)always false => override can't fire.Native A/B (PaywallsTester, instrumented
IntroOfferEligibilityContextwith temporary logs, since reverted), eligibility genuinely true:compute for=[] -> []; tabs stay visible.compute for=[$rc_annual,$rc_monthly] -> true; tabs hide.falseonly because the StoreKit config lacked a valid intro offer / wasn't applied undersimctl launch.Review follow-up (vegaro). Asked whether promos should behave the same as intros. They should, and the promo offer product code is reachable (
PackageComponent.applePromoOfferProductCodeincollectPackages). Extended the fix to thread it throughWorkflowPackageContextand union it into the promo eligibility computation; the earlier "promo stays on-screen only" framing was wrong and is gone.Honesty caveat. The originally-reported symptom (carousel not hiding on the screen that does have packages) was an eligibility-state issue, not an SDK bug: that screen hides correctly once the user is genuinely eligible, with or without this change. This fix's real effect is the packageless workflow step.
Verification.
swift buildok; unit tests forintroEligibilityPackages+promoEligibilityPackageInfospass; SwiftLint clean; native PaywallsTester A/B as above. Added the new test file toRevenueCat.xcodeprojto satisfy the Danger project-sync check.Not done / follow-ups. No end-to-end snapshot test for the full render path (unit tests cover the package-selection decision only).
Note
Medium Risk
Touches paywall purchase-path eligibility and workflow package context; behavior change is scoped to workflow steps without local package components, with unit tests covering the merge logic.
Overview
Fixes Paywalls V2 workflow steps that have no package components but inherit packages from another step:
intro_offer_conditionandpromo_offer_conditionoverrides could not resolve because eligibility ran only over on-screen packages (empty on those steps).PaywallsV2Viewnow unions inheritedworkflowPackages(and their promo codes) into intro and promo eligibility viaintroEligibilityPackagesandpromoEligibilityPackageInfos, with deduplication and on-screen values winning for promos.WorkflowPackageContextgainspromoOfferCodesByPackageId, populated from package components’applePromoOfferProductCodeinWorkflowContext.collectPackages, and threaded throughWorkflowPaywallView. Standalone paywalls are unchanged whenworkflowPackagesis nil.Adds
PaywallsV2ViewTestsfor the merge/dedupe helpers and registers the file in the Xcode project.Reviewed by Cursor Bugbot for commit 836e1d0. Bugbot is set up for automated code reviews on this repo. Configure here.