Skip to content

feat: add Workflows right-sidebar tab with live run streaming#3624

Merged
ThomasK33 merged 1 commit into
mainfrom
worktree-workflows-tab
Jun 24, 2026
Merged

feat: add Workflows right-sidebar tab with live run streaming#3624
ThomasK33 merged 1 commit into
mainfrom
worktree-workflows-tab

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Adds a Workflows tab to the right sidebar so a workspace's durable workflow runs get a dedicated, live observation surface — instead of relying on the large in-chat workflow tool call card. Implements the imported "Workflows Tab" design.

The tab is gated on the existing dynamic-workflows experiment (it is that feature's observation surface) and shows the focused run live, with run history and an empty-state launcher.

Backend

  • workflows.subscribe — push stream (initial snapshot + per-write deltas) of a workspace's top-level runs. WorkflowService is constructed per oRPC request, so it can't be the singleton event source a subscription needs; instead every run mutation already flows through WorkflowRunStore.writeRunFile, which now notifies a module-level workflowRunStreamHub that the subscribe handler listens to. This decouples who runs the workflow (chat tool, CLI, background, crash recovery) from who is watching it.
  • workflows.listScripts — enumerates runnable workflow scripts (built-in + project + global skills exposing a workflow.js) for the empty-state launcher, reusing the existing resolver/skill discovery and surfacing each script's declared args.

Frontend

  • A pure, unit-tested projector folds the intentionally-lean run record (events + steps; steps carry no phase/title/usage) into the phase→step view: phase assignment by event sequence, titles from task events, durations from timestamps, final report/error from events.
  • Timeline UI: run header (interrupt / resume / retry-from-checkpoint / re-run), phases (collapsed by default so a 20+ step fan-out stays scannable, with expandable phase info objects), expandable steps with per-step output + structured output, run history, and an empty-state launcher with a per-arg input form. The final report is collapsible and renders the full structured output returned to the agent, not just summary chips.
  • Tab registration mirrors the memory/browser experiment-gated tabs (added to the layout via a per-experiment effect), with a live active-run count badge on the label.

Behavior change

When the Workflows tab is available, the in-chat workflow tool card auto-collapses by default (any status). Without it, the prior behavior (auto-collapse completed runs only) is preserved — so behavior and existing tests are unchanged when the experiment is off.

Deferred (deliberate)

  • Per-step token/cost: sub-agent usage rolls up into the parent workspace and isn't reliably queryable by task once a step completes. The projector/UI already accept a usage overlay for when per-step capture lands.
  • Background a live run: needs runner detach support; Interrupt covers the stop case.

Testing

make typecheck, make lint, and the workflow suites all green (205 tests across the frontend Workflows + WorkflowRunToolCall + backend workflow + schema tests, including a dedicated projector test).

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 09e6abb to 4b760e3 Compare June 24, 2026 11:56
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b760e314a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/projectWorkflowRun.ts Outdated
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 4b760e3 to bfa9011 Compare June 24, 2026 12:07
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the P2: phase assignment now derives each step's first sequence from all step-bearing events (task, patch, workflow, and legacy action/validation) instead of only task events, so apply-patch and nested-workflow steps are grouped under their active phase rather than the ungrouped bucket. Nested-workflow steps also take their title from the child workflow name. Added a regression test (projectWorkflowRun — non-task step events).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bfa9011e9c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowsTab.tsx
Comment thread src/node/services/workflows/workflowScriptDiscovery.ts Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowTimeline.tsx Outdated
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from bfa9011 to 2dd9011 Compare June 24, 2026 12:21
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed all three P2 findings:

  • WorkflowsTab: reset scripts/busyScriptName/runError at the start of the discovery effect so a workspace switch can't show or launch a stale script.
  • workflowScriptDiscovery: moved descriptor build + arg summarization inside the per-skill try/catch, so a single workflow with malformed arg metadata is skipped instead of aborting discovery for the whole workspace.
  • WorkflowTimeline final report: gate the structured-output block on !== undefined (not != null) so a valid structuredOutput: null still renders instead of leaving an empty report.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dd9011697

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowTimeline.tsx Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowTimeline.tsx
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowRunHeader.tsx
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 2dd9011 to 88128f4 Compare June 24, 2026 12:32
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed all three P2 findings:

  • Failed phases now initialize expanded, and the phase header shows a destructive alert icon when the phase has a failed step, so the error isn't hidden behind a collapsed phase.
  • The timeline now renders a run-level error banner from view.errorMessage for failed runs, so pre-step setup/compile/eval failures show a reason instead of "No steps yet".
  • Re-run is only offered when the record stores a resolvable script path (canonical/source/requested); the bare-name fallback is removed so legacy records don't surface a Re-run button that would fail.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88128f464a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowTimeline.tsx Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowTimeline.tsx Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both P2s: phase and step disclosure now use a shared useDisclosureOpenOnFailure helper (React "adjust state during render" pattern) that opens not only when the phase/step is failed at first mount but also when it transitions to failed via the live subscription — so failures in an in-flight run are no longer hidden behind a collapsed phase/step. Manual collapse still wins; only a fresh false→true failure transition forces it open.

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 88128f4 to 25e22c2 Compare June 24, 2026 12:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25e22c2685

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 25e22c2 to 156bfeb Compare June 24, 2026 12:46
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both P2s in the empty-state launcher:

  • Untouched fields (including booleans) are now omitted from the submitted args, so the backend applies the script's declared default / omit semantics instead of us forcing false. Only fields the user actually edited are sent.
  • Integer inputs are only coerced when the whole string is a valid integer (/^[+-]?\d+$/); partial input like 1.9 or 10abc is passed through as a string so the backend validates and reports it rather than parseInt silently truncating it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 156bfeb6fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the P2: the launcher's required-field check now ignores required args that declare a default (arg.default === undefined added to the predicate). Such fields no longer block Start — submit omits the untouched field and the backend applies the default before validating required, matching slash/chat launches.

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 156bfeb to efe36ad Compare June 24, 2026 12:55

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: efe36adac9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the P2: required boolean args with no default now block Start until the user sets the checkbox (the required-field predicate handles booleans via values[arg.name] === undefined rather than excluding them), so the launcher no longer offers an enabled Start that fails backend validateRequired. Required args with a declared default still don't block (backend applies the default).

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from efe36ad to fda04fb Compare June 24, 2026 13:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fda04fbc40

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx Outdated
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from fda04fb to 407b5fc Compare June 24, 2026 13:21
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both P2s in the launcher:

  • Row state (configuring/busy) is now keyed by the unique scriptPath instead of descriptor.name, so duplicate-named skill workflows (which normalize to "workflow") no longer expand/disable each other's rows.
  • The boolean checkbox now reflects the declared default when untouched (arg.default === true), so the visible state matches the value that will actually run (submit still omits untouched fields and the backend applies the default).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 407b5fc4c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 407b5fc to ba87d1b Compare June 24, 2026 13:47
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Test-only change: WorkflowRunToolCall.test.tsx now mocks useExperimentValue → false so the suite is hermetic. The component reads the dynamic-workflows experiment to gate auto-collapse; in the full test run, cross-file experiment state (shared happy-dom localStorage) was flipping it on and collapsing the card, hiding the expanded content these tests assert. Forcing the experiment off restores the intended experiment-off behavior under test. No production changes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba87d1b309

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/RightSidebar/Workflows/WorkflowEmptyState.tsx
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the P3: required boolean args with no default are now seeded to false when the form mounts, so their unchecked state is immediately submittable (Start enabled) and launching with false no longer requires a check→uncheck dance. Optional booleans and booleans with a declared default remain untouched (omitted on submit; backend applies the default).

@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from ba87d1b to 855d3ad Compare June 24, 2026 13:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 855d3ad618

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/features/Tools/WorkflowRunToolCall.tsx Outdated
Comment thread src/browser/features/RightSidebar/Workflows/WorkflowsTab.tsx Outdated
Implement the "Workflows Tab" design (imported from claude.ai/design) so a
workspace's durable workflow runs get a dedicated, live observation surface in
the right sidebar instead of relying on the large in-chat workflow tool card.

Backend
- workflows.subscribe: push stream (initial snapshot + per-write deltas) of a
  workspace's top-level runs. WorkflowService is constructed per oRPC request, so
  it can't be the singleton event source a subscription needs; instead every run
  mutation already flows through WorkflowRunStore.writeRunFile, which now notifies
  a module-level workflowRunStreamHub that the subscribe handler listens to. This
  decouples "who runs the workflow" (chat tool, CLI, background, crash recovery)
  from "who is watching it".
- workflows.listScripts: enumerates runnable workflow scripts (built-in + project
  + global skills exposing a workflow.js) for the empty-state launcher, reusing
  the existing resolver/skill discovery and surfacing each script's declared args.

Frontend
- A pure, unit-tested projector folds the intentionally-lean run record
  (events + steps; steps carry no phase/title/usage) into the phase->step view the
  tab renders: phase assignment by event sequence, titles from task events,
  durations from timestamps, final report/error from events.
- Timeline UI: run header (interrupt / resume / retry-from-checkpoint / re-run),
  phases (collapsed by default so a 20+ step fan-out stays scannable, with
  expandable phase info objects), expandable steps with per-step output +
  structured output, run history, and an empty-state launcher with a per-arg
  input form. The final report is collapsible and renders the full structured
  output returned to the agent, not just the summary chips.
- The tab is gated on the dynamic-workflows experiment (it is that feature's
  observation surface) and added to the layout via the same per-experiment effect
  the memory/browser tabs use, with a live active-run count badge on the label.

When the tab is available, the in-chat workflow tool card auto-collapses by
default (any status); without it the prior behavior (auto-collapse completed runs
only) is preserved, so behavior and the existing tests are unchanged when the
experiment is off.

Deferred deliberately: per-step token/cost (sub-agent usage rolls up into the
parent workspace and isn't reliably queryable by task once a step completes) and
converting a live foreground run to backgrounded (needs runner detach support;
Interrupt covers the stop case). The projector/UI already accept a usage overlay
for when per-step usage capture lands.

Change-Id: I2bc47dc9c850af7b7d232c36aea18c4464fbdb78
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33 ThomasK33 force-pushed the worktree-workflows-tab branch from 855d3ad to 9e7c63e Compare June 24, 2026 14:09
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both:

  • P2: the in-chat workflow card no longer auto-collapses when it carries a tool error (errorResult != null). Pre-run failures (invalid args / unresolved script path) create no durable run, so the Workflows tab has nothing to show and the error must stay visible in chat. Non-error cards still auto-collapse when the tab is enabled (and completed runs without it).
  • P3: the focused-run header/timeline is now keyed by focusedRun.id, so switching runs from history gives fresh UI state (no stale action error, and useDisclosureOpenOnFailure correctly auto-opens a new failed phase even if a prior same-named phase was collapsed).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 9e7c63ef03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33 ThomasK33 added this pull request to the merge queue Jun 24, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 24, 2026
@ThomasK33 ThomasK33 added this pull request to the merge queue Jun 24, 2026
Merged via the queue into main with commit 3f86fa0 Jun 24, 2026
24 checks passed
@ThomasK33 ThomasK33 deleted the worktree-workflows-tab branch June 24, 2026 14:47
@mux-bot mux-bot Bot mentioned this pull request Jun 24, 2026
LeonidasZhak pushed a commit to LeonidasZhak/mux that referenced this pull request Jun 30, 2026
## Summary

Long-lived auto-cleanup PR maintained by the **Auto-Cleanup Agent**.
Each pass lands at most one extremely low-risk, behavior-preserving
cleanup drawn from recently merged `main` activity, then advances the
checkpoint below.

Auto-cleanup checkpoint: 620c2a6

This PR currently contains six accumulated cleanups against `main`:

1. `src/node/services/taskService.ts` — dedupe queued-message foreground
backgrounding into a private helper.
2. `src/node/services/workflows/workflowScriptResolver.ts` — reuse the
`SKILL_SCRIPT_PATH_PREFIX` constant for canonical-path construction.
3. `src/node/services/workflows/WorkflowTaskServiceAdapter.ts` — extract
the duplicated agent-task creation arg shape into a shared
`WorkflowTaskCreateArgs` type.
4. `src/constants/workspaceTags.ts` (new) — centralize the
workspace-turn task tag keys, removing the cross-layer
`"mux.taskHandleId"` string duplication.
5. `src/node/services/tools/workflowProgress.ts` — extract the
duplicated "latest phase" lookup into a shared `getLatestPhaseEvent`
helper.
6. `src/browser/features/RightSidebar/Workflows/WorkflowBadges.tsx` —
map workflow run-status glyphs through an exhaustive
`Record<WorkflowRunStatus, LucideIcon>` instead of a repeated
`if`-chain.

## This pass

Rebased the branch onto the latest `origin/main` (clean) and considered
the three new commits since the prior checkpoint:

- coder#3624 (`feat: add Workflows right-sidebar tab with live run
streaming`)
- coder#3626 (`tests: add UI primitive stories and fix design-sync previews`)
- coder#3627 (`feat: return workflow plan agent results`)

coder#3624 added `WorkflowBadges.tsx`, whose `WorkflowStatusIcon` selected a
glyph through a four-branch `if`-chain that re-spelled the identical
`className="h-3 w-3 shrink-0"` + `style={{ color }}` props in every
branch and fell back to a default `<Circle>` for unmatched statuses.
Replaced that with a module-level `WORKFLOW_STATUS_ICON:
Record<WorkflowRunStatus, LucideIcon>` map (mirroring the existing
`WORKFLOW_STATUS_META` / `WORKFLOW_TONE_VAR` records in the same
feature) and render the looked-up icon once. Behavior-preserving: the
map reproduces the prior mapping exactly (`pending`/`running` →
`Circle`, `backgrounded`/`interrupted` → `Pause`, `completed` → `Check`,
`failed` → `X`), and using a `Record` makes the mapping exhaustive so a
newly added run status is a compile error here rather than a silent
fall-through. coder#3626 (Storybook/design-sync, test-only) and coder#3627
(already extracts its own `__muxAgentReturnValue` runtime helper)
offered no additional low-risk dedup.

<details>
<summary>Prior pass — workflowProgress getLatestPhaseEvent
helper</summary>

coder#3623 added `src/node/services/tools/workflowProgress.ts`, in which both
`buildWorkflowProgressSummary` and `formatWorkflowProgressNote`
independently re-spelled the same `run.events.findLast((event) =>
event.type === "phase")` expression to find the latest phase event.
Extracted that into a single private `getLatestPhaseEvent(run)` helper
and referenced it from both functions, giving the "latest phase"
definition one source of truth so the summary builder and the note
formatter can't drift. Behavior-preserving: the helper's body and
inferred return type are identical to the inline expression, so both
call sites compute exactly the same value.

</details>

<details>
<summary>Prior pass — checkpoint-only advance for coder#3621 (Claude Design
integration)</summary>

coder#3621 is purely additive and lives entirely under `.design-sync/` (plus
one `.gitignore` entry); it contains zero production (`src/`) code.
`.design-sync/**` is outside both the ESLint scope (`src/**`) and the
TypeScript `include`, so `make static-check` cannot validate the
behavior-preservation of any refactor there. That pass advanced the
checkpoint without a code change.

</details>

<details>
<summary>Prior pass — workspace-turn task tag keys
centralization</summary>

The workspace-turn task tag key `"mux.taskHandleId"` is **written** by
`TaskService.createWorkspaceTurn` (node, coder#3617/coder#3619) and **read** by
`findWorkspaceForTaskTarget` in `TaskToolCall.tsx` (browser, coder#3613) —
the same magic string duplicated across the node/browser boundary.
Extracted the three workspace-turn task tag keys (`handle`,
`ownerWorkspaceId`, `turn`) into a new `@/constants/workspaceTags`
module and referenced `WORKSPACE_TURN_TASK_TAGS` from both the node
write site and the browser read site. Behavior-preserving: the extracted
values are byte-identical to the previous literals, so the persisted tag
keys and all lookups are unchanged.

</details>

<details>
<summary>Prior pass — WorkflowTaskServiceAdapter WorkflowTaskCreateArgs
type</summary>

`WorkflowTaskServiceLike` (in `WorkflowTaskServiceAdapter.ts`) declared
the agent-task creation argument object **twice** — once inline in
`create(args: { ... })` and again inside `createMany?(args: Array<{ ...
}>)` — as byte-identical 10-field shapes. Extracted a named
`WorkflowTaskCreateArgs` interface and referenced it from both `create`
and `createMany`. Behavior-preserving: structurally identical interface,
signatures unchanged.

</details>

<details>
<summary>Prior pass — workflowScriptResolver SKILL_SCRIPT_PATH_PREFIX
reuse</summary>

In `workflowScriptResolver.ts`, the `skill://` prefix is named by the
module-level constant `SKILL_SCRIPT_PATH_PREFIX`, but the two
canonical-path builders re-spelled the literal `` `skill://${...}` ``
instead of reusing the constant. Both builders now interpolate
`${SKILL_SCRIPT_PATH_PREFIX}`. Behavior-preserving:
`SKILL_SCRIPT_PATH_PREFIX` is exactly `"skill://"`, so the interpolation
is byte-identical.

</details>

<details>
<summary>Prior pass — taskService queued-message dedup</summary>

Considered coder#3605 (`fix: background foreground waits for prequeued
messages`), which open-coded the same queued-message guard at two
`TaskService` wait-registration sites. Both sites now delegate to a
single private helper
`backgroundForegroundWaitIfQueued(shouldBackgroundOnQueuedMessage,
requestingWorkspaceId)`. Behavior-preserving: the helper folds in the
`requestingWorkspaceId` truthiness guard and the pushed call is
unchanged.

</details>

## Validation

- `make static-check` is green for the touched code (ESLint, `tsconfig`
+ `tsconfig.main.json`, Prettier). (`fmt-shell-check` is the only
non-passing step, solely because the `shfmt` binary is absent in this
environment; no shell files are touched.)
- Targeted tests pass: `bun test
src/browser/features/RightSidebar/Workflows/workflowDisplay.test.ts
src/browser/features/RightSidebar/Workflows/projectWorkflowRun.test.ts`
(32 tests) cover the same Workflows feature module the change lives in.

## Risks

Minimal. All accumulated changes are pure local extractions / constant
reuse; no logic, types, or call semantics change.

---

_Generated with `mux` • Model: `anthropic:claude-opus-4-8` • Thinking:
`xhigh`_

<!-- mux-attribution: model=anthropic:claude-opus-4-8 thinking=xhigh -->

---------

Co-authored-by: mux-bot[bot] <264182336+mux-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant