Skip to content

Commit a0ca6a7

Browse files
committed
feat(stack-encrypt)!: order floats through cllw-ore's F64 target
An `f32` or `f64` order term is cllw-ore's vitaminc encryption of the value at the `F64` target, whose vitaminc-ore encoding folds `-0.0` into `0.0` and every NaN into one value above `+Infinity`: Postgres's `float8` order. So the ordering operators are now answered over floats, on the typed path (`op::Ordered` for `f32` and `f64`) and over a data plan's `float32` and `float64` fields, and stashgen writes `Lt`, `Lte`, `Gt`, `Gte` and `Between` on a float field with `ore` or `ope`. An `f32` is ordered as the `f64` it widens to: its `Orderable` target is `F64` and vitaminc widens it exactly, so an `f32` and its `f64` are one term and `f32` can join `op::Ordered`. That settles what the earlier draft refused with `TermError::NarrowFloat`, which is gone. A float `Between` is not refused when inverted (a range from NaN, which sorts last, matches nothing), as SQL's `BETWEEN` is not. Float pins, the float ordering baseline, the integer-width lengths and the `score` field in the cross-path fixture carry over from the earlier draft; the fixtures and UI snapshots are re-recorded. Claude-Session: https://claude.ai/code/session_01BZhkvKLpNtKuzj3HCfMXoL
1 parent ccd4431 commit a0ca6a7

27 files changed

Lines changed: 682 additions & 75 deletions

‎languages/golang/CHANGELOG.md‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,16 @@ listed under **Breaking**. Releases are tagged `languages/golang/vX.Y.Z`.
4646
folded form (ADR-0002: case and accents folded, under Unicode 16), so
4747
`Café` and `cafe` tie and `alice` orders before `Zoe`. Text order terms
4848
change bytes from the alpha's; none was deployed.
49+
- **Ordering methods on floats.** A `float32` or `float64` field with
50+
`index=ore` or `index=ope` gets `Lt`, `Lte`, `Gt`, `Gte` and `Between`.
51+
Floats order as PostgreSQL's `float8` does (ADR-0002): `-0.0` ties `0.0`,
52+
and every NaN is one value, above `+Inf`. A `float32` orders as the
53+
`float64` it widens to. Every order term changes bytes from the alpha's,
54+
now that the engine encrypts them through cllw-ore's vitaminc schemes;
55+
none was deployed.
4956
- **stashgen notices an index no generated method queries**: an `ore` or
50-
`ope` index on bytes or a float (the engine answers the orderings over
51-
integers and text only), or the second of two order indexes on a field.
57+
`ope` index on bytes (the engine answers the orderings over integers,
58+
floats and text only), or the second of two order indexes on a field.
5259
The index is still stored; the notice is on stderr and in the file.
5360

5461
### Changed

‎languages/golang/cmd/stashgen/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ For `-type User`, the file `user_stash.go` holds:
124124
- `Fields`, with one entry for each sealed field.
125125
An opaque struct, or a struct with no sealed field outside an opaque one, gets no `Fields`: nothing in it is sealed on its own, so nothing can be queried.
126126
An entry encrypts one value, and has one query method for each operator the engine answers on the field: `Eq`, `Lt`, `Lte`, `Gt`, `Gte`, `Between` or `Matches`.
127-
stashgen asks the embedded engine which operators each field answers, and which index answers each one, so it holds no copy of those rules: an equality index answers `Eq`, a match index on a string `Matches`, and an ORE or OPE index on an integer or a string the four orderings and `Between`, through ORE when the field declares both. A string orders by its folded form: case and accents folded, under Unicode 16.
127+
stashgen asks the embedded engine which operators each field answers, and which index answers each one, so it holds no copy of those rules: an equality index answers `Eq`, a match index on a string `Matches`, and an ORE or OPE index on an integer, a float or a string the four orderings and `Between`, through ORE when the field declares both. A float orders as PostgreSQL's `float8` does (`-0.0` ties `0.0`, NaN sorts last), and a string by its folded form: case and accents folded, under Unicode 16.
128128
`encrypt_into=TextEq` answers `Eq`, which returns the type's query value, `eql.TextEqQuery`.
129129
`encrypt_into=TextMatch` answers `Matches`, which returns an `encrypt.EQLMatchQuery`: the `eql.TextMatchQuery` operand, with `Verify` and `TargetLimit`.
130130
The query of `Matches` carries `Verify` and `TargetLimit`, because its answer can hold rows that do not match; an exact operator's query carries neither.

‎languages/golang/encrypt/README.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,12 @@ range matches nothing. So `Between("b", "A")` matches nothing, since `A`
261261
folds to `a`, below `b`. Text holding a code point Unicode 16 does not assign has no
262262
fold, and its query or write is refused with `encrypt.ErrTerm`.
263263
264-
An order index on bytes or a float stores its term but answers no ordering
264+
Floats order as PostgreSQL's `float8` does (ADR-0002): `-0.0` and `0.0` are
265+
one value, and every NaN is one value, above `+Inf`, so `Between(math.NaN(),
266+
math.Inf(1))` matches nothing. A `float32` orders as the `float64` it
267+
widens to.
268+
269+
An order index on bytes stores its term but answers no ordering
265270
operator, so such a field has no `Lt`; nor does the `ope` index of a field
266271
that declares `ore` too, since `ore` answers the orderings. stashgen prints a notice for each such index, on stderr and in
267272
the generated file: the terms are stored, and only your own code can compare

‎languages/golang/encrypt/doc.go‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@
138138
// Eq returns an [EqualityTerm] (or, for a field with encrypt_into, the EQL
139139
// type's query value), an ordering an [OreTerm] or [OpeTerm], and Between a
140140
// [Range] of two. Their answers are exact. The orderings are answered on
141-
// integers and on text, which orders by its folded form (case and accents
142-
// folded, under Unicode 16), so Café and cafe tie and alice orders before
143-
// Zoe. Matches returns a [MatchQuery],
141+
// integers, on floats, which order as PostgreSQL's float8 does (-0.0 ties
142+
// 0.0, NaN sorts last), and on text, which orders by its folded form (case
143+
// and accents folded, under Unicode 16), so Café and cafe tie and alice
144+
// orders before Zoe. Matches returns a [MatchQuery],
144145
// whose answer can hold rows that do not match: size the fetch with
145146
// [MatchQuery.TargetLimit], then decrypt the rows and keep those
146147
// [MatchQuery.Verify] reports true, one call into the engine for the page.

‎languages/golang/encrypt/internal/testusers/kinds_stash.go‎

Lines changed: 25 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎languages/golang/encrypt/internal/testusers/probe_stash.go‎

Lines changed: 132 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)