Repository navigation
Refuse a dimension sent with no value instead of filing it at slot 0 - #9
Merged
Merged
Conversation
A report carrying `dims: {"cliId": null}` was accepted, and the device
was filed under value 0 of that dimension. On a dimension declared with
a `capacity`, slot 0 is the first value ever reported, so every filter
on that value matched every null-reporting device: in the instance
behind #8, `f.cliId=65` returned 1126 devices for 1 real one. Used as a
per-client restriction, that shows one client's map to another.
The cause was `Schema::cells_for` reading a present-but-empty value
list -- which is what `null` and `[]` deserialise to -- the same way as
an absent dimension. It now refuses one, naming the dimension; the
route already names the device, so the 400 reads
`device "orphan": "cliId" has no value (null or an empty list); ...`.
The check sits in the schema, so compact reports, metadata patches and
GeoJSON all go through it.
GeoJSON needed two more changes to reach it. A `null` under a
dimension's name in `properties` was read through `Option` as an absent
property, which also lands at 0; it is now present and empty, and
refused like the compact form. A `null` inside a list (`[1, null]`,
`[null]`) silently vanished; it is now a parse error, the same 422 a
fractional value gets.
A dimension that is absent altogether still takes value 0, as
documented. That has the same exposure on a capacity dimension and is
left for its own change, since closing it means reserving a slot.
Fixes #8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Fixes #8.
Problem
dims: {"cliId": null}was accepted, and the device was filed under value 0 of the dimension. On a dimension declared with acapacity, slot 0 is the first value ever reported, so every filter on that value also matched every null-reporting device. In the instance from the issue,f.cliId=65returned 1126 devices instead of 1. When the filter is used to restrict a map to one client, that client sees devices that aren't theirs.Cause
Schema::cells_fortreated a value list that was present but empty the same as a dimension that was absent, and put both at index 0.nulland[]both deserialise to an empty list.Change
schema.rs: a dimension sent with no value (nullor[]) is now refused with a 400. The message names the dimension, and the route adds the device id:device "orphan": "cliId" has no value (null or an empty list); report an explicit value, such as "none", for a device that has none.Compact reports, metadata patches and GeoJSON all go through this check.
geojson.rs:nullunder a dimension's name in GeoJSONpropertiesused to be read as an absent property, which also ends up at 0. It is now refused the same way as the compact form.nullinside a list ([1, null],[null]) used to be dropped silently. It is now rejected while the body is parsed: 422unprocessable_body, the same response a fractional value gets.README.md: one sentence describing the rule.Behaviour change
Clients that send
nullor[]for a dimension now get an error instead of a silent mis-filing. The workaround from the issue still works: report an explicit value (e.g.0or"none"), which gets its own slot.Not in this PR
A dimension that is absent still takes value 0, as documented. That covers a new device reported without
dims, and a report that names some dimensions but not others. On a capacity dimension this has the same exposure. Fixing it means reserving a slot for "unassigned" (which affects snapshots), so it should be its own change.Testing
a_dimension_with_no_value_is_refused_not_filed_under_the_first_one(tests/regressions.rs). It replays the issue's setup and sendsnull,[]and[null]in compact form, in GeoJSON and as a metadata patch. It checks that each is rejected with the dimension and the device (or GeoJSON feature) named, that nothing is stored, and thatf.cliId=65still totals 1. Against the old code it fails with{"accepted":1,...}, which is the bug.geojson.rsunit tests for the newnullhandling.cargo test --workspace(run inrust:1.98-slim-bookworm): all 218 tests pass.🤖 Generated with Claude Code