9.4 KiB
Created
Created by LocalTicketBackend create.
Intake summary
Existing Ticket refined enough for Orchestrator routing. Request is an implementation-ready bug fix: make client::PodClient own/cancel its background Unix-socket reader task on drop so short-lived panel probes do not leak file descriptors. Acceptance focuses on Drop-triggered reader abort, preserving normal event receive behavior while alive, regression coverage for repeated connect/drop cleanup, and validation via focused client tests plus formatting/diff/ticket doctor checks. needs_preflight: false; risk_flags: [async-cancellation, pod-client-lifecycle, fd-leak].
State changed
Intake marked ready: requirements, acceptance criteria, implementation boundary, validation, and escalation surface are clear enough for Orchestrator routing. No implementation is started by Intake.
State changed
Ticket queued for Orchestrator routing.
Decision
Routing decision: implementation_ready
Reason:
- Intake marked this as ready with
needs_preflight: false; the Ticket describes a concrete bug and a narrow lifecycle fix. - Requirements and acceptance criteria are observable:
PodClientmust own/cancel its background reader task, dropping the client must abort the reader and release the read half promptly, and existing send/receive behavior must remain intact. - The relevant code map is narrow:
crates/client/src/pod_client.rsownsPodClient::connect, the spawned reader task, send/recv methods, and existing client tests;crates/tui/src/pod_list.rsexercises repeated short-lived live status probes. - Remaining uncertainty is bounded async test design, not a product/API/authority boundary decision.
Evidence checked:
- Ticket body: background, goal, requirements, acceptance criteria.
- Thread: intake summary and
ready -> queuedevent. - Workspace state: no matching branch/worktree exists; main has unrelated Ticket-record changes for
allow-spawnpod-child-workspace-cwdthat are understood and outside the implementation paths. - Code map search for
PodClient,PodClient::connect, reader task spawn, live status probing, andtry_connect_live_pod. - Ticket doctor: 0 errors; existing warnings are unrelated legacy closed-Ticket diagnostics.
IntentPacket:
Intent:
- Fix the
PodClientreader-task lifecycle so short-lived clients used by panel/live Pod probing do not leak Unix socket file descriptors.
Binding decisions / invariants:
PodClientowns the lifetime of the background reader task created byPodClient::connect().- Dropping
PodClientmust cancel/abort the reader task without relying on remote socket close. - Aborting the reader task must drop the read half of the Unix socket promptly.
- While
PodClientis alive, normal event receive behavior must continue to work. - Existing one-shot clients, TUI clients, Ticket role launcher communication, and Pod-management tools must continue using
PodClientnormally. - Do not change Pod socket protocol, event format, controller behavior, registry semantics, or panel polling policy unless a focused test shows a minimal caller adjustment is necessary.
Requirements / acceptance criteria:
- Store the reader task
JoinHandleinPodClientor provide equivalent owned cancellation. - Implement
DropforPodClientto abort/cancel the reader task. - Preserve
send,try_recv_event, andrecv_eventbehavior while alive. - Add focused regression coverage proving drop aborts/cleans up the reader task or otherwise closes repeated connect/drop clients without leaking stuck reader tasks.
- Add/adjust live status probe tests if needed.
- Avoid brittle FD-count-only tests if a deterministic task/connection cleanup assertion is more robust.
Implementation latitude:
- Coder may choose exact field names, test seams, and whether to expose test-only observability through existing module tests.
- Coder may use server-side connection closure or task completion probes in tests if they deterministically prove the dropped client no longer holds the socket read half.
- Coder may add a small helper if it improves readability, but should avoid broad refactors.
Escalate if:
- Fixing reader-task cleanup requires changing
PodClientpublic API or Pod socket protocol. - Drop-based cancellation conflicts with long-lived TUI event consumption.
- Deterministic regression coverage is impossible without invasive test-only hooks.
- The observed FD leak appears to come from a different source after inspecting
PodClient.
Validation:
- Focused client tests for
pod_client/ reader-task drop behavior. - Relevant TUI live status probe tests if changed.
cargo test -p client ... --libor focused equivalent selected by coder.cargo test -p tui pod_listif status probing is touched.cargo fmt --check.git diff --check.cargo run -q -p yoi -- ticket doctor.- If runtime/client behavior is touched, final merge-completion should include
nix build .#yoi.
Current code map:
crates/client/src/pod_client.rs:PodClientstruct,connect, spawned reader task, send/recv tests.crates/tui/src/pod_list.rs: repeatedPodClient::connectlive status probing and existing probe tests.crates/tui/src/single_pod.rsandcrates/client/src/ticket_role.rs: long-lived / one-shot client users to preserve conceptually.
Critical risks / reviewer focus:
- Dropping
PodClientmust abort the reader task even if the server stays open and silent. - The fix must not drop or abort the reader while a live client is still expected to receive events.
- Regression tests should fail against the old behavior rather than only checking that a field exists.
- Avoid masking leaks by relying only on remote close or timeout behavior.
State changed
Accepted queued implementation after reading the Ticket, workspace state, and PodClient code map. This acceptance precedes worktree creation and coder/reviewer Pod spawning.
Plan
Implementation routing accepted and worktree created.
Worktree plan:
- Branch:
abort-podclient-reader-task-on-drop - Worktree:
.worktree/abort-podclient-reader-task-on-drop - Base:
89b4369 ticket: route podclient reader cleanup - Scope: implement
PodClientreader-task owned cancellation and focused cleanup tests.
Delegation plan:
- Spawn sibling coder Pod with write scope limited to
.worktree/abort-podclient-reader-task-on-drop. - Coder must run Bash commands from the child worktree, not from the main workspace.
- Coder must not edit main-workspace
.yoi/ Ticket / workflow / docs records, and must not create generated memory/local/runtime/secret-like files. - Reviewer will be spawned read-only after coder reports diff/commits and validation evidence.
Concurrency note:
- Main workspace has unrelated Ticket-record edits for other queued/intake work. This implementation is isolated to the child worktree and should not edit those records.
Stop/completion policy:
- Because the human authorized cleanup after completion, this Orchestrator will proceed through reviewer approval, merge-completion validation, Ticket close, Pod stop, worktree removal, and branch deletion if the branch is approved and merge authority remains clear.
Implementation report
Coder completed and reviewer delegated.
Coder result:
- Pod:
coder-abort-podclient-reader - Commit:
aec75b3 fix: abort PodClient reader task on drop - Worktree status: clean after commit.
- Diff against
develop: 1 file changed, 143 insertions, 2 deletions.
Files touched by coder:
crates/client/src/pod_client.rs
Coder reported implementation:
- Added owned
reader_task: JoinHandle<()>field toPodClient. - Stored the background reader task created by
PodClient::connect(). - Implemented
DropforPodClientto abort the reader task. - Preserved send and receive behavior while
PodClientis alive. - Added focused tests for receiving while alive, sending while alive, repeated connect/drop connection cleanup, and aborting a blocked reader so the Unix socket read half is released.
Coder reported validation:
cargo test -p client pod_client --libcargo test -p client --libcargo test -p tui pod_list --libcargo fmt --checkgit diff --checkcargo run -q -p yoi -- ticket doctornix build .#yoi
Reviewer delegation:
- Spawned sibling reviewer Pod:
reviewer-abort-podclient-reader. - Reviewer scope: read-only child worktree plus non-recursive parent-root read required by launch cwd validation.
- Reviewer was instructed to judge against the recorded Ticket requirements and binding decisions.
Pending:
- Await reviewer verdict before merge-ready dossier / merge-completion.
- No merge, close, final approval, or cleanup has occurred for this Ticket.