From 15345540f25ca43c61e5ad7697e5b09c76d4ea84 Mon Sep 17 00:00:00 2001 From: vikingowl Date: Mon, 6 Apr 2026 00:58:54 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20ClassifyTask=20priority=20ordering=20?= =?UTF-8?q?=E2=80=94=20orchestration=20below=20operational=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operational task types (debug, review, refactor, test, explain) now gate before orchestration in the keyword cascade. Previously, prompts like "review the orchestration layer" or "refactor the pipeline dispatch" matched "orchestrat"/"dispatch" and misclassified as TaskOrchestration. Planning is also moved below the operational types. Expanded orchestration keywords to cover common intent that the original four keywords missed: "fan out", "subtask", "delegate to", "spawn elf". Adds regression tests for false-positive cases and positive tests for new keywords. --- internal/router/router_test.go | 41 ++++++++++++++++++++++++++++++++++ internal/router/task.go | 16 ++++++++----- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/internal/router/router_test.go b/internal/router/router_test.go index d055f1c..d5b8cba 100644 --- a/internal/router/router_test.go +++ b/internal/router/router_test.go @@ -35,6 +35,47 @@ func TestClassifyTask(t *testing.T) { } } +func TestClassifyTask_OrchestrationNotFalsePositive(t *testing.T) { + // Words like "coordinator", "pipeline", "dispatch" appear in non-orchestration contexts. + // More specific classifications (debug, review, refactor, explain) must win. + tests := []struct { + prompt string + want TaskType + }{ + {"fix the coordinator bug", TaskDebug}, // "coordinator" contains "coordinate" + {"review the orchestration layer", TaskReview}, // "orchestrat" present but review wins + {"refactor the pipeline dispatch", TaskRefactor}, // "dispatch" present but refactor wins + {"explain how coordination works", TaskExplain}, // "coordinat" present but explain wins + {"debug the dispatch table", TaskDebug}, // "dispatch" present but debug wins + } + for _, tt := range tests { + task := ClassifyTask(tt.prompt) + if task.Type != tt.want { + t.Errorf("ClassifyTask(%q).Type = %s, want %s", tt.prompt, task.Type, tt.want) + } + } +} + +func TestClassifyTask_OrchestrationKeywords(t *testing.T) { + // Explicit orchestration-intent phrases should still classify correctly. + tests := []struct { + prompt string + want TaskType + }{ + {"orchestrate the migration across services", TaskOrchestration}, + {"fan out the work to 5 elfs", TaskOrchestration}, + {"split this into subtasks and run them in parallel", TaskOrchestration}, + {"delegate to worker elfs for parallel processing", TaskOrchestration}, + {"spawn elfs to handle this", TaskOrchestration}, + } + for _, tt := range tests { + task := ClassifyTask(tt.prompt) + if task.Type != tt.want { + t.Errorf("ClassifyTask(%q).Type = %s, want %s", tt.prompt, task.Type, tt.want) + } + } +} + func TestClassifyTask_RequiresTools(t *testing.T) { // Explain tasks don't require tools task := ClassifyTask("explain how generics work") diff --git a/internal/router/task.go b/internal/router/task.go index 2997004..f123d47 100644 --- a/internal/router/task.go +++ b/internal/router/task.go @@ -123,16 +123,14 @@ func ClassifyTask(prompt string) Task { RequiresTools: true, // assume tools needed by default } - // Check for task type keywords (order matters — more specific first) + // Check for task type keywords (order matters — more specific/common first). + // Orchestration is placed late: its keywords ("dispatch", "pipeline", "orchestrat") + // appear as nouns in non-orchestration prompts (e.g. "refactor the pipeline dispatch", + // "review the orchestration layer"). Operational task types must gate first. switch { case containsAny(lower, "security", "vulnerability", "cve", "owasp", "xss", "injection", "audit security"): task.Type = TaskSecurityReview task.Priority = PriorityHigh - case containsAny(lower, "plan", "architect", "design", "strategy", "roadmap"): - task.Type = TaskPlanning - case containsAny(lower, "orchestrat", "coordinate", "dispatch", "pipeline"): - task.Type = TaskOrchestration - task.Priority = PriorityHigh case containsAny(lower, "debug", "fix", "troubleshoot", "not working", "error", "crash", "failing", "bug"): task.Type = TaskDebug case containsAny(lower, "review", "check", "analyze", "audit", "inspect"): @@ -144,6 +142,12 @@ func ClassifyTask(prompt string) Task { case containsAny(lower, "explain", "what is", "how does", "describe", "tell me about"): task.Type = TaskExplain task.RequiresTools = false + case containsAny(lower, "plan", "architect", "design", "strategy", "roadmap"): + task.Type = TaskPlanning + case containsAny(lower, "orchestrat", "coordinate", "dispatch", "pipeline", + "fan out", "subtask", "delegate to", "spawn elf"): + task.Type = TaskOrchestration + task.Priority = PriorityHigh case containsAny(lower, "create", "implement", "build", "add", "write", "generate", "make"): task.Type = TaskGeneration case containsAny(lower, "scaffold", "boilerplate", "template", "stub", "skeleton"):