Repository navigation
Description
#3022 reads an OpenCode subagent's end from its parent session's record (the subagent call block, or the background notice), ready for anomalyco/opencode#57418. It ships behind Settings → Appearance → Read OpenCode subagent ends from their session (experimental), off by default. With it off, the reader takes no parent rows and behaves as before. The review of #3022 left these cases open. Each one blocks turning the setting on by default.
1. (Fixed in #3022 before merge.) A crashed foreground call held a child that the restarted service woke and ended. A waiting call last written before the service started now waits on nothing.
2. A late background notice ends a newer call (reproduced with a fixture; the upstream ordering is not verified).
A background run finishes, the parent calls the same child again (foreground) before the old notice lands, and the notice is written after the new call. The newest row wins, so the reader takes the stale notice and ends the new call while the parent still waits. A notice does not name the call it answers. A fix needs to pair notices with calls, for example by the job's start, or to ignore a notice for a child whose newer call is still running. main reads this case the same way, from the child's idle row.
3. A cold read of a long parent history can miss the turn-end frame (traced, not reproduced).
OpencodeSubagentStatus.poll takes two synchronous steps. The first read after a pane binds, or a read after its log starts over (/undo), pages the parent's rows first. With more than about 1000 parent rows, that read can finish only after the frame that ends the turn, so a turn that started a subagent may be told DONE before the count arrives. Warm reads are not affected. A fix could read a cold parent log only back to the oldest child still kept, or let the poll that ends a turn finish its read before telling.
5. Turning the setting off mid-wait holds BG up to a minute (from review). If a parent still waits on an idle child when the setting goes off, the count drops to 0 and BackgroundWait's 60-second grace starts. With the setting off throughout, that child would never have held anything. A fix could drop the hold at once when the count falls because of the toggle.
4. A staged /undo is applied after only the newest record per child is kept (reproduced, same on main).
If a later call to the same child is hidden by a staged /undo, the older visible call cannot take over, and the child's own rows decide. The boundary should be applied before "newest wins".
Measured cost with the setting on, a 100 MB parent (5000 steps, 100 children), through the tracker: first read about 220 ms, then warm polls about 10-15 ms over main (one pass over the row headers). Codex measured about 90 ms on 250,000 rows.
Activity
fix(opencode): look up rewritten parent rows by id, and reread a log …
fix(opencode): close the parent-record subagent end cases (experiment…