Skip to content

Upgrade cel-rust 0.12 → 0.13 (then revisit 0.14 once released) #31

Closed

Description

@hardbyte

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 — Value becomes an outer convenience layer over Box<dyn Val>, Context stores dyn Val directly (no longer Send), and trait-driven dispatch (Adder, Comparer, Indexer, Sizer, etc.) replaces the previous ad-hoc impls. Also: no type coercion on map index access; NoSuchOverload when 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), Optional proper overloads, removes lifetimes from Type/Env, and removes contains from 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 — exhaustive Value::* pattern matching for Python conversions (Null, Bool, Int, UInt, Float, Timestamp, Duration, String, List, Bytes, Map, Opaque).
  • cel::Context construction and variable insertion.
  • cel::Program::compile and execution.
  • cel::ExecutionError — we match exhaustively to map to typed Python exceptions (UndeclaredReference, UnsupportedBinaryOperator, FunctionError, …).
  • cel::objects::{Key, OptionalValue, TryIntoValue}.
  • cel::extractors::Arguments for user-registered functions.
  • Value::Opaque(Arc<…>) for our Optional wrapper.

Plan

Phase 1 — Upgrade to 0.13.0

  • Bump cel = "0.13" in Cargo.toml.
  • Migrate Value/Context interop to the dyn-Val model (Context stores dyn Val; we lose Send).
  • Update ExecutionError mapping 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/Env usage.
  • Adjust: contains no 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-rust to the cel-rust org (#237). Update any links/docs once the move completes.

Related upstream activity worth watching

Activity

  1. hardbyte commented on May 12, 2026

    @hardbyte
    OwnerAuthor

    0.14 investigation — decision: hold

    Did an exploratory branch (cel-0.14-upgrade, local — kept in a stash) pointing cel at upstream main rev cc7c378. Findings inform the plan.

    Status of 0.14 upstream

    • Not yet released to crates.io. Release PR clarkmcc/cel-rust#279 has been open since 2026-03-12.
    • The struct work and most other 0.14 changes are already on master.

    Rust API surface

    Unchanged for us. Value::Struct is feature-gated behind structs, which we don't enable. Clean compile against cc7c378 with no source modifications.

    User-visible regressions

    1. min/max removed from the default stdlib (upstream now requires explicit context.add_function("min", cel::functions::min)). Fixable on our side by registering them in build_environment — already prototyped in the stash.
    2. Stdlib conversion overloads now shadow user-registered functions. cel 0.14 adds int/uint/double/string/bytes/duration/timestamp as overload-resolved stdlib functions. When a user calls context.add_function("double", their_fn), dispatch silently picks the stdlib cast (objects.rs:1331 — env consulted before user functions).
    3. Some test assertions need refreshing for fold/reduce error message changes — minor.

    What the CEL spec actually says

    Verified against langdef.md:

    • Type conversion functions (int, uint, double, …) are not reserved keywords — they're "normal functions". The reserved list is only as break const continue else for function if import let loop package namespace return var void while.
    • However, the "Extension Functions" section says: "An application domain of CEL can add a new overload to the size function above, provided this overload's argument types do not overlap with any existing overload."
    • Dispatch order between user-provided and standard functions is implementation-defined (not specified).

    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)

    • Hardcoded-name-list warning at Context.add_function — feasible (~30 LOC) but bit-rots and false-positives on legitimate non-overlapping extensions.
    • cel::Context::empty() escape hatch — too coarse; drops size, optional, time getters along with conversions.
    • Custom curated cel::Env — fragile; per-type stdlib() modules mix conversions + useful methods (bytes::stdlib adds both bytes() cast AND size_bytes), and reaching the internals would mean re-implementing upstream's registration logic.
    • Signature-overlap detection (what the spec actually constrains) requires upstream introspection API we don't have.

    Decision

    Ship the 0.13 PR (#32) as our next release. Hold on 0.14 until at least one of:

    1. Upstream releases 0.14 to crates.io (we want a stable target, not a git rev).
    2. Upstream adds an 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, Type lifetime 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.

  2. changed the title [-]Upgrade cel-rust 0.12 → 0.13 → 0.14[/-] [+]Upgrade cel-rust 0.12 → 0.13 (then revisit 0.14 once released)[/+] on May 12, 2026
  3. hardbyte commented on Jul 4, 2026

    @hardbyte
    OwnerAuthor

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions