[PATCH 09/26] lucid: show failed loop items on screen

Daniel Gomez <[email protected]> Tue, 19 May 2026 15:28:06 +0200
Newsgroups dev.linux.lists.kdevops
Message-ID <[email protected]>
From: Daniel Gomez <[email protected]>

The previous change recorded per-item loop failures to the log file
but the screen only showed the aggregate task-level failure line,
which forced the user to open the log just to discover which iteration
broke. That defeats the purpose of collecting the per-item context in
the first place when the user is watching a live run.

Add a _display_failed_items helper that renders the command, stderr,
stdout, and msg recorded for each failed item with appropriate colors,
and invoke it from both the static path in _handle_result and the
dynamic freeze path in _freeze_and_show_output just before the
aggregate result is shown. The helper clears self.failed_items after
rendering so retries of the same task do not replay stale items, and
the output appears directly after the task header so the failing
iteration is the first thing the user sees at failure time.

Generated-by: Claude AI
Signed-off-by: Daniel Gomez <[email protected]>
---
 callback_plugins/lucid.py | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/callback_plugins/lucid.py b/callback_plugins/lucid.py
index e1d14e62..6bd822a3 100644
--- a/callback_plugins/lucid.py
+++ b/callback_plugins/lucid.py
@@ -637,6 +637,9 @@ class CallbackModule(CallbackBase):
             if status in ("failed", "unreachable") and not ignore_errors:
                 self._freeze_and_show_output(result_data)
         else:
+            # Show per-item failures before the aggregate result
+            if self.failed_items and status == "failed":
+                self._display_failed_items()
             # Static mode - display immediately
             self._display_result_static(result, status, duration)
 
@@ -915,6 +918,20 @@ class CallbackModule(CallbackBase):
             sys.stdout.flush()
             self.display_lines = 0
 
+    def _display_failed_items(self):
+        """Display collected per-item failures and clear the list"""
+        for fi in self.failed_items:
+            label = fi["item"]
+            if fi["cmd"]:
+                self._display.display(f"  [{label}] $ {fi['cmd']}", color=C.COLOR_VERBOSE)
+            if fi["stderr"]:
+                self._display.display(f"  [{label}] stderr: {fi['stderr']}", color=C.COLOR_ERROR)
+            if fi["stdout"]:
+                self._display.display(f"  [{label}] stdout: {fi['stdout']}")
+            if fi["msg"] and not fi["stdout"]:
+                self._display.display(f"  [{label}] msg: {fi['msg']}", color=C.COLOR_ERROR)
+        self.failed_items = []
+
     def _freeze_and_show_output(self, result_data):
         """
         Freeze display and show task output in dynamic mode for failures.
@@ -933,6 +950,10 @@ class CallbackModule(CallbackBase):
         msg = f"TASK: {self.current_task_name}"
         self._display_message(msg, C.COLOR_HIGHLIGHT)
 
+        # Show per-item failures before the aggregate result
+        if self.failed_items:
+            self._display_failed_items()
+
         # Show result with output
         self._display_result_static(result, status, duration)
 

-- 
2.53.0