{"record":{"id":"f2a880de67387f5e","repo":"Hmbown/CodeWhale","slug":"canonical-workspace","errorCode":null,"errorMessage":"canonical workspace","messagePattern":"canonical workspace","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":8366,"sourceCode":"    assert!(\n        !registry.envelope_permits(\"bash\", &touch),\n        \"mutating command must stay refused by the scout envelope\"\n    );\n    assert!(\n        !registry.envelope_permits(\"Bash\", &git_log),\n        \"legacy `Bash` is not the carve-out name; the envelope must keep refusing it\"\n    );\n}\n\n/// #5595: catalog admission, role posture, and the execution envelope are not\n/// enough. The concrete read-only executor must accept the canonical Git shape\n/// agents use when the repository is not their process cwd. This is the exact\n/// end-to-end gap from the v0.9.11 dogfood failure.\n#[tokio::test]\nasync fn read_only_inspection_roles_execute_pwd_and_absolute_git_log() {\n    let tmp = tempdir().expect(\"tempdir\");\n    init_claim_repo(tmp.path());\n    let workspace = tmp.path().canonicalize().expect(\"canonical workspace\");\n    let git_log = format!(\"git -C {} log --oneline -20\", workspace.to_string_lossy());\n\n    for role in [FleetRole::Scout, FleetRole::Reviewer, FleetRole::Planner] {\n        let mut runtime =\n            stub_runtime().with_agent_tool_surface_options(enabled_agent_surface_options());\n        runtime.context = ToolContext::new(workspace.clone());\n        runtime.worker_profile = WorkerRuntimeProfile::for_role(role.clone());\n        seed_read_only_role_deny_list(&mut runtime);\n        let registry = SubAgentToolRegistry::new(\n            runtime,\n            role.clone(),\n            None,\n            crate::tools::todo::new_shared_todo_list(),\n            crate::tools::plan::new_shared_plan_state(),\n        );\n\n        for input in [\n            json!({\"command\": \"pwd\"}),","sourceCodeStart":8348,"sourceCodeEnd":8384,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/tests.rs#L8348-L8384","documentation":"Panic from `.expect(\"canonical workspace\")` on `tmp.path().canonicalize()` in the subagent read-only-role test (crates/tui/src/tools/subagent/tests.rs:8366). `canonicalize` resolves the path to an absolute one with symlinks resolved (e.g. macOS `/var` → `/private/var`); it fails with an io::Error when the path does not exist or cannot be resolved. The test needs the canonical form so `git -C <abs-path>` works even when the repo is not the process cwd.","triggerScenarios":"The temp directory created one line earlier was removed between creation and canonicalization (aggressive tmp cleaners, `TMPDIR` on a flaky mount), or the platform denies path resolution. Also surfaces if `init_claim_repo` inadvertently removes the directory.","commonSituations":"Running tests in containers with systemd-tmpfiles or `tmpwatch` pruning; sandboxed runners where `/tmp` symlinks cannot be resolved; macOS environments relying on the `/var` → `/private/var` canonicalization with restrictive TCC settings.","solutions":["Re-run with a stable TMPDIR you created yourself: `TMPDIR=$(mktemp -d) cargo test read_only_inspection_roles`.","Confirm no tmp-cleaner deleted the directory mid-run; disable tmp pruning for the CI session.","If reproducible locally, verify `tmp.path()` still exists immediately after `tempdir()` — if not, the failure is in temp creation, not canonicalization.","As a fixture hardening step, canonicalize before `init_claim_repo` and panic with the io::Error chain so the OS cause is visible."],"exampleFix":"// before\nlet workspace = tmp.path().canonicalize().expect(\"canonical workspace\");\n// after\nlet workspace = tmp.path().canonicalize()\n    .with_context(|| format!(\"canonicalize {:?}\", tmp.path()))\n    .expect(\"canonical workspace\");","handlingStrategy":"validation","validationCode":"let raw = tmp.path();\nassert!(raw.exists(), \"temp path {:?} vanished before canonicalize\", raw);\nlet workspace = raw.canonicalize().expect(\"canonical workspace\");","typeGuard":null,"tryCatchPattern":"let workspace = tmp.path().canonicalize()\n    .with_context(|| format!(\"canonicalize {:?}\", tmp.path()))?;","preventionTips":["Canonicalize immediately after creating the temp dir, before any setup that could remove it.","Disable aggressive tmp cleaners for the duration of test runs.","Include the failing path in the panic message for diagnosability."],"tags":["filesystem","path-canonicalization","testing","panic"],"backgroundTag":"file-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}