feat(roles): switch daemon to config-based roles, remove role beads (Phase 2+3)
Phase 2: Daemon now uses config.LoadRoleDefinition() instead of role beads - lifecycle.go: getRoleConfigForIdentity() reads from TOML configs - Layered override resolution: builtin → town → rig Phase 3: Remove role bead creation and references - Remove RoleBead field from AgentFields struct - gt install no longer creates role beads - Remove 'role' from custom types list - Delete migrate_agents.go (no longer needed) - Deprecate beads_role.go (kept for reading existing beads) - Rewrite role_beads_check.go to validate TOML configs Existing role beads are orphaned but harmless. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
544cacf36d
commit
a610283078
@@ -4,15 +4,64 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
)
|
||||
|
||||
func TestRoleBeadsCheck_Run(t *testing.T) {
|
||||
t.Run("no town beads returns warning", func(t *testing.T) {
|
||||
func TestRoleConfigCheck_Run(t *testing.T) {
|
||||
t.Run("no overrides returns OK with defaults message", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
// Create minimal town structure without .beads
|
||||
if err := os.MkdirAll(filepath.Join(tmpDir, "mayor"), 0755); err != nil {
|
||||
|
||||
check := NewRoleBeadsCheck()
|
||||
ctx := &CheckContext{TownRoot: tmpDir}
|
||||
result := check.Run(ctx)
|
||||
|
||||
if result.Status != StatusOK {
|
||||
t.Errorf("expected StatusOK, got %v: %s", result.Status, result.Message)
|
||||
}
|
||||
if result.Message != "Role config uses built-in defaults" {
|
||||
t.Errorf("unexpected message: %s", result.Message)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valid town override returns OK", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
rolesDir := filepath.Join(tmpDir, "roles")
|
||||
if err := os.MkdirAll(rolesDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a valid TOML override
|
||||
override := `
|
||||
role = "witness"
|
||||
scope = "rig"
|
||||
|
||||
[session]
|
||||
start_command = "exec echo test"
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(rolesDir, "witness.toml"), []byte(override), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := NewRoleBeadsCheck()
|
||||
ctx := &CheckContext{TownRoot: tmpDir}
|
||||
result := check.Run(ctx)
|
||||
|
||||
if result.Status != StatusOK {
|
||||
t.Errorf("expected StatusOK, got %v: %s", result.Status, result.Message)
|
||||
}
|
||||
if result.Message != "Role config valid (1 override file(s))" {
|
||||
t.Errorf("unexpected message: %s", result.Message)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid town override returns warning", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
rolesDir := filepath.Join(tmpDir, "roles")
|
||||
if err := os.MkdirAll(rolesDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create an invalid TOML file
|
||||
if err := os.WriteFile(filepath.Join(rolesDir, "witness.toml"), []byte("invalid { toml"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -20,49 +69,53 @@ func TestRoleBeadsCheck_Run(t *testing.T) {
|
||||
ctx := &CheckContext{TownRoot: tmpDir}
|
||||
result := check.Run(ctx)
|
||||
|
||||
// Without .beads directory, all role beads are "missing"
|
||||
expectedCount := len(beads.AllRoleBeadDefs())
|
||||
if result.Status != StatusWarning {
|
||||
t.Errorf("expected StatusWarning, got %v: %s", result.Status, result.Message)
|
||||
}
|
||||
if len(result.Details) != expectedCount {
|
||||
t.Errorf("expected %d missing role beads, got %d: %v", expectedCount, len(result.Details), result.Details)
|
||||
if len(result.Details) != 1 {
|
||||
t.Errorf("expected 1 warning detail, got %d", len(result.Details))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check is fixable", func(t *testing.T) {
|
||||
t.Run("valid rig override returns OK", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
rigName := "testrig"
|
||||
rigDir := filepath.Join(tmpDir, rigName)
|
||||
rigRolesDir := filepath.Join(rigDir, "roles")
|
||||
if err := os.MkdirAll(rigRolesDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create rig.json to mark this as a rig
|
||||
if err := os.WriteFile(filepath.Join(rigDir, "rig.json"), []byte(`{"name": "testrig"}`), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a valid TOML override
|
||||
override := `
|
||||
role = "refinery"
|
||||
scope = "rig"
|
||||
|
||||
[session]
|
||||
needs_pre_sync = true
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(rigRolesDir, "refinery.toml"), []byte(override), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := NewRoleBeadsCheck()
|
||||
if !check.CanFix() {
|
||||
t.Error("RoleBeadsCheck should be fixable")
|
||||
ctx := &CheckContext{TownRoot: tmpDir}
|
||||
result := check.Run(ctx)
|
||||
|
||||
if result.Status != StatusOK {
|
||||
t.Errorf("expected StatusOK, got %v: %s", result.Status, result.Message)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check is not fixable", func(t *testing.T) {
|
||||
check := NewRoleBeadsCheck()
|
||||
if check.CanFix() {
|
||||
t.Error("RoleConfigCheck should not be fixable (config issues need manual fix)")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoleBeadsCheck_usesSharedDefs(t *testing.T) {
|
||||
// Verify the check uses beads.AllRoleBeadDefs()
|
||||
roleDefs := beads.AllRoleBeadDefs()
|
||||
|
||||
if len(roleDefs) < 7 {
|
||||
t.Errorf("expected at least 7 role beads, got %d", len(roleDefs))
|
||||
}
|
||||
|
||||
// Verify key roles are present
|
||||
expectedIDs := map[string]bool{
|
||||
"hq-mayor-role": false,
|
||||
"hq-deacon-role": false,
|
||||
"hq-witness-role": false,
|
||||
"hq-refinery-role": false,
|
||||
}
|
||||
|
||||
for _, role := range roleDefs {
|
||||
if _, exists := expectedIDs[role.ID]; exists {
|
||||
expectedIDs[role.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
for id, found := range expectedIDs {
|
||||
if !found {
|
||||
t.Errorf("expected role %s not found in AllRoleBeadDefs()", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user