summaryrefslogtreecommitdiff
path: root/internal/executor/channel_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/executor/channel_test.go')
-rw-r--r--internal/executor/channel_test.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/internal/executor/channel_test.go b/internal/executor/channel_test.go
index 250e8eb..157cb0c 100644
--- a/internal/executor/channel_test.go
+++ b/internal/executor/channel_test.go
@@ -97,6 +97,88 @@ func TestStoreChannel_SpawnSubtask_CreatesChildWithParent(t *testing.T) {
}
}
+// TestStoreChannel_SpawnSubtask_RoleSet verifies that when spec.Role is set,
+// the child task gets Agent.Role populated and Agent.Type/Model left empty
+// so executor.Pool.execute()'s role-based dispatch (Phase 5) resolves them
+// from the role's escalation ladder, exactly like any other role-typed task.
+func TestStoreChannel_SpawnSubtask_RoleSet(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "parent-1")
+ id, err := ch.SpawnSubtask(context.Background(), SubtaskSpec{
+ Name: "evaluator",
+ Instructions: "evaluate the change",
+ Model: "should-be-ignored",
+ MaxBudgetUSD: 2.0,
+ Role: "evaluator_quality",
+ })
+ if err != nil {
+ t.Fatalf("SpawnSubtask: %v", err)
+ }
+ if len(store.createdTasks) != 1 {
+ t.Fatalf("expected 1 created task, got %d", len(store.createdTasks))
+ }
+ ct := store.createdTasks[0]
+ if ct.ID != id {
+ t.Errorf("returned id %q != created task id %q", id, ct.ID)
+ }
+ if ct.Agent.Role != "evaluator_quality" {
+ t.Errorf("Agent.Role: want evaluator_quality, got %q", ct.Agent.Role)
+ }
+ if ct.Agent.Type != "" {
+ t.Errorf("Agent.Type: want empty (resolved later by role dispatch), got %q", ct.Agent.Type)
+ }
+ if ct.Agent.Model != "" {
+ t.Errorf("Agent.Model: want empty (resolved later by role dispatch), got %q", ct.Agent.Model)
+ }
+ if ct.Agent.Instructions != "evaluate the change" || ct.Agent.MaxBudgetUSD != 2.0 {
+ t.Errorf("non-role fields not propagated: %+v", ct.Agent)
+ }
+}
+
+// TestStoreChannel_SpawnSubtask_NoRole_RegressionUnchanged is a regression
+// test proving that spec.Role == "" (every pre-Phase-6 caller) still
+// produces exactly today's behavior: Agent.Type hardcoded to "claude" and
+// Agent.Model set from spec.Model. This must keep passing unmodified by any
+// future change to role-typed spawning.
+func TestStoreChannel_SpawnSubtask_NoRole_RegressionUnchanged(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "parent-1")
+ id, err := ch.SpawnSubtask(context.Background(), SubtaskSpec{
+ Name: "child",
+ Instructions: "do it",
+ Model: "sonnet",
+ MaxBudgetUSD: 1.5,
+ })
+ if err != nil {
+ t.Fatalf("SpawnSubtask: %v", err)
+ }
+ if len(store.createdTasks) != 1 {
+ t.Fatalf("expected 1 created task, got %d", len(store.createdTasks))
+ }
+ ct := store.createdTasks[0]
+ if ct.ID != id {
+ t.Errorf("returned id %q != created task id %q", id, ct.ID)
+ }
+ if ct.ParentTaskID != "parent-1" {
+ t.Errorf("ParentTaskID: got %q want parent-1", ct.ParentTaskID)
+ }
+ if ct.Agent.Type != "claude" {
+ t.Errorf("Agent.Type: want claude (unchanged backward-compat default), got %q", ct.Agent.Type)
+ }
+ if ct.Agent.Model != "sonnet" {
+ t.Errorf("Agent.Model: want sonnet, got %q", ct.Agent.Model)
+ }
+ if ct.Agent.Role != "" {
+ t.Errorf("Agent.Role: want empty, got %q", ct.Agent.Role)
+ }
+ if ct.Agent.Instructions != "do it" || ct.Agent.MaxBudgetUSD != 1.5 {
+ t.Errorf("agent config not propagated: %+v", ct.Agent)
+ }
+ if ct.State != task.StatePending {
+ t.Errorf("expected PENDING child, got %s", ct.State)
+ }
+}
+
func TestStoreChannel_SpawnSubtask_PropagatesError(t *testing.T) {
store := &fakeChannelStore{createTaskErr: errors.New("boom")}
ch := newStoreChannel(store, "parent-1")