fix: ClassifyTask priority ordering — orchestration below operational types

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.
This commit is contained in:
2026-04-06 00:58:54 +02:00
parent 32c8691a43
commit 15345540f2
2 changed files with 51 additions and 6 deletions

View File

@@ -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")

View File

@@ -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"):