Skip to content

Latest commit

 

History

History
131 lines (103 loc) · 6.75 KB

File metadata and controls

131 lines (103 loc) · 6.75 KB

Known Issues

Confirmed defects that are understood well enough to describe but are not yet fixed or covered by an OpenSpec change. Each entry records the symptom, what diagnosis has already ruled out (so it isn't redone), and the suggested next step. Remove an entry when a fix lands; if a fix becomes an OpenSpec change, note the change name here until it archives.

Issues 1 and 2 below were discovered during the 2026-07-07 live QA of the subagent-ui-party-frames change (archived in openspec/changes/archive/). Neither was introduced by that change.

1. Cmd lifecycle-end sentinel can be silently lost mid-session → permanent zombie running records

Symptom: a cmd subagent finishes its work (TUI back at the idle prompt) but its tracker record stays running indefinitely. The Stop hook — cmd's lifecycle-end sentinel writer — fails with:

Stop hook error: /home/dev/Local/personal/tmux-pilot/.commandcode/.pi-tmux-hook.sh: No such file or directory

Observed live 2026-07-07 (~18:26): two cmd agents spawned at ~18:23 (which rewrites the hook script — CmdHarness.setupEnvironment() always rewrites it) hit a missing hook at Stop time ~2–3 minutes later. Both .commandcode/.pi-tmux-hook.sh AND .commandcode/settings.json were gone, while user-owned files in .commandcode/ (skills/, taste/) survived — a surgical deletion of exactly the two files tmux-pilot writes.

Impact: without the sentinel, harness.isComplete() never becomes true, and with staleness-timeout-ms: 0 and max-runtime-ms: 0 (both disabled by default) nothing else bounds the agent — the record is a permanent zombie. Auto-cleanup never runs; the GC command won't reap it either (window still alive ⇒ not a zombie by isReapable()'s definition).

Widget symptom now contained (not the root cause): these zombie running records used to bleed into a NEW parent session's widget as stale frames. The subagent-ui-theming-and-style change scopes the widget to the owning parent (selectVisibleAgents's ownership predicate + the reconciler adopt policy — see AGENTS.md), so a foreign or unverifiable zombie no longer renders in an unrelated session. The underlying sentinel loss below is still open — the record itself remains a zombie until reaped.

Recovery: steer_subagent with kill: true (→ interrupted, teardown runs normally).

Ruled out by inspection (don't re-check):

  • CmdHarness.cleanup() — restores settings.json only when it pre-existed (hasOriginalSettings === "true"), explicitly never deletes the hook script.
  • teardownSubagent() — config-dir removal is gated by isOwnedConfigDir(), which refuses .commandcode; temp-file removal is gated to /tmp pi-* files.
  • Worktree bootstrap (worktree-bootstrap.ts) — only creates/removes symlinks on the worktree side; skips when a real file/dir occupies the link path.

Next step: root cause is unknown. Run an inotify audit (e.g. inotifywait -m .commandcode/) during a cmd QA session with overlapping spawns/teardowns and catch the deleting process. Separately worth considering as a robustness fix regardless of root cause: have the Stop-hook registration verify the script exists (or make the hook self-healing / embed the sentinel write inline in settings.json instead of dispatching to a shared script).

2. Cmd tool visibility (cast bar / raid tool hint) can never work

Symptom: cmd subagents never show a cast bar (⟪ tool ⟫) in party frames or a tool hint in raid cells, even during a long-running bash command. The pi path works (verified live: ⟪ bash ⟫ during a 30s sleep).

Three independent defects, all required for a fix:

  1. src/status-poller.tspoll() does if (!record.statusFilePath) continue; before the hooks-audit branch. Cmd records never have a statusFilePath (cmd doesn't use PI_TMUX_SUBAGENT_STATUS_FILE by design), so pollHooksAudit() is unreachable for every cmd agent.
  2. src/tracker.tscreateTask() copies partial.statusFilePath but drops partial.hooksAuditPath; it is never persisted (same defect class as the partial.harness drop fixed in the party-frames change).
  3. src/spawner.tscreateTask() runs at Phase 4 (window creation), but cmd only discovers env.hooksAuditPath during waitForReady() at Phase 5 (it needs the cmd session ID). The value passed to createTask is always undefined, and nothing back-fills it afterward.

Impact: presentation-only — lifecycle, completion, and turn counting are unaffected (those come from the session file and the Stop-hook sentinel).

Next step: small dedicated change: reorder the poll() guard so the hooks-audit branch runs independently of statusFilePath, persist hooksAuditPath in createTask(), and add a tracker back-fill setter called after waitForReady() resolves the path. Needs a regression test that a running cmd record with only hooksAuditPath gets currentTool set.

3. Spawn queue is often too transient to observe on fast local spawns

Symptom: the widget's # in Q: N row may not visibly appear even when a subagent tool call is made. The party/raid frame appears directly instead.

Diagnosis: SpawnQueue is populated at UUID allocation and is correctly removed once a tracker record exists. Pi schedules extension-widget redraws asynchronously (next-tick, with a 16 ms minimum cadence), while the spawner can create that tracker record in the same event-loop turn before a paint occurs. The queue is therefore a best-effort pre-tracker cue, not a guaranteed observable state.

Impact: presentation-only. The tracker frame immediately provides the agent's identity and running state; the spawn tool also retains one compact ▸ spawning <role> chat line per call.

Next step: no change currently planned. A guaranteed visible queue would require a short post-handoff presentation linger, deliberately overlapping the queue and tracker frame.

Resolved QA notes

2026-07-23 subagent-hover-preview QA-pilot findings

The isolated live QA run found and fixed two integration issues before the change was completed:

  1. Pi invokes extension-widget component factories synchronously during setWidget(). The extension originally attached the widget before installing the hover factory, leaving the first controller unmounted. The factory is now installed before widget.attach().
  2. The live Pi and cmd TUIs on this host render on tmux's primary screen, so capture-pane -a -e -p returns no alternate screen. The tmux capture path retains the alternate-screen attempt and falls back only for that explicit response; the regression is covered by the real-tmux capture test.

There is no unresolved known issue from this QA run.