From 810571932bce56a87bf6f095a27176d0554584aa Mon Sep 17 00:00:00 2001 From: Sephyi Date: Sun, 19 Apr 2026 18:42:06 +0200 Subject: [PATCH] fix(services): log JoinSet task panics in concurrent file fetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JoinSet loop in `fetch_file_contents` previously used `if let Ok(..)` to unpack the join result, silently discarding the `Err(JoinError)` variant emitted when a spawned git-show task panics or is cancelled. Panics under the async runtime were therefore invisible to operators even in `--verbose` / `COMMITBEE_LOG=debug` runs, making root-cause analysis of missing diff context nearly impossible. Switch to a full `match` arm and emit `tracing::warn!` with the JoinError context when a task fails to join. The returned HashMap shape is unchanged — panicked tasks are still omitted from the maps, matching the previous fallback behaviour — so no caller logic has to change. Closes audit entry F-008 from #3. --- src/services/git.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/services/git.rs b/src/services/git.rs index 5d3ee8a..896d033 100644 --- a/src/services/git.rs +++ b/src/services/git.rs @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use tokio::process::Command; +use tracing::warn; use crate::domain::{ChangeStatus, DiffStats, FileCategory, FileChange, StagedChanges}; use crate::error::{Error, Result}; @@ -247,12 +248,19 @@ impl GitService { let mut head_map = HashMap::new(); while let Some(result) = set.join_next().await { - if let Ok((path, staged, head)) = result { - if let Some(content) = staged { - staged_map.insert(path.clone(), content); + match result { + Ok((path, staged, head)) => { + if let Some(content) = staged { + staged_map.insert(path.clone(), content); + } + if let Some(content) = head { + head_map.insert(path, content); + } } - if let Some(content) = head { - head_map.insert(path, content); + Err(join_err) => { + // Task panicked or was cancelled — log and omit from results + // (callers handle missing entries as "content unavailable"). + warn!(error = %join_err, "git-show task failed to join"); } } }