Skip to content

fix: prevent pipeline hang when subroutine completes with empty result#993

Open
acarr wants to merge 1 commit into
cyrusagents:mainfrom
acarr:fix/pipeline-hang-empty-result
Open

fix: prevent pipeline hang when subroutine completes with empty result#993
acarr wants to merge 1 commit into
cyrusagents:mainfrom
acarr:fix/pipeline-hang-empty-result

Conversation

@acarr
Copy link
Copy Markdown

@acarr acarr commented Mar 16, 2026

Problem

Cyrus intermittently appears "hung" in Linear — the timer keeps running, the transcript shows work is done, but the ticket is never updated with a commit, PR, or summary. The only recourse is to manually stop the session.

Root Cause

In AgentSessionManager.completeSession(), the condition that decides whether to advance the subroutine pipeline is:

if ("result" in resultMessage && resultMessage.result) {

Some subroutines (observed on changelog-update, but could affect any) complete with subtype: "success" but no result textresult is undefined or empty string. When this happens:

  1. The if above evaluates to false (result is falsy)
  2. All else if branches check subtype !== "success", which is also false
  3. The function silently returns — no pipeline advancement, no error, no log
  4. The Linear ticket shows "still working" indefinitely

Fix

Change the primary check from requiring result text to checking the success status:

if (resultMessage.subtype === "success") {

When result text is empty, a placeholder "(completed successfully)" is synthesized so downstream code that expects a string still works.

Also fixes a secondary issue: when a user clicks "stop" in Linear but the session had already completed successfully, the pipeline was being abandoned. Now it checks whether the stop was actually effective (non-success result) vs. arrived too late (success result).

Evidence

Reproduced

  • ABC-215, ABC-216: Both hung at changelog-update with diagnostic logs showing subtype=success hasResult=false followed by silence
  • ABC-227, ABC-231: Hit the same hasResult=false condition, but with the fix active — logs show success with empty result — synthesizing result text and the pipeline continued to completion

Diagnostic log showing the fix in action (WAZ-227)

completeSession ENTERED ... subtype=success hasResult=true    ← normal subroutine
completeSession ENTERED ... subtype=success hasResult=true    ← normal subroutine
completeSession ENTERED ... subtype=success hasResult=false   ← BUG TRIGGERED
  success with empty result — synthesizing result text        ← FIX CAUGHT IT
  calling handleProcedureCompletion                           ← pipeline continued
completeSession ENTERED ... subtype=success hasResult=true    ← rest completed normally

Historical analysis

Analyzed 28 previous Cyrus tickets. 6 hung with the same pattern — Session completed with N messages logged by ClaudeRunner but no Subroutine completed, advancing to next from AgentSessionManager. Task type and complexity showed no correlation — both simple (Settings screen) and complex (4-package polling system) tickets hung.

Test plan

  • New test: advances pipeline when success result has empty result text — the core regression test
  • New test: continues pipeline when stop arrives too late — stop + success doesn't kill pipeline
  • Updated test: skips pipeline when stop is effective — uses non-success subtype
  • All 630 existing tests pass
  • TypeScript compiles cleanly (typecheck passes in pre-commit hook)
  • Verified with 16+ live Cyrus tickets across multiple batches

🤖 Generated with Claude Code

When a subroutine (especially changelog-update) completes with
subtype="success" but no result text, the condition
`"result" in resultMessage && resultMessage.result` evaluated to false.
All else-if branches check `subtype !== "success"` which was also false,
causing completeSession() to silently return without advancing the
pipeline. This left the Linear ticket appearing "hung" indefinitely.

Fix: check `resultMessage.subtype === "success"` instead, and synthesize
a placeholder result text for the empty case. Also handle the case where
a stop signal arrives after a successful completion (stop arrived too
late).

Reproduced and verified with live Cyrus sessions (WAZ-215, WAZ-216)
using diagnostic logging that confirmed the exact code path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@acarr acarr marked this pull request as ready for review March 16, 2026 00:39
@Connoropolous
Copy link
Copy Markdown
Contributor

thanks @acarr we are queueing this up for review

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.

2 participants