---
phase: quick-260414-4dl
plan: 01
subsystem: owl-messaging
tags: [bugfix, poll-loop, spool, idle-ready, race-condition]
dependency_graph:
  requires: []
  provides: [tcp-only-poll-listener, spool-based-idle-delivery, correct-parent-idle-semantics]
  affects: [src/common/listener.rs, src/owl/poll.rs, src/owl/hook_check.rs, src/owl/hook_subagent_start.rs]
tech_stack:
  added: []
  patterns: [spool-drain-all-on-idle, tcp-only-listener]
key_files:
  created: []
  modified:
    - src/common/listener.rs
    - src/owl/poll.rs
    - src/owl/hook_check.rs
    - src/owl/hook_subagent_start.rs
decisions:
  - PollListener is now TCP-only; spool drain responsibility moved to poll loop idle path
  - Parent idle-ready preserved while subagents are active; only parent's own PreToolUse clears it
metrics:
  duration_seconds: 179
  completed: "2026-04-14"
  tasks_completed: 2
  tasks_total: 2
---

# Quick 260414-4dl: Fix Poll Loop Spool Drain/Respool Race

TCP-only PollListener eliminates drain/respool cycle racing with PreToolUse peek_all; idle path now drains spool directly; subagent hooks no longer clear parent idle-ready.

## Changes Made

### Task 1: Remove spool drain from PollListener and fix poll idle-delivery path (c178745)

**PollListener (listener.rs):**
- Removed `spool::drain_one` fallback from both `check_message()` and `check_message_blocking()`
- Removed unused `spool` import
- Updated doc comments to reflect TCP-only behavior

**Poll loop (poll.rs):**
- Replaced `inbox::drain_inbox(id)` with `spool::drain_all(id, &owlery)` in TCP idle-delivery block (when TCP message arrives while idle)
- Replaced `inbox::drain_inbox(id)` with `spool::drain_all(id, &owlery)` in standalone idle check block (periodic spool drain when idle)
- Updated module comment to reflect spool-based idle delivery

### Task 2: Remove subagent idle-ready clearing on parent perch (9f48394)

**hook_check.rs:**
- Removed `inbox::clear_idle_ready(parent)` call from `handle_subagent` when parent found via working perch lookup
- Removed `inbox::clear_idle_ready(&id)` call from session_id fallback branch in `handle_subagent`
- Updated doc comments

**hook_subagent_start.rs:**
- Removed `inbox::clear_idle_ready(&parent_id)` call from SubagentStart handler
- Removed unused `inbox` import
- Updated module doc comment

## Deviations from Plan

None - plan executed exactly as written.

## Verification

- `cargo build --release` compiles with no new warnings (3 pre-existing warnings in unrelated files)
- `cargo test` passes all 13 tests
- grep confirms no `drain_one` calls remain in listener.rs
- grep confirms no `clear_idle_ready` calls on parent in hook_check.rs handle_subagent or hook_subagent_start.rs

## Self-Check: PASSED

All modified files exist and both commits verified:
- c178745: listener.rs + poll.rs
- 9f48394: hook_check.rs + hook_subagent_start.rs
