diff --git a/crates/kebab-cli/src/main.rs b/crates/kebab-cli/src/main.rs index 5f733ae..f649c86 100644 --- a/crates/kebab-cli/src/main.rs +++ b/crates/kebab-cli/src/main.rs @@ -306,6 +306,9 @@ fn run(cli: &Cli) -> anyhow::Result<()> { // Join the display thread *before* surfacing the ingest // outcome so the spinner / final newline is flushed // regardless of whether ingest returned Ok or Err. + // join() returns Result, Box>; + // we discard both — display thread errors / panics are + // best-effort and must not change ingest's exit code. let _ = display_handle.join(); let report = ingest_result?; diff --git a/crates/kebab-cli/src/progress.rs b/crates/kebab-cli/src/progress.rs index 77f110b..c73152e 100644 --- a/crates/kebab-cli/src/progress.rs +++ b/crates/kebab-cli/src/progress.rs @@ -87,6 +87,15 @@ impl ProgressDisplay { } } + /// Render an event in human mode. **Best-effort**: every + /// `writeln!` into stderr swallows IO errors (`let _ = ...`) + /// because the progress display must not fail the ingest run if + /// the terminal is closed mid-stream. Likewise the + /// `self.bar.as_ref()` / `as_mut()` branches treat a missing + /// bar as silent skip — the bar is initialized lazily in the + /// `ScanStarted` arm and §2.4a's ordering invariant + /// (`ScanStarted` < everything else) guarantees it is `Some` by + /// the time later events arrive. fn handle_human(&mut self, event: &IngestEvent, tty: bool) -> anyhow::Result<()> { match event { IngestEvent::ScanStarted { root } => {