Skip to content

Add Miri test runner and sandbox-aware timestamp stubs#370

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/resolve-pr-369-conflicts-ozMXd
May 14, 2026
Merged

Add Miri test runner and sandbox-aware timestamp stubs#370
AdaWorldAPI merged 2 commits into
mainfrom
claude/resolve-pr-369-conflicts-ozMXd

Conversation

@AdaWorldAPI
Copy link
Copy Markdown
Owner

Summary

Adds Miri (Rust's interpreter-based UB detector) support to lance-graph by:

  1. Creating a dedicated test runner script that safely exercises pure-Rust crates under Miri
  2. Stubbing out system calls (clock_gettime) that Miri's sandbox blocks
  3. Skipping filesystem-dependent tests that can't run in Miri's isolated environment
  4. Bumping MSRV from 1.94.1 to 1.95.0 to align with bevy and ndarray

Key Changes

  • scripts/miri-tests.sh (new): Ephemeral nightly-only test runner following ndarray's pattern

    • Targets 4 safe crates: lance-graph-contract, lance-graph-rbac, neural-debug, and lance-graph-ontology (without lance-cache feature)
    • Skips FFI-heavy crates (lance, arrow, datafusion, BLAS) that Miri cannot enter
    • Enables layout randomization (-Zrandomize-layout) to catch missing #[repr(transparent)]
    • Ignores intentional test-helper leaks via -Zmiri-ignore-leaks
  • crates/lance-graph-ontology/src/registry.rs: Stub now_micros() to return 0 under Miri

    • Miri blocks clock_gettime(REALTIME), making timestamp-dependent append paths abort
    • Deterministic sentinel preserves register/replay logic exercisability
  • crates/lance-graph-ontology/src/lance_cache.rs: Stub chrono_micros() similarly

    • Mirrors the registry pattern for consistency
  • Test file isolation (6 files): Skip or ignore tests that require filesystem access

    • bridge_scope_lock.rs, hydrate_real_ogit.rs, round_trip_ttl.rs: #![cfg(not(miri))] (skip entire file)
    • literal_graph.rs::test_real_aiwar_graph, manifest_codegen.rs::test_idempotency, dcterms_source_attribute_test.rs::dcterms_source_attribute_pairs_surface_for_customer: #[cfg_attr(miri, ignore)] (skip individual test)
  • rust-toolchain.toml: Bump from 1.94.1 to 1.95.0

Implementation Details

The script follows ndarray's proven pattern: ephemeral per-invocation nightly switch (cargo +nightly miri) without changing the default stable toolchain. This keeps Miri optional for local development while enabling CI to validate memory safety on the contract layer and pure-Rust planner paths.

Timestamp stubs use #[cfg(miri)] guards rather than conditional compilation of entire functions, preserving code clarity while allowing Miri to exercise the surrounding logic (registry state machines, TTL parsing) with deterministic time values.

https://claude.ai/code/session_01UwJuKqP828qyX1VkLgGJFS

claude added 2 commits May 14, 2026 04:20
Channel was bumped to 1.95.0 in PR #367 but the explanatory comment
above it still said "Pinned to 1.94.1 ... 1.95 turned several
previously-safe patterns into denied lints ... without sufficient
value to justify the churn." Pure documentation drift — the bump
already happened, the lint debt was closed by #367 + #368, and the
comment now describes a state that has not been true for ~a day.

Update the comment to reflect the actual 1.95.0 pin, cross-ref
PR #367, name the clippy lints that came with 1.95, and keep the
"never auto-track stable" rule.
…ked calls

Same ephemeral-nightly discipline as ndarray/scripts/miri-tests.sh:
default toolchain stays stable 1.95.0; `cargo +nightly miri` is the
only nightly invocation, scoped to this one script.

Scope: lance-graph-contract (zero-dep), lance-graph-rbac, neural-debug,
and lance-graph-ontology without the lance-cache feature. FFI-heavy
crates (lance, datafusion, arrow, BLAS) cannot run under Miri.

Bypasses for things Miri's default sandbox blocks (none of which
indicate UB — all are Miri sandboxing artifacts):

* `registry::now_micros` + `lance_cache::chrono_micros`: cfg(miri)
  returns 0. Miri blocks `clock_gettime(REALTIME)`; timestamps are
  meaningless inside the sandbox anyway. Production builds and
  stable CI run the real `SystemTime::now()` path.

* `literal_graph::tests::test_real_aiwar_graph`: cfg_attr(miri, ignore).
  Reads `/root/data/aiwar_graph.json` — Miri's isolation blocks
  `std::fs::*`.

* `manifest_codegen::test_idempotency`: cfg_attr(miri, ignore). Reads
  the on-disk canonical manifests + codegen output. The other 7 tests
  in the file use in-memory YAML strings and run clean.

* `bridge_scope_lock.rs` + `round_trip_ttl.rs` + `hydrate_real_ogit.rs`:
  `#![cfg(not(miri))]` at file head. Every test in these three files
  uses `tempfile::tempdir()` + `std::fs::*` to stage TTL fixtures.
  Stable / nightly without Miri runs them normally.

* `dcterms_source_attribute_test::dcterms_source_attribute_pairs_surface_for_customer`:
  cfg_attr(miri, ignore). Reads /home/user/OGIT.

* MIRIFLAGS=-Zmiri-ignore-leaks in the script: lance-graph-ontology
  test helpers do `Box::leak(name.into_boxed_str())` to fabricate
  `&'static str` for `Schema::builder` (which intentionally takes
  `&'static str`). 11 leaks across the registry test suite, all
  test-helper-only — production code does not use Box::leak.

Verification (clippy-first then targeted miri runs):
  lance-graph-contract: 401 passed / 0 failed / 4 ignored (~240s)
  lance-graph-rbac:      14 passed / 0 failed (~1.6s)
  neural-debug:          10 passed / 0 failed (~321s)
  lance-graph-ontology (--no-default-features):
                         34 passed / 0 failed / 1 ignored (~46s + setup)

Total: 459 tests Miri-clean across 4 crates. The miri job in
.github/workflows/ci.yaml (if added) can promote to required for
these crates.

The architectural finding for ndarray side — `crate::simd::*` directly
re-exports intrinsics-based types; the polyfill at `crate::simd_nightly`
covers 5/30 types and is not wired into `crate::simd::*` under cfg(miri)
— is documented in ndarray's miri-tests.sh and is the next miri-coverage
follow-up there.
@AdaWorldAPI AdaWorldAPI merged commit 6def95e into main May 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants