From cba5e829fcfb4b834819c31486fb6f4433d90d26 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Mon, 4 May 2026 20:17:43 -0500 Subject: [PATCH] diag(tui): trace view_stack push/pop for post-mortem black-screen repro Maintainer-reported (handoff): after spawning a sub-agent in YOLO, the transcript renders solid black and scroll keys go dead, but footer + sidebar still render fine. The shape (black + dead input together) strongly suggests a `View` is on the stack that returns empty layout AND intercepts key events at the top level. The fix wants a tighter repro than we have today. Add `tracing::debug!` to every push / push_boxed / pop on `ViewStack` and to the implicit pops in `apply_action` (Close + EmitAndClose). Each line carries the `ModalKind` and post-action depth, so a future `RUST_LOG=deepseek_tui::view_stack=debug` capture will show exactly which view stayed pushed when the symptom recurred. No behavior change. The handoff explicitly suggested this as the first-look diagnostic step; we ship the diagnostic now so the next report comes with evidence. Refs the unresolved sub-agent black-transcript symptom captured in session-3 handoff. Will surface to a tracking issue once we have a concrete repro from the maintainer. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/tui/src/tui/views/mod.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index 6ff4c67a..6e57fbf9 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -235,18 +235,26 @@ impl ViewStack { } pub fn push(&mut self, view: V) { + let kind = view.kind(); self.views.push(Box::new(view)); + tracing::debug!(target: "deepseek_tui::view_stack", action = "push", kind = ?kind, depth = self.views.len(), "view pushed"); } /// Push an already-boxed view back onto the stack. Used by call sites /// that pop a view, mutate it externally, and need to restore it without /// the generic `push` re-boxing dance. pub fn push_boxed(&mut self, view: Box) { + let kind = view.kind(); self.views.push(view); + tracing::debug!(target: "deepseek_tui::view_stack", action = "push_boxed", kind = ?kind, depth = self.views.len(), "view pushed"); } pub fn pop(&mut self) -> Option> { - self.views.pop() + let popped = self.views.pop(); + if let Some(view) = popped.as_ref() { + tracing::debug!(target: "deepseek_tui::view_stack", action = "pop", kind = ?view.kind(), depth = self.views.len(), "view popped"); + } + popped } pub fn render(&self, area: Rect, buf: &mut Buffer) { @@ -301,14 +309,18 @@ impl ViewStack { match action { ViewAction::None => {} ViewAction::Close => { - self.views.pop(); + if let Some(view) = self.views.pop() { + tracing::debug!(target: "deepseek_tui::view_stack", action = "close", kind = ?view.kind(), depth = self.views.len(), "view closed via action"); + } } ViewAction::Emit(event) => { events.push(event); } ViewAction::EmitAndClose(event) => { events.push(event); - self.views.pop(); + if let Some(view) = self.views.pop() { + tracing::debug!(target: "deepseek_tui::view_stack", action = "emit_and_close", kind = ?view.kind(), depth = self.views.len(), "view closed via action"); + } } } events