Skip to content

Rules v0 Integration branch#3117

Merged
vegaro merged 11 commits into
mainfrom
cesar/conditional-configurability
Mar 6, 2026
Merged

Rules v0 Integration branch#3117
vegaro merged 11 commits into
mainfrom
cesar/conditional-configurability

Conversation

@vegaro

@vegaro vegaro commented Feb 18, 2026

Copy link
Copy Markdown
Member

THIS IS A BASE BRANCH NO NEED TO REVIEW

Add support for Conditional Configurability in paywalls

Ability to set rules for:

  • All custom variables
  • Selected Package
    • Identifier
    • Intro offer presence and eligibility
    • Promo offer presence and eligibility

And ability to configure component/Package visibility


Note

Medium Risk
Changes paywall component override deserialization and application logic (new condition types + rule stripping on unsupported conditions), which can affect which overrides render at runtime. Backward-compat fallbacks are added, but malformed/unknown config paths may still change paywall presentation.

Overview
Adds v0 conditional configurability for paywall component overrides by introducing new ComponentOverride.Condition rule types (selected package, custom variable, intro/promo offer with operators) and evaluating them via a new ConditionContext threaded through component state.

Improves robustness and backwards-compat by making SealedDeserializerWithDefault fall back on unknown or malformed JSON, and by detecting any Unsupported condition in the paywall tree to strip all rule-based overrides (and the unsupported ones) so the UI renders a “default paywall” using only base conditions.

Exposes CustomVariableValue.Number/Boolean publicly and updates examples/testers to use typed values (including editor input), adds kotlinx-serialization-json as a runtime dependency, and expands tests for the new condition parsing, evaluation, and stripping behavior.

Written by Cursor Bugbot for commit 50c1246. This will update automatically on new commits. Configure here.

vegaro commented Feb 18, 2026

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@vegaro vegaro changed the title [Conditional Configurability] Base branch Conditional Configurability v0 Feb 18, 2026
@vegaro vegaro changed the title Conditional Configurability v0 [DONT REVIEW] Conditional Configurability v0 Feb 18, 2026
@codecov

codecov Bot commented Feb 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.44444% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.29%. Comparing base (34e5466) to head (50c1246).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
...es/paywalls/components/common/ComponentOverride.kt 67.85% 5 Missing and 4 partials ⚠️
...utils/serializers/SealedDeserializerWithDefault.kt 75.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3117      +/-   ##
==========================================
- Coverage   79.30%   79.29%   -0.01%     
==========================================
  Files         347      347              
  Lines       13992    14024      +32     
  Branches     1902     1907       +5     
==========================================
+ Hits        11096    11121      +25     
- Misses       2110     2115       +5     
- Partials      786      788       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

vegaro and others added 3 commits February 19, 2026 12:56
…nal configurability (#3110)

### Motivation
The conditional configurability V0 feature requires new condition types
in the data layer to support dynamic paywall component visibility based
on variables, packages, and extended intro/promo offer conditions.

### Description
- Adds `Variable`, `Package`, `SelectedPackage` data classes to
`ComponentOverride.Condition` sealed interface
- Extends `IntroOffer` and `PromoOffer` conditions from simple objects
to data classes with `operator` and `value` fields (backwards compatible
with legacy format)
- Adds `EqualityOperator`, `ArrayOperator`, and `ConditionValue` types
for condition evaluation
- Updates `ConditionSerializer` to handle new types with fallback to
`Unsupported` on parse errors
- Comprehensive unit tests for deserialization, backwards compatibility,
unknown types, and malformed data

**Tasks:** PW-169 (1.1–1.13)

Co-authored-by: Cursor <cursoragent@cursor.com>
…on evaluation (#3111)

### Motivation
The `selected_package` condition allows paywall components to change
their appearance based on which package the user has selected (e.g.,
show different text when annual vs monthly is selected).

### Description
- Introduces `ConditionContext` to carry evaluation state
(`selectedPackageId`, `currentPackageId`, `customVariables`)
- Extends `buildPresentedPartial` to accept `ConditionContext` parameter
- Implements `SelectedPackage` condition evaluation with `in` / `not in`
operators
- Threads selected package ID from all component state classes through
to condition evaluation
- Unit tests for `selected_package` condition evaluation (in, not in, no
selection)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…, and extended intro/promo condition evaluation (#3112)

### Motivation
Completes the V0 condition evaluation logic. 

- With variable conditions paywalls can adapt based on developer custom
variables.
- Selected package conditions let components change based on which
package the user has selected.
- Intro/promo conditions now support explicit operator (`=`/`!=`) and
value fields for more precise control.

### Description
- Implements `Variable` condition evaluation with equality comparison
and type coercion (string, bool, int, double)
- Implements `SelectedPackage` condition evaluation against the
currently selected package ID
- Implements extended `IntroOffer` and `PromoOffer` evaluation with
`operator` (`=`/`!=`) and `value` fields
- Removes `Package` condition (not used by backend or dashboard)
- Threads `customVariables` through `ConditionContext` to all component
state classes
- Wires `customVariables` from `PaywallState.Loaded` into the evaluation
pipeline

Co-authored-by: Cursor <cursoragent@cursor.com>
@vegaro vegaro force-pushed the cesar/conditional-configurability branch from 114c8c1 to b583bb3 Compare February 19, 2026 11:59
… to trigger fallback paywall (#3113)

### Motivation
When a paywall uses condition types that this SDK version doesn't
understand (e.g., conditions added in a newer backend version), the SDK
should gracefully fall back to the default paywall rather than rendering
incorrectly.

### Description
- Adds `UnsupportedCondition` validation in `toPresentedOverrides`. If
any override contains an `Unsupported` condition, it produces a
`PaywallValidationError`
- Adds `PaywallValidationError.UnsupportedCondition` error type with
descriptive error string

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
We were missing support for boolean and number custom variables

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Public API surface changes by making `CustomVariableValue.Number` and
`CustomVariableValue.Boolean` publicly constructible and updating call
sites to use typed values, which could affect downstream integrations
and string formatting expectations.
> 
> **Overview**
> Adds first-class support for numeric and boolean custom paywall
variables by making `CustomVariableValue.Number` and
`CustomVariableValue.Boolean` public and exporting them in the public
API (`api.txt`).
> 
> Updates the tester apps and examples to construct and pass typed
`Number`/`Boolean` values (instead of stringifying), including the
custom variables editor dialog’s value creation logic and sample
`CUSTOM_VARIABLES`/API tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
84aec0f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
vegaro and others added 4 commits February 27, 2026 11:53
Now that we know the JSON is not changing, adjusted the logic to be
simpler. Also found we can use `JSONPrimitive` and simplify things a
lot.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes core JSON deserialization/fallback behavior for paywall
components and override conditions; malformed payloads will now preserve
the declared `type`, which could alter fallback outcomes in edge cases.
> 
> **Overview**
> Simplifies component override variable conditions by replacing the
custom `ConditionValue` sealed type/serializer with a raw
`JsonPrimitive`, and updates variable-matching logic in
`PresentedPartial` to interpret strings/booleans/numbers directly.
> 
> Hardens `SealedDeserializerWithDefault` to handle non-object JSON and
to **preserve the discriminator `type`** when deserialization of a known
type fails (instead of losing it), with expanded tests covering
malformed known types, extra/unknown fields, and `null` variable values.
Also promotes `kotlinx-serialization-json` to a runtime dependency in
`revenuecatui` since `JsonPrimitive` parsing is now used in production
code.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
92e8e9a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- CURSOR_SUMMARY -->
> [!NOTE]
> **Low Risk**
> Test-only changes that broaden coverage for conditional override
evaluation and compose visibility; minimal risk beyond potential
CI/runtime cost from added UI tests.
> 
> **Overview**
> Expands `BuildPresentedPartialTests` to cover more edge cases in
override selection/merging, including *last-match wins* behavior,
`intro_offer`/`promo_offer` operator handling (`equals`/`not_equals`),
and variable type-mismatch scenarios.
> 
> Adds a large new `VisibilityConditionTests` suite exercising Compose
rendering for conditional visibility/styling across components
(carousel/timeline/video/text/stack/tabs), including interactions driven
by `selected_package`, sibling independence, and footer/body
cross-effects.
> 
> Updates test helpers (`FakePaywallState`, test
`toComponentsPaywallState`) to support injecting `customVariables` and a
`stickyFooter` so the new UI tests can build realistic states.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c0c5ed6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Updates conditions to not reuse the old `intro_offer` and `promo_offer`
ones. This way old SDKs behave as expected when a newer paywall with
conditions sends some of the new ones.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes condition JSON deserialization keys and
runtime evaluation for offer-based overrides, which could cause
overrides to stop applying if payloads or clients are mismatched.
Backward compatibility is partially maintained for legacy
`intro_offer`/`promo_offer` objects, but new payloads must use the
renamed `*_condition` types.
> 
> **Overview**
> **Updates the paywall override condition schema to avoid reusing
legacy condition keys.** `intro_offer`/`promo_offer` are now plain
boolean conditions (no operator/value), while new types
`intro_offer_condition` and `promo_offer_condition` carry `operator` +
`value`.
> 
> **Renames the JSON `type` keys for parameterized conditions** from
`selected_package` and `variable` to `selected_package_condition` and
`variable_condition`, and updates `ConditionSerializer` mappings plus
UI-side condition evaluation to match. Tests are adjusted to cover
legacy payload tolerance (extra fields ignored for
`intro_offer`/`promo_offer`) and the new `*_condition` types.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
918d463. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Facundo Menzella <facumenzella@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@RevenueCat-Danger-Bot

RevenueCat-Danger-Bot commented Mar 4, 2026

Copy link
Copy Markdown
1 Warning
⚠️ This PR increases the size of the repo by more than 100.00 KB (increased by 219.76 KB).

Generated by 🚫 Danger

@vegaro vegaro force-pushed the cesar/conditional-configurability branch 2 times, most recently from 4aab30a to d26ef51 Compare March 4, 2026 14:31

@cursor cursor Bot left a comment

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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@vegaro vegaro force-pushed the cesar/conditional-configurability branch from 8c423a1 to 07b8d82 Compare March 4, 2026 15:18
@vegaro vegaro changed the title [DONT REVIEW] Conditional Configurability v0 [DONT REVIEW] Rules v0 Mar 5, 2026
…nditions (#3175)

When an unsupported condition is encountered, instead of falling back to
the generic fallback paywall, the SDK now renders the same components
paywall with only base condition overrides applied, stripping all
rule-based overrides.

Also renames `IntroOfferCondition`/`PromoOfferCondition` to
`IntroOfferRule`/`PromoOfferRule` and adds `Condition.isRule` to
distinguish rule conditions from base conditions.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Alters runtime paywall rendering/override selection when unknown
conditions are encountered, which may change UI behavior for some
configurations. Logic is well-covered by new traversal and
override-filtering tests, but impacts core presentation paths.
> 
> **Overview**
> **Unsupported condition handling is softened:** when any
`ComponentOverride.Condition.Unsupported` is detected anywhere in the
components tree, the SDK now renders the components paywall but *strips
all overrides that use rule-based conditions* (plus the unsupported
ones), leaving only base-condition overrides.
> 
> This introduces `Condition.isRule` and renames
`IntroOfferCondition`/`PromoOfferCondition` to
`IntroOfferRule`/`PromoOfferRule`, updates condition
evaluation/serialization accordingly, removes the `UnsupportedCondition`
validation error pathway, and adds a recursive
`containsUnsupportedCondition()` scan with expanded unit test coverage.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ba8a4cb. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@vegaro vegaro force-pushed the cesar/conditional-configurability branch from a209892 to f14b962 Compare March 5, 2026 14:46
@vegaro vegaro changed the title [DONT REVIEW] Rules v0 Rules v0 Integration branch Mar 5, 2026
@JZDesign JZDesign requested a review from a team March 5, 2026 17:41

@facumenzella facumenzella left a comment

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.

Showtime 🚀

@vegaro vegaro added this pull request to the merge queue Mar 6, 2026
Merged via the queue into main with commit 11a523d Mar 6, 2026
31 checks passed
@vegaro vegaro deleted the cesar/conditional-configurability branch March 6, 2026 16:19
This was referenced Mar 11, 2026
github-merge-queue Bot pushed a commit that referenced this pull request Mar 12, 2026
**This is an automatic release.**

## RevenueCat SDK
### ✨ New Features
* [EXPERIMENTAL]: Beta Galaxy Store Support (#2903) via Will Taylor
(@fire-at-will)
### 🐞 Bugfixes
* Skip installation on GCP CLI in run-firebase-test (#3218) via Will
Taylor (@fire-at-will)
* Fix reduced timeouts being used for HTTP requests when a proxy URL is
configured (#3188) via Rick (@rickvdl)

## RevenueCatUI SDK
### 🐞 Bugfixes
* Fix missing ripple effect in View-based paywall wrappers (#3206) via
Toni Rico (@tonidero)
### Paywallv2
#### ✨ New Features
* Rules v0 Integration branch (#3117) via Cesar de la Vega (@vegaro)

### 🔄 Other Changes
* [Galaxy]: Add promotionEligibilities comment (#3214) via Will Taylor
(@fire-at-will)
* [EXTERNAL] Migrate deprecated buildDir to layout API (#3202)
contributed by @AlexanderTalledo (#3212) via Toni Rico (@tonidero)
* Remove automatic Claude code review workflow (#3211) via Cesar de la
Vega (@vegaro)
* Remove unused convention plugin (#3195) via Toni Rico (@tonidero)
* [EXTERNAL] Integrate convention plugins into Version Catalogs (#3181)
contributed by @AlexanderTalledo (#3194) via Toni Rico (@tonidero)
* [EXTERNAL] Migrate androidx cardview dependency to version catalogs
(#3192) contributed by @AlenxanderTalledo (#3193) via Toni Rico
(@tonidero)
* Improve AdMob adapter test coverage (#3204) via Pol Miro (@polmiro)
* Bump fastlane-plugin-revenuecat_internal from `f5c099b` to `e146447`
(#3197) via dependabot[bot] (@dependabot[bot])
* Fix integration tests (#3196) via Toni Rico (@tonidero)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk release bookkeeping: version strings and deployment paths are
updated from `9.24.0-SNAPSHOT` to `9.24.0`, plus changelog/docs refresh.
Main risk is accidental publishing/docs deployment to the wrong
versioned location.
> 
> **Overview**
> Cuts the `9.24.0` release by updating all version references from
`9.24.0-SNAPSHOT` to `9.24.0` (root `.version`, `gradle.properties`, and
`Config.frameworkVersion`), and aligning sample/test app version
catalogs to consume the released artifact.
> 
> Updates documentation publishing to point at the `9.24.0` directory
(CircleCI S3 sync and `docs/index.html` redirect) and refreshes
`CHANGELOG.latest.md`/`CHANGELOG.md` with the `9.24.0` release notes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8e6d567. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants