Add council review start command

This commit is contained in:
2026-03-19 14:56:38 +08:00
parent 10ffb13f75
commit c1beacb703
9 changed files with 797 additions and 6 deletions
+144
View File
@@ -1,6 +1,7 @@
package orch
import (
"database/sql"
"os"
"path/filepath"
"testing"
@@ -1396,3 +1397,146 @@ func TestOrchCleanupRemovesCompletedWorktree(t *testing.T) {
t.Fatalf("expected cleaned worktree path to be removed, err=%v", err)
}
}
func TestOrchCouncilStartDispatchesThreeReviewers(t *testing.T) {
t.Parallel()
dbPath := filepath.Join(t.TempDir(), "coord.db")
startOut := runOrchCommand(
t,
"--db", dbPath,
"--json",
"council", "start",
"--run", "council_blog_001",
"--target", "Review the current blog architecture and propose optimizations.",
"--target-type", "mixed",
"--output", "both",
)
var startResp map[string]any
mustDecodeJSON(t, startOut, &startResp)
if got := nestedString(t, startResp, "data", "run_id"); got != "council_blog_001" {
t.Fatalf("expected council run id, got %q", got)
}
if got := nestedString(t, startResp, "data", "mode"); got != "brainstorm" {
t.Fatalf("expected default council mode brainstorm, got %q", got)
}
reviewers := nestedArray(t, startResp, "data", "reviewers")
if len(reviewers) != 3 {
t.Fatalf("expected three council reviewers, got %#v", reviewers)
}
sqlDB, err := openOrchDB(t.Context(), dbPath)
if err != nil {
t.Fatalf("open orch db: %v", err)
}
defer sqlDB.Close()
var (
mode string
targetType string
outputMode string
onlyUnanimous int
)
if err := sqlDB.QueryRowContext(
t.Context(),
`SELECT mode, target_type, output_mode, only_unanimous
FROM council_runs
WHERE run_id = ?`,
"council_blog_001",
).Scan(&mode, &targetType, &outputMode, &onlyUnanimous); err != nil {
t.Fatalf("query council_runs: %v", err)
}
if mode != "brainstorm" || targetType != "mixed" || outputMode != "both" || onlyUnanimous != 0 {
t.Fatalf("unexpected council run metadata: mode=%q targetType=%q outputMode=%q onlyUnanimous=%d", mode, targetType, outputMode, onlyUnanimous)
}
var (
prompt string
targetFile string
repoPath string
targetTaskID string
)
if err := sqlDB.QueryRowContext(
t.Context(),
`SELECT prompt, target_file, repo_path, target_task_id
FROM council_inputs
WHERE run_id = ?`,
"council_blog_001",
).Scan(&prompt, &targetFile, &repoPath, &targetTaskID); err != nil {
t.Fatalf("query council_inputs: %v", err)
}
if prompt == "" || targetFile != "" || repoPath != "" || targetTaskID != "" {
t.Fatalf("unexpected council input row: prompt=%q targetFile=%q repoPath=%q targetTaskID=%q", prompt, targetFile, repoPath, targetTaskID)
}
rows, err := sqlDB.QueryContext(
t.Context(),
`SELECT reviewer_role, task_id, status
FROM council_reviewers
WHERE run_id = ?
ORDER BY reviewer_role ASC`,
"council_blog_001",
)
if err != nil {
t.Fatalf("query council_reviewers: %v", err)
}
defer rows.Close()
var reviewerRows int
for rows.Next() {
var (
reviewerRole string
taskID string
status string
)
if err := rows.Scan(&reviewerRole, &taskID, &status); err != nil {
t.Fatalf("scan council reviewer row: %v", err)
}
reviewerRows++
if status != "dispatched" {
t.Fatalf("expected council reviewer status dispatched, got %q for %s", status, reviewerRole)
}
var worktreePath sql.NullString
if err := sqlDB.QueryRowContext(
t.Context(),
`SELECT a.worktree_path
FROM task_attempts a
WHERE a.run_id = ? AND a.task_id = ? AND a.attempt_no = 1`,
"council_blog_001",
taskID,
).Scan(&worktreePath); err != nil {
t.Fatalf("query council attempt worktree path for %s: %v", taskID, err)
}
if worktreePath.Valid && worktreePath.String != "" {
t.Fatalf("expected council reviewer task %s to avoid worktree allocation, got %q", taskID, worktreePath.String)
}
}
if err := rows.Err(); err != nil {
t.Fatalf("iterate council reviewers: %v", err)
}
if reviewerRows != 3 {
t.Fatalf("expected three stored council reviewers, got %d", reviewerRows)
}
statusOut := runOrchCommand(
t,
"--db", dbPath,
"--json",
"status",
"--run", "council_blog_001",
)
var statusResp map[string]any
mustDecodeJSON(t, statusOut, &statusResp)
if got := nestedString(t, statusResp, "data", "run", "status"); got != "running" {
t.Fatalf("expected council run status running, got %q", got)
}
tasks := nestedArray(t, statusResp, "data", "tasks")
if len(tasks) != 3 {
t.Fatalf("expected three council tasks, got %#v", tasks)
}
}