summaryrefslogtreecommitdiff
path: root/internal/executor/channel_test.go
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator>2026-07-08 08:35:14 +0000
committerClaudomator Agent <agent@claudomator>2026-07-08 08:35:14 +0000
commit02489d25b98d67f332fe0c93156bb767c2e860a1 (patch)
tree987e71906e522f7d1dfd1af2d63c7e8ea3ccb06b /internal/executor/channel_test.go
parent8d9d42ba4f6c5f8cb729fcb851e5ef30fff46d37 (diff)
feat(agentchannel): add DependsOn to SubtaskSpec so a decomposing task can order its own subtasks
Diffstat (limited to 'internal/executor/channel_test.go')
-rw-r--r--internal/executor/channel_test.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/internal/executor/channel_test.go b/internal/executor/channel_test.go
index 522f23a..84cad89 100644
--- a/internal/executor/channel_test.go
+++ b/internal/executor/channel_test.go
@@ -269,6 +269,75 @@ func TestStoreChannel_SpawnSubtask_PropagatesError(t *testing.T) {
}
}
+// TestStoreChannel_SpawnSubtask_SetsDependsOn proves a caller can chain a
+// new subtask after a sibling it already spawned, by passing the sibling's
+// returned ID back in DependsOn -- the mechanism a decomposing task uses to
+// express "this step must wait for that one", not just fan-out-and-wait.
+func TestStoreChannel_SpawnSubtask_SetsDependsOn(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "parent-task-1")
+
+ firstID, err := ch.SpawnSubtask(context.Background(), agentchannel.SubtaskSpec{
+ Name: "step 1",
+ Instructions: "do the first thing",
+ })
+ if err != nil {
+ t.Fatalf("spawn first subtask: %v", err)
+ }
+
+ secondID, err := ch.SpawnSubtask(context.Background(), agentchannel.SubtaskSpec{
+ Name: "step 2",
+ Instructions: "do the second thing",
+ DependsOn: []string{firstID},
+ })
+ if err != nil {
+ t.Fatalf("spawn second subtask: %v", err)
+ }
+
+ var second *task.Task
+ for _, ct := range store.createdTasks {
+ if ct.ID == secondID {
+ second = ct
+ }
+ }
+ if second == nil {
+ t.Fatal("second subtask not found in store.createdTasks")
+ }
+ if len(second.DependsOn) != 1 || second.DependsOn[0] != firstID {
+ t.Errorf("expected DependsOn=[%q], got %v", firstID, second.DependsOn)
+ }
+}
+
+// TestStoreChannel_SpawnSubtask_DependsOnDefaultsEmpty proves the
+// backward-compatible default: a caller that never sets DependsOn (every
+// pre-existing caller) gets a child task with no dependencies, exactly as
+// before this change.
+func TestStoreChannel_SpawnSubtask_DependsOnDefaultsEmpty(t *testing.T) {
+ store := &fakeChannelStore{}
+ ch := newStoreChannel(store, "parent-task-1")
+
+ id, err := ch.SpawnSubtask(context.Background(), agentchannel.SubtaskSpec{
+ Name: "solo step",
+ Instructions: "do the thing",
+ })
+ if err != nil {
+ t.Fatalf("spawn subtask: %v", err)
+ }
+
+ var got *task.Task
+ for _, ct := range store.createdTasks {
+ if ct.ID == id {
+ got = ct
+ }
+ }
+ if got == nil {
+ t.Fatal("subtask not found in store.createdTasks")
+ }
+ if len(got.DependsOn) != 0 {
+ t.Errorf("expected empty DependsOn by default, got %v", got.DependsOn)
+ }
+}
+
func TestStoreChannel_RecordProgress_EmitsAgentMessage(t *testing.T) {
store := &fakeChannelStore{}
ch := newStoreChannel(store, "task-1")