diff --git a/.story_kit/work/1_upcoming/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md b/.story_kit/work/1_upcoming/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md index f29f9bb..90f4a7a 100644 --- a/.story_kit/work/1_upcoming/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md +++ b/.story_kit/work/1_upcoming/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md @@ -6,30 +6,57 @@ name: "qa-2 agent never auto-assigned because pipeline_stage only matches exact ## Description -server/src/agents.rs line 154: pipeline_stage() matches qa exactly but qa-2 falls through to Other. Fix: change line 156 from exact match to starts_with, same as coders: +The `pipeline_stage()` function in `server/src/agents.rs` (line 154) determines an agent's pipeline role by parsing its **name** — there's no structured `stage` field in the agent config. This means `qa-2` falls through to `PipelineStage::Other` because it doesn't exactly match `"qa"`. -Current: - qa => PipelineStage::Qa, +### Root Cause -Fix: - name if name.starts_with(qa) => PipelineStage::Qa, +`project.toml` agent config has `name` and `role` (freetext description), but no `stage` or `pipeline_role` field. The code guesses the pipeline stage from the name: -Also update the test at line 3542 to cover qa-2. +```rust +match agent_name { + "qa" => PipelineStage::Qa, + "mergemaster" => PipelineStage::Mergemaster, + name if name.starts_with("coder") => PipelineStage::Coder, + _ => PipelineStage::Other, +} +``` + +### The Fix + +1. Add a `stage` field to `[[agent]]` in `project.toml` config schema. Valid values: `"coder"`, `"qa"`, `"mergemaster"`, `"other"`. +2. Update `ProjectConfig` / agent config deserialization in the server to parse the new field. +3. Replace `pipeline_stage(agent_name)` with a lookup from the agent's config `stage` field. +4. Update `project.toml` to add `stage` to all agents: + - supervisor: `stage = "other"` + - coder-1, coder-2, coder-opus: `stage = "coder"` + - qa, qa-2: `stage = "qa"` + - mergemaster: `stage = "mergemaster"` +5. Keep the name-based `pipeline_stage()` as a fallback for backwards compatibility if `stage` is not set. + +### Key Files +- `server/src/agents.rs` line 154: `pipeline_stage()` — name-based matching +- `server/src/agents.rs` line 1728: `find_free_agent_for_stage()` — uses `pipeline_stage()` +- `server/src/config.rs` (or wherever `ProjectConfig` is defined): agent config deserialization +- `.story_kit/project.toml`: agent definitions ## How to Reproduce -1. Have multiple items in 3_qa/ -2. qa agent gets assigned to one -3. qa-2 never gets assigned to the others +1. Have multiple items in `3_qa/` +2. `qa` agent gets assigned to one +3. `qa-2` never gets assigned to the others ## Actual Result -qa-2 is never auto-assigned. pipeline_stage(qa-2) returns PipelineStage::Other instead of PipelineStage::Qa. +`qa-2` is never auto-assigned. `pipeline_stage("qa-2")` returns `PipelineStage::Other`. ## Expected Result -qa-2 should be recognized as a QA agent and auto-assigned to items in 3_qa/. +`qa-2` should be recognized as a QA agent and auto-assigned to items in `3_qa/`. ## Acceptance Criteria -- [ ] Bug is fixed and verified +- [ ] Agent config in `project.toml` supports a `stage` field (`coder`, `qa`, `mergemaster`, `other`) +- [ ] `find_free_agent_for_stage` uses the config `stage` field instead of name parsing +- [ ] `qa-2` is correctly auto-assigned to QA work +- [ ] Backwards compatible: if `stage` is not set, falls back to name-based matching +- [ ] All existing agents in `project.toml` have `stage` set