summaryrefslogtreecommitdiff
path: root/internal/storage/seed_test.go
blob: cd7c8e7699aad164d1a9a87f271e1872daa60051 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package storage

import (
	"encoding/json"
	"testing"

	"github.com/thepeterstone/claudomator/internal/role"
)

func TestSeedRoleConfigs_CreatesAndActivatesBuilder(t *testing.T) {
	db := testDB(t)

	if err := db.SeedRoleConfigs(); err != nil {
		t.Fatalf("SeedRoleConfigs: %v", err)
	}

	row, err := db.GetActiveRoleConfig("builder")
	if err != nil {
		t.Fatalf("GetActiveRoleConfig(builder): %v", err)
	}
	if row.Version != 1 {
		t.Errorf("expected version 1, got %d", row.Version)
	}
	if row.ProposedBy != "seed" {
		t.Errorf("expected proposed_by 'seed', got %q", row.ProposedBy)
	}

	var cfg role.RoleConfig
	if err := json.Unmarshal([]byte(row.ConfigJSON), &cfg); err != nil {
		t.Fatalf("unmarshal seeded config: %v", err)
	}
	if cfg.Role != "builder" {
		t.Errorf("cfg.Role = %q, want builder", cfg.Role)
	}
	if cfg.SystemPrompt == "" {
		t.Error("cfg.SystemPrompt is empty, want the decompose-or-implement guidance")
	}
	if len(cfg.EscalationLadder) != 2 {
		t.Fatalf("expected 2 escalation tiers, got %d", len(cfg.EscalationLadder))
	}
	if cfg.EscalationLadder[0].Candidates[0].Provider != "claude" {
		t.Errorf("tier 0 provider = %q, want claude", cfg.EscalationLadder[0].Candidates[0].Provider)
	}
}

func TestSeedRoleConfigs_Idempotent_DoesNotDuplicateOrOverwrite(t *testing.T) {
	db := testDB(t)

	if err := db.SeedRoleConfigs(); err != nil {
		t.Fatalf("first SeedRoleConfigs: %v", err)
	}
	if err := db.SeedRoleConfigs(); err != nil {
		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))
	}
}

func TestSeedRoleConfigs_DoesNotOverwriteHumanCustomizedVersion(t *testing.T) {
	db := testDB(t)

	// A human (or the retro role's propose_role_config tool) already
	// created and activated their own version before the seed ever ran.
	custom, err := db.CreateRoleConfig("builder", `{"role":"builder","system_prompt":"custom prompt"}`, "human")
	if err != nil {
		t.Fatalf("CreateRoleConfig: %v", err)
	}
	if err := db.ActivateRoleConfigVersion("builder", custom.Version); err != nil {
		t.Fatalf("ActivateRoleConfigVersion: %v", err)
	}

	if err := db.SeedRoleConfigs(); err != nil {
		t.Fatalf("SeedRoleConfigs: %v", err)
	}

	row, err := db.GetActiveRoleConfig("builder")
	if err != nil {
		t.Fatalf("GetActiveRoleConfig: %v", err)
	}
	if row.ProposedBy != "human" {
		t.Errorf("active role config proposed_by = %q, want unchanged 'human' -- seed must not overwrite a human-authored active version", row.ProposedBy)
	}

	versions, err := db.ListRoleConfigVersions("builder")
	if err != nil {
		t.Fatalf("ListRoleConfigVersions: %v", err)
	}
	if len(versions) != 1 {
		t.Fatalf("expected exactly 1 version (seed must not create a competing draft), got %d", len(versions))
	}
}