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'], }, }, {