From 392d9039d891f03617516b8893624d229a5397d4 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Mon, 15 Jun 2026 09:40:46 -0700 Subject: [PATCH] fix: 'check' returns combined output (was silent on success) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check composite returned ActionResult with no output on success, so the dashboard's 'Check All' (and the CLI) showed nothing when checks passed — only a failing sub-verb ever produced output. It now accumulates each sub-verb's output with a ✓/✗ marker (lint / type-check / test), on both success and failure, so the output panel always shows what ran. Also fixes lan-info's type-check: socket.getaddrinfo sockaddr is loosely typed, so str(infos[0][4][0]) makes the address an unambiguous str. core 94 green; ruff clean; verified POST /programs/lan-info/check returns output. --- core/src/castle_core/stacks.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/castle_core/stacks.py b/core/src/castle_core/stacks.py index 3ee7c12..3ae5e9f 100644 --- a/core/src/castle_core/stacks.py +++ b/core/src/castle_core/stacks.py @@ -338,14 +338,20 @@ async def run_action(verb: str, name: str, comp: ProgramSpec, root: Path) -> Act program=name, action="check", status="error", output="No checkable verbs available.", ) + sections: list[str] = [] for sub in subs: result = await run_action(sub, name, comp, root) + mark = "✓" if result.status == "ok" else "✗" + body = result.output.strip() + sections.append(f"{mark} {sub}" + (f"\n{body}" if body else "")) if result.status != "ok": return ActionResult( program=name, action="check", status="error", - output=f"{sub} failed:\n{result.output}", + output="\n\n".join(sections), ) - return ActionResult(program=name, action="check", status="ok") + return ActionResult( + program=name, action="check", status="ok", output="\n\n".join(sections) + ) # 1. Declared command overrides the stack default. declared = _declared_commands(comp, verb)