Skip to content

Retire Z3: migrate the core translation validator to ordeal and drop the C++ dependency #313

Description

@avrabe

Decision: standardize on ordeal as loom's only solver and remove Z3. Recording it as an issue because it is an architecture change with consequences beyond the verifier, and because the evidence for doing it now has accumulated rather than been argued.

Why now — four independent pressures, not a preference

  1. It is shipping broken binaries. release: the x86_64-unknown-linux-gnu binary needs GLIBC 2.38 — won't load on ubuntu-22.04 (a supported GitHub runner) #311: the v1.2.0 Linux release required GLIBCXX_3.4.31 and would not load on ubuntu-22.04. That symbol requirement exists only because loom links Z3 (C++). v1.3.0 pins the builder image and asserts the floor, but that is a workaround for a dependency we intend to delete.
  2. It is the wasip2 friction. Building loom for wasm32-wasip2 locally fails in z3-sys with could not find native static library c++`` — we carry a forked z3.rs branch for wasi-sdk support to get as far as we do. A pure-Rust solver removes the fork and the C++ sysroot problem together.
  3. Tier-1 already proved the pattern. Adopt ordeal for certificate-checked optimization-rule verification (replace loom's own Z3 path) #277 moved the algebraic rule verifier behind a swappable backend: 38/38 rules proven, reported identically by both engines, and in both mode the harness runs both per obligation and panics on divergence — it did not. The migration seam, the differential harness and the answer to "do they agree" all exist already.
  4. The last capability blocker is gone. ordeal#70 (symbolic-index array select/store) shipped in 0.11.0; loom is on 0.17.0. There is no longer a modelling gap that forces Z3 for the memory fragment.

Measured surface — smaller than the line count suggests

verify.rs is 9,696 lines, but the Z3 API surface across the whole crate is eight types in five files:

verify.rs        use z3::ast::{Array, BV, Bool};
                 use z3::{Config, FuncDecl, SatResult, Solver, Sort, with_z3_config};
verify_rules.rs  verify_e2e.rs  islands.rs  rule_solver.rs

Every one has a direct ordeal counterpart — BvTerm/BoolTerm, Solver/CheckResult, Sort, and sliver's array + uninterpreted-function support for Array/FuncDecl. The bulk of those 9.7k lines is term construction over BV/Bool, which is mechanical to port, not a redesign.

Plan

Sequencing with #300 — this is the important one

#300 asks for refinement-based validation with traps as first-class state, rather than value-equivalence plus guards. Do not port the current total-model encoding to ordeal and then re-architect it. Tier-2 and #300 are one piece of work: port and change the relation in the same pass, keeping the existing static guards as a floor throughout. Porting twice is the only way to make this expensive.

What it buys

Honest risks

  • verify.rs is the safety-critical core; a silent regression here is the worst failure mode loom has. The both-mode differential is the mitigation and it must stay on for the whole migration, not just the start.
  • Float modelling (Investigate: verify.rs opaque-float shared const name may unify distinct float ops (verifier soundness) #283) must be resolved during the port, not transcribed. Carrying a suspected soundness bug across a migration would launder it into 'new code'.
  • Performance is unmeasured at the core-validator scale. Tier-1 showed agreement, not throughput parity. If ordeal is materially slower on the big obligations, that is a finding to publish, not to hide.

Refs #277, #300, #311, #283, #246

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions