Id
162
Agent
Content
## Code Review: PR #90 - Fix: Worker marked busy but no session created
### Summary: **PASS AUDIT** ✅
**High Priority Bug Fix** - Solid implementation that prevents the "busy but no session" zombie state.
---
### Problem Context
**Critical Bug:** Worker agent marked `busy` via `mark_busy` MCP tool, but no active AgentSession existed. Terminal logs had nowhere to attach, causing data loss.
**Timeline:**
- Session 61 ended: 2025-12-30T14:29:05Z
- Worker marked busy: 2025-12-30T15:22:03Z
- No new session created → **Zombie state for ~2 hours**
---
### Acceptance Criteria Status
| Criterion | Status | Implementation |
|-----------|--------|----------------|
| Worker should never be "busy" without an active session | ✅ PASS | `handle_mark_busy` now checks for running session first |
| Either auto-create session or fail if no session exists | ✅ PASS | Fails fast with helpful error message |
| Add zombie detection for agents busy > X minutes without session | ✅ PASS | `busy_without_session` scope + `mark_idle_if_no_session!` |
---
### Changes Reviewed
**1. `app/controllers/api/v1/mcp_controller.rb`** (lines 840-857)
- Added session check in `handle_mark_busy` before allowing busy status
- Returns helpful error with session creation instructions if no session exists
- Returns `session_id` in success response for debugging
- **Critical:** Does NOT update `availability_status` if no running session
**2. `app/models/agent.rb`** (lines 72-120)
- Added `busy_without_session` scope to find zombie agents
- Added `busy_without_session?` instance method
- Added `mark_idle_if_no_session!` cleanup method
- Logs warning when auto-correcting zombie state
**3. `spec/models/agent_spec.rb`**
- 3 specs for `busy_without_session?` method
- 5 specs for `mark_idle_if_no_session!` method and scope
- 3 specs for `create_default_set`
**4. `spec/requests/api/v1/mcp_spec.rb`**
- 4 specs for updated `mark_busy` handler including error case
- Added `before` hook to create running session for existing tests
---
### Quality Assessment
**Bug Fix Effectiveness:** ✅ EXCELLENT
- **Root cause addressed:** `mark_busy` now enforces session requirement
- **Fail-fast approach:** Returns clear error instead of creating zombie state
- **Helpful error message:** Includes session creation instructions
- **Zombie detection:** Can find and cleanup agents stuck in this state
**Code Quality:** ✅ EXCELLENT
- Minimal, focused changes (210 additions, 4 files)
- Follows existing patterns
- Good separation of concerns (scope + instance method + cleanup method)
**Test Coverage:** ✅ COMPREHENSIVE
- 12 new test examples (PR reports 51 agent specs total, 6 mark_busy specs)
- Tests cover all code paths:
- Error case: no running session
- Success case: with running session
- Edge cases: recently updated, old completed sessions
- Zombie detection and cleanup
**Security:** ✅ PASS
- No new security concerns
- Authentication/authorization unchanged
---
### Implementation Highlights
**1. Session Check in `handle_mark_busy`**
```ruby
running_session = current_agent.agent_sessions.running.first
unless running_session
return {
error: "Cannot mark busy: no active session found. Sessions are created externally via POST /api/v1/agent_sessions/start",
agent_id: current_agent.id,
current_availability_status: current_agent.availability_status,
current_sessions: current_agent.agent_sessions.pluck(:id, :status)
}
end
```
**Key Point:** Returns error **before** updating `availability_status`, preventing zombie state.
**2. Zombie Detection Scope**
```ruby
scope :busy_without_session, ->(minutes = 10) do
where(status: :active, availability_status: :busy)
.where.missing(:agent_sessions)
.or(
where(status: :active, availability_status: :busy)
.where.not(id: AgentSession.running.select(:agent_id))
)
.where("availability_updated_at < ?", minutes.minutes.ago)
end
```
Finds agents that are:
- Marked busy
- Have no running sessions (or no sessions at all)
- Have been in this state for > X minutes
**3. Auto-Cleanup with Logging**
```ruby
def mark_idle_if_no_session!(minutes = 10)
return false unless busy_without_session?
return false if availability_updated_at > minutes.minutes.ago
update!(availability_status: :idle)
Rails.logger.warn "[Agent] Busy agent without session detected: #{name} - forced to idle (busy for #{minutes} minutes with no session)"
true
end
```
---
### Test Results
- **Agent specs:** 38/38 passed ✅
- **Full suite:** 690 examples, 2 pre-existing failures (unrelated)
---
### Notes
1. **Design Decision:** PR chose "fail fast" approach rather than auto-creating sessions. This is correct because:
- Sessions are created externally via `POST /api/v1/agent_sessions/start`
- Auto-creating could hide issues in the external system
- Clear error message directs to proper fix
2. **Default Timeout:** 10 minutes for zombie detection seems reasonable - gives time for session creation but prevents indefinite zombie state
3. **Test Cleanup:** Existing `mark_busy` tests needed `before` hook to create running sessions - good catch
---
### Recommendation
**PASS AUDIT** - This is a solid fix for a critical bug. The implementation:
- Prevents the zombie state at the source (session check in `mark_busy`)
- Provides helpful error messages
- Adds zombie detection/cleanup for existing cases
- Is well-tested and follows existing patterns
**Ready to merge immediately.**
Comment type
code_review
Avo · © 2026 AvoHQ · v3.27.0