From b4ec7edc60d436684b37dc63e51c18a150d58753 Mon Sep 17 00:00:00 2001 From: DocTator Date: Tue, 19 May 2026 07:03:46 -0400 Subject: [PATCH 1/5] ci: install protoc so clippy and test can build lance-encoding `lance-encoding`'s build.rs invokes `protoc` to generate prost bindings. Without it `cargo clippy` and `cargo test` fail at compile time with "Could not find `protoc`. If `protoc` is installed, try setting the `PROTOC` environment variable..." This was masked previously because CI bailed at the `cargo fmt --check` step (229 sites of fmt drift across upstream main). After the fmt cleanup in 508e9e6, PRs now reach the clippy step and surface this dep. Three currently-open PRs (#11 #12 #14) hit this on their last CI runs. Adding `apt-get install protobuf-compiler` before the rust toolchain step matches the standard pattern for Rust projects with prost-build deps (see lancedb, datafusion, deltalake CI configs). Co-Authored-By: Claude Opus 4.7 --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c09e2c..ce810aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install build deps + # lance-encoding's build.rs invokes protoc to generate prost + # bindings; without this, `cargo clippy` and `cargo test` fail + # with "Could not find `protoc`" once they get past the fmt step. + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends protobuf-compiler - uses: dtolnay/rust-toolchain@stable with: components: clippy, rustfmt From 07db99fcdd065f7546984bc7f0ae43280176bef2 Mon Sep 17 00:00:00 2001 From: DocTator Date: Tue, 19 May 2026 07:10:12 -0400 Subject: [PATCH 2/5] chore: cargo fmt drift in api/mod.rs and retrieve/pipeline.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same content as #11 — folding into this PR so a single merge fixes everything currently broken in CI. - 5 long `format!` chains in api/mod.rs from the percent-encoding fix in 3472c74 — now wrapped to per-line args - One `.iter().find().unwrap()` chain in pipeline.rs from the `test_rrf_normalize_weak_top_not_inflated` test added in #9 Pure fmt, no logic. Co-Authored-By: Claude Opus 4.7 --- omem-server/src/api/mod.rs | 25 ++++++++++++++++++++----- omem-server/src/retrieve/pipeline.rs | 5 ++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/omem-server/src/api/mod.rs b/omem-server/src/api/mod.rs index 1cb5d98..1b273b2 100644 --- a/omem-server/src/api/mod.rs +++ b/omem-server/src/api/mod.rs @@ -1327,7 +1327,10 @@ mod tests { .oneshot( Request::builder() .method("POST") - .uri(format!("/v1/spaces/{}/members", utf8_percent_encode(&space_id, NON_ALPHANUMERIC))) + .uri(format!( + "/v1/spaces/{}/members", + utf8_percent_encode(&space_id, NON_ALPHANUMERIC) + )) .header("content-type", "application/json") .header("x-api-key", &api_key) .body(Body::from(r#"{"user_id":"bob","role":"member"}"#)) @@ -1386,7 +1389,10 @@ mod tests { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/v1/spaces/{}/members/alice", utf8_percent_encode(&space_id, NON_ALPHANUMERIC))) + .uri(format!( + "/v1/spaces/{}/members/alice", + utf8_percent_encode(&space_id, NON_ALPHANUMERIC) + )) .header("x-api-key", &api_key) .body(Body::empty()) .expect("request"), @@ -1518,7 +1524,10 @@ mod tests { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/v1/spaces/{}", utf8_percent_encode(&space_id, NON_ALPHANUMERIC))) + .uri(format!( + "/v1/spaces/{}", + utf8_percent_encode(&space_id, NON_ALPHANUMERIC) + )) .header("x-api-key", &api_key) .body(Body::empty()) .expect("request"), @@ -1532,7 +1541,10 @@ mod tests { .clone() .oneshot( Request::builder() - .uri(format!("/v1/spaces/{}", utf8_percent_encode(&space_id, NON_ALPHANUMERIC))) + .uri(format!( + "/v1/spaces/{}", + utf8_percent_encode(&space_id, NON_ALPHANUMERIC) + )) .header("x-api-key", &api_key) .body(Body::empty()) .expect("request"), @@ -1578,7 +1590,10 @@ mod tests { .oneshot( Request::builder() .method("PUT") - .uri(format!("/v1/spaces/{}/members/carol", utf8_percent_encode(&space_id, NON_ALPHANUMERIC))) + .uri(format!( + "/v1/spaces/{}/members/carol", + utf8_percent_encode(&space_id, NON_ALPHANUMERIC) + )) .header("content-type", "application/json") .header("x-api-key", &api_key) .body(Body::from(r#"{"role":"admin"}"#)) diff --git a/omem-server/src/retrieve/pipeline.rs b/omem-server/src/retrieve/pipeline.rs index 137d0c2..26d336f 100644 --- a/omem-server/src/retrieve/pipeline.rs +++ b/omem-server/src/retrieve/pipeline.rs @@ -1184,7 +1184,10 @@ mod tests { ]; let (result, _) = RetrievalPipeline::stage_rrf_normalize(entries); - let top = result.iter().find(|e| e.memory.content == "weak-top").unwrap(); + let top = result + .iter() + .find(|e| e.memory.content == "weak-top") + .unwrap(); assert!( top.rrf_score < 0.25, "weak top result should stay below 0.25, got {}", From a2fe097b74d21d6b9be298a8583d4deb962b2808 Mon Sep 17 00:00:00 2001 From: DocTator Date: Tue, 19 May 2026 07:14:02 -0400 Subject: [PATCH 3/5] ci: also install libprotobuf-dev for well-known proto types `protobuf-compiler` only ships the `protoc` binary; the `google/protobuf/empty.proto` and friends that lance-encoding's .proto files import live in `libprotobuf-dev` under /usr/include/google/protobuf/. Without both, clippy gets past the missing-protoc stage and dies on "google/protobuf/empty.proto: File not found" instead. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce810aa..26e2d1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,14 @@ jobs: - uses: actions/checkout@v4 - name: Install build deps # lance-encoding's build.rs invokes protoc to generate prost - # bindings; without this, `cargo clippy` and `cargo test` fail - # with "Could not find `protoc`" once they get past the fmt step. + # bindings. `protobuf-compiler` provides the `protoc` binary; + # `libprotobuf-dev` provides the well-known types (e.g. + # google/protobuf/empty.proto) under /usr/include/google/protobuf/ + # that lance-encoding's .proto files import. Both are needed. run: | sudo apt-get update -qq - sudo apt-get install -y --no-install-recommends protobuf-compiler + sudo apt-get install -y --no-install-recommends \ + protobuf-compiler libprotobuf-dev - uses: dtolnay/rust-toolchain@stable with: components: clippy, rustfmt From e07c1f8ca12905c145be3ad2753a800fa5c0c3e6 Mon Sep 17 00:00:00 2001 From: DocTator Date: Tue, 19 May 2026 07:20:30 -0400 Subject: [PATCH 4/5] chore: fix 7 clippy lints (rust 1.95 stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CI workflow runs `cargo clippy -- -D warnings`. Rust 1.95 (installed by dtolnay/rust-toolchain@stable) added two new lint categories that hit upstream code: - 4× `useless_into_iter` on `stream::iter(x.into_iter())` — `stream::iter` accepts `IntoIterator` directly. (sharing.rs:516, 924, 1090, 1263) - 3× `unnecessary_sort_by` on `sort_by(|a, b| b.1.cmp(&a.1))` — `sort_by_key(|t| std::cmp::Reverse(t.1))` is the clippy-preferred form for "reverse-sort on a field." (stats.rs:307, 557, 761) Mechanical fixes only — no behavior change. `cargo clippy --lib -- -D warnings` is clean locally after. Other `sort_by` call sites with multi-field or date-based comparisons aren't flagged (clippy is precise about which closures are reducible to a key function). Co-Authored-By: Claude Opus 4.7 --- omem-server/src/api/handlers/sharing.rs | 8 ++++---- omem-server/src/api/handlers/stats.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/omem-server/src/api/handlers/sharing.rs b/omem-server/src/api/handlers/sharing.rs index cbb7c79..8fcd164 100644 --- a/omem-server/src/api/handlers/sharing.rs +++ b/omem-server/src/api/handlers/sharing.rs @@ -513,7 +513,7 @@ pub async fn batch_share( use futures::stream::{self, StreamExt}; let results: Vec<(String, Result)> = - stream::iter(body.memory_ids.into_iter()) + stream::iter(body.memory_ids) .map(|mem_id| { let source_store = source_store.clone(); let target_store = target_store.clone(); @@ -921,7 +921,7 @@ pub async fn share_all( use futures::stream::{self, StreamExt}; - let results: Vec<(bool, bool)> = stream::iter(filtered_ids.into_iter()) + let results: Vec<(bool, bool)> = stream::iter(filtered_ids) .map(|mem_id| { let source_store = source_store.clone(); let target_store = target_store.clone(); @@ -1087,7 +1087,7 @@ pub async fn share_all_to_user( use futures::stream::{self, StreamExt}; - let results: Vec<(bool, bool)> = stream::iter(filtered_ids.into_iter()) + let results: Vec<(bool, bool)> = stream::iter(filtered_ids) .map(|mem_id| { let source_store = source_store.clone(); let target_store = target_store.clone(); @@ -1260,7 +1260,7 @@ pub async fn org_publish( use futures::stream::{self, StreamExt}; - let results: Vec<(bool, bool)> = stream::iter(memory_ids.clone().into_iter()) + let results: Vec<(bool, bool)> = stream::iter(memory_ids.clone()) .map(|mem_id| { let source_store = source_store.clone(); let target_store = target_store.clone(); diff --git a/omem-server/src/api/handlers/stats.rs b/omem-server/src/api/handlers/stats.rs index a994341..89f57ce 100644 --- a/omem-server/src/api/handlers/stats.rs +++ b/omem-server/src/api/handlers/stats.rs @@ -304,7 +304,7 @@ pub async fn get_tags( .into_iter() .filter(|(_, c)| *c >= params.min_count) .collect(); - tags.sort_by(|a, b| b.1.cmp(&a.1)); + tags.sort_by_key(|t| std::cmp::Reverse(t.1)); let total_unique = tags.len(); tags.truncate(params.limit); @@ -554,7 +554,7 @@ pub async fn get_spaces_stats( } let mut top_categories: Vec<(String, usize)> = category_counts.into_iter().collect(); - top_categories.sort_by(|a, b| b.1.cmp(&a.1)); + top_categories.sort_by_key(|c| std::cmp::Reverse(c.1)); top_categories.truncate(3); space_stats.push(serde_json::json!({ @@ -758,7 +758,7 @@ pub async fn get_agents_stats( } let mut top_categories: Vec<(String, usize)> = category_counts.into_iter().collect(); - top_categories.sort_by(|a, b| b.1.cmp(&a.1)); + top_categories.sort_by_key(|c| std::cmp::Reverse(c.1)); top_categories.truncate(3); let share_count = agent_share_counts.get(agent_id).copied().unwrap_or(0); From eaf46780f86b814e8683c6b09aba80008abe672c Mon Sep 17 00:00:00 2001 From: DocTator Date: Tue, 19 May 2026 07:22:22 -0400 Subject: [PATCH 5/5] chore: rustfmt the shortened stream::iter() lines Removing `.into_iter()` made the call expressions shorter, so rustfmt wants the surrounding multi-line blocks in sharing.rs re-wrapped to a tighter form. Pure fmt, no logic. Co-Authored-By: Claude Opus 4.7 --- omem-server/src/api/handlers/sharing.rs | 51 ++++++++++++------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/omem-server/src/api/handlers/sharing.rs b/omem-server/src/api/handlers/sharing.rs index 8fcd164..faa5225 100644 --- a/omem-server/src/api/handlers/sharing.rs +++ b/omem-server/src/api/handlers/sharing.rs @@ -512,32 +512,31 @@ pub async fn batch_share( use futures::stream::{self, StreamExt}; - let results: Vec<(String, Result)> = - stream::iter(body.memory_ids) - .map(|mem_id| { - let source_store = source_store.clone(); - let target_store = target_store.clone(); - let space_store = state.space_store.clone(); - let target_space_id = target_space.id.clone(); - let user_id = auth.tenant_id.clone(); - let agent_id = agent_id.clone(); - async move { - let result = share_single( - &source_store, - &target_store, - &space_store, - &mem_id, - &target_space_id, - &user_id, - &agent_id, - ) - .await; - (mem_id, result) - } - }) - .buffer_unordered(10) - .collect() - .await; + let results: Vec<(String, Result)> = stream::iter(body.memory_ids) + .map(|mem_id| { + let source_store = source_store.clone(); + let target_store = target_store.clone(); + let space_store = state.space_store.clone(); + let target_space_id = target_space.id.clone(); + let user_id = auth.tenant_id.clone(); + let agent_id = agent_id.clone(); + async move { + let result = share_single( + &source_store, + &target_store, + &space_store, + &mem_id, + &target_space_id, + &user_id, + &agent_id, + ) + .await; + (mem_id, result) + } + }) + .buffer_unordered(10) + .collect() + .await; let mut succeeded = Vec::new(); let mut failed = Vec::new();