From 507863f86ab238517f14ca8214d45c9e86920262 Mon Sep 17 00:00:00 2001 From: Hare Date: Tue, 9 Jun 2026 21:31:33 +0900 Subject: [PATCH] fix: lock project role feature surfaces --- .yoi/profiles/companion.lua | 2 +- .yoi/profiles/intake.lua | 2 +- .yoi/profiles/orchestrator.lua | 2 +- .yoi/profiles/reviewer.lua | 2 +- crates/pod/tests/controller_test.rs | 92 +++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/.yoi/profiles/companion.lua b/.yoi/profiles/companion.lua index 9d5f888d..aaa5e43d 100644 --- a/.yoi/profiles/companion.lua +++ b/.yoi/profiles/companion.lua @@ -5,7 +5,7 @@ return base { description = "Companion role profile: GPT-5.5 with bundled default behavior", model_ref = "codex-oauth/gpt-5.5", feature = { - task = { enabled = true }, + task = { enabled = false }, memory = { enabled = true }, web = { enabled = true }, pods = { enabled = false }, diff --git a/.yoi/profiles/intake.lua b/.yoi/profiles/intake.lua index afc82901..91f96d7b 100644 --- a/.yoi/profiles/intake.lua +++ b/.yoi/profiles/intake.lua @@ -5,7 +5,7 @@ return base { description = "Intake role profile: GPT-5.5 with bundled default behavior", model_ref = "codex-oauth/gpt-5.5", feature = { - task = { enabled = true }, + task = { enabled = false }, memory = { enabled = true }, web = { enabled = true }, pods = { enabled = false }, diff --git a/.yoi/profiles/orchestrator.lua b/.yoi/profiles/orchestrator.lua index 83964c38..ac6b6f9e 100644 --- a/.yoi/profiles/orchestrator.lua +++ b/.yoi/profiles/orchestrator.lua @@ -6,7 +6,7 @@ return base { description = "Orchestrator role profile: GPT-5.5 with bundled default behavior", delegation_scope = scope.workspace_write(), feature = { - task = { enabled = true }, + task = { enabled = false }, memory = { enabled = true }, web = { enabled = true }, pods = { enabled = true }, diff --git a/.yoi/profiles/reviewer.lua b/.yoi/profiles/reviewer.lua index 1e54870c..a185480c 100644 --- a/.yoi/profiles/reviewer.lua +++ b/.yoi/profiles/reviewer.lua @@ -5,7 +5,7 @@ return base { description = "Reviewer role profile: GPT-5.5 with bundled default behavior", model_ref = "codex-oauth/gpt-5.5", feature = { - task = { enabled = true }, + task = { enabled = false }, memory = { enabled = true }, web = { enabled = true }, pods = { enabled = false }, diff --git a/crates/pod/tests/controller_test.rs b/crates/pod/tests/controller_test.rs index 938462f1..fd040d53 100644 --- a/crates/pod/tests/controller_test.rs +++ b/crates/pod/tests/controller_test.rs @@ -303,6 +303,98 @@ permission = "write" assert!(!names.iter().any(|name| name == "MemoryRead")); } +#[tokio::test] +async fn project_role_tool_surfaces_keep_task_disabled_and_pods_role_scoped() { + struct Case { + role: &'static str, + pods_enabled: bool, + } + + let cases = [ + Case { + role: "orchestrator", + pods_enabled: true, + }, + Case { + role: "coder", + pods_enabled: false, + }, + Case { + role: "intake", + pods_enabled: false, + }, + Case { + role: "reviewer", + pods_enabled: false, + }, + Case { + role: "companion", + pods_enabled: false, + }, + ]; + + for case in cases { + let delegation = if case.pods_enabled { + r#" +[[delegation_scope.allow]] +target = "/tmp" +permission = "write" +"# + } else { + "" + }; + let manifest = format!( + r#" +[pod] +name = "role-surface-{role}" +pwd = "./" + +[model] +scheme = "anthropic" +model_id = "test-model" + +[worker] +max_tokens = 100 + +[feature.task] +enabled = false + +[feature.pods] +enabled = {pods_enabled} + +[[scope.allow]] +target = "./" +permission = "write" +{delegation} +"#, + role = case.role, + pods_enabled = case.pods_enabled, + delegation = delegation, + ); + let client = MockClient::new(simple_text_events()); + let client_for_assert = client.clone(); + let pod = make_pod_with_pwd_and_manifest(client, &manifest).await.0; + let handle = spawn_controller(pod).await; + + handle.send(Method::run_text("Hello")).await.unwrap(); + wait_for_status(&handle, PodStatus::Idle).await; + + let request = wait_for_captured_request(&client_for_assert).await; + let names = request_tool_names(&request); + assert!( + !names.iter().any(|name| name == "TaskCreate"), + "{} role must not expose Task tools: {names:?}", + case.role + ); + assert_eq!( + names.iter().any(|name| name == "SpawnPod"), + case.pods_enabled, + "{} role Pod tool exposure mismatch: {names:?}", + case.role + ); + } +} + #[tokio::test] async fn pods_feature_requires_delegation_scope() { let manifest = r#"