Skip to content

fix(spawn): transition executor state from spawning to running after spawn - #1021

Merged
namastex888 merged 4 commits into
devfrom
fix-tmux-spawns
Apr 3, 2026
Merged

namastex888 merged 4 commits into
devfrom
fix-tmux-spawns

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Summary

  • Executor state transition: After awaitAgentReadiness() in launchTmuxSpawn(), transition executor from spawning → running and legacy worker to idle. Previously nothing triggered this transition, leaving all executors permanently stuck in spawning.
  • Stale spawn reconciliation guard: Add current_executor_id IS NULL to reconcileStaleSpawns() query so agent identity records (from findOrCreateAgent) are not falsely marked as error after 60s.
  • Identity record state default: Set state = NULL explicitly in findOrCreateAgent() instead of inheriting the spawning default, preventing identity records from being caught by state-based reconciliation.

Root Cause

The executor model (migration 012) introduced a split between agent identity records and executor records. Identity records default to state='spawning' with pane_id=''. reconcileStaleSpawns() matched these after 60s and marked them as errors, triggering false [executor.error] events. Additionally, the spawn flow never transitioned executors from spawning to running after successful pane creation.

Test plan

  • Existing reconcileStaleSpawns tests still pass (74 tests in agent-registry)
  • New test: identity records with current_executor_id are excluded from reconciliation
  • Full gate: 1833 tests pass, 0 failures
  • Typecheck, lint, dead-code all pass

…spawn

Three fixes for agents/executors stuck permanently in 'spawning' state:

1. launchTmuxSpawn: after awaitAgentReadiness(), transition executor to
   'running' and legacy worker to 'idle' — previously nothing triggered
   this transition, leaving all executors stuck in 'spawning'

2. reconcileStaleSpawns: add current_executor_id IS NULL guard so agent
   identity records (from findOrCreateAgent) are not falsely marked as
   errors — they track state through their executor, not the legacy
   state column

3. findOrCreateAgent: explicitly set state=NULL on identity records
   instead of inheriting the 'spawning' default, preventing them from
   being caught by any state-based reconciliation queries
@coderabbitai

coderabbitai Bot commented Apr 3, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 707783ca-f3ef-4fd9-8f52-a212556fe65b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-tmux-spawns

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the agent registry to prevent reconcileStaleSpawns from erroneously flagging identity records by adding a current_executor_id IS NULL check and initializing records with a NULL state. It also adds state transitions in launchTmuxSpawn. Reviewers suggested extending these transitions to resumeAgent and launchInlineSpawn for consistency and updating the test case to explicitly set the agent state to 'spawning' to ensure the SQL guard is correctly tested.

Comment on lines +916 to +920
// Transition executor + legacy worker from 'spawning' to 'running'
if (ctx.executorId) {
await executorRegistry.updateExecutorState(ctx.executorId, 'running').catch(() => {});
}
await registry.update(ctx.workerId, { state: 'idle' }).catch(() => {});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The state transition logic added here is important for fixing executors stuck in the spawning state. However, this transition is currently missing from the resumeAgent and launchInlineSpawn functions. To ensure consistency and prevent executors from being stuck in spawning across all lifecycle paths, similar updates should be applied to those functions as well.


// Backdate started_at so it would match the threshold
const sql = await getConnection();
await sql`UPDATE agents SET started_at = now() - interval '10 seconds' WHERE id = ${agent.id}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To effectively test the current_executor_id IS NULL guard in reconcileStaleSpawns, the test should explicitly set the agent's state to 'spawning'. Currently, findOrCreateAgent sets the state to NULL, which already causes reconcileStaleSpawns to skip the record regardless of the current_executor_id value.

Suggested change
await sql`UPDATE agents SET started_at = now() - interval '10 seconds' WHERE id = ${agent.id}`;
await sql("UPDATE agents SET started_at = now() - interval '10 seconds', state = 'spawning' WHERE id = " + agent.id);

Test added 3 commits April 3, 2026 04:31
… from concurrency cap

Bug 1: reconcileStaleSpawns second pass (added in prior commit) now verified
by updating the integration test to expect dead-pane agents ARE cleaned up.

Bug 2: The concurrency cap in attemptAgentResume counted 'spawning' agents
as active, causing zombie spawning agents to block all auto-resume. Adding
'spawning' to the exclusion list fixes this — spawning agents are not yet
consuming compute and should not count toward the cap.
@namastex888
namastex888 merged commit 16e673b into dev Apr 3, 2026
6 checks passed
@namastex888
namastex888 deleted the fix-tmux-spawns branch April 10, 2026 16:18
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