diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a63f4e72..aac324cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,26 @@ on: pull_request: env: + # PINNED, not `stable`. On 2026-07-29 the runner moved to clippy 1.97, which + # added `question_mark`, and the lint gate went red with no commit behind it — + # a compiler release is not a change to this repository and must not be able + # to fail its CI. + # + # Pinning here rather than in a `rust-toolchain.toml`: the toolchain action + # exports RUSTUP_TOOLCHAIN, which takes precedence over that file, so the + # pin would be ignored in exactly the place it is needed. The file exists too, + # for local parity. + # + # To bump: raise this, run `cargo + clippy --workspace --all-targets -- + # -D warnings` and `cargo + fmt --all -- --check` locally first, and fix + # whatever the new release added in the same commit. + RUST_VERSION: "1.97.0" CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 - MSRV: "1.85" + # The version this project promises to build on, verified by the job below + # against the WHOLE workspace. Keep in step with `rust-version` in the root + # Cargo.toml, which is where consumers read it. + MSRV: "1.91" jobs: # MSRV (Minimum Supported Rust Version) check @@ -43,8 +60,11 @@ jobs: restore-keys: | ${{ runner.os }}-cargo-msrv- + # `-p aingle_minimal` before, which is the one member with no wasmer in + # its dependency tree — so it passed at 1.85 while the workspace could + # not build below 1.91. A promise nothing checks is not a promise. - name: Check MSRV - run: cargo check -p aingle_minimal + run: cargo check --workspace --all-targets # Format check fmt: @@ -54,8 +74,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ env.RUST_VERSION }} components: rustfmt - name: Check formatting @@ -69,8 +90,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ env.RUST_VERSION }} components: clippy - name: Install system dependencies @@ -118,7 +140,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | @@ -151,7 +175,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | @@ -183,7 +209,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | @@ -227,7 +255,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install cargo-audit run: cargo install cargo-audit @@ -245,8 +275,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ env.RUST_VERSION }} components: llvm-tools-preview - name: Install system dependencies @@ -288,7 +319,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | @@ -327,7 +360,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | @@ -356,7 +391,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3a83cbcb..63c391cc 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,6 +15,8 @@ concurrency: cancel-in-progress: true env: + # Pinned on purpose: see the note in ci.yml. + RUST_VERSION: "1.97.0" CARGO_TERM_COLOR: always jobs: @@ -25,7 +27,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c6c64d3c..bd5c0652 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,6 +15,8 @@ permissions: contents: write env: + # Pinned on purpose: see the note in ci.yml. + RUST_VERSION: "1.97.0" CARGO_TERM_COLOR: always jobs: @@ -50,8 +52,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ env.RUST_VERSION }} targets: ${{ matrix.target }} - name: Install system dependencies (Linux) @@ -163,7 +166,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install system dependencies run: | diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index bd585f82..8fb37bf7 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -17,6 +17,8 @@ on: workflow_dispatch: env: + # Pinned on purpose: see the note in ci.yml. + RUST_VERSION: "1.97.0" CARGO_TERM_COLOR: always jobs: @@ -28,7 +30,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install cargo-audit run: cargo install cargo-audit @@ -60,7 +64,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install cargo-deny run: cargo install cargo-deny @@ -109,7 +115,9 @@ jobs: - uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} - name: Install cargo-vet run: cargo install cargo-vet diff --git a/Cargo.toml b/Cargo.toml index 3c691e85..da696937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,17 @@ +[workspace.package] +# The MSRV, declared ONCE. It said 1.83 in twelve crates, 1.85 in the CI +# environment and 1.83 in CLAUDE.md, and the truth was none of those: the +# workspace needs 1.91, because `wasmer` (via aingle_contracts) requires it +# and `cranelift` under it requires 1.90. Verified by bisection — 1.85 and +# 1.90 both fail, 1.91 builds. Nothing had ever checked, because the MSRV job +# ran `cargo check -p aingle_minimal`: the one member with no wasmer in its +# tree. +# +# Uniform rather than per-crate on purpose: a lower number on a crate that +# has not been built at that version is the same unverified promise this is +# replacing. Refine per crate only with a run behind each figure. +rust-version = "1.91" + [workspace] resolver = "2" members = [ diff --git a/crates/aingle_ai/Cargo.toml b/crates/aingle_ai/Cargo.toml index 6f2e2d10..2dcf34df 100644 --- a/crates/aingle_ai/Cargo.toml +++ b/crates/aingle_ai/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "ai", "titans", "nested-learning", "memory"] categories = ["science", "algorithms"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [dependencies] # Serialization serde = { version = "1", features = ["derive"] } diff --git a/crates/aingle_ai/src/nested_learning/mod.rs b/crates/aingle_ai/src/nested_learning/mod.rs index 7021b764..352050df 100644 --- a/crates/aingle_ai/src/nested_learning/mod.rs +++ b/crates/aingle_ai/src/nested_learning/mod.rs @@ -93,7 +93,10 @@ impl NestedLearning { self.tx_count += 1; // 4. Check if optimizer-level update is needed - if self.tx_count % self.config.optimizer_update_interval == 0 { + if self + .tx_count + .is_multiple_of(self.config.optimizer_update_interval) + { debug!( tx_count = self.tx_count, "Triggering optimizer-level update" @@ -114,7 +117,10 @@ impl NestedLearning { self.block_count += 1; // Check if meta-level update is needed - if self.block_count % self.config.meta_update_interval == 0 { + if self + .block_count + .is_multiple_of(self.config.meta_update_interval) + { debug!( block_count = self.block_count, "Triggering meta-level update" diff --git a/crates/aingle_contracts/Cargo.toml b/crates/aingle_contracts/Cargo.toml index 605b2cd6..71f74d5b 100644 --- a/crates/aingle_contracts/Cargo.toml +++ b/crates/aingle_contracts/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "smart-contracts", "wasm", "dsl", "blockchain"] categories = ["wasm", "database"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["runtime"] runtime = ["dep:wasmer"] diff --git a/crates/aingle_cortex/Cargo.toml b/crates/aingle_cortex/Cargo.toml index a0529c0e..02f1a776 100644 --- a/crates/aingle_cortex/Cargo.toml +++ b/crates/aingle_cortex/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "api", "graphql", "sparql", "rest"] categories = ["web-programming", "database"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["rest", "sparql", "auth", "dag"] rest = [] diff --git a/crates/aingle_cortex/src/service/validate.rs b/crates/aingle_cortex/src/service/validate.rs index a98cfff7..bc76afbf 100644 --- a/crates/aingle_cortex/src/service/validate.rs +++ b/crates/aingle_cortex/src/service/validate.rs @@ -262,7 +262,7 @@ mod tests { let s = v .as_str() .unwrap_or_else(|| panic!("expected hex, got {v}")); - assert!(s.len() % 2 == 0, "hex must be byte-aligned: {s:?}"); + assert!(s.len().is_multiple_of(2), "hex must be byte-aligned: {s:?}"); (0..s.len() / 2) .map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).expect("hex digit")) .collect() diff --git a/crates/aingle_graph/Cargo.toml b/crates/aingle_graph/Cargo.toml index 453ea2aa..83b48b23 100644 --- a/crates/aingle_graph/Cargo.toml +++ b/crates/aingle_graph/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "graph", "rdf", "semantic", "triplestore"] categories = ["database", "data-structures"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["sled-backend"] # Storage backends diff --git a/crates/aingle_ingest/Cargo.toml b/crates/aingle_ingest/Cargo.toml index 21b1e49b..2617c120 100644 --- a/crates/aingle_ingest/Cargo.toml +++ b/crates/aingle_ingest/Cargo.toml @@ -4,8 +4,7 @@ version = "0.8.0" description = "Structural extraction of triples and text chunks from markdown/code for AIngle" license = "Apache-2.0 OR LicenseRef-Commercial" edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [dependencies] aingle_graph = { version = "0.8", path = "../aingle_graph", features = ["dag"] } serde = { version = "1.0", features = ["derive"] } diff --git a/crates/aingle_logic/Cargo.toml b/crates/aingle_logic/Cargo.toml index d2d6a683..ce81182b 100644 --- a/crates/aingle_logic/Cargo.toml +++ b/crates/aingle_logic/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "logic", "reasoning", "validation", "rules"] categories = ["algorithms", "data-structures"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = [] # Enable SPARQL-like query rules diff --git a/crates/aingle_minimal/Cargo.toml b/crates/aingle_minimal/Cargo.toml index d59a0cb3..41f5d6f4 100644 --- a/crates/aingle_minimal/Cargo.toml +++ b/crates/aingle_minimal/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "iot", "dag", "embedded"] categories = ["embedded", "network-programming"] edition = "2021" -rust-version = "1.85" - +rust-version.workspace = true [features] default = ["std", "coap", "sqlite"] std = [] diff --git a/crates/aingle_minimal/src/node.rs b/crates/aingle_minimal/src/node.rs index 3bef02a1..3f89b76f 100644 --- a/crates/aingle_minimal/src/node.rs +++ b/crates/aingle_minimal/src/node.rs @@ -569,7 +569,7 @@ impl MinimalNode { while self.running.load(Ordering::SeqCst) { // Sync discovered peers periodically (every 100 iterations = ~1 second) discovery_sync_counter = discovery_sync_counter.wrapping_add(1); - if discovery_sync_counter % 100 == 0 { + if discovery_sync_counter.is_multiple_of(100) { self.network.sync_discovered_peers(); } diff --git a/crates/aingle_minimal/src/ota.rs b/crates/aingle_minimal/src/ota.rs index 01ac4c7b..af76b91e 100644 --- a/crates/aingle_minimal/src/ota.rs +++ b/crates/aingle_minimal/src/ota.rs @@ -558,7 +558,7 @@ mod hex { } pub fn decode(s: &str) -> Result, String> { - if s.len() % 2 != 0 { + if !s.len().is_multiple_of(2) { return Err("Invalid hex string length".to_string()); } diff --git a/crates/aingle_minimal/src/types.rs b/crates/aingle_minimal/src/types.rs index 5de73a15..78750b06 100644 --- a/crates/aingle_minimal/src/types.rs +++ b/crates/aingle_minimal/src/types.rs @@ -732,7 +732,7 @@ mod hex { } pub fn decode(s: &str) -> Result, FromHexError> { - if s.len() % 2 != 0 { + if !s.len().is_multiple_of(2) { return Err(FromHexError::OddLength); } (0..s.len()) diff --git a/crates/aingle_raft/Cargo.toml b/crates/aingle_raft/Cargo.toml index c197fb3b..afd50472 100644 --- a/crates/aingle_raft/Cargo.toml +++ b/crates/aingle_raft/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "raft", "consensus", "clustering"] categories = ["database"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = [] dag = ["aingle_graph/dag"] diff --git a/crates/aingle_viz/Cargo.toml b/crates/aingle_viz/Cargo.toml index 45e4f806..6bf1c6cf 100644 --- a/crates/aingle_viz/Cargo.toml +++ b/crates/aingle_viz/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "visualization", "dag", "graph"] categories = ["visualization", "web-programming"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = [] diff --git a/crates/aingle_wal/Cargo.toml b/crates/aingle_wal/Cargo.toml index 85b53903..6ad89fa8 100644 --- a/crates/aingle_wal/Cargo.toml +++ b/crates/aingle_wal/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "wal", "replication", "clustering"] categories = ["database"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [dependencies] serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/crates/aingle_zk/Cargo.toml b/crates/aingle_zk/Cargo.toml index cdccfa20..918db1f2 100644 --- a/crates/aingle_zk/Cargo.toml +++ b/crates/aingle_zk/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "zkp", "zero-knowledge", "privacy", "cryptography"] categories = ["cryptography"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["std"] std = [] diff --git a/crates/aingle_zk/src/merkle.rs b/crates/aingle_zk/src/merkle.rs index f69eb957..ad22e6f3 100644 --- a/crates/aingle_zk/src/merkle.rs +++ b/crates/aingle_zk/src/merkle.rs @@ -136,7 +136,7 @@ impl MerkleTree { while level_size > 1 { // Sibling index - let sibling_index = if current_index % 2 == 0 { + let sibling_index = if current_index.is_multiple_of(2) { current_index + 1 } else { current_index - 1 diff --git a/crates/ineru/Cargo.toml b/crates/ineru/Cargo.toml index 850a50c4..cbfbffd4 100644 --- a/crates/ineru/Cargo.toml +++ b/crates/ineru/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "ai", "memory", "neural", "agents"] categories = ["science", "data-structures"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["std"] std = [] diff --git a/crates/ineru/benches/memory_bench.rs b/crates/ineru/benches/memory_bench.rs index 25157415..7c2d1a75 100644 --- a/crates/ineru/benches/memory_bench.rs +++ b/crates/ineru/benches/memory_bench.rs @@ -187,7 +187,7 @@ fn bench_iot_mode(c: &mut Criterion) { let recent = memory.recall_recent(5); // 3. Periodic maintenance (every 100 readings) - if counter % 100 == 0 { + if counter.is_multiple_of(100) { let _ = memory.decay(); } diff --git a/crates/kaneru/Cargo.toml b/crates/kaneru/Cargo.toml index 2bfb982f..25820958 100644 --- a/crates/kaneru/Cargo.toml +++ b/crates/kaneru/Cargo.toml @@ -10,8 +10,7 @@ authors = ["Apilium Technologies "] keywords = ["aingle", "ai", "agents", "rl", "iot"] categories = ["science", "network-programming"] edition = "2021" -rust-version = "1.83" - +rust-version.workspace = true [features] default = ["std"] std = [] diff --git a/crates/kaneru/src/kaneru_agent.rs b/crates/kaneru/src/kaneru_agent.rs index c948d3fb..d212174d 100644 --- a/crates/kaneru/src/kaneru_agent.rs +++ b/crates/kaneru/src/kaneru_agent.rs @@ -383,7 +383,7 @@ impl KaneruAgent { self.learning.add_experience(exp); // 5. Perform experience replay - if self.stats.total_steps % 10 == 0 { + if self.stats.total_steps.is_multiple_of(10) { self.learning.replay_batch(32, &self.available_actions); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..01d3e090 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,10 @@ +# Local parity with CI, which pins `RUST_VERSION` in .github/workflows/ci.yml — +# see the note there for why the pin lives in the workflow rather than only here. +# +# CI overrides this file (the toolchain action exports RUSTUP_TOOLCHAIN), so the +# two must be bumped together or a developer will verify against a version the +# runner does not use. That is how a lint gate goes red on a machine that +# reported it green. +[toolchain] +channel = "1.97.0" +components = ["clippy", "rustfmt"]