Files
gastown/internal/daemon/role_config_integration_test.go
gastown/crew/max a610283078 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>
2026-01-20 12:58:01 -08:00

146 lines
4.2 KiB
Go

//go:build integration
package daemon
import (
"io"
"log"
"os"
"path/filepath"
"testing"
)
// TestGetRoleConfigForIdentity_UsesBuiltinDefaults tests that the daemon
// uses built-in role definitions from embedded TOML files when no overrides exist.
func TestGetRoleConfigForIdentity_UsesBuiltinDefaults(t *testing.T) {
townRoot := t.TempDir()
d := &Daemon{
config: &Config{TownRoot: townRoot},
logger: log.New(io.Discard, "", 0),
}
// Should load witness role from built-in defaults
cfg, parsed, err := d.getRoleConfigForIdentity("myrig-witness")
if err != nil {
t.Fatalf("getRoleConfigForIdentity: %v", err)
}
if parsed == nil || parsed.RoleType != "witness" {
t.Fatalf("parsed = %#v, want roleType witness", parsed)
}
if cfg == nil {
t.Fatal("cfg is nil, expected built-in defaults")
}
// Built-in witness has session pattern "gt-{rig}-witness"
if cfg.SessionPattern != "gt-{rig}-witness" {
t.Errorf("cfg.SessionPattern = %q, want %q", cfg.SessionPattern, "gt-{rig}-witness")
}
}
// TestGetRoleConfigForIdentity_TownOverride tests that town-level TOML overrides
// are merged with built-in defaults.
func TestGetRoleConfigForIdentity_TownOverride(t *testing.T) {
townRoot := t.TempDir()
// Create town-level override
rolesDir := filepath.Join(townRoot, "roles")
if err := os.MkdirAll(rolesDir, 0755); err != nil {
t.Fatalf("mkdir roles: %v", err)
}
// Override start_command for witness role
witnessOverride := `
role = "witness"
scope = "rig"
[session]
start_command = "exec echo custom-town-command"
`
if err := os.WriteFile(filepath.Join(rolesDir, "witness.toml"), []byte(witnessOverride), 0644); err != nil {
t.Fatalf("write witness.toml: %v", err)
}
d := &Daemon{
config: &Config{TownRoot: townRoot},
logger: log.New(io.Discard, "", 0),
}
cfg, parsed, err := d.getRoleConfigForIdentity("myrig-witness")
if err != nil {
t.Fatalf("getRoleConfigForIdentity: %v", err)
}
if parsed == nil || parsed.RoleType != "witness" {
t.Fatalf("parsed = %#v, want roleType witness", parsed)
}
if cfg == nil {
t.Fatal("cfg is nil")
}
// Should have the overridden start_command
if cfg.StartCommand != "exec echo custom-town-command" {
t.Errorf("cfg.StartCommand = %q, want %q", cfg.StartCommand, "exec echo custom-town-command")
}
// Should still have built-in session pattern (not overridden)
if cfg.SessionPattern != "gt-{rig}-witness" {
t.Errorf("cfg.SessionPattern = %q, want %q", cfg.SessionPattern, "gt-{rig}-witness")
}
}
// TestGetRoleConfigForIdentity_RigOverride tests that rig-level TOML overrides
// take precedence over town-level overrides.
func TestGetRoleConfigForIdentity_RigOverride(t *testing.T) {
townRoot := t.TempDir()
rigPath := filepath.Join(townRoot, "myrig")
// Create town-level override
townRolesDir := filepath.Join(townRoot, "roles")
if err := os.MkdirAll(townRolesDir, 0755); err != nil {
t.Fatalf("mkdir town roles: %v", err)
}
townOverride := `
role = "witness"
scope = "rig"
[session]
start_command = "exec echo town-command"
`
if err := os.WriteFile(filepath.Join(townRolesDir, "witness.toml"), []byte(townOverride), 0644); err != nil {
t.Fatalf("write town witness.toml: %v", err)
}
// Create rig-level override (should take precedence)
rigRolesDir := filepath.Join(rigPath, "roles")
if err := os.MkdirAll(rigRolesDir, 0755); err != nil {
t.Fatalf("mkdir rig roles: %v", err)
}
rigOverride := `
role = "witness"
scope = "rig"
[session]
start_command = "exec echo rig-command"
`
if err := os.WriteFile(filepath.Join(rigRolesDir, "witness.toml"), []byte(rigOverride), 0644); err != nil {
t.Fatalf("write rig witness.toml: %v", err)
}
d := &Daemon{
config: &Config{TownRoot: townRoot},
logger: log.New(io.Discard, "", 0),
}
cfg, parsed, err := d.getRoleConfigForIdentity("myrig-witness")
if err != nil {
t.Fatalf("getRoleConfigForIdentity: %v", err)
}
if parsed == nil || parsed.RoleType != "witness" {
t.Fatalf("parsed = %#v, want roleType witness", parsed)
}
if cfg == nil {
t.Fatal("cfg is nil")
}
// Should have the rig-level override (takes precedence over town)
if cfg.StartCommand != "exec echo rig-command" {
t.Errorf("cfg.StartCommand = %q, want %q", cfg.StartCommand, "exec echo rig-command")
}
}