From 89d967c81dbb9a2df2cc8f031abc7d22210e1cb6 Mon Sep 17 00:00:00 2001 From: harishghasolia07 <100846446+harishghasolia07@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:45:17 +0000 Subject: [PATCH] Record the board-write cassettes, and fix the two bugs recording exposed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BOARD_AGENT_WRITES shipped with no recordings, so the one mode that shows an agent being refused by a gate was the one mode nobody could watch. A flag that is documented and never exercised is the same shape as the four unreachable modules this repo has already shipped. Now it replays offline on both providers, no key. Recording one scenario before all sixteen paid for itself twice: - create_task listed `description` as optional while the gate requires it. The tool was lying to the model about what a valid write looks like, and the model believed it: five refusals in one run, every one the schema's fault. Required now, and the parent_id description says to read the parent's comments first because the evidence gate will ask. - Operations were attributed to planned actions by exact signature only. The agent is invited to reword, so it commented on the right card in its own words, the signature missed, and Pass 2d reported "no comment landed on t200" for a comment plainly visible in the trace landing on t200. The write was correct and the attribution was wrong, which is worse than the reverse: it makes a working run look broken and teaches a reader to discount the audit. Matching now falls back to the target card, leaving Pass 2d free to ask its own question. What the recordings actually show, which is why they were worth buying: the agent reads cards and their history before writing, then departs from the plan where the board tells it something the pipeline could not — commenting on the duplicate's card rather than silently skipping it, and filing the email copy as a subtask of the redesign it had just read. 55 new cassettes, both providers. Zero drift across all seven demo modes: the tool list is part of the prompt fingerprint, so that zero is what proves the write tools did not leak into the read-only path. --- README.md | 16 ++++-- .../01-meeting-mixed/board/write/turn-1.json | 12 +++++ .../board/write/turn-1.json.sha | 1 + .../01-meeting-mixed/board/write/turn-2.json | 33 ++++++++++++ .../board/write/turn-2.json.sha | 1 + .../01-meeting-mixed/board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../board/write/turn-1.json | 19 +++++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 21 ++++++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../board/write/turn-1.json | 12 +++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 33 ++++++++++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../05-corrections/board/write/turn-1.json | 15 ++++++ .../board/write/turn-1.json.sha | 1 + .../05-corrections/board/write/turn-2.txt | 1 + .../05-corrections/board/write/turn-2.txt.sha | 1 + .../board/write/turn-1.json | 19 +++++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 19 +++++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.json | 34 ++++++++++++ .../board/write/turn-3.json.sha | 1 + .../06-github-activity/board/write/turn-4.txt | 1 + .../board/write/turn-4.txt.sha | 1 + .../07-email-thread/board/write/turn-1.json | 15 ++++++ .../board/write/turn-1.json.sha | 1 + .../07-email-thread/board/write/turn-2.txt | 1 + .../board/write/turn-2.txt.sha | 1 + .../08-drive-activity/board/write/turn-1.txt | 1 + .../board/write/turn-1.txt.sha | 1 + .../01-meeting-mixed/board/write/turn-1.json | 47 +++++++++++++++++ .../board/write/turn-1.json.sha | 1 + .../01-meeting-mixed/board/write/turn-2.json | 52 +++++++++++++++++++ .../board/write/turn-2.json.sha | 1 + .../01-meeting-mixed/board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../board/write/turn-1.json | 33 ++++++++++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 21 ++++++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../board/write/turn-1.json | 40 ++++++++++++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 43 +++++++++++++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + .../05-corrections/board/write/turn-1.json | 19 +++++++ .../board/write/turn-1.json.sha | 1 + .../05-corrections/board/write/turn-2.json | 15 ++++++ .../board/write/turn-2.json.sha | 1 + .../05-corrections/board/write/turn-3.txt | 1 + .../05-corrections/board/write/turn-3.txt.sha | 1 + .../board/write/turn-1.json | 12 +++++ .../board/write/turn-1.json.sha | 1 + .../board/write/turn-2.json | 12 +++++ .../board/write/turn-2.json.sha | 1 + .../board/write/turn-3.json | 13 +++++ .../board/write/turn-3.json.sha | 1 + .../06-github-activity/board/write/turn-4.txt | 1 + .../board/write/turn-4.txt.sha | 1 + .../07-email-thread/board/write/turn-1.json | 19 +++++++ .../board/write/turn-1.json.sha | 1 + .../07-email-thread/board/write/turn-2.json | 19 +++++++ .../board/write/turn-2.json.sha | 1 + .../07-email-thread/board/write/turn-3.json | 23 ++++++++ .../board/write/turn-3.json.sha | 1 + .../07-email-thread/board/write/turn-4.txt | 4 ++ .../board/write/turn-4.txt.sha | 1 + .../08-drive-activity/board/write/turn-1.json | 19 +++++++ .../board/write/turn-1.json.sha | 1 + .../08-drive-activity/board/write/turn-2.json | 27 ++++++++++ .../board/write/turn-2.json.sha | 1 + .../08-drive-activity/board/write/turn-3.txt | 1 + .../board/write/turn-3.txt.sha | 1 + src/agents/boardAgent.ts | 29 +++++++++-- src/cli/record.ts | 11 +++- src/pipeline/toolLoop.ts | 18 +++++-- 86 files changed, 765 insertions(+), 13 deletions(-) create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt create mode 100644 fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt create mode 100644 fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt create mode 100644 fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt.sha create mode 100644 fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt create mode 100644 fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt.sha create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt.sha create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json.sha create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt create mode 100644 fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt.sha create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json.sha create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt create mode 100644 fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt.sha create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json.sha create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json.sha create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt create mode 100644 fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt.sha diff --git a/README.md b/README.md index c2881d5..e474e07 100644 --- a/README.md +++ b/README.md @@ -114,10 +114,18 @@ npm run demo -- --agents # with the agent layer on (see AGENTS.md) A redelivery costs nothing, and the check that stops it runs *before* the first token is spent rather than discarding a finished run at the end. -**`--board-writes` has no recorded cassettes and will not replay offline.** The flag is real (see -[AGENTS.md](AGENTS.md)), but recording that mode needs live API keys against both providers, so -`npm run demo -- --agents --board-writes` stops on a missing cassette rather than running green -having done nothing. That error is the intended behaviour, not a broken build. +**The board agent can also do the writing, and that replays offline too:** + +```bash +npm run demo -- --agents --board-writes # PRD §5's "authority to write", the shape production runs +``` + +Worth watching rather than skimming. The agent reads the cards and their comment history *before* +writing, then departs from the plan where the board tells it something the pipeline could not — on +`01-meeting-mixed` it comments on the duplicate's card instead of silently skipping it, and files the +email copy as a subtask of the redesign it had just read. Every write it originates is re-run through +the same deterministic gates first, so one the gates refuse becomes a hold rather than a card. Off by +default; see [AGENTS.md](AGENTS.md) and [SECURITY.md](SECURITY.md) for what each mode guarantees. ``` ▶ 01-meeting-mixed — A normal standup: four categories exercised, four cards created, one duplicate diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json new file mode 100644 index 0000000..92021ed --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json @@ -0,0 +1,12 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01HGMH6E5yjhkbDk7KMAWzd2", + "name": "get_task_comments", + "arguments": { + "task_id": "t200" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json.sha new file mode 100644 index 0000000..c2da385 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-1.json.sha @@ -0,0 +1 @@ +bebc72d6a42d \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json new file mode 100644 index 0000000..f777d55 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json @@ -0,0 +1,33 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01F9TqfjGHTutbqfWR29AG6q", + "name": "add_comment", + "arguments": { + "task_id": "t200", + "body": "Rate limiting sign-off pending." + } + }, + { + "id": "toolu_017k9qZfz7DFk7pNJrVm8vpx", + "name": "create_task", + "arguments": { + "title": "Add request-size cap on upload endpoint", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Add a request-size cap on the upload endpoint to prevent oversized uploads." + } + }, + { + "id": "toolu_01URuuNrGnqASXeubumyUosS", + "name": "create_task", + "arguments": { + "title": "Write spec for usage-based billing idea", + "list_key": "product", + "assignee": "Jules Kim", + "description": "Write a spec exploring the usage-based billing idea." + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json.sha b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json.sha new file mode 100644 index 0000000..3d76c82 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-2.json.sha @@ -0,0 +1 @@ +4bd62dfb246d \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt new file mode 100644 index 0000000..01a2065 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt @@ -0,0 +1 @@ +All three items have been written to the board. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt.sha b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt.sha new file mode 100644 index 0000000..b0c05a9 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/01-meeting-mixed/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +cb2abfbd908e \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json new file mode 100644 index 0000000..25bf1b0 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01FAMhpQbuN8Gtp58bcoJx4P", + "name": "get_task_comments", + "arguments": { + "task_id": "t500" + } + }, + { + "id": "toolu_0162ggDZvNBA224ZuQ7ExvmB", + "name": "get_task_comments", + "arguments": { + "task_id": "t600" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json.sha new file mode 100644 index 0000000..0ec4d60 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-1.json.sha @@ -0,0 +1 @@ +c60b0d4cab3e \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json new file mode 100644 index 0000000..ef7dba1 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json @@ -0,0 +1,21 @@ +{ + "text": "Both items are duplicates of existing cards. I'll comment on each rather than create new cards.", + "toolCalls": [ + { + "id": "toolu_01Rf1qepasrCmkw3GFFVCTGH", + "name": "add_comment", + "arguments": { + "task_id": "t500", + "body": "Duplicate reported: \"Own onboarding revamp\" — this is the same work as this card (first-run experience for new signups). Tracking here instead of a new card." + } + }, + { + "id": "toolu_015xtxhC1nJN8syLrnmkHqg8", + "name": "add_comment", + "arguments": { + "task_id": "t600", + "body": "Duplicate reported: \"Handle partial deploy failures in pipeline\" — this is the same work as this card (deploy pipeline resilience to partial failures). Tracking here instead of a new card." + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json.sha b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json.sha new file mode 100644 index 0000000..cbbd874 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-2.json.sha @@ -0,0 +1 @@ +cd4208ee9b24 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt new file mode 100644 index 0000000..d432c88 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt @@ -0,0 +1 @@ +Both items accounted for as duplicates via comments on t500 and t600. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt.sha b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt.sha new file mode 100644 index 0000000..cf0bcce --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/02-meeting-duplicates/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +88b83a5bdc0a \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json new file mode 100644 index 0000000..b506c30 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json @@ -0,0 +1,12 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_012ayRxi2JsPjr68i4tJVSPE", + "name": "get_task_comments", + "arguments": { + "task_id": "t800" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json.sha new file mode 100644 index 0000000..a0ac90e --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-1.json.sha @@ -0,0 +1 @@ +57c5d925be9b \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json new file mode 100644 index 0000000..1a18434 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json @@ -0,0 +1,33 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01LWknZHU4WMqSmDbg6MNa4N", + "name": "create_task", + "arguments": { + "title": "Raise connection pool size and add alert", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Increase database/service connection pool size to handle load, and add an alert to monitor pool saturation going forward." + } + }, + { + "id": "toolu_011AM4bDVpfYCfQ1f6VezmTE", + "name": "create_task", + "arguments": { + "title": "Write runbook documentation", + "list_key": "backend", + "assignee": "Sky Patel", + "description": "Document operational runbook covering common issues, diagnostics, and remediation steps." + } + }, + { + "id": "toolu_01FJrtFAFkN2azke2uQHD72w", + "name": "add_comment", + "arguments": { + "task_id": "t800", + "body": "Status update: search relevance tuning work is ongoing." + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json.sha b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json.sha new file mode 100644 index 0000000..7849c27 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-2.json.sha @@ -0,0 +1 @@ +8cd00873ce55 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt new file mode 100644 index 0000000..bcd8995 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt @@ -0,0 +1 @@ +All three items have been written to the board successfully. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt.sha b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt.sha new file mode 100644 index 0000000..03c5807 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/04-channel-messages/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +e35c54adc857 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json new file mode 100644 index 0000000..8fa46b3 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json @@ -0,0 +1,15 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_018jAs3kiPpqNa6ASuEZfxrC", + "name": "create_task", + "arguments": { + "title": "Fix billing invoice API endpoint field bug", + "list_key": "backend", + "assignee": "Rowan Diaz", + "description": "Fix a field bug in the billing invoice API endpoint." + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json.sha new file mode 100644 index 0000000..e179715 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-1.json.sha @@ -0,0 +1 @@ +c3f3dcb0b8c3 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt new file mode 100644 index 0000000..ff81b53 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt @@ -0,0 +1 @@ +Created as mem-0001. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt.sha b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt.sha new file mode 100644 index 0000000..5cfad94 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/05-corrections/board/write/turn-2.txt.sha @@ -0,0 +1 @@ +a76958643bfa \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json new file mode 100644 index 0000000..dcf2179 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01EWT7XxBsdTvyN2SJQNhfqf", + "name": "get_task", + "arguments": { + "task_id": "t901" + } + }, + { + "id": "toolu_01RzkJ74ifkEqKUdcywDWLJP", + "name": "get_task", + "arguments": { + "task_id": "t900" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json.sha new file mode 100644 index 0000000..64995f8 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-1.json.sha @@ -0,0 +1 @@ +956191932ed7 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json new file mode 100644 index 0000000..1a56c5c --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_0184zXNXoP8t2W4asKQYoUnt", + "name": "get_task_comments", + "arguments": { + "task_id": "t901" + } + }, + { + "id": "toolu_01E829bgrHRKExGHm3e2N1xJ", + "name": "get_task_comments", + "arguments": { + "task_id": "t900" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json.sha b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json.sha new file mode 100644 index 0000000..ecfa0d7 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-2.json.sha @@ -0,0 +1 @@ +98e01d9ea856 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json new file mode 100644 index 0000000..1d156d6 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json @@ -0,0 +1,34 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_01J871fZzogMyY8bDfHSheRf", + "name": "create_task", + "arguments": { + "title": "Build rate limit usage dashboard", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Build a dashboard to visualize per-key API usage against rate limits, to help monitor and tune limits once rate limiting ships." + } + }, + { + "id": "toolu_01VC88djTumtVy1PtyBDRfrX", + "name": "add_comment", + "arguments": { + "task_id": "t901", + "body": "Refactor settings module: proceeding as tidy-up only, no behaviour change, per plan." + } + }, + { + "id": "toolu_01KN47a4wv4SLptQmgoRPr1p", + "name": "create_task", + "arguments": { + "title": "Fix off-by-one in the retry backoff", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Retry backoff calculation has an off-by-one error, contributing to the retry-loop overload issue described in the parent rate limiting task.", + "parent_id": "t900" + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json.sha b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json.sha new file mode 100644 index 0000000..ece7004 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-3.json.sha @@ -0,0 +1 @@ +fc279551be94 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt new file mode 100644 index 0000000..b189d13 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt @@ -0,0 +1 @@ +All three items written: new dashboard task created, settings cleanup update logged as a comment on t901, and the retry backoff fix created as a subtask of t900. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt.sha b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt.sha new file mode 100644 index 0000000..8cc71f3 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/06-github-activity/board/write/turn-4.txt.sha @@ -0,0 +1 @@ +2be68a247355 \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json new file mode 100644 index 0000000..b118085 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json @@ -0,0 +1,15 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "toolu_0186JYcEQMtmDaFwqnUQCzm4", + "name": "create_task", + "arguments": { + "title": "Add pagination to export endpoint", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Add pagination support to the export endpoint to handle large result sets efficiently." + } + } + ] +} diff --git a/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json.sha b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json.sha new file mode 100644 index 0000000..0447bf3 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-1.json.sha @@ -0,0 +1 @@ +18f8205132af \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt new file mode 100644 index 0000000..8e3ad53 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt @@ -0,0 +1 @@ +Task written to the board. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt.sha b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt.sha new file mode 100644 index 0000000..3514d15 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/07-email-thread/board/write/turn-2.txt.sha @@ -0,0 +1 @@ +6c5f2ea2f7cb \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt b/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt new file mode 100644 index 0000000..b760fdb --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt @@ -0,0 +1 @@ +No items were listed under the pipeline's decisions section — there is nothing to write to the board. Since the task is empty, there's nothing to reconcile against the existing card (t920), and no action is needed. \ No newline at end of file diff --git a/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt.sha b/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt.sha new file mode 100644 index 0000000..d2e3901 --- /dev/null +++ b/fixtures/cassettes-agents-anthropic/08-drive-activity/board/write/turn-1.txt.sha @@ -0,0 +1 @@ +8a92318e473c \ No newline at end of file diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json new file mode 100644 index 0000000..c8cfcd6 --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json @@ -0,0 +1,47 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_yMj3lgtFZpwRYLClWztX0716", + "name": "get_task", + "arguments": { + "task_id": "t100" + } + }, + { + "id": "call_01_xxZWYBmhme2Jznem4iJg9805", + "name": "get_task", + "arguments": { + "task_id": "t200" + } + }, + { + "id": "call_02_4HjHHTZuhCpekQ1GmGZJ0984", + "name": "get_task", + "arguments": { + "task_id": "t300" + } + }, + { + "id": "call_03_DRFP3TYcf5IGiLD5GPG33727", + "name": "get_task_comments", + "arguments": { + "task_id": "t100" + } + }, + { + "id": "call_04_t7fOMwqZTZb3u2QOl9rZ8162", + "name": "get_task_comments", + "arguments": { + "task_id": "t200" + } + }, + { + "id": "call_05_vWvn4BmbjY2fNv7XbQiL0478", + "name": "get_task_comments", + "arguments": { + "task_id": "t300" + } + } + ] +} diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json.sha b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json.sha new file mode 100644 index 0000000..2d2044d --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-1.json.sha @@ -0,0 +1 @@ +969bf48a0070 \ No newline at end of file diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json new file mode 100644 index 0000000..e8915c0 --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json @@ -0,0 +1,52 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_ecCSAu6kJP5TiaVIlCuj0017", + "name": "add_comment", + "arguments": { + "task_id": "t200", + "body": "Update: ship Public API rate limiting this Friday." + } + }, + { + "id": "call_01_sD8qZVPDd1sWssuF6vnv2545", + "name": "create_task", + "arguments": { + "title": "Add a hard request-size cap to the upload endpoint", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Add a hard cap on request body size for the upload endpoint and reject requests over the limit." + } + }, + { + "id": "call_02_ZtgN0G2i8n2R1S2pe88B0648", + "name": "create_task", + "arguments": { + "title": "Write welcome email copy for the onboarding revamp", + "list_key": "design", + "assignee": "Rowan Diaz", + "description": "Draft the welcome email copy that goes out to new users as part of the onboarding flow redesign.", + "parent_id": "t100" + } + }, + { + "id": "call_03_yTdtIHst29wejYpGNTLk9243", + "name": "add_comment", + "arguments": { + "task_id": "t300", + "body": "Duplicate item noted: \"Refresh pricing page copy this week\" is already covered by this card." + } + }, + { + "id": "call_04_KE4hyMT05FKDSdgKjxCe7071", + "name": "create_task", + "arguments": { + "title": "Write a written spec for usage-based billing", + "list_key": "product", + "assignee": "Jules Kim", + "description": "Produce a written specification for usage-based billing." + } + } + ] +} diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json.sha b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json.sha new file mode 100644 index 0000000..5347b2e --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-2.json.sha @@ -0,0 +1 @@ +98122ddb4325 \ No newline at end of file diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt new file mode 100644 index 0000000..51100b5 --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt @@ -0,0 +1 @@ +All items have been written or accounted for. \ No newline at end of file diff --git a/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt.sha b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt.sha new file mode 100644 index 0000000..7eede20 --- /dev/null +++ b/fixtures/cassettes-agents/01-meeting-mixed/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +4249cb9cc9e0 \ No newline at end of file diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json new file mode 100644 index 0000000..abb2925 --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json @@ -0,0 +1,33 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_xYqNiToFVHHWwkW1QWKS7389", + "name": "get_task", + "arguments": { + "task_id": "t500" + } + }, + { + "id": "call_01_hXS0pWiLOoM6dmLUkzOu5618", + "name": "get_task", + "arguments": { + "task_id": "t600" + } + }, + { + "id": "call_02_S1y17injNETRTXABoiks5136", + "name": "get_task_comments", + "arguments": { + "task_id": "t500" + } + }, + { + "id": "call_03_O9gmszRVuP9twgR4hOVW1889", + "name": "get_task_comments", + "arguments": { + "task_id": "t600" + } + } + ] +} diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json.sha b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json.sha new file mode 100644 index 0000000..6cd84b2 --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-1.json.sha @@ -0,0 +1 @@ +a5e0178b663f \ No newline at end of file diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json new file mode 100644 index 0000000..2e9f367 --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json @@ -0,0 +1,21 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_4qmhTyGSsebeRhTl7mHF2253", + "name": "add_comment", + "arguments": { + "task_id": "t500", + "body": "Pipeline flagged \"Own the onboarding revamp\" as a duplicate of this card — no new card created." + } + }, + { + "id": "call_01_8Qy3nVSvSXBtH8ClTZar4522", + "name": "add_comment", + "arguments": { + "task_id": "t600", + "body": "Pipeline flagged \"Make the pipeline handle partial failure properly\" as a duplicate of this card — no new card created." + } + } + ] +} diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json.sha b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json.sha new file mode 100644 index 0000000..f012258 --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-2.json.sha @@ -0,0 +1 @@ +5a246d2e6436 \ No newline at end of file diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt new file mode 100644 index 0000000..81af80c --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt @@ -0,0 +1 @@ +Both items were accounted for as duplicates of existing cards. I read t500 and t600 (and their comment histories) and added a comment to each card noting the pipeline's duplicate decision — no new cards were created. \ No newline at end of file diff --git a/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt.sha b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt.sha new file mode 100644 index 0000000..512485c --- /dev/null +++ b/fixtures/cassettes-agents/02-meeting-duplicates/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +cd8257df6a12 \ No newline at end of file diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json new file mode 100644 index 0000000..361b47d --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json @@ -0,0 +1,40 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_p27lH6hsrRNbCFR7Fcs44473", + "name": "get_task", + "arguments": { + "task_id": "t800" + } + }, + { + "id": "call_01_WstR976qXmTnPzmHPi3W4016", + "name": "get_task_comments", + "arguments": { + "task_id": "t800" + } + }, + { + "id": "call_02_EsFrxxZpCxvzpUcH3V3z7334", + "name": "search_tasks", + "arguments": { + "query": "pool size" + } + }, + { + "id": "call_03_FL7qN8BwXXq1XgulaMei8384", + "name": "search_tasks", + "arguments": { + "query": "pool exhaustion" + } + }, + { + "id": "call_04_0YsiySmUWDkUpZw0UD652246", + "name": "search_tasks", + "arguments": { + "query": "runbook" + } + } + ] +} diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json.sha b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json.sha new file mode 100644 index 0000000..c2ca34c --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-1.json.sha @@ -0,0 +1 @@ +5cfd9c66dd62 \ No newline at end of file diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json new file mode 100644 index 0000000..63b8ed3 --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json @@ -0,0 +1,43 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_ZyTAmNC89OibhnlALza95576", + "name": "create_task", + "arguments": { + "title": "Raise the pool size", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Increase the connection pool size to reduce pool exhaustion events." + } + }, + { + "id": "call_01_nEeDg28HRdA6ipEc6x7W7787", + "name": "create_task", + "arguments": { + "title": "Add an alert for connection pool exhaustion", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Add monitoring and alerting that fires when the connection pool is near exhaustion." + } + }, + { + "id": "call_02_Kc2DwP97UjmCnS4NEQil4708", + "name": "create_task", + "arguments": { + "title": "Document the runbook for the pool exhaustion issue", + "list_key": "backend", + "assignee": "Sky Patel", + "description": "Write the operational runbook covering detection and remediation steps for connection pool exhaustion." + } + }, + { + "id": "call_03_nxHH8tn8EsL1oL3ASQqc2755", + "name": "add_comment", + "arguments": { + "task_id": "t800", + "body": "Review search relevance work: reviewing the current search relevance tuning changes for correctness and impact." + } + } + ] +} diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json.sha b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json.sha new file mode 100644 index 0000000..1d66499 --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-2.json.sha @@ -0,0 +1 @@ +2cf5e970e977 \ No newline at end of file diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt new file mode 100644 index 0000000..69840e8 --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt @@ -0,0 +1 @@ +All four pipeline items have been written to the board. \ No newline at end of file diff --git a/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt.sha b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt.sha new file mode 100644 index 0000000..6061161 --- /dev/null +++ b/fixtures/cassettes-agents/04-channel-messages/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +f4b78d28018e \ No newline at end of file diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json b/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json new file mode 100644 index 0000000..dfccc4b --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_mZvCo18rgaSrbdP6Ym4o2284", + "name": "search_tasks", + "arguments": { + "query": "billing invoice API endpoint totals" + } + }, + { + "id": "call_01_6vZoiB9MXtPp2viWFMO30410", + "name": "search_tasks", + "arguments": { + "query": "invoice totals field" + } + } + ] +} diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json.sha b/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json.sha new file mode 100644 index 0000000..86b0b5e --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-1.json.sha @@ -0,0 +1 @@ +87457ba67dce \ No newline at end of file diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json b/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json new file mode 100644 index 0000000..9044ea9 --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json @@ -0,0 +1,15 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_sp7pq5pTNcPGL1QWMaWy7411", + "name": "create_task", + "arguments": { + "title": "Fix the billing invoice API endpoint totals field", + "list_key": "backend", + "assignee": "Rowan Diaz", + "description": "Fix the totals field on the billing invoice API endpoint so it returns the correct computed value." + } + } + ] +} diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json.sha b/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json.sha new file mode 100644 index 0000000..4ab1c71 --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-2.json.sha @@ -0,0 +1 @@ +1025026afcf0 \ No newline at end of file diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt b/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt new file mode 100644 index 0000000..3925a0d --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt @@ -0,0 +1 @@ +Done. \ No newline at end of file diff --git a/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt.sha b/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt.sha new file mode 100644 index 0000000..a5c51b8 --- /dev/null +++ b/fixtures/cassettes-agents/05-corrections/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +bcf094983e5e \ No newline at end of file diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json b/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json new file mode 100644 index 0000000..f44c059 --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json @@ -0,0 +1,12 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_HYO9BBzy856KYp5BKjNB4924", + "name": "get_task", + "arguments": { + "task_id": "t901" + } + } + ] +} diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json.sha b/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json.sha new file mode 100644 index 0000000..474ed2b --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-1.json.sha @@ -0,0 +1 @@ +c41a50867e2e \ No newline at end of file diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json b/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json new file mode 100644 index 0000000..69e187d --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json @@ -0,0 +1,12 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_FZGYPZcRdUeFPVVXCa7j1838", + "name": "get_task_comments", + "arguments": { + "task_id": "t901" + } + } + ] +} diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json.sha b/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json.sha new file mode 100644 index 0000000..a1a517f --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-2.json.sha @@ -0,0 +1 @@ +06ac15003c51 \ No newline at end of file diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json b/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json new file mode 100644 index 0000000..c21ded8 --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json @@ -0,0 +1,13 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_bn5Wd1SWvOcECWWt0xmq8565", + "name": "add_comment", + "arguments": { + "task_id": "t901", + "body": "UPDATE: Refactor the settings module. This card now covers the settings-module refactor rather than tidy-up only." + } + } + ] +} diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json.sha b/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json.sha new file mode 100644 index 0000000..cc66bf1 --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-3.json.sha @@ -0,0 +1 @@ +3c13c605835f \ No newline at end of file diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt b/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt new file mode 100644 index 0000000..bb0be06 --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt @@ -0,0 +1 @@ +Done. The pipeline's update for t901 has been recorded on the existing card. \ No newline at end of file diff --git a/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt.sha b/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt.sha new file mode 100644 index 0000000..6051b65 --- /dev/null +++ b/fixtures/cassettes-agents/06-github-activity/board/write/turn-4.txt.sha @@ -0,0 +1 @@ +65d2ecfe4e5b \ No newline at end of file diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json b/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json new file mode 100644 index 0000000..a343f8b --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_rapQQiMz98fJNSOj5whP6934", + "name": "get_task", + "arguments": { + "task_id": "t910" + } + }, + { + "id": "call_01_hOEhhl1UFeXe09Ca7U582883", + "name": "get_task_comments", + "arguments": { + "task_id": "t910" + } + } + ] +} diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json.sha b/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json.sha new file mode 100644 index 0000000..a94ce8b --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-1.json.sha @@ -0,0 +1 @@ +5f77380fd074 \ No newline at end of file diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json b/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json new file mode 100644 index 0000000..9297c91 --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_2zT7WKDgxyJjh2kTF2Y19043", + "name": "search_tasks", + "arguments": { + "query": "pagination" + } + }, + { + "id": "call_01_rfqxtNgFrMZ2QsuajDDU9730", + "name": "search_tasks", + "arguments": { + "query": "export endpoint" + } + } + ] +} diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json.sha b/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json.sha new file mode 100644 index 0000000..7d51b2d --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-2.json.sha @@ -0,0 +1 @@ +09ea667df315 \ No newline at end of file diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json b/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json new file mode 100644 index 0000000..e5a1adc --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json @@ -0,0 +1,23 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_DkmmNn8Vz3Mz3UCAem812034", + "name": "create_task", + "arguments": { + "title": "Add pagination to export endpoint", + "list_key": "backend", + "assignee": "Avery Chen", + "description": "Add pagination support to the export endpoint so large result sets are returned in pages rather than a single response." + } + }, + { + "id": "call_01_JvBedSpvbFFENzsPpIkB6986", + "name": "add_comment", + "arguments": { + "task_id": "t910", + "body": "Go-live confirmed for 28 August (already reflected in the card description)." + } + } + ] +} diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json.sha b/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json.sha new file mode 100644 index 0000000..6a01048 --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-3.json.sha @@ -0,0 +1 @@ +6398e6340490 \ No newline at end of file diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt b/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt new file mode 100644 index 0000000..8d66021 --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt @@ -0,0 +1,4 @@ +Both items are written: + +- t910: the go-live on 28 August was already in the card description, so I commented on t910 rather than duplicating the work. +- New card created: "Add pagination to export endpoint" in `backend`, assigned to Avery Chen. \ No newline at end of file diff --git a/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt.sha b/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt.sha new file mode 100644 index 0000000..a57d756 --- /dev/null +++ b/fixtures/cassettes-agents/07-email-thread/board/write/turn-4.txt.sha @@ -0,0 +1 @@ +b0e16a9944c9 \ No newline at end of file diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json new file mode 100644 index 0000000..67a5345 --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json @@ -0,0 +1,19 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_i9l2YuY4pdtMu8iGiCPo7897", + "name": "get_task", + "arguments": { + "task_id": "t920" + } + }, + { + "id": "call_01_2IxmHuPusiApxkCvWYY22234", + "name": "get_task_comments", + "arguments": { + "task_id": "t920" + } + } + ] +} diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json.sha b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json.sha new file mode 100644 index 0000000..f26108d --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-1.json.sha @@ -0,0 +1 @@ +c1f8883b992e \ No newline at end of file diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json new file mode 100644 index 0000000..15ec18c --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json @@ -0,0 +1,27 @@ +{ + "text": "", + "toolCalls": [ + { + "id": "call_00_OmuIcuDVhHcZK60xG9aC2193", + "name": "create_task", + "arguments": { + "title": "Add declined-card and expired-session error state screens to the spec", + "list_key": "design", + "assignee": "Rowan Diaz", + "description": "Add declined-card and expired-session error state screens to the checkout redesign spec, ahead of engineering pickup.", + "parent_id": "t920" + } + }, + { + "id": "call_01_avrpCbo7FpXsw3DhpBi78184", + "name": "create_task", + "arguments": { + "title": "Fix the 'reciept' typo in the second paragraph", + "list_key": "design", + "assignee": "Rowan Diaz", + "description": "Fix the 'reciept' typo in the second paragraph of the checkout redesign spec.", + "parent_id": "t920" + } + } + ] +} diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json.sha b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json.sha new file mode 100644 index 0000000..512a4b7 --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-2.json.sha @@ -0,0 +1 @@ +5718f8d3e39c \ No newline at end of file diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt new file mode 100644 index 0000000..8736dc9 --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt @@ -0,0 +1 @@ +Both planned items have been written to the board as subtasks of t920. \ No newline at end of file diff --git a/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt.sha b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt.sha new file mode 100644 index 0000000..aaba0cc --- /dev/null +++ b/fixtures/cassettes-agents/08-drive-activity/board/write/turn-3.txt.sha @@ -0,0 +1 @@ +fc064a5e6502 \ No newline at end of file diff --git a/src/agents/boardAgent.ts b/src/agents/boardAgent.ts index f910177..ccdb79a 100644 --- a/src/agents/boardAgent.ts +++ b/src/agents/boardAgent.ts @@ -26,7 +26,7 @@ import { type ExecuteResult, type ExecutedAction, type PlanContext, planOperations } from '../pipeline/passes/execute'; import type { CategorizationItem } from '../pipeline/parsing/categorizationManifest'; import type { HeldItem } from '../pipeline/gates/contractGates'; -import { approvedOpSet, governedTracker } from '../pipeline/gates/governedTracker'; +import { approvedOpSet, governedTracker, opSignature } from '../pipeline/gates/governedTracker'; import type { DeterministicGateOptions } from '../pipeline/passes/contractCheck'; import { READ_ONLY_TOOLS, WRITE_TOOLS, makeToolLoopRunner } from '../pipeline/toolLoop'; import { screenedPrimary } from '../utils/security'; @@ -298,16 +298,37 @@ export function buildBoardWritePrompt(items: CategorizationItem[], boardText: st ].join('\n'); } +/** + * Do two operations of the same kind concern the same thing? + * + * Deliberately coarse — the card id for anything touching an existing card, the exact title for a + * create. It answers "did the agent do this item's work", not "did it do it the way we planned", + * because the second question is Pass 2d's and it should get to ask it independently. + */ +function sameTarget(a: TrackerOperation, b: TrackerOperation): boolean { + const target = (op: TrackerOperation): string => + 'taskId' in op ? op.taskId : op.kind === 'createTask' ? op.title.trim().toLowerCase() : ''; + const t = target(a); + return t !== '' && t === target(b); +} + /** Fold the operations the tracker actually performed back into per-action results. */ function tally(plan: ReturnType, performed: Array<{ op: TrackerOperation; outcome: OpOutcome }>): ExecuteResult { const counts = { created: 0, commented: 0, skipped: 0, refused: 0, failed: 0, unsupported: 0 }; const left = [...performed]; const actions: ExecutedAction[] = plan.map((action) => { - // An op belongs to the action that planned it. Agent-originated ops match nothing here and are - // gathered into their own action below rather than being silently attributed to a planned item. + // An op belongs to the action that planned it — matched first exactly, then by **target**. + // + // Exact-only matching was a bug with a misleading symptom. The agent is invited to reword, so it + // commented on the right card with its own phrasing; the signature did not match, the op fell + // into the agent-originated bucket, and Pass 2d then reported "no comment landed on t200" for a + // comment that had demonstrably landed on t200. The write was fine and the *attribution* was + // wrong, which is the worse of the two failures to ship: it makes a working run look broken and + // trains a reader to discount the audit. const results = action.ops.flatMap((planned) => { - const i = left.findIndex((p) => p.op === planned || JSON.stringify(p.op) === JSON.stringify(planned)); + let i = left.findIndex((p) => opSignature(p.op) === opSignature(planned)); + if (i === -1) i = left.findIndex((p) => p.op.kind === planned.kind && sameTarget(p.op, planned)); return i === -1 ? [] : left.splice(i, 1); }); return { ...action, results, ok: results.length > 0 && results.every((r) => r.outcome.status === 'applied' || r.outcome.status === 'unchanged') }; diff --git a/src/cli/record.ts b/src/cli/record.ts index e9f93b4..2ff03bb 100644 --- a/src/cli/record.ts +++ b/src/cli/record.ts @@ -27,6 +27,10 @@ async function main(): Promise { const provider = (arg('provider') ?? 'deepseek') as ProviderName; const fresh = process.argv.includes('--fresh'); const agents = process.argv.includes('--agents'); + // Records into the SAME agent set. The board-write turns are additional keys (`board/write/...`), + // not replacements, so every cassette recorded before this flag existed replays untouched and the + // two modes share one directory rather than doubling the sets to four. + const boardWrites = process.argv.includes('--board-writes'); const scenarios = process.argv.includes('--all') ? listScenarios() : [arg('scenario') ?? ''].filter(Boolean); if (scenarios.length === 0) { @@ -43,12 +47,15 @@ async function main(): Promise { const dir = join(root, name); if (fresh) rmSync(dir, { recursive: true, force: true }); - console.log(`\n▶ recording ${name} against ${provider}${agents ? ' (agent layer ON)' : ''}`); + console.log( + `\n▶ recording ${name} against ${provider}${agents ? ' (agent layer ON)' : ''}` + + `${boardWrites ? ' (board agent writes)' : ''}` + ); // A miss records through the live provider; a hit replays. That makes re-running cheap and makes // a partially-recorded scenario finishable rather than all-or-nothing. const model = cassetteClient(dir, { record: makeModelClient({ provider }) }); - const run = await runScenario(scenario, { model, agents }); + const run = await runScenario(scenario, { model, agents, boardWrites }); console.log(` ${run.modelCalls} model call(s)`); diff --git a/src/pipeline/toolLoop.ts b/src/pipeline/toolLoop.ts index 289503b..75b0eb9 100644 --- a/src/pipeline/toolLoop.ts +++ b/src/pipeline/toolLoop.ts @@ -107,10 +107,22 @@ export const WRITE_TOOLS: ToolSpec[] = [ title: { type: 'string' }, list_key: { type: 'string', description: 'Which list the card belongs on.' }, assignee: { type: 'string', description: 'Canonical name of the owner.' }, - description: { type: 'string' }, - parent_id: { type: 'string', description: 'Set to make this a subtask of an existing card.' }, + description: { + type: 'string', + description: 'What the work actually is. Required — a card with no body is refused.', + }, + parent_id: { + type: 'string', + description: + 'Set to make this a subtask of an existing card. Read that card\'s comments first, or the ' + + 'evidence gate refuses the write.', + }, }, - required: ['title', 'list_key', 'assignee'], + // `description` is required here because the gate requires it: a create with no FINAL_DESC is + // refused as an unresolvable field. Listing it optional made the tool lie about what a valid + // write looks like, and the model believed the tool — five refusals in one recorded run, every + // one of them the schema's fault rather than the model's. + required: ['title', 'list_key', 'assignee', 'description'], }, }, {