Skip to content

A number attribute matches a rule's "is one of" set, so a reading stored as 3.0 is one of {3} - #1403

Open
rudycelekli wants to merge 2 commits into
deeplethe:devfrom
rudycelekli:fix/rule-set-numeric-reading
Open

rudycelekli wants to merge 2 commits into
deeplethe:devfrom
rudycelekli:fix/rule-set-numeric-reading

Conversation

@rudycelekli

Copy link
Copy Markdown
Contributor

Why

in and not_in conditions compare a reading's text with the set's text. A typed number attribute is stored as an f64 (normalize_attr_value / attribute_value go through Number::from_f64), so a reading of 3 comes back from object_value as 3.0, and text() turned it into "3.0". The set operand is written as [3] or ["3"] and parsed to "3". The two strings never match, so a rule such as "grade is one of {1, 2, 3}" on a number attribute never fires, and not_in fires for every reading. Nothing reports an error.

What changes

text() writes a JSON number in f64 form, so 3.0 reads as "3" and 2.5 stays "2.5". String and boolean readings are unchanged.

How it was checked

New test a_stored_number_is_one_of_the_numbers_in_the_set: a reading json!(3.0) against In {"3"} gives one hit.

  • cargo test -p utopia-reason --lib: 109 passed.
  • With the fix reverted, the new test fails with left: 0, right: 1.
  • cargo fmt --all --check and cargo clippy -p utopia-reason --all-targets -- -D warnings pass.

I did not run this against a database. The 3.0 shape comes from the f64 written by attribute_value, which Postgres jsonb keeps as 3.0.

Before review

  • Every commit is signed off (git commit -s)
  • cargo fmt --all --check, cargo clippy and cargo test pass for the touched crate

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

Thanks, the bug is real, but this breaks sets written as [3.0]: parse_operand stores them as "3.0", which matches a 3.0 reading today and no longer would. Please compare numerically when both the reading and the set item parse as numbers, and add a line to ADR 0029, which says set membership compares strings exactly.

…red as 3.0 is one of {3}

Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
…a set written [3.0] still holds a reading of 3, and ADR 0029 says so

Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
@rudycelekli
rudycelekli force-pushed the fix/rule-set-numeric-reading branch from 7d0c9a2 to e6819d3 Compare November 5, 2026 03:27
@rudycelekli

Copy link
Copy Markdown
Contributor Author

Set membership now compares numerically when both the reading and the set item parse as numbers, and otherwise compares strings exactly as before, so a 3.0 reading is in {3} and a reading of 3 is in a set written [3.0]. text() is back to its dev form, the test covers both directions plus a non-numeric case, ADR 0029 has the line, and the branch is rebased on dev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants