From 6465073125d1e9a8844a40abc1f053bdbbb6f4b4 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:52:48 -0700 Subject: [PATCH] chore(agent-status): move STA-4119 evidence out of the repo root The reproduction record, the plan, and the two captured last-status payloads were committed at the repo root, which the root-directory guard rejects. Evidence belongs on the PR; the content is preserved verbatim in a PR comment. --- STA-4119-PLAN.md | 90 ------------- STA-4119-REPRO.md | 162 ----------------------- sta-4119-macos-last-status-entry.json | 57 -------- sta-4119-windows-last-status-fields.json | 19 --- 4 files changed, 328 deletions(-) delete mode 100644 STA-4119-PLAN.md delete mode 100644 STA-4119-REPRO.md delete mode 100644 sta-4119-macos-last-status-entry.json delete mode 100644 sta-4119-windows-last-status-fields.json diff --git a/STA-4119-PLAN.md b/STA-4119-PLAN.md deleted file mode 100644 index 39bc27ff533..00000000000 --- a/STA-4119-PLAN.md +++ /dev/null @@ -1,90 +0,0 @@ -# STA-4119 plan — leftover non-agent inventory must not hold a finished lead at `working` - -## Decision - -A Claude lead turn that has ended (`Stop` / `StopFailure` with `lead.state === 'done'`) must publish **`done`** even when a background shell / monitor is still in `background_tasks`. Live **child agents** on the roster still hold the pane at `working`. Session crons stay on the existing cron gate (out of scope). - -This is a write-path change in `resolveClaudePaneState`, not a PTY-liveness backstop. Lane STA-4612 owns dead-pane / exit-path recovery. This lane owns the live pane whose lead is over and whose leftover process inventory currently upgrades `done` back to `working`. - -## Why this, not a refresh loop - -`claudeRunningNonAgentTaskPaneKeys` is written from `background_tasks` on lead events (`updateClaudeRunningNonAgentTask` in `src/shared/agent-hook-listener.ts`). An idle parent never emits another inventory, so the set is a one-way latch until the next lead turn. - -Two ways to “re-evaluate the gate”: - -1. **Keep the latch and poll / wait for a later inventory.** That reconciles after the fact, needs a signal the idle parent does not emit, and still publishes `working` while the shell is actually alive. It fails the acceptance oracle in `STA-4119-REPRO.md` (card/tab must reach `done` **while the background shell is still alive**). -2. **Stop letting leftover non-agent inventory participate in pane `state`.** Then a finished lead cannot be represented as `working` just because a child process lives. The latch can still be recorded for interrupt inference; it must not be an input to `resolveClaudePaneState`. - -(2) makes the reported state unrepresentable. (1) does not. - -`UserPromptSubmit` / `PreToolUse` / other mid-turn events still report `working` before `resolveClaudePaneState` sees a done lead. The pane stays `working` for a genuine lead turn, including one that happens to have a shell. That is the regression the coordinator forbade. - -## Code change (single decision, few call sites) - -In `resolveClaudePaneState` (`src/shared/agent-hook-listener.ts`), when `lead.state === 'done'`, return `working` only if: - -- the roster has a working child, or -- the lead is not interrupted **and** `claudeActiveSessionCronPaneKeys` has the pane. - -Remove `claudeRunningNonAgentTaskPaneKeys` from that predicate. - -Same leftover-shell predicate is inlined in two other places and must be aligned so a shell cannot keep looking like a confirmed working gate after the lead is done: - -- SubagentStop `hasConfirmedDoneGate` (~2682). That flag only decides whether a restored-child drain is “confirmed leftover inventory” vs “unconfirmed restore.” After this change a leftover shell is no longer a confirmed *working* gate, so this check must not treat the shell set as confirmation either. Otherwise a start-less `SubagentStop` (the reporter’s last event) can still mark the pane unconfirmed. After the resolve change, the re-emit is `done` if the cached lead is `done` and no child is working. -- The restored-snapshot guard on a lead Stop (~3110) currently requires `!claudeRunningNonAgentTaskPaneKeys.has(paneKey)` before marking `claudeUnconfirmedRestoredStatusPaneKeys`. A leftover shell would then skip that mark. Align this guard with the new resolve predicate (shells do not count as confirmation). Cron can stay. - -Do **not**: - -- add a PTY / pid liveness join (STA-4612) -- register `SessionEnd` -- map TUI-idle to `done` while the lead turn is still `working` -- invent a `backgroundOnly` render marker (closed #14620). Acceptance is `state === 'done'` on the card/tab. - -Keep writing `claudeRunningNonAgentTaskPaneKeys` on lead inventories. `server.ts` still consults it so Escape/Ctrl+C at an idle prompt does not infer “interrupted done” over a provider-owned shell. That is interrupt inference, not sidebar `state`. - -`turnCompletedAt` is only stamped when a lead Stop is gated **up** to `working`. After this change a shell-only Stop publishes `done` and does not need that stamp; the working→done edge is the completion notification. Stamping remains for a Stop that is still gated by a **working child** (existing #14580 behavior, unchanged). - -## Tests (red before the resolve change, green after) - -Add in `src/shared/claude-background-task-status.test.ts` (or the existing Claude subagent listener file) a STA-4119 case that is **red on current main**: - -1. `UserPromptSubmit` → `working` -2. Lead `Stop` with `background_tasks: [{ type: 'shell', status: 'running' }]` and no child → **`done`** (today: `working`) -3. Start-less `SubagentStop` (native unmatched child stop) → still **`done`**, last published row is not `working` (today: `SubagentStop` / `working` — the reporter’s `last-status.json`) -4. `UserPromptSubmit` again → **`working`** (lead is active; leftover shell must not be “force everything to done”) -5. `Stop` while a roster child is `working` → still **`working`** + `turnCompletedAt` (do not ignore real child work) - -Update existing tests that currently require `Stop` + `RUNNING_SHELL` → `working` so they expect `done` when no child is working. Keep tests that require `Stop` + running **subagent** → `working`. - -Notification tests in `agent-hook-completion-background-turn-notifications.test.ts`: the shell-only sequence should announce on the `done` Stop, not on a gated-working Stop. The subagent-gated sequence stays on `turnCompletedAt`. - -No new hook opcode, no new persisted field. Publishing `done` instead of `working` for this inventory is the intended product change; mixed-version remotes already understand both states. - -## Hibernation / keep-awake (accepted tradeoff) - -`agent-hibernation-planner.ts` refuses any pane with `state !== 'done'`. After this change a finished lead with a live leftover shell is hibernation-eligible. That matches “the lead is idle.” Killing a long-lived `npm run dev` by sleeping the worktree is the same class of leftover-process risk the reporter already works around by putting servers in a dedicated tab. Not in scope to invent a third pane state. - -## Precedent (local reference checkouts; names omitted from this file on purpose) - -A peer agent-session tracker in the local reference tree uses this exact state machine for hook-driven session status: - -- `userPromptSubmit` / `preToolUse` / `postToolUse` → working -- `stop` → **idle** -- `subagentStop` → **unchanged** (a child finishing does not make the parent working) -- process-exit is a backstop only for a session that has **ended**, not for leftover children of a live idle parent - -That is the same split this plan uses: lead Stop is idle; leftover child processes are session inventory; dead-pane recovery is a different ticket. - -I did not find a peer that treats “provider-owned background shell still running” as “the lead turn is still working.” If we kept that latch we would be the unusual one, and we would fail the acceptance oracle. - -## Acceptance (from `STA-4119-REPRO.md`) - -After implement, re-run the exact macOS repro: - -- TUI idle, `1 shell still running`, PTY alive -- card/tab **`done`** (not `working`) -- last-status not stuck on `SubagentStop` / `working` -- control (no shell) still `Stop` / `done` -- a turn that is actually running tools still shows `working` - -Do not implement until a Claude Fable review and a fresh Codex verify of this plan both return clean. diff --git a/STA-4119-REPRO.md b/STA-4119-REPRO.md deleted file mode 100644 index 161ebc49465..00000000000 --- a/STA-4119-REPRO.md +++ /dev/null @@ -1,162 +0,0 @@ -# STA-4119 reproduction - -**Verdict: reproduced on both macOS and Windows.** The reported mechanism is real and is not a Windows-only artifact. It is also not the phantom-working bug fixed by #14375 / #15082. - -The pane stays `working` after the lead turn ends because a live background shell (and a start-less `SubagentStop`) keeps the background-task / child gate up. The owning Claude PTY is still alive, sitting at an idle `❯` prompt. A hooks-independent PTY-liveness join (STA-4612 as specified) does **not** clear this case. - -## Builds - -| Surface | App | Contains #14375 / #15082 / #14580? | Claude Code | -| --- | --- | --- | --- | -| Local macOS Orca (authoritative "has the merged status PRs" build) | `1.4.185-adhoc.20260817215434` | Yes. Source worktree HEAD `8cd338357ee35e7348cb08d3a0522fee161b2e28` is a descendant of `d137bb93e1` (#14375), `60805f5c45` (#15082), and `5e9e38fa75` (#14580). The running adhoc binary stamps `turnCompletedAt` on the gated working row, which is the #14580 signal. | v2.1.233 | -| Windows high spec remote (`runtimeId` `70a74ef9-bd02-4f76-b08b-846e230d2dc5`) | `1.4.184` (runtime ready; desktop app not running) | No. 1.4.184 predates those merges. Confirmed in-product: the working row has **no** `turnCompletedAt`. | v2.1.234 | -| Windows low spec | Unreachable (`ok: false`) | n/a | n/a | - -This lane did not cherry-pick anything. The macOS run is the "still broken after the two merged status PRs" result. The Windows run is the original-platform result on the shipped 1.4.184 the reporter's era used. - -## Exact steps (what I actually ran) - -Throwaway fixture, not the orca repo (no setup hooks, no sibling-worktree discovery): - -1. Create `/tmp/sta-4119-bg-fixture` with `package.json` `dev` → `python3 serve.py` (sleeps 3600s). `orca repo add --path /tmp/sta-4119-bg-fixture`. -2. **macOS:** `orca worktree create --repo id:a2200db1-ead2-44b2-98ef-305f17644241 --name sta-4119-repro-macos --no-parent --agent claude --setup skip` - - handle `term_0a08d384-10a2-49ec-a5da-a6defc516cac` - - paneKey `b1a746f4-93d0-483a-9b56-841d3d38b3c5:45175c2f-d16d-4ff4-bc95-809fed804872` -3. **Windows:** `orca worktree create --environment "Windows high spec" --repo id:be84c937-38c9-426c-aa55-300e8f658a83 --name sta-4119-repro-win --no-parent --agent claude --setup skip` - - handle `term_ab5aff7b-d73e-4946-b445-dfdfc729b68f` - - paneKey `0eefb1da-3af1-40cb-ab8c-309eea05e5cb:d96df5f8-1870-42e2-b11b-a50bbc6c6985` - - path `C:/Users/neil/orca/workspaces/orca-setup-shell-repro/sta-4119-repro-win` -4. Accept Claude's workspace-trust prompt (`1. Yes, I trust this folder`). -5. Send the same lead prompt on both panes: - - > Do exactly these steps, then end your turn. Do not start a subagent. Do not ask questions. - > 1. Start this long-lived process as a background/async Bash shell and do NOT wait for it to exit: `python3 -c "import time; print(\"sta-4119-bg-started\", flush=True); time.sleep(3600)"` (fallback `python` / `sleep 3600`). - > 2. Confirm the process is running in the background. - > 3. Reply with exactly `STA-4119-TURN-DONE`. - -6. Wait until `orca terminal wait --for tui-idle` is satisfied and the TUI shows the final assistant line plus an idle `❯`. -7. Read `last-status.json` for that pane and `orca worktree ps` card/agent state. Re-check ~5 minutes later. - -**Control (same macOS adhoc build, no background work):** worktree `sta-4119-control-macos`, prompt "Reply with exactly STA-4119-CONTROL-DONE and end your turn. Do not run any shell command." - -## What I observed - -### Both platforms (the reported bug) - -After the lead printed `STA-4119-TURN-DONE`: - -- Claude TUI sat at an idle `❯`. Footer: `1 shell` / `1 shell still running`. Status line also showed `← for agents` even though the prompt forbade a subagent. -- `orca terminal wait --for tui-idle` returned satisfied. The PTY was still running. -- Worktree card / agent row stayed `working`. Windows tab title kept the working glyph (`✳ STA-4119 background shell test`). -- Last hook Orca stored for the pane was **`SubagentStop` with `payload.state: "working"`**. No later hook arrived while the background shell lived. -- The `SubagentStop` carried a `toolAgentId` that never had a matching visible `SubagentStart` in the pane status. That matches the already-measured fact that start-less `SubagentStop` is native traffic. - -Re-check at 16:37:44 local, ~5 minutes after the macOS `SubagentStop` (16:32:58) and the Windows one (`receivedAt` 1787009583714): **same last event, still `working`.** This is not a brief race. - -Windows extra: Claude printed `Background command "Start long-lived background process" failed with exit code 49` and still showed `1 shell still running`. The inventory Orca consumed was still a live shell as far as Claude's own status line was concerned. - -### macOS 1.4.185-adhoc (has #14375 / #15082 / #14580) - -`~/Library/Application Support/orca/agent-hooks/last-status.json` pane entry (full dump: `sta-4119-macos-last-status-entry.json`): - -```json -{ - "hookEventName": "SubagentStop", - "toolAgentId": "ac4a0c329a0e18cd9", - "payload": { - "state": "working", - "lastAssistantMessage": "STA-4119-TURN-DONE", - "toolName": "Bash", - "turnCompletedAt": 1787009576866 - }, - "receivedAt": 1787009578408, - "stateStartedAt": 1787009567895 -} -``` - -`orca worktree ps`: card `status=working`, agent `state=working`, last message `STA-4119-TURN-DONE`. Unchanged 5 minutes later. - -`turnCompletedAt` is present. That is the #14580 stamp: lead `Stop` was gated back up to `working` by the background shell, and the listener recorded the turn-end time so the completion coordinator *can* announce without waiting for `done`. - -### Windows 1.4.184 (original platform, pre-#14580) - -`C:\Users\neil\AppData\Roaming\orca\agent-hooks\last-status.json` for pane `0eefb1da-…:d96df5f8-…` (fields: `sta-4119-windows-last-status-fields.json`; full entry on the host at `sta-4119-win-last-status.json` in that worktree): - -- `hookEventName=SubagentStop` -- `state=working` -- `turnCompletedAt=None` — **not in `payloadKeys`** -- `lastAssistantMessage=STA-4119-TURN-DONE` -- `toolName=Read` -- `toolAgentId=a0dc6d9fd3ea4d8be` -- `receivedAt=1787009583714` - -This is the reporter's evidence, reproduced on the reported OS, on 1.4.184. - -### Control (macOS adhoc, no background shell) - -```json -{ - "hookEventName": "Stop", - "payload": { - "state": "done", - "lastAssistantMessage": "STA-4119-CONTROL-DONE" - } -} -``` - -Card `status=active`, agent `state=done`. Same build, same Claude major, no background inventory → the working→done edge happens. - -## Did the completion notification fire? - -| Build | Notification | -| --- | --- | -| Windows 1.4.184 | **No path for it to fire.** Last row is `working` with no `turnCompletedAt` and no later `done`. The old coordinator only announces on a working→done (or equivalent) edge. Matches the reporter ("no completion notification, no sound, no chip"). | -| macOS 1.4.185-adhoc | **Stamp present, banner not independently observed.** The gated working row carries `turnCompletedAt=1787009576866`, which is exactly the signal #14580 added so the coordinator can announce the finished turn while the pane stays `working`. I searched `~/Library/Application Support/orca/logs/main.trace.ndjson` and `daemon.log` for `agent-task-complete` / this paneKey / `STA-4119-TURN-DONE` and found no dispatch log. I did not see an OS banner from this session. I am **not** claiming the live banner fired; I am claiming the data the coordinator needs is on the row. | - -#14580 (`fix(agent-status): announce Claude turn complete while background work runs`) is already on this source HEAD. #14620 (stop *rendering* the leftover gate as foreground work) was **closed unmerged**. So on current main the remaining user-visible half of STA-4119 is the spinner/card staying "Claude is working right now" while the TUI is idle. - -## Mechanism (checked against this tree, not the handoff line numbers) - -`resolveClaudePaneState` (`src/shared/agent-hook-listener.ts`) returns `working` when the lead is `done` if a roster child is working **or** `claudeRunningNonAgentTaskPaneKeys` / session-cron gates are set. - -`updateClaudeRunningNonAgentTask` runs on lead events that carry `background_tasks`. A running `type: "shell"` is a non-agent task (`src/shared/claude-background-task-inventory.ts`). Folding the inventory into the roster happens on a **lead turn boundary** (`Stop` / `StopFailure`). An idle parent never emits another inventory. - -A later start-less `SubagentStop` (native traffic; we saw one on both platforms after a prompt that forbade subagents) re-emits the cached lead as `working`. That is why `last-status.json` ends on `SubagentStop` / `working` — same as the reporter — rather than on the lead `Stop`. - -This is **not** the #14375 phantom: the gate has positive evidence (Claude's own "1 shell still running", a `turnCompletedAt` stamp on the adhoc build, a live PTY). Working is what the current state machine intends given that inventory. - -## STA-4612 subsumption verdict: **does not subsume this case** - -STA-4612 proposes a hooks-independent backstop that is either: - -1. process-exit of the owning agent, keyed by pid + start time, or -2. a read-time liveness join with "the owning session/PTY is still live" - -so a *dead* pane cannot stay `working`. - -**Here the pane is alive.** Claude is at an idle prompt. `orca terminal wait --for tui-idle` succeeds. The background shell is a **child of that still-live PTY**, not a replacement for it. Intersecting status with "PTY live" still yields live + `working`. Process-exit never fires because the Claude process has not exited. - -STA-4612's write-up also lists "background-task gate never refreshed" for the *other* failure: a background task **ends** while the parent stays idle, so the inventory is stale and nothing clears the gate. That is a sibling, not this ticket. This ticket's reporter case is "the shell is still running, the turn is over, stop looking like foreground work / fire the finish notification." PTY liveness does not distinguish those. - -A TUI-idle → `done` fallback (the reporter's first suggestion) would also fight keep-awake / hibernation, which currently treat `state !== 'done'` as live work. #14620's closed approach — keep `state=working` for those systems, but stop *drawing* it as foreground activity — is the product-shaped remaining fix if notification-on-`turnCompletedAt` is accepted as sufficient for the banner half. - -## Post-fix (this worktree) - -Plan: `STA-4119-PLAN.md`. Reviewed CLEAN by Claude Fable (`task_599c4da8f712`) then independently verified CLEAN by a fresh Codex worker (`task_fa35d597c48c`) before any production edit. - -The reporter sequence is now a unit test (`does not hold a finished lead at working for a leftover background shell`). It was **red** on the pre-change listener (`Stop` + running shell published `working`) and is **green** after removing leftover shells from `resolveClaudePaneState` / the two sibling predicates. - -147 related tests pass (`claude-background-task-status`, Claude subagent listener, background-turn notifications, last-status write/lead-boundary, hook ingest, interrupt inference, relay hook server). - -Live UI re-run against this commit is **not** possible in the currently running desktop (`1.4.185-adhoc.20260817215434`): that binary does not load this worktree. The leftover `sta-4119-repro-macos` / `sta-4119-repro-win` panes will stay `working` until a build that contains this change processes a new hook (or the session is restarted on that build). - -## What is left - -- Merge the PR that implements `STA-4119-PLAN.md`. -- Re-run the live macOS repro on a desktop that includes this commit: card/tab must be `done` while `1 shell still running`. -- Repro worktrees left running on purpose: `sta-4119-repro-macos` (local) and `sta-4119-repro-win` (Windows high spec). Kill the background `sleep`/python if they should not keep a core parked. - -## Evidence files - -- `sta-4119-macos-last-status-entry.json` — full local last-status rows for repro + control -- `sta-4119-windows-last-status-fields.json` — extracted Windows last-status fields diff --git a/sta-4119-macos-last-status-entry.json b/sta-4119-macos-last-status-entry.json deleted file mode 100644 index 3627aa25fef..00000000000 --- a/sta-4119-macos-last-status-entry.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "capturedAtLocal": "2026-08-17T16:37:44-07:00", - "localAppVersion": "1.4.185-adhoc.20260817215434", - "sourceWorktreeHead": "8cd338357ee35e7348cb08d3a0522fee161b2e28", - "reproPane": { - "paneKey": "b1a746f4-93d0-483a-9b56-841d3d38b3c5:45175c2f-d16d-4ff4-bc95-809fed804872", - "source": "claude", - "tabId": "b1a746f4-93d0-483a-9b56-841d3d38b3c5", - "worktreeId": "a2200db1-ead2-44b2-98ef-305f17644241::/Users/brennanbenson/orca/workspaces/sta-4119-bg-fixture/sta-4119-repro-macos", - "connectionId": null, - "hasExplicitPrompt": false, - "hookEventName": "SubagentStop", - "providerPromptId": "cd77def5-25b9-40b3-a721-b4a66b6c8004", - "toolAgentId": "ac4a0c329a0e18cd9", - "providerSession": { - "key": "session_id", - "id": "4598b6d9-e09d-4a1c-896a-df301d180f44", - "transcriptPath": "/Users/brennanbenson/.claude/projects/-Users-brennanbenson-orca-workspaces-sta-4119-bg-fixture-sta-4119-repro-macos/4598b6d9-e09d-4a1c-896a-df301d180f44.jsonl" - }, - "payload": { - "state": "working", - "prompt": "Do exactly these steps, then end your turn. Do not start a subagent. Do not ask questions. 1. Start this long-lived process as a background/async Bash shell and do NOT wait for it to exit: python3 ", - "agentType": "claude", - "toolName": "Bash", - "toolInput": "cat /private/tmp/claude-501/-Users-brennanbenson-orca-workspaces-sta-4119-bg-fixture-sta-4119-repro-macos/4598b6d9-e09d-4a1c-896a-df301d180f44/tasks/b0icpu59e.o", - "lastAssistantMessage": "STA-4119-TURN-DONE", - "turnCompletedAt": 1787009576866 - }, - "receivedAt": 1787009578408, - "stateStartedAt": 1787009567895, - "launchTokenHash": "dee6f186298eb5a60bb0a854ae0a6ced88cebfa4dc3988bd5dc48d84cce6896c" - }, - "controlPane": { - "paneKey": "032f97d0-4e98-4833-a2c9-b360e1ecd162:92bc0766-7177-4cd6-89dd-a45130e36e70", - "source": "claude", - "tabId": "032f97d0-4e98-4833-a2c9-b360e1ecd162", - "worktreeId": "a2200db1-ead2-44b2-98ef-305f17644241::/Users/brennanbenson/orca/workspaces/sta-4119-bg-fixture/sta-4119-control-macos", - "connectionId": null, - "hasExplicitPrompt": false, - "hookEventName": "Stop", - "providerPromptId": "982d1b47-9d7b-47d0-bfb3-ccfb217e850d", - "providerSession": { - "key": "session_id", - "id": "e8ddb7ac-d5ec-424f-bead-4b76ff64ce16", - "transcriptPath": "/Users/brennanbenson/.claude/projects/-Users-brennanbenson-orca-workspaces-sta-4119-bg-fixture-sta-4119-control-macos/e8ddb7ac-d5ec-424f-bead-4b76ff64ce16.jsonl" - }, - "payload": { - "state": "done", - "prompt": "Reply with exactly STA-4119-CONTROL-DONE and end your turn. Do not run any shell command. Do not start a background process. Do not start a subagent.", - "agentType": "claude", - "lastAssistantMessage": "STA-4119-CONTROL-DONE" - }, - "receivedAt": 1787009672621, - "stateStartedAt": 1787009672621, - "launchTokenHash": "e3a4bc871a4a496087b8f220b65468476673ab9a7d297e9b7da4f5c4a7d5956f" - } -} diff --git a/sta-4119-windows-last-status-fields.json b/sta-4119-windows-last-status-fields.json deleted file mode 100644 index 93ed34dceb3..00000000000 --- a/sta-4119-windows-last-status-fields.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "capturedAtLocal": "2026-08-17T16:38:30-07:00", - "windowsEnvironment": "Windows high spec", - "windowsAppVersion": "1.4.184", - "windowsRuntimeId": "70a74ef9-bd02-4f76-b08b-846e230d2dc5", - "lastStatusPath": "C:\\Users\\neil\\AppData\\Roaming\\orca\\agent-hooks\\last-status.json", - "paneKey": "0eefb1da-3af1-40cb-ab8c-309eea05e5cb:d96df5f8-1870-42e2-b11b-a50bbc6c6985", - "hookEventName": "SubagentStop", - "state": "working", - "turnCompletedAt": null, - "lastAssistantMessage": "STA-4119-TURN-DONE", - "toolName": "Read", - "toolAgentId": "a0dc6d9fd3ea4d8be", - "receivedAt": 1787009583714, - "stateStartedAt": 1787009565488, - "payloadKeys": ["state", "prompt", "agentType", "toolName", "toolInput", "lastAssistantMessage"], - "subagents": null, - "note": "Fields extracted on the Windows host from last-status.json. Full entry also written on that host as C:/Users/neil/orca/workspaces/orca-setup-shell-repro/sta-4119-repro-win/sta-4119-win-last-status.json" -}