{"record":{"id":"83af6868276b79b2","repo":"Hmbown/CodeWhale","slug":"read-only-roles-may-revise-their-private-working-notes","errorCode":null,"errorMessage":"read-only roles may revise their private working notes","messagePattern":"read-only roles may revise their private working notes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":8528,"sourceCode":"            assert!(\n                registry.is_tool_allowed(\"image_ocr\"),\n                \"{role:?} must allow image_ocr\"\n            );\n            assert!(\n                !registry.role_blocks_unhardened_process_tool(\"image_ocr\"),\n                \"{role:?} must not hide proven read-only tool image_ocr\"\n            );\n        }\n\n        // Private working notes are writable; workspace writes are not.\n        registry\n            .execute(\n                \"agent_read_only\",\n                \"todo_write\",\n                json!({\"todos\": [{\"content\": \"inspect issue evidence\", \"status\": \"in_progress\"}]}),\n            )\n            .await\n            .expect(\"read-only roles may revise their private working notes\");\n        assert_eq!(\n            todo_contents(&todo_list).await,\n            vec![\"inspect issue evidence\"],\n            \"the bounded notes write lands only in this child's todo list\"\n        );\n        assert!(\n            registry\n                .envelope_refusal(\n                    \"File\",\n                    &json!({\"action\": \"write\", \"path\": \"src/lib.rs\", \"content\": \"nope\"})\n                )\n                .is_some(),\n            \"agent-owned notes must not widen workspace writes\"\n        );\n    }\n}\n\n#[tokio::test]","sourceCodeStart":8510,"sourceCodeEnd":8546,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tools/subagent/tests.rs#L8510-L8546","documentation":"This panic comes from `.expect(\"read-only roles may revise their private working notes\")` on `registry.execute(\"agent_read_only\", \"todo_write\", ...)` in crates/tui/src/tools/subagent/tests.rs:8528. It asserts the contract that read-only Fleet roles can still write to their own private todo list even though other write tools are denied. If the registry's read-only deny list incorrectly blocks `todo_write`, the tool returns an error and the expect panics.","triggerScenarios":"Executing `todo_write` against an `agent_read_only` SubAgentToolRegistry whose deny-list/allow-list construction no longer exempts the private todo tool — e.g. after tightening role permissions, changing the tool name, or seeding a deny list that includes todo_write.","commonSituations":"Refactoring the permission allowlist for read-only roles, renaming the todo tool, or adding a new write-protection layer that sweeps in the private notes surface; also seen when tests forget to enable the agent tool surface options.","solutions":["Check the read-only role's tool catalog/deny list construction and ensure `todo_write` is explicitly permitted for read-only roles.","Confirm the tool name string \"todo_write\" matches the registered tool identifier (grep the registry catalog).","Verify the registry was built with the intended `ToolContext` and auto-approve settings so the write isn't rejected for approval reasons.","Run the test with the registry construction logged (tool list) to see whether todo_write is present in the child's catalog."],"exampleFix":"// before: blanket deny of all write-suffixed tools for read-only roles\nlet denied = tools.iter().filter(|t| t.name().ends_with(\"write\"));\n// after: exempt the private working notes surface\nlet denied = tools.iter()\n    .filter(|t| t.name().ends_with(\"write\") && t.name() != \"todo_write\");","handlingStrategy":"validation","validationCode":"// before relying on a role's catalog, assert the surface:\nfn expects_tool(registry: &SubAgentToolRegistry, tool: &str) -> bool {\n    registry.catalog_names().any(|n| n == tool)\n}\nassert!(expects_tool(&registry, \"todo_write\"), \"read-only roles must keep todo_write\");","typeGuard":"fn is_private_notes_tool(tool: &str) -> bool {\n    matches!(tool, \"todo_write\" | \"todo_read\")\n}","tryCatchPattern":"match registry.execute(\"agent_read_only\", \"todo_write\", payload).await {\n    Ok(out) => assert_eq!(out, expected),\n    Err(e) => panic!(\"todo_write denied for read-only role: {e:?} — check the deny-list exemption\"),\n}","preventionTips":["When tightening read-only deny lists, always exempt the private working-notes tools explicitly.","Keep a contract test per role that enumerates its catalog and pins todo_write presence.","Centralize the read-only exemption list so per-role edits cannot silently drop it.","Grep for tool-name string literals when renaming tools to update all policy references."],"tags":["rust","permissions","subagent","test-assertion"],"backgroundTag":"permission-denied","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}