From 7ef59d3d5eceecdfc73d8888354d8b2d6c4ccbb7 Mon Sep 17 00:00:00 2001 From: techysneha14 <343708768+shehatathe@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:05:43 +0200 Subject: [PATCH 1/2] ci(loom): select only the loom_model modules in the nightly loom job The krishiv-io loom step filtered on the substring `runtime_filter`, which also selected the ordinary test `parquet::late_tests::runtime_filter_keys_filter_while_decoding`. Under `--cfg loom` that test builds a `RuntimeFilter`, whose atomics are loom's, outside `loom::model`, and loom panics ("cannot access Loom execution state from outside a Loom model"). The model itself passes; nothing in the engine is unsynchronised. Every loom step now filters on `loom_model::`, and the krishiv-memory and krishiv-exec model modules are renamed from `loom_tests` to `loom_model` so one convention covers all three crates. A policy test checks that each loom step selects only `loom_model`, that every crate building a `loom::model` has a step, and that models live in a `loom_model` module. Signed-off-by: techysneha14 <343708768+shehatathe@users.noreply.github.com> --- .github/workflows/nightly.yml | 13 ++- crates/krishiv-exec/CLAUDE.md | 4 +- crates/krishiv-exec/src/join/grace.rs | 4 +- crates/krishiv-exec/src/lib.rs | 2 +- .../src/{loom_tests.rs => loom_model.rs} | 2 +- crates/krishiv-exec/src/sync.rs | 2 +- crates/krishiv-io/src/runtime_filter/tests.rs | 2 +- crates/krishiv-memory/CLAUDE.md | 4 +- crates/krishiv-memory/src/lib.rs | 2 +- .../src/{loom_tests.rs => loom_model.rs} | 2 +- crates/krishiv-memory/src/sync.rs | 2 +- xtask/tests/policy.rs | 92 +++++++++++++++++++ 12 files changed, 113 insertions(+), 18 deletions(-) rename crates/krishiv-exec/src/{loom_tests.rs => loom_model.rs} (99%) rename crates/krishiv-memory/src/{loom_tests.rs => loom_model.rs} (99%) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3a3424cd..0dcb3187 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -161,9 +161,9 @@ jobs: fail_ci_if_error: false # P2-T010: loom models of the memory pool accounting, spill protocol, round - # admission and arbitration (`crates/krishiv-memory/src/loom_tests.rs`); + # admission and arbitration (`crates/krishiv-memory/src/loom_model.rs`); # P2-T050: the executor's morsel cursor, finalize countdown, cancellation - # and result channel (`crates/krishiv-exec/src/loom_tests.rs`). + # and result channel (`crates/krishiv-exec/src/loom_model.rs`). # P2-T163: runtime filter snapshot publication # (`crates/krishiv-io/src/runtime_filter/tests.rs`). # P2-T103: every wheel target, built and tested (wheels.yml). @@ -180,6 +180,9 @@ jobs: env: RUSTC_WRAPPER: "" # `--cfg loom` rebuilds every dependency; not worth caching RUSTFLAGS: --cfg loom + # Each step selects only the `loom_model` modules: a loom primitive used + # outside `loom::model` panics, so ordinary tests must never be selected + # (xtask policy test `loom_steps_select_only_loom_models`). steps: - name: Harden the runner (audit egress) uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 @@ -191,11 +194,11 @@ jobs: - name: Toolchain (from rust-toolchain.toml) run: rustup show active-toolchain - name: loom models (krishiv-memory) - run: cargo test -p krishiv-memory --lib --release --locked + run: cargo test -p krishiv-memory --lib --release --locked loom_model:: - name: loom models (krishiv-exec) - run: cargo test -p krishiv-exec --lib --release --locked + run: cargo test -p krishiv-exec --lib --release --locked loom_model:: - name: loom models (krishiv-io runtime filters) - run: cargo test -p krishiv-io --lib --release --locked runtime_filter + run: cargo test -p krishiv-io --lib --release --locked loom_model:: # cargo-fuzz targets (`fuzz/`), one hour each: the reusable `fuzz.yml` # (regression replay, cached corpus, crash triage). The weekly long run is diff --git a/crates/krishiv-exec/CLAUDE.md b/crates/krishiv-exec/CLAUDE.md index 0845c010..fd311840 100644 --- a/crates/krishiv-exec/CLAUDE.md +++ b/crates/krishiv-exec/CLAUDE.md @@ -11,7 +11,7 @@ Batch execution engine: operators, pipelines, morsel scheduling within a node. driver (yields, batch-boundary checks, NeedMemory, spill servicing, stall detector) · `runner.rs` QueryRunner / Scheduler (coordinator, first error wins) · `channel.rs` bounded result stream · `executor.rs` Executor seam + TokioExecutor · `context.rs` QueryContext/TaskContext/MemoryHandle · `morsel.rs` cursor + finalize countdown · -`testing.rs` test operators (also used by benches) · `loom_tests.rs`. +`testing.rs` test operators (also used by benches) · `loom_model.rs`. `operators/` (P2-T051) stateless operators: `scan.rs` MemoryScan + `ScanPushdown` (pushdowns decided once as an immutable `ScanPushdowns`; implemented by scan factories: MemoryScan, FileScan) · `filter.rs` · `project.rs` · `limit.rs` · `union.rs` (per-branch `UnionAlign`; UNION ALL fan-in is T074, distinct UNION is the aggregate's) · @@ -62,5 +62,5 @@ only where a requirement is unmet; on one worker instantiation lowers each excha ## Test `cargo nextest run -p krishiv-exec --no-tests=pass` · `cargo clippy -p krishiv-exec --all-targets -- -D warnings` · -loom models: `RUSTFLAGS="--cfg loom" cargo test -p krishiv-exec --lib --release` (use a separate target dir) · +loom models: `RUSTFLAGS="--cfg loom" cargo test -p krishiv-exec --lib --release loom_model::` (use a separate target dir) · benches: `cargo bench -p krishiv-exec --bench pipeline` · `--bench operators` diff --git a/crates/krishiv-exec/src/join/grace.rs b/crates/krishiv-exec/src/join/grace.rs index e923d00f..31eb5891 100644 --- a/crates/krishiv-exec/src/join/grace.rs +++ b/crates/krishiv-exec/src/join/grace.rs @@ -1343,9 +1343,9 @@ fn scatter( /// Loom models of the grace phase's claims and waits (no I/O: tasks with /// no rows). `RUSTFLAGS="--cfg loom" cargo test -p krishiv-exec --lib -/// --release`. +/// --release loom_model::`. #[cfg(all(test, loom))] -mod loom_tests { +mod loom_model { use loom::future::block_on; use loom::thread; diff --git a/crates/krishiv-exec/src/lib.rs b/crates/krishiv-exec/src/lib.rs index 4f2c3719..1b49831d 100644 --- a/crates/krishiv-exec/src/lib.rs +++ b/crates/krishiv-exec/src/lib.rs @@ -126,4 +126,4 @@ pub use runner::{QueryRunner, Scheduler}; mod tests; #[cfg(all(test, loom))] -mod loom_tests; +mod loom_model; diff --git a/crates/krishiv-exec/src/loom_tests.rs b/crates/krishiv-exec/src/loom_model.rs similarity index 99% rename from crates/krishiv-exec/src/loom_tests.rs rename to crates/krishiv-exec/src/loom_model.rs index 4e8c047a..a593579f 100644 --- a/crates/krishiv-exec/src/loom_tests.rs +++ b/crates/krishiv-exec/src/loom_model.rs @@ -6,7 +6,7 @@ //! protocol model was checked to fail with a planted bug (Relaxed //! countdown; check-before-listen in the wait loop, in `blocking_done` and //! in `Barrier::wait`; `drop_receiver` not waking senders). -//! `RUSTFLAGS="--cfg loom" cargo test -p krishiv-exec --lib --release`. +//! `RUSTFLAGS="--cfg loom" cargo test -p krishiv-exec --lib --release loom_model::`. use std::sync::Arc; diff --git a/crates/krishiv-exec/src/sync.rs b/crates/krishiv-exec/src/sync.rs index d633358b..b08eabf5 100644 --- a/crates/krishiv-exec/src/sync.rs +++ b/crates/krishiv-exec/src/sync.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 //! Synchronisation primitives, swapped for loom's under `--cfg loom` so the -//! models in `loom_tests.rs` explore every interleaving of the morsel +//! models in `loom_model.rs` explore every interleaving of the morsel //! cursor, the finalize countdown, cancellation and the result channel. //! //! [`Event`] is a broadcast wake-up with no lost notifications: a listener diff --git a/crates/krishiv-io/src/runtime_filter/tests.rs b/crates/krishiv-io/src/runtime_filter/tests.rs index cf03fe21..528a5883 100644 --- a/crates/krishiv-io/src/runtime_filter/tests.rs +++ b/crates/krishiv-io/src/runtime_filter/tests.rs @@ -648,7 +648,7 @@ mod unit { /// The publication protocol under loom: a reader that sees a generation /// finds that generation's snapshot (never an older one), and a consumer's /// cache never pairs a generation with another snapshot. -/// `RUSTFLAGS="--cfg loom" cargo test -p krishiv-io --lib --release runtime_filter`. +/// `RUSTFLAGS="--cfg loom" cargo test -p krishiv-io --lib --release loom_model::`. #[cfg(loom)] mod loom_model { use std::sync::Arc; diff --git a/crates/krishiv-memory/CLAUDE.md b/crates/krishiv-memory/CLAUDE.md index 8bae2983..12274aed 100644 --- a/crates/krishiv-memory/CLAUDE.md +++ b/crates/krishiv-memory/CLAUDE.md @@ -9,7 +9,7 @@ Memory management: pools, reservations, the memory arbitrator and spill accounti ## Invariants - Every operator allocation is accounted through reservations; pools are empty at query end (tested). - Arbitration and OOM paths return typed errors or trigger spill; never panic. -- Concurrency primitives tested with loom (`src/loom_tests.rs`; `src/sync.rs` swaps in loom's types). +- Concurrency primitives tested with loom (`src/loom_model.rs`; `src/sync.rs` swaps in loom's types). - Arbitration is cooperative: never call into, lock or mutate another task's operator state; no sync lock across an await. - `unsafe` allowed; every block has a `// SAFETY:` comment; runs under Miri in CI and nightly ASan/TSan (ADR 0029). - Spill files (`spillfile`): a finished `.spill` is complete (temp file + rename; no fsync by design: scratch data, deleted at the @@ -23,4 +23,4 @@ Memory management: pools, reservations, the memory arbitrator and spill accounti ## Test `cargo nextest run -p krishiv-memory --no-tests=pass` · `cargo clippy -p krishiv-memory --all-targets -- -D warnings` · -loom models: `RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release` (use a separate target dir) +loom models: `RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release loom_model::` (use a separate target dir) diff --git a/crates/krishiv-memory/src/lib.rs b/crates/krishiv-memory/src/lib.rs index 1efb6ed7..53be1fa6 100644 --- a/crates/krishiv-memory/src/lib.rs +++ b/crates/krishiv-memory/src/lib.rs @@ -208,4 +208,4 @@ pub trait MemoryPool: Send + Sync + std::fmt::Debug { mod tests; #[cfg(all(test, loom))] -mod loom_tests; +mod loom_model; diff --git a/crates/krishiv-memory/src/loom_tests.rs b/crates/krishiv-memory/src/loom_model.rs similarity index 99% rename from crates/krishiv-memory/src/loom_tests.rs rename to crates/krishiv-memory/src/loom_model.rs index af94f80e..f89a697a 100644 --- a/crates/krishiv-memory/src/loom_tests.rs +++ b/crates/krishiv-memory/src/loom_model.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 //! Loom models of reserve/release accounting and the cooperative spill //! protocol (request, ack, give-up). Bounded for CI: -//! `RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release`. +//! `RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release loom_model::`. use std::sync::Arc; use std::time::Duration; diff --git a/crates/krishiv-memory/src/sync.rs b/crates/krishiv-memory/src/sync.rs index 627539ca..f5182472 100644 --- a/crates/krishiv-memory/src/sync.rs +++ b/crates/krishiv-memory/src/sync.rs @@ -2,7 +2,7 @@ //! Synchronisation primitives, swapped for loom's under `--cfg loom`, so //! the model tests explore every interleaving of the accounting, wake-up //! and arbitration code (the models inject a clock that never fires) -//! (`RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release`). +//! (`RUSTFLAGS="--cfg loom" cargo test -p krishiv-memory --lib --release loom_model::`). #[cfg(all(test, loom))] pub(crate) use loom::sync::{ diff --git a/xtask/tests/policy.rs b/xtask/tests/policy.rs index 240cf3a1..c13e6dc7 100644 --- a/xtask/tests/policy.rs +++ b/xtask/tests/policy.rs @@ -660,3 +660,95 @@ fn release_publishing_is_manual_and_gated() { "quickstart-test.sh must run Python with TMPDIR=\"$work\"" ); } + +/// The `cargo test` commands of a loom job that do not select exactly the +/// `loom_model` modules (`--lib`, filter `loom_model::`). +fn loom_steps_off_the_models(loom_job: &str) -> Vec { + loom_job + .lines() + .map(|l| l.trim().trim_start_matches("- ")) + .filter_map(|l| l.strip_prefix("run: ")) + .filter(|cmd| cmd.starts_with("cargo test")) + .filter(|cmd| { + let words: Vec<&str> = cmd.split_whitespace().collect(); + !(words.contains(&"--lib") && words.last() == Some(&"loom_model::")) + }) + .map(str::to_owned) + .collect() +} + +/// The crates whose sources build a `loom::model`, each checked to keep its +/// models in a module named `loom_model`. +fn crates_with_loom_models() -> Vec { + fn walk(dir: &Path, files: &mut Vec) { + for entry in std::fs::read_dir(dir).unwrap() { + let path = entry.unwrap().path(); + if path.is_dir() { + walk(&path, files); + } else if path.extension().is_some_and(|e| e == "rs") { + files.push(path); + } + } + } + let mut crates = Vec::new(); + for entry in std::fs::read_dir(root().join("crates")).unwrap() { + let krate = entry.unwrap().path(); + let src = krate.join("src"); + if !src.is_dir() { + continue; + } + let mut files = Vec::new(); + walk(&src, &mut files); + for file in files { + let text = std::fs::read_to_string(&file).unwrap(); + if !text.contains("loom::model") { + continue; + } + assert!( + file.file_stem().is_some_and(|s| s == "loom_model") + || text.contains("mod loom_model {"), + "{} builds a loom model outside a `loom_model` module", + file.display() + ); + let name = krate.file_name().unwrap().to_string_lossy().into_owned(); + if !crates.contains(&name) { + crates.push(name); + } + } + } + crates.sort(); + crates +} + +/// A loom primitive used outside `loom::model` panics, so the nightly loom +/// steps select only the `loom_model` modules, and every crate with loom +/// models has a step. +#[test] +fn loom_steps_select_only_loom_models() { + let nightly = read(".github/workflows/nightly.yml"); + let loom = job(&nightly, "loom"); + assert_eq!(loom_steps_off_the_models(loom), Vec::::new()); + let crates = crates_with_loom_models(); + assert!(!crates.is_empty(), "no loom models found"); + for krate in crates { + let step = format!("run: cargo test -p {krate} --lib --release --locked loom_model::"); + assert!(loom.contains(&step), "the nightly loom job lacks {step:?}"); + } +} + +#[test] +fn loom_step_check_rejects_name_filters_and_whole_crates() { + let job = " steps:\n - run: rustup show\n \ + - run: cargo test -p a --lib --release --locked runtime_filter\n \ + - run: cargo test -p b --lib --release --locked\n \ + - run: cargo test -p c --release --locked loom_model::\n \ + - run: cargo test -p d --lib --release --locked loom_model::\n"; + assert_eq!( + loom_steps_off_the_models(job), + [ + "cargo test -p a --lib --release --locked runtime_filter", + "cargo test -p b --lib --release --locked", + "cargo test -p c --release --locked loom_model::", + ] + ); +} From c13117a8169934836b619bbe26f4dfb3bf7f632d Mon Sep 17 00:00:00 2001 From: techysneha14 <343708768+shehatathe@users.noreply.github.com> Date: Sat, 24 Oct 2026 06:13:03 +0200 Subject: [PATCH 2/2] ci(loom): quote the loom_model filters so nightly.yml parses Unquoted trailing '::' is not a valid YAML plain scalar and broke parsing of the loom job. Quote each loom run command and strip the quotes in the policy check before matching. Signed-off-by: techysneha14 <343708768+shehatathe@users.noreply.github.com> --- .github/workflows/nightly.yml | 6 +++--- xtask/tests/policy.rs | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0dcb3187..4f75b0d5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -194,11 +194,11 @@ jobs: - name: Toolchain (from rust-toolchain.toml) run: rustup show active-toolchain - name: loom models (krishiv-memory) - run: cargo test -p krishiv-memory --lib --release --locked loom_model:: + run: "cargo test -p krishiv-memory --lib --release --locked loom_model::" - name: loom models (krishiv-exec) - run: cargo test -p krishiv-exec --lib --release --locked loom_model:: + run: "cargo test -p krishiv-exec --lib --release --locked loom_model::" - name: loom models (krishiv-io runtime filters) - run: cargo test -p krishiv-io --lib --release --locked loom_model:: + run: "cargo test -p krishiv-io --lib --release --locked loom_model::" # cargo-fuzz targets (`fuzz/`), one hour each: the reusable `fuzz.yml` # (regression replay, cached corpus, crash triage). The weekly long run is diff --git a/xtask/tests/policy.rs b/xtask/tests/policy.rs index c13e6dc7..310e77fc 100644 --- a/xtask/tests/policy.rs +++ b/xtask/tests/policy.rs @@ -662,18 +662,28 @@ fn release_publishing_is_manual_and_gated() { } /// The `cargo test` commands of a loom job that do not select exactly the -/// `loom_model` modules (`--lib`, filter `loom_model::`). +/// `loom_model` modules (`--lib`, filter `loom_model::`). The `run:` value +/// is YAML-quoted (a trailing `::` is not a valid plain scalar), so +/// surrounding quotes are stripped before matching. fn loom_steps_off_the_models(loom_job: &str) -> Vec { loom_job .lines() .map(|l| l.trim().trim_start_matches("- ")) .filter_map(|l| l.strip_prefix("run: ")) + .map(|cmd| { + cmd.trim() + .trim_matches(|c| c == '"' || c == '\'') + .trim() + .to_owned() + }) .filter(|cmd| cmd.starts_with("cargo test")) .filter(|cmd| { let words: Vec<&str> = cmd.split_whitespace().collect(); - !(words.contains(&"--lib") && words.last() == Some(&"loom_model::")) + let last = words + .last() + .map(|w| w.trim_matches(|c| c == '"' || c == '\'')); + !(words.contains(&"--lib") && last == Some("loom_model::")) }) - .map(str::to_owned) .collect() } @@ -731,7 +741,7 @@ fn loom_steps_select_only_loom_models() { let crates = crates_with_loom_models(); assert!(!crates.is_empty(), "no loom models found"); for krate in crates { - let step = format!("run: cargo test -p {krate} --lib --release --locked loom_model::"); + let step = format!("run: \"cargo test -p {krate} --lib --release --locked loom_model::\""); assert!(loom.contains(&step), "the nightly loom job lacks {step:?}"); } } @@ -742,7 +752,10 @@ fn loom_step_check_rejects_name_filters_and_whole_crates() { - run: cargo test -p a --lib --release --locked runtime_filter\n \ - run: cargo test -p b --lib --release --locked\n \ - run: cargo test -p c --release --locked loom_model::\n \ - - run: cargo test -p d --lib --release --locked loom_model::\n"; + - run: cargo test -p d --lib --release --locked loom_model::\n \ + - run: \"cargo test -p e --lib --release --locked loom_model::\"\n \ + - run: 'cargo test -p f --lib --release --locked loom_model::'\n \ + - run: cargo test -p g --lib --release --locked \"loom_model::\"\n"; assert_eq!( loom_steps_off_the_models(job), [