-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Description
What state is duplicated
The daemon maintains pending-<pid> placeholder session IDs when a launch starts before the adapter's real session ID is known. A 10-second background interval (startPendingResolution) polls adapter.discover() to match PIDs and replace pending IDs with real UUIDs.
Files:
session-tracker.ts:resolvePendingSessions(),resolvePendingId(),startPendingResolution()state.ts: pending-* entries stored asSessionRecordinstate.json
Where is the ground truth?
The adapter's native session creation. The real session ID is created by the adapter (Claude Code, OpenCode, Codex) when it initializes — agentctl shouldn't need to track the mapping.
How does it desync?
- Resolution never completes: If the adapter can't match the PID to a session (race, crash, or PID dies before discovery), the pending-* entry persists indefinitely in state.json. Evidence:
~/.agentctl/opencode-sessions/currently has 20+pending-*.jsonfiles for dead sessions. - PID recycling during resolution: Between launch and resolution (up to seconds), the PID could theoretically be recycled (unlikely but possible on busy systems).
- Lock coupling: Auto-locks reference pending-* IDs. If resolution fails, the lock is stuck until manual cleanup.
- Duplicate sessions: If resolution matches wrong PID (adapter has multiple processes for same cwd), both the pending entry and the real session appear in results.
User-visible symptom
agentctl list -ashows stalepending-*entries for sessions that died long agolock listshows locks with pending-* session IDs that can't be auto-cleaned- Inconsistent state between list (daemon-enriched) and status (adapter-direct)
Proposed fix
- Add TTL to pending entries: If a pending-* isn't resolved within 2 minutes, check PID liveness. If dead, remove it and release associated locks.
- Move ID resolution to adapter: The adapter's
launch()already polls for the real session ID (e.g.,pollForSessionIdin claude-code.ts). Increase the poll timeout and have launch() return the real ID synchronously — eliminating the need for background resolution. - If pending must exist: Treat them as write-behind metadata, not as session status records. They should never influence what
agentctl listreports.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels