Skip to content

Add JSON Logic min and max operators#6825

Merged
ajpallares merged 39 commits into
mainfrom
pallares/json-logic-min-max-operators
Jun 8, 2026
Merged

Add JSON Logic min and max operators#6825
ajpallares merged 39 commits into
mainfrom
pallares/json-logic-min-max-operators

Conversation

@ajpallares

@ajpallares ajpallares commented May 20, 2026

Copy link
Copy Markdown
Member

Checklist

  • Tests (as JSON predicate fixtures)

Motivation

Adds min / max so audience predicates can compare values against numeric extrema. Resolves SDK-4344. Stacked on #6817.

Description

  • Variadic flat-list shape per json-logic-js; operands coerce via JS Number() (like - / / / %, not parseFloat as in + / *). No iteration or projection.
  • Empty input returns ±∞ (mirrors Math.min() / Math.max()); non-numeric operands coerce to NaN and poison the result, so a malformed predicate fails closed against a numeric threshold.
  • Coverage is declarative JSON (min.json / max.json) run by the shared fixture runner; no Swift unit tests.

Note

Low Risk
Isolated rules-engine operator addition with extensive fixture tests; no auth, purchases, or data-path changes.

Overview
Adds JSON Logic min and max operators to the rules engine so audience predicates can compare values against numeric extrema (aligned with JS Math.min / Math.max).

Operands are a flat variadic list ({"min": [a, b, ...]}); each value coerces via Value.asNumber (JS Number()). Empty lists yield ±∞; invalid operands yield NaN, which fails closed when compared to thresholds. Wiring is in Operators.dispatch via new MinMaxOperators; coverage is declarative fixtures (min.json, max.json) with the shared fixture count raised to 307.

Reviewed by Cursor Bugbot for commit 7482442. Bugbot is set up for automated code reviews on this repo. Configure here.

@ajpallares ajpallares marked this pull request as ready for review May 20, 2026 18:35
@ajpallares ajpallares requested a review from a team as a code owner May 20, 2026 18:35
@ajpallares ajpallares requested a review from a team May 20, 2026 18:35

@rickvdl rickvdl 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.

Nice addition!

@ajpallares ajpallares changed the base branch from pallares/json-logic-string-array-operators to pallares/json-logic-iteration-operators May 27, 2026 08:47
@ajpallares ajpallares force-pushed the pallares/json-logic-iteration-operators branch from f6c4c80 to d11529c Compare June 2, 2026 12:43
@ajpallares ajpallares force-pushed the pallares/json-logic-min-max-operators branch from d2ca6d6 to e73eabe Compare June 2, 2026 12:43
@ajpallares ajpallares force-pushed the pallares/json-logic-iteration-operators branch from d11529c to f6c4c80 Compare June 2, 2026 12:48
@ajpallares ajpallares force-pushed the pallares/json-logic-min-max-operators branch from e73eabe to d2ca6d6 Compare June 2, 2026 12:48
…tures

Convert the hand-written operator unit tests for operators available at the
string+array level into declarative JSON predicate fixtures sharing khepri's
conformance format, run by a shared runner that auto-discovers every file in
PredicateFixtures/. `expected` is a khepri-compatible superset (Bool or
{ "error": ... }) plus optional `description` and `expectedWarnings`.

Adds a test-only Value: Decodable conformance so predicates and variables
decode straight into the engine's value model; production Value is unchanged.
Tests that can't be expressed as predicate->Bool stay in Swift; ValueTests
untouched. Test-only change.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 40901e5)
@ajpallares ajpallares force-pushed the pallares/json-logic-iteration-operators branch from f6c4c80 to 874649b Compare June 2, 2026 14:12
@ajpallares ajpallares force-pushed the pallares/json-logic-min-max-operators branch from d2ca6d6 to 03295d9 Compare June 2, 2026 14:13
ajpallares and others added 7 commits June 2, 2026 17:07
Load the in-repo fixtures once and feed the decoded cases straight into
the parameterized test, instead of collecting IDs and re-reading every
file to find the matching case per ID. PredicateConformanceFixtureCase
gains Identifiable + Sendable (for the arguments) and a
CustomTestStringConvertible extension so each case still displays by id.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Asserting an exact warning count coupled the fixtures to engine
internals. Match warnings by substring only (count-agnostic); an empty
`contains` now asserts that no warning is emitted, preserving the
"does not warn" cases. The three count-only fixtures gain the
"missing variable" substring they actually emit.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the khepri single-file plumbing (defaultFixtureURL, fixtureURL,
the no-arg loadCases(), the env var, and the unused fixtureNotFound
error). This PR only runs the in-repo PredicateFixtures/ directory; the
khepri conformance loader lands with its test in the conformance PR.

