Repository navigation
Conversation
Text ordering is decided: the order key is the system ADR-0002's text fold, which vitaminc 0.6 ships in vitaminc-ore, and the ORE and OPE indexes answer the orderings on text over it. The ADR no longer says "if the catalog keeps text ordering" or that the paragraph goes if text ordering is dropped, and decision 7 names text beside the integer types.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…the orderings on text
Text could not be ordered: no ordering operator was answered on a text
field, and the ORE and OPE terms stored for text went through cllw-ore's
own collation, which keeps case, so Zoe ordered before alice and é after
z. ADR-0002 defines text's order key as its fold (Unicode 16 NFC with case
and accents folded), and vitaminc 0.6 ships it in vitaminc-ore.
Text ORE and OPE terms now derive over that key on the typed and the
data-plan paths alike: the text is folded with vitaminc_ore::text and the
folded bytes go to cllw-ore's byte encryption, whose ciphertext type is
the one it gives text, so OreTerm<String> and OpeTerm<String> keep their
type. The released cllw-ore and ore-rs do not implement vitaminc-ore's
OrderScheme yet, so the CLLW schemes the engine already uses encrypt the
key. A text term's key is derived under a framing that adds the fold's
frozen label; integer, float and bytes order terms keep their bytes and
framing. Café, cafe, CAFÉ and cafe with a combining accent are one term.
Text holding a code point Unicode 16 does not assign has no fold and no
order term.
op::Ordered covers String, whose Between judges an inverted range on the
folded keys through a new sealed method, Ordered::inverted: ("b", "A") is
inverted, ("A", "a") is one value. The data path answers the orderings on
text too, refuses an inverted text range and unfoldable order text at its
boundary, and the Go generator now writes Lt, Lte, Gt, Gte and Between on
a string field with ore or ope. Its notice is left for order indexes on
bytes or a float, and for a second order index.
Closes #1234.
Mutation testing (cargo-mutants,
|
| caught | missed | unviable | timeout |
|---|---|---|---|
| 24 | 0 | 18 | 0 |
Every mutant in the changed lines was caught by a test.
There was a problem hiding this comment.
🔵 Needs a closer look
Changes to cryptographic term derivation, key framing, and stored-byte compatibility warrant final human review.
No open issues 🎉
2 files not reviewed
languages/golang/encrypt/internal/testusers/kinds_stash.go: Generated filelanguages/golang/encrypt/internal/testusers/probe_stash.go: Generated file
What changed in this PR
Enables folded text ordering in the Rust encryption engine and Go SDK, preparing for EQL text-order types.
Changes:
- Derives text order terms using Unicode 16 case-and-accent folding.
- Enables text comparisons and validates folded range bounds.
- Updates generated Go methods, regression tests, documentation, and dependencies.
| File | Description |
|---|---|
| packages/stack-encrypt/tests/ui/pass/plan_chain.rs | Adds compiling text queries. |
| packages/stack-encrypt/tests/ui/op_order_on_text.stderr | Removes obsolete rejection snapshot. |
| packages/stack-encrypt/tests/ui/op_order_on_text.rs | Removes text-order rejection test. |
| packages/stack-encrypt/tests/ui/op_order_on_bytes.stderr | Adds bytes-order rejection snapshot. |
| packages/stack-encrypt/tests/ui/op_order_on_bytes.rs | Checks bytes ordering remains unavailable. |
| packages/stack-encrypt/tests/ui/op_between_takes_a_pair.stderr | Updates ordering diagnostics. |
| packages/stack-encrypt/tests/term_bytes.rs | Pins folded terms and rejection behavior. |
| packages/stack-encrypt/tests/op.rs | Tests folded comparisons and ranges. |
| packages/stack-encrypt/src/sem/mod.rs | Folds text and separates its key framing. |
| packages/stack-encrypt/src/op/mod.rs | Enables typed text ordering. |
| packages/stack-encrypt/src/dynamic/term.rs | Updates text-order documentation. |
| packages/stack-encrypt/src/dynamic/query.rs | Enables and validates dynamic text queries. |
| packages/stack-encrypt/fuzz/Cargo.lock | Locks the folding dependency. |
| packages/stack-encrypt/docs/adr/0009-operators-select-the-index-and-a-query-term-is-not-the-stored-term.md | Records text ordering as decided. |
| packages/stack-encrypt/CHANGELOG.md | Documents changed text term bytes. |
| packages/stack-encrypt/Cargo.toml | Adds vitaminc-ore. |
| packages/eql/Cargo.lock | Updates engine dependencies. |
| languages/golang/stashgen/testdata/cases/orders/order_stash.go.golden | Adds expected string ordering methods. |
| languages/golang/stashgen/refusal_test.go | Updates unused-index notice coverage. |
| languages/golang/stashgen/enginetest/enginetest.go | Mirrors text-order capability. |
| languages/golang/stashgen/emit.go | Updates unused-index explanations. |
| languages/golang/encrypt/README.md | Explains folded ordering and refusals. |
| languages/golang/encrypt/order_test.go | Tests folded ordering and generated queries. |
| languages/golang/encrypt/internal/testusers/probe_stash.go | Regenerates string ordering methods. |
| languages/golang/encrypt/internal/testusers/kinds_stash.go | Adds named-string ordering methods. |
| languages/golang/encrypt/guest/Cargo.lock | Updates guest dependencies. |
| languages/golang/encrypt/doc.go | Documents text ordering semantics. |
| languages/golang/cmd/stashgen/README.md | Documents generated string comparisons. |
| languages/golang/CHANGELOG.md | Records text ordering support. |
| Cargo.toml | Declares workspace folding dependency. |
| Cargo.lock | Locks vitaminc-ore and dependencies. |
Review effort: Balanced
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
cipherstash-agent
left a comment
There was a problem hiding this comment.
Automated review attestation
Source: Claude Code scheduled review (/code-review medium + /cross-check-review-findings) at head 54a204d. This is an automated review, not a human approval.
Critical / blocking issues: none.
Findings: none survived cross-check.
Reviewed (packages/stack-encrypt/src):
sem/mod.rs:OrderSourceandtext_order_key. Text goes through the folded key. The PRF context adds the frozenTEXTdomain label only for text, so integer, float and bytes terms keep their bytes. The key is zeroizing and moved, not copied.op/mod.rs: sealedOrdered::inverted. TheStringimpl compares folded keys. Integers keeplo > hi.dynamic/query.rs:ordered(kind),bound_orderand thecheck_inputfold refusal. They agree with the typed path (("b","A")inverted,("A","a")a tie, an unassigned code point refused before a keyset).- Docs, ADR-0009, trybuild snapshots, lockfiles and the Go generated/golden files, checked for consistency with the Rust change.
Cross-check against CI on this head:
- fmt/clippy/nextest/doctests/rustdoc, the Go matrix (Linux/macOS/Windows), Go lint and live tests, the EQL suites and the fuzz regressions are green.
- The mutants gate caught 24 of 24 mutants (0 missed).
- Copilot raised no issues.
- The Codex code and security reviews were still running when this review was posted.
Notes (non-blocking):
OrderSource::ofselects the text path by runtimeAnydowncast onString,Zeroizing<String>and&'static str. A new owned text type passed to an order term would silently take the non-foldedValuepath. This is fine today becauseOrderedis sealed, and the PR notes it. A test asserting everyOrderedtext form takes the folded path would guard it.- Text order terms change bytes (the CHANGELOG notes this as Breaking, with none deployed). Confirm no stored text ORE/OPE terms exist outside tests before merge.
- Changeset-bot reports no changeset. That looks acceptable here since the touched crates and the Go module use their own CHANGELOGs, but a maintainer should confirm.
Generated by Claude Code
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54a204d924
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /// not assign, whose folding is not known. | ||
| pub(crate) fn text_order_key(text: &str) -> Result<Zeroizing<Vec<u8>>, TermError> { | ||
| use vitaminc_protected::Controlled; | ||
| Ok(Zeroizing::new(vitaminc_ore::text(text)?.risky_unwrap())) |
There was a problem hiding this comment.
Preserve unassigned code points in text order keys
For any valid string containing a code point unassigned in Unicode 16—including characters introduced by later Unicode versions—propagating this error makes every ORE/OPE write and query fail. This contradicts ADR-0002's frozen-transform contract in docs/adr/0002-one-value-model-three-encodings-and-eql-v4-by-producer.md:187-195, which requires such code points to pass through unchanged so existing columns remain usable as Unicode evolves; derive the stable pass-through key rather than rejecting the value.
Useful? React with 👍 / 👎.
|
Parked until new This PR folds text inside Stack Encrypt ( No released or built version of either crate implements vitaminc-ore 0.6 yet. Once they do, this PR gets reworked:
The engine surface stays: |
Summary
Stack Encrypt (CipherStash's Rust encryption engine) could not order text: no
<,>,BETWEENorORDER BYquery was answered on a text field. The order terms it stored for text went through cllw-ore's own collation, which keeps case, soZoeordered beforealiceandéafterz. This PR makes text orderable over the folded order key that ADR-0002 defines and vitaminc 0.6 ships: case and accents folded, under Unicode 16. A Go string field withindex=oreorindex=openow getsLt,Lte,Gt,GteandBetween.Draft.
Changes
sem):vitaminc_ore::text's folded key. The folded bytes go through cllw-ore's byte encryption, whose ciphertext type is the one it gives text, soOreTerm<String>/OpeTerm<String>keep their type.vitaminc/ore/value/text-folded/unicode-16/v1). Integer, float and bytes order terms keep their bytes and framing.TermError::Normalize).op::OrderedcoversString. A new sealedOrdered::invertedmakesBetweenjudge an inverted range on folded keys:("b", "A")is inverted,("A", "a")is one value.ordered(kind)includes text, so bindings get the orderings.ore_of/ope_ofproduce the typed path's bytes.ore/ope.enginetest.Staticmirrors the engine.doc.goand the stashgen README describe the fold.vitaminc-ore = "0.6.0"in the root workspace and stack-encrypt. The lockfiles of the root,packages/eql, the encrypt guest and the stack-encrypt fuzz crate are refreshed and pass--locked.Verification
mise x --env test -- cargo nextest run --workspace --all-features: 1183 passed.-D warnings(workspace, all targets and features),cargo fmt --check, stack-encrypt rustdoc-Dwarningsandmise run test:doc: clean.op_order_on_text(ordering text no longer fails to compile) is nowop_order_on_bytes.pass/plan_chain.rsgainsLtandBetweenon a text plan.op_between_takes_a_pair.stderris re-recorded for the newOrderedmessage.term_bytes.rs);Lt/Betweenon text: ties,alice < eclair < Élan < emu < Zoein OPE byte order, OREalice < Zoe, folded inverted ranges (tests/op.rs);cargo test --locked -p eql-bindings --all-featuresandmise run types:checkpass.mise run wasm:guest:testpasses,mise run go:testpasses,mise run go:lintreports 0 issues, andgo generate ./...leaves no diff.a/A,e/é/É/NFDé,ss/ß/SSandcafé/CAFEtie; mixed-case names order by the fold.Probe.S.LtofCaféequals the stored term ofcafe, and thatBetween("b", "A")isErrTerm.DATABASE_URL) and the CI mutants gate.Related
Closes #1234. Stacked on #1216. Builds toward #1131 and #1132 (the EQL text order types).
Review notes
cllw-ore0.5.1,ore-rs0.9.0-rc.1) don't implement vitaminc-ore 0.6'sOrderScheme, so the engine encrypts vitaminc-ore's key with the CLLW ORE/OPE it already uses. Block ORE (EQL'sTextOrdOre) stays with stashgen refuses TextOrdOre and TextSearchOre — EQL stores block ORE terms and the engine derives CLLW ORE #1132.String,Zeroizing<String>,&'static str) insidesem'sOrderSource, so no public type or trait bound changed.