{
 "model": "claude-haiku-5-5",
 "category": "background",
 "scenarios": [
  {
   "id": "d1-two-servers",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Started servers on 8810 and 8811 and curl returned 200 on both. TaskStop on the first returned exit 143 with status stopped; curl then got exit 7 on 8810 and 200 on 8811. TaskOutput reported stopped/143 and running. I checked exit code 0, turn-complete, 7/7 tool pairs in adjacent messages, leftovers empty, and that 8811 was gone after driver exit. Cost recomputed to $0.00184796, matching result.json.",
   "notes": "Tool states were all complete and tasks frames tracked each state change. The request had 31 tools, including Skill with the 6 bundled skills and TeamMemoryWrite, with no MCP or DeferredToolCall. No learned/patterns.json, which is correct because no verification command ran. The model batched the two starts."
  },
  {
   "id": "d2-bad-bg-command",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "The bad command reported failed with exit 127 and the stderr line; the sh command reported failed with exit 3 and output 'starting/crashed'. Both tool states were failed, tasks frames showed failed, and TaskOutput gave the same codes. There was no hang. Exit code 0, leftovers empty, 4/4 pairs, cost matches at $0.001119685.",
   "notes": "The exit code appears three times in the model-facing result, which is known and reads fine. The model correctly noted that TaskOutput merges stdout and stderr."
  },
  {
   "id": "d3-unicode-bg",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Six lines of Chinese, ✅, ANSI colour and ZWJ emoji were read intact twice: once while running (header 'running') and once after finishing ('completed, exit code 0'). There were 0 U+FFFD and 0 lone surrogates across the log and saved session, including tasks frame tails. Bytes 54 to 324 grew by 54 per line. ESC bytes were kept raw. Exit code 0, leftovers empty, 3/3 pairs, cost matches at $0.00136247.",
   "notes": "Model misstatement, not a G-Code defect: its final reply says the first TaskOutput returned lines 1 to 4 and that 5 and 6 had not been printed. The frame shows that read returned all 6 lines with status running, while Python was in its last sleep; the 4-line output was the Bash start result. 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. After driver exit, result.json leftovers were empty (no node process, port free), and nothing from the run was present when I rechecked. I ran the project's server.mjs on a scratch port: it returned 'updated', and I stopped it. Cost matches at $0.001605255.",
   "notes": "The FileEdit outputs frame recorded the baseline and new version correctly. The server's own listening output is empty by design, so 'No output yet.' is accurate."
  },
  {
   "id": "d5-max-bg",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "Eight tasks started. #9 got the clear 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. All 10 tasks ended stopped/143 and TaskList listed 10 backgroundShells, all 'stopped, exit code 143'. Leftovers empty, 23/23 pairs, cost matches at $0.00334786.",
   "notes": "The model stopped two tasks and retried #9 and #10 so that all 10 did start, then stopped everything. That is a reasonable reading of the request. Driver toolFailures 2 counts both the failed and the refused call, and tool-use frames (22) are one fewer than tool-result frames (23) because the refused call has no tool-use frame, as designed."
  },
  {
   "id": "d6-interrupt-resume",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "SIGINT arrived during TaskStop. The error frame read 'Stopped before this turn finished.', TaskStop reported 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 synthetic results, and the shell died: 8835 was refused 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. 14/14 pairs, both exit codes 0, leftovers empty, cost matches at $0.00366555. I ran the final app on a scratch port: /health and /time both worked, and I stopped it.",
   "notes": "Resume context correctly stated that bg-1cebd44c was stopped when the process ended. The model re-ran /health on the new process, which is reasonable after a restart. No learned/patterns.json: `test -f` and `npm i` are correctly not treated as checks."
  },
  {
   "id": "d7-sigkill-orphan",
   "status": "pass",
   "product_defects": [],
   "task_outcome": "CLI was killed with SIGKILL during the foreground `sleep 200` (exit 137, exitedEarly, by design). result.json shows killed: true and serverGoneMs: 353, well inside the ~5 s limit. Leftovers empty and driver.err empty. The session JSON is valid, with 3/3 pairs and an '[Interrupted: the process ended before this turn finished…]' marker. Cost matches at $0.000910065.",
   "notes": "The last saved card for the sleep call is 'preparing' because the checkpoint preceded the kill by about 170 ms; store.ts:473 settles non-terminal cards as cancelled on load (code read, not run). The runner's leftover check matches on the run path, so it would not catch a bare `sleep 200`. Bash passes killOnExit: true (BashTool.ts:1190), which puts it under the group watchdog; this is from reading code, not live evidence, and the sleep had expired by review time. No resume is part of this scenario."
  }
 ]
}