From 3dd2b75e2b38d268de229422eaf6be34d749bc51 Mon Sep 17 00:00:00 2001 From: jedarden Date: Thu, 9 Jul 2026 09:01:26 -0400 Subject: [PATCH] feat(miroir-core): add reshard executor source document-count helper (bf-14wgq) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `compute_source_document_count` on `ReshardExecutor` — the reshard backfill denominator (bf-2ynu5, AC #1). It delegates to the shared `crate::index_stats::aggregate_index_stats`, reusing the executor's existing `http_client` field as the reqwest transport, and returns `total_documents` (reduced via `max` across source-node replicas). Pure additive: no change to `start_backfill`, `advance_backfill`, or persisted `ReshardOperation`. Wiring into `start_backfill` is a sibling bead. `cargo build -p miroir-core` green. Co-Authored-By: Claude --- crates/miroir-core/src/reshard/executor.rs | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/miroir-core/src/reshard/executor.rs b/crates/miroir-core/src/reshard/executor.rs index b615197..3199c21 100644 --- a/crates/miroir-core/src/reshard/executor.rs +++ b/crates/miroir-core/src/reshard/executor.rs @@ -529,6 +529,36 @@ impl ReshardExecutor { Ok(()) } + /// Aggregate the source index's real document count across all source nodes. + /// + /// This is the reshard backfill denominator described in plan §13.1 step 3 + /// (bf-2ynu5). It delegates to the shared [`crate::index_stats`] module so + /// that reshard and ILM rollover (plan §13.17) compute an index's document + /// count the *same* way: iterate the source `node_addresses`, + /// `GET /indexes/{uid}/stats`, and reduce `numberOfDocuments` with `max` + /// (each address hosts a full replica, so `sum` would over-count by the + /// replication factor). + /// + /// The aggregation is infallible from the caller's perspective — a node that + /// fails to respond (network / non-2xx / parse error) is logged and skipped, + /// and the count is `0` only if every node fails or reports zero — but this + /// returns [`Result`] to match the executor's method conventions and leave + /// the `start_backfill` caller (wired in a sibling bead) free to propagate a + /// future failure mode. + /// + /// Pure additive helper: this method is *not* called from the reshard state + /// machine in this bead. + pub async fn compute_source_document_count(&self, index_uid: &str) -> Result { + let stats = crate::index_stats::aggregate_index_stats( + &self.http_client, + &self.node_addresses, + &self.master_key, + index_uid, + ) + .await; + Ok(stats.total_documents) + } + /// Check if backfill is complete. async fn is_backfill_complete(&self, state: &ReshardState) -> Result { Ok(state