Co-authored-by: Cursor <cursoragent@cursor.com>
Implements the json-logic-js some/all iteration predicates. Operator coverage
is expressed as JSON predicate fixtures (some.json / all.json) run by the
shared fixture runner introduced downstack, replacing hand-written unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit d11529c)
@ajpallares ajpallares force-pushed the pallares/json-logic-iteration-operators branch from 874649b to db50103 Compare June 3, 2026 12:59
Implements the json-logic-js min/max operators (variadic flat list, ±∞ for
empty input, NaN propagation for non-numeric operands). Coverage is expressed
as JSON predicate fixtures (min.json / max.json) run by the shared fixture
runner, replacing hand-written unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit e73eabe)
@ajpallares ajpallares force-pushed the pallares/json-logic-min-max-operators branch from 03295d9 to 8a445e2 Compare June 3, 2026 12:59
ajpallares added a commit that referenced this pull request Jun 3, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
ajpallares added a commit that referenced this pull request Jun 5, 2026
ajpallares and others added 12 commits June 5, 2026 17:37
Expresses the "empty-string key resolves to the whole scope and is not
missing" case as a `{"!!":{"missing":[""]}}` -> false fixture; the string
coercion the other missing fixtures use can't distinguish [] from [""].
Bumps the pinned fixture count to 237. Keeps the corpus in sync with the
purchases-android counterpart.

Co-authored-by: Cursor <cursoragent@cursor.com>
Adds fixtures for the empty-segment dot-path splits, var default-vs-null-leaf
behavior, and the non-numeric missing_some threshold (7 new cases), bumping
the pinned count to 244. Also adds the var-null-path Swift test so the
non-fixturizable cases match the purchases-android counterpart. Keeps the
fixture corpus byte-identical across both repos.

Co-authored-by: Cursor <cursoragent@cursor.com>
…-logic-iteration-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
…json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Co-authored-by: Cursor <cursoragent@cursor.com>
- Rename the object-array some/all fixtures to describe behavior instead
  of referencing the khepri oracle
- Add fixtures for literal predicates and non-boolean truthy predicate
  results
- Drop the unused opName parameter from parseIterationArgs and return an
  optional items list so a non-array source is distinguishable from an
  empty one
- Bump pinned fixture count to 271

Co-authored-by: Cursor <cursoragent@cursor.com>
Place operator docs on each op instead of duplicating at the type level;
drop "not vacuous truth" wording.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add var-fed cases (including the single-array-arg NaN gotcha), min
fail-closed and empty-list fail-closed coverage. Collapse the two-pass
NaN scan + extremum into a single reducing fold. Pinned fixture count
294 -> 301.

Co-authored-by: Cursor <cursoragent@cursor.com>
…erators' into pallares/json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
ajpallares and others added 4 commits June 8, 2026 10:24
…teration-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Label each operator grouping in Operators.dispatch per PR review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
Rename the all-match fixture and add cases where only the first or only
the middle item matches, addressing PR review feedback that the existing
some coverage was order dependent.

Co-authored-by: Cursor <cursoragent@cursor.com>
khepri guards all with notEmpty, so it returns false for an empty array
like json-logic-js; drop the inaccurate claim that khepri returns true.

Co-authored-by: Cursor <cursoragent@cursor.com>
Base automatically changed from pallares/json-logic-iteration-operators to main June 8, 2026 09:05
…erators' into pallares/json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit 4d696d6. Configure here.

Comment thread RevenueCat.xcodeproj/project.pbxproj Outdated
Remove the duplicate WorkflowsCacheTests.swift PBXFileReference introduced
during a merge, and add a dedicated "Min and max" grouping comment so the
min/max cases are no longer lumped under arithmetic.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ajpallares

Copy link
Copy Markdown
Member Author

Merging based on the prior approval + the approval from RevenueCat/purchases-android#3552 which is the same diff but in Android

@ajpallares ajpallares merged commit 7fbf5e1 into main Jun 8, 2026
18 of 20 checks passed
@ajpallares ajpallares deleted the pallares/json-logic-min-max-operators branch June 8, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants