{
 "model": "claude-haiku-5-5",
 "category": "background",
 "scenarios": [
  {
   "id": "d1-two-servers",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Both servers started on 8810 and 8811, and curl returned 200 on each. TaskStop on the first reported exit 143 and status stopped. Curl then got exit 7 on 8810 and 200 on 8811, and TaskOutput reported stopped/143 and running. Exit code 0, turn-complete, 8/8 tool pairs adjacent, driver.err empty, leftovers empty (8811 gone after driver exit, none listening at review). Cost recomputed to $0.0020896, an exact match, with 94350 cache-read tokens.",
   "notes": "tasks frames tracked each state change. The request had 31 tools, including Skill with the 6 bundled skills and TeamMemoryWrite, and no mcp__* or DeferredToolCall tool. There is no learned/patterns.json, which is correct because no check command ran, and no ~/.gcode/auth or dsh folder. The model made one extra Bash call first (ls plus lsof), which is harmless."
  },
  {
   "id": "d2-bad-bg-command",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "The bad command reported failed, exit 127, with 'bash: definitely-not-a-command: command not found'. The sh command ran about 1 s and reported failed, exit 3, with output starting/crashed. TaskOutput said 'failed, exit code 3'. Both Bash states are failed, tasks frames show failed/127 and failed/3, and nothing hung. Exit code 0, 3/3 pairs, leftovers empty. Cost matches at $0.00110592.",
   "notes": "The exit code appears three times in the model-facing result, which is known and reads fine. The ended-task notice did not repeat either failure, since each was already reported in its own tool result. The model correctly noted that the output merges stdout and stderr."
  },
  {
   "id": "d3-unicode-bg",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Six lines of Chinese, ✅, ANSI colour and ZWJ emoji came through intact in the Bash start result, both TaskOutput results and all tasks frame tails. There are 0 U+FFFD and no mojibake patterns in the log, and 0 U+FFFD in the saved session. outputBytes grew by exactly 54 per line (54 to 324), matching my byte count of the line. ESC bytes stayed raw. Exit code 0, 3/3 pairs, leftovers empty. Cost matches at $0.00124632.",
   "notes": "Model behaviour, not a G-Code defect: the model sent both TaskOutput calls in one reply about 1.3 s after the 2 s start wait, by which time the task had just finished, so both honestly read 'completed, exit code 0'. No TaskOutput read happened while it was running; the running-state output was the Bash start result ('Output so far', lines 1-4). The final reply wrongly says the first TaskOutput came while running and showed lines 1-4. The model's displayed text dropped the ESC bytes and it said so."
  },
  {
   "id": "d4-watcher-left-running",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "node --watch started and curl returned 'ok'. After FileEdit, the task output showed 'Change detected'/'Restarting' and curl returned 'updated'. The watcher was left running as asked and the reply said it ends with the session. After driver exit, leftovers are empty (no process on the run path, port free), including the --watch child. I ran server.mjs on a scratch port: it returned 'updated', and I stopped it. Exit code 0, 7/7 pairs. Cost matches at $0.001592185.",
   "notes": "The outputs frame recorded the FileEdit baseline and new version. 'No output yet.' is accurate because the server prints nothing at start."
  },
  {
   "id": "d5-max-bg",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Eight tasks started. #9 got 'Error: 8 background tasks are already running. Stop one with TaskStop first.' and settled as failed. #10 got the repeat-guard 'Not run: this exact Bash call failed…' and settled as refused, as this round requires. All 8 TaskStops returned exit 143, the tasks frame shows all 8 stopped, and TaskList's backgroundShells lists 8, each 'stopped, exit code 143'. The model's report is accurate. Exit code 0, 19/19 pairs, leftovers empty. Cost matches at $0.00255568.",
   "notes": "#9 and #10 differ only in description, and failureBudget.ts:57-62 deliberately drops the Bash description from the call's identity, so 'this exact Bash call' is by design. The model batched all 10 calls in one reply and did not retry after stopping. Each start waits about 2 s when there is no output. The runner's leftover check cannot see a bare 'sleep 300' by path, but every TaskStop confirmed exit 143 and no sleep process remained at review. Driver toolFailures 2 counts the failed and the refused call. The 18 tool-use versus 19 tool-result frames are the known no-tool-use-frame case for a refused call."
  },
  {
   "id": "d6-interrupt-resume",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "SIGINT arrived during TaskStop. The error frame read 'Stopped before this turn finished.' TaskStop's result stated the SIGTERM/SIGKILL note once, and the unstarted FileEdit read 'Not run: the turn was stopped…'. Both settled cancelled. The partial turn was saved with an incomplete marker and tool results, and the resume context correctly said bg-a267f769 was stopped with the process. Port 8835 was free on resume. The resumed session (same id, no 400) did not repeat npm init, install or file creation; it added /time, restarted, verified and stopped the server. Both exit codes 0, 14/14 pairs, leftovers empty. Cost matches at $0.00345817 over 10 requests. I ran the final app on a scratch port: /health and /time both worked, and I stopped it.",
   "notes": "Stopping the server to add /time before the interrupt was the model's plan, so the interrupted TaskStop was its own step. Restarting the server and re-checking /health after the restart is reasonable. The 13 tool-use versus 14 tool-result frames come from the never-started FileEdit, which has no tool-use frame. No learned/patterns.json, which is correct because npm init/i and curl are not checks."
  },
  {
   "id": "d7-sigkill-orphan",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "The CLI was SIGKILLed during the foreground 'sleep 200' (exit 137, exitedEarly, by design). result.json shows killed: true and serverGoneMs: 1082, inside the ~5 s limit. Leftovers empty, driver.err empty. The saved session is valid with 3/3 pairs: a 'No result was recorded: the process ended…' synthetic result plus an '[The process ended before this turn finished…]' marker. Cost matches at $0.00078323.",
   "notes": "The last Bash card is saved as 'running' and is settled to cancelled on load (state/store.ts:473, code read; no resume in this scenario). The runner's leftover check matches on the run path, so it cannot see a bare 'sleep 200'. To cover that gap I ran snapshot10y's runSubprocess with BashTool's options (group, killOnExit) in a temporary script and SIGKILLed the script. The foreground sleep was gone within 0.5 s and the watchdog exited afterwards. This is a code-level probe, not evidence from this run's own sleep, which had expired by review. I removed the script. The model prefixed the start with 'ls -la server.mjs &&', which is harmless."
  }
 ]
}