Repository navigation
Upgrade cel-rust 0.12 → 0.13 (then revisit 0.14 once released) #31
Copy link
Copy link
Closed
Description
Goal
Upgrade our cel dependency from 0.12.0 to 0.14.0 in two steps, with 0.13 as a stable midpoint.
Why two steps
- 0.13.0 (2026-03-12) introduced the "dyn Val" rewrite —
Valuebecomes an outer convenience layer overBox<dyn Val>,Contextstoresdyn Valdirectly (no longerSend), and trait-driven dispatch (Adder,Comparer,Indexer,Sizer, etc.) replaces the previous ad-hoc impls. Also: no type coercion on map index access;NoSuchOverloadwhen indexing into strings;Err-resilient AND/OR. - 0.14.0 (release PR clarkmcc/cel-rust#279, open since 2026-03-12) adds struct support (
StructDef,CelStruct),Optionalproper overloads, removes lifetimes fromType/Env, and removescontainsfrom containers (string-only).
Going through 0.13 first lets us absorb the dyn-Val refactor against a released, semver-stable target before chasing the moving 0.14 surface.
Our cel surface area (everything that will need to change)
src/lib.rs/src/context.rs— exhaustiveValue::*pattern matching for Python conversions (Null, Bool, Int, UInt, Float, Timestamp, Duration, String, List, Bytes, Map, Opaque).cel::Contextconstruction and variable insertion.cel::Program::compileand execution.cel::ExecutionError— we match exhaustively to map to typed Python exceptions (UndeclaredReference,UnsupportedBinaryOperator,FunctionError, …).cel::objects::{Key, OptionalValue, TryIntoValue}.cel::extractors::Argumentsfor user-registered functions.Value::Opaque(Arc<…>)for ourOptionalwrapper.
Plan
Phase 1 — Upgrade to 0.13.0
- Bump
cel = "0.13"inCargo.toml. - Migrate
Value/Contextinterop to the dyn-Val model (Context storesdyn Val; we loseSend). - Update
ExecutionErrormapping for any renamed/removed variants. - Verify map indexing — no more type coercion; ensure our tests still pass or update behaviour intentionally.
- Verify string indexing now errors (was previously allowed) — surface as a Python exception.
- Re-run benchmarks (
bench.py) and note any regression. - Full test suite green.
Phase 2 — Upgrade to 0.14.0 (wait for release)
- Track clarkmcc/cel-rust#279; upgrade once published to crates.io.
- Drop lifetimes from
Type/Envusage. - Adjust:
containsno longer works on containers (string-only). - Decide whether to expose CEL struct support to Python.
Phase 3 — Repo move
- Upstream is moving from
clarkmcc/cel-rustto thecel-rustorg (#237). Update any links/docs once the move completes.
Related upstream activity worth watching
- #284 — More explicit
NoSuchOverload. Relevant to Distinguish parse errors from execution errors with different exception types #23 (typed exception split). - #276 — Custom MacroExpander API. Relevant to Support for fold or reduce? #14 (fold/reduce).
- #291 / #251 — Conformance test suites.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
hardbyte commentedon May 12, 2026
0.14 investigation — decision: hold
Did an exploratory branch (
cel-0.14-upgrade, local — kept in a stash) pointingcelat upstream main revcc7c378. Findings inform the plan.Status of 0.14 upstream
master.Rust API surface
Unchanged for us.
Value::Structis feature-gated behindstructs, which we don't enable. Clean compile againstcc7c378with no source modifications.User-visible regressions
min/maxremoved from the default stdlib (upstream now requires explicitcontext.add_function("min", cel::functions::min)). Fixable on our side by registering them inbuild_environment— already prototyped in the stash.cel 0.14addsint/uint/double/string/bytes/duration/timestampas overload-resolved stdlib functions. When a user callscontext.add_function("double", their_fn), dispatch silently picks the stdlib cast (objects.rs:1331— env consulted before user functions).fold/reduceerror message changes — minor.What the CEL spec actually says
Verified against
langdef.md:int,uint,double, …) are not reserved keywords — they're "normal functions". The reserved list is onlyas break const continue else for function if import let loop package namespace return var void while.sizefunction above, provided this overload's argument types do not overlap with any existing overload."So cel-rust 0.14's behaviour (stdlib wins on overlap) is closer to spec than "user functions should override stdlib" would be. Asking upstream to flip dispatch order isn't a spec-aligned ask.
Workaround landscape (purely our side)
Context.add_function— feasible (~30 LOC) but bit-rots and false-positives on legitimate non-overlapping extensions.cel::Context::empty()escape hatch — too coarse; dropssize, optional, time getters along with conversions.cel::Env— fragile; per-typestdlib()modules mix conversions + useful methods (bytes::stdlibadds bothbytes()cast ANDsize_bytes), and reaching the internals would mean re-implementing upstream's registration logic.Decision
Ship the 0.13 PR (#32) as our next release. Hold on 0.14 until at least one of:
Env::remove_overload/Env::has_overload/ similar introspection API that gives wrappers a clean way to handle the shadowing.Net 0.14 benefit for our wrapper is small — most of the marquee work (structs,
Typelifetime cleanup) is behind features we don't enable or refactors we don't touch. Worth waiting for a clean target.The exploratory branch + stash are preserved locally for whenever we pick this back up.
[-]Upgrade cel-rust 0.12 → 0.13 → 0.14[/-][+]Upgrade cel-rust 0.12 → 0.13 (then revisit 0.14 once released)[/+]Upgrade cel-rust to 0.13.0 and trim docs (#32)
hardbyte commentedon Jul 4, 2026
Resolved in v0.7.0, which upgraded straight to cel-rust 0.14 (past 0.13). See https://github.com/hardbyte/python-common-expression-language/releases/tag/v0.7.0