From 81828e2ada1bb1ca9764dc201ab46e5437417296 Mon Sep 17 00:00:00 2001 From: Paul Gebheim <86010+pgebheim@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:26:18 +0000 Subject: [PATCH 1/2] fix(workflows): guard ctx.input arrays for 0.32 UI discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Smithers 0.32's gateway renders each workflow's at startup to discover its views, calling the component with an empty `ctx.input` (schema defaults are NOT applied during discovery). rig-sync and rig-loop both call an array method on an input field at module top — `ctx.input.units.filter(...)` and `ctx.input.built.join(...)` — so discovery throws `TypeError: undefined is not an object`, the UI fails to register, and the run's custom UI never renders in the monitor. Guard both with `?? []`, which restores exactly the schema's own `.default([])` during discovery and is a no-op at run time. Verified against a 0.32 gateway: the two "workflow UI discovery render failed" warnings are gone and both UIs register. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01TMUG7KT32tVitdDTjjyrgE --- smithers/workflows/rig-loop.tsx | 2 +- smithers/workflows/rig-sync.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/smithers/workflows/rig-loop.tsx b/smithers/workflows/rig-loop.tsx index aa0d35f..22823ca 100644 --- a/smithers/workflows/rig-loop.tsx +++ b/smithers/workflows/rig-loop.tsx @@ -65,7 +65,7 @@ const { Workflow, Sequence, Parallel, Task, Loop, Branch, smithers, outputs } = export default smithers((ctx) => { const advisor = ctx.input.advisor !== false; - const seed = ctx.input.built.join(", ") || "(none)"; + const seed = (ctx.input.built ?? []).join(", ") || "(none)"; const pick = ctx.latest(outputs.pick, "pick"); const backlogDry = Boolean(pick && (pick.ready === false || (pick.ticketId ?? "") === "")); diff --git a/smithers/workflows/rig-sync.tsx b/smithers/workflows/rig-sync.tsx index 783b0de..84f9dcb 100644 --- a/smithers/workflows/rig-sync.tsx +++ b/smithers/workflows/rig-sync.tsx @@ -89,7 +89,7 @@ without it. Else return blockers. Set unitId: "${u.id}".`} export default smithers( (ctx) => { - const work = ctx.input.units.filter((u) => u.klass === "work"); + const work = (ctx.input.units ?? []).filter((u) => u.klass === "work"); // Gates are DECISION NODES; subsequent steps are gated on the recorded // decision (rig's EpicFlow convention) — nesting steps as Approval children // does not schedule them. From b81db5cb61cb913bac1a0043d5e5e2aacdde11a2 Mon Sep 17 00:00:00 2001 From: Paul Gebheim <86010+pgebheim@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:36:26 +0000 Subject: [PATCH 2/2] fix(rig-sync): type the `key` prop on the Unit lane component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `` is rendered in `work.map(...)`, but Unit is a plain function component whose props type didn't declare `key`. Under the smithers JSX types, `key` isn't auto-injected for function components (built-ins like / carry it), so it was rejected as an excess prop — TS2322 at the call site. Declaring `key?: string` on Unit's props keeps the list-identity key and makes `typecheck smithers/` pass. Pre-existing failure on feature/smithers, surfaced independently of the UI-discovery guard. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01TMUG7KT32tVitdDTjjyrgE --- smithers/workflows/rig-sync.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smithers/workflows/rig-sync.tsx b/smithers/workflows/rig-sync.tsx index 84f9dcb..807c627 100644 --- a/smithers/workflows/rig-sync.tsx +++ b/smithers/workflows/rig-sync.tsx @@ -64,7 +64,7 @@ const { Workflow, smithers, outputs } = createSmithers({ /** One reconciling lane: isolated worktree, coder↔reviewer until approved. * RED→GREEN→review for code — the rig-task loop, in-workflow. */ -function Unit({ ctx, u, baseBranch }: { ctx: any; u: z.infer; baseBranch: string }) { +function Unit({ ctx, u, baseBranch }: { ctx: any; u: z.infer; baseBranch: string; key?: string }) { const s = slug(u.id); return (