diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-11 05:37:45 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-11 05:38:25 +0000 |
| commit | 204fe6c536d5d3bca2cb712f66b1d63054807dac (patch) | |
| tree | c7d4515690d59efb08143bf6a4f228c15fe44fb4 /internal/storage/seed_test.go | |
| parent | 858756244129fa326af53495561882b51815f4d3 (diff) | |
fix(scheduler): make arbitration fail-closed on a missing verdict, seed planner's system prompt
A live production run (2026-07-11) showed finalizeArbitration's 'no
verdict reported = approve' default silently shipping work an evaluator
had already flagged as factually wrong -- the arbitration agent never
called report_verdict because the planner role had no system prompt
telling it to. finalizeArbitration now treats a missing verdict the same
as an explicit rejection (fail-closed), and SeedRoleConfigs now also
seeds planner with a prompt that explicitly mandates calling
report_verdict before finishing.
Diffstat (limited to 'internal/storage/seed_test.go')
| -rw-r--r-- | internal/storage/seed_test.go | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/internal/storage/seed_test.go b/internal/storage/seed_test.go index cd7c8e7..5b5b674 100644 --- a/internal/storage/seed_test.go +++ b/internal/storage/seed_test.go @@ -2,6 +2,7 @@ package storage import ( "encoding/json" + "strings" "testing" "github.com/thepeterstone/claudomator/internal/role" @@ -43,6 +44,43 @@ func TestSeedRoleConfigs_CreatesAndActivatesBuilder(t *testing.T) { } } +// TestSeedRoleConfigs_CreatesAndActivatesPlanner proves the arbitration +// role's system prompt is seeded too (added 2026-07-11 alongside +// finalizeArbitration's fail-closed default -- see that const's doc +// comment for why: a live run showed an arbitration agent with no system +// prompt at all never called report_verdict). Specifically checks the +// prompt actually names the report_verdict tool, since that's the whole +// point of this seed. +func TestSeedRoleConfigs_CreatesAndActivatesPlanner(t *testing.T) { + db := testDB(t) + + if err := db.SeedRoleConfigs(); err != nil { + t.Fatalf("SeedRoleConfigs: %v", err) + } + + row, err := db.GetActiveRoleConfig("planner") + if err != nil { + t.Fatalf("GetActiveRoleConfig(planner): %v", err) + } + if row.Version != 1 { + t.Errorf("expected version 1, got %d", row.Version) + } + + var cfg role.RoleConfig + if err := json.Unmarshal([]byte(row.ConfigJSON), &cfg); err != nil { + t.Fatalf("unmarshal seeded config: %v", err) + } + if cfg.Role != "planner" { + t.Errorf("cfg.Role = %q, want planner", cfg.Role) + } + if !strings.Contains(cfg.SystemPrompt, "report_verdict") { + t.Error("cfg.SystemPrompt does not mention report_verdict -- the whole point of this seed is mandating that call") + } + if len(cfg.EscalationLadder) != 2 { + t.Fatalf("expected 2 escalation tiers, got %d", len(cfg.EscalationLadder)) + } +} + func TestSeedRoleConfigs_Idempotent_DoesNotDuplicateOrOverwrite(t *testing.T) { db := testDB(t) @@ -53,12 +91,14 @@ func TestSeedRoleConfigs_Idempotent_DoesNotDuplicateOrOverwrite(t *testing.T) { t.Fatalf("second SeedRoleConfigs: %v", err) } - versions, err := db.ListRoleConfigVersions("builder") - if err != nil { - t.Fatalf("ListRoleConfigVersions: %v", err) - } - if len(versions) != 1 { - t.Fatalf("expected exactly 1 version after calling SeedRoleConfigs twice, got %d", len(versions)) + for _, r := range []string{"builder", "planner"} { + versions, err := db.ListRoleConfigVersions(r) + if err != nil { + t.Fatalf("ListRoleConfigVersions(%s): %v", r, err) + } + if len(versions) != 1 { + t.Fatalf("%s: expected exactly 1 version after calling SeedRoleConfigs twice, got %d", r, len(versions)) + } } } |
