Skip to content

Commit 0f13138

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. `Between` judges a float range in the same order (`(0.0, -0.0)` is one value, `(NaN, 1.0)` is inverted), by the comparison #1235 added. 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 f915cf5 commit 0f13138

27 files changed

Lines changed: 716 additions & 79 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
@@ -259,7 +259,12 @@ after `z`. `Between("b", "A")` is refused as an inverted range, since `A`
259259
folds to `a`. Text holding a code point Unicode 16 does not assign has no
260260
fold, and its query or write is refused with `encrypt.ErrTerm`.
261261
262-
An order index on bytes or a float stores its term but answers no ordering
262+
Floats order as PostgreSQL's `float8` does (ADR-0002): `-0.0` and `0.0` are
263+
one value, and every NaN is one value, above `+Inf`, so `Between(math.NaN(),
264+
math.Inf(1))` is refused as an inverted range. A `float32` orders as the
265+
`float64` it widens to.
266+
267+
An order index on bytes stores its term but answers no ordering
263268
operator, so such a field has no `Lt`; nor does the `ope` index of a field
264269
that declares `ore` too, since `ore` answers the orderings. stashgen prints a notice for each such index, on stderr and in
265270
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)