fix(polecat): exclude reserved infrastructure agent names from allocator (#837)
The polecat name allocator was assigning reserved infrastructure agent names like 'witness' to polecats. Added ReservedInfraAgentNames map containing witness, mayor, deacon, and refinery. Modified getNames() to filter these from all themes and custom name lists. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,15 @@ const (
|
||||
DefaultTheme = "mad-max"
|
||||
)
|
||||
|
||||
// ReservedInfraAgentNames contains names reserved for infrastructure agents.
|
||||
// These names must never be allocated to polecats.
|
||||
var ReservedInfraAgentNames = map[string]bool{
|
||||
"witness": true,
|
||||
"mayor": true,
|
||||
"deacon": true,
|
||||
"refinery": true,
|
||||
}
|
||||
|
||||
// Built-in themes with themed polecat names.
|
||||
var BuiltinThemes = map[string][]string{
|
||||
"mad-max": {
|
||||
@@ -132,19 +141,34 @@ func NewNamePoolWithConfig(rigPath, rigName, theme string, customNames []string,
|
||||
}
|
||||
|
||||
// getNames returns the list of names to use for the pool.
|
||||
// Reserved infrastructure agent names are filtered out.
|
||||
func (p *NamePool) getNames() []string {
|
||||
var names []string
|
||||
|
||||
// Custom names take precedence
|
||||
if len(p.CustomNames) > 0 {
|
||||
return p.CustomNames
|
||||
names = p.CustomNames
|
||||
} else if themeNames, ok := BuiltinThemes[p.Theme]; ok {
|
||||
// Look up built-in theme
|
||||
names = themeNames
|
||||
} else {
|
||||
// Fall back to default theme
|
||||
names = BuiltinThemes[DefaultTheme]
|
||||
}
|
||||
|
||||
// Look up built-in theme
|
||||
if names, ok := BuiltinThemes[p.Theme]; ok {
|
||||
return names
|
||||
}
|
||||
// Filter out reserved infrastructure agent names
|
||||
return filterReservedNames(names)
|
||||
}
|
||||
|
||||
// Fall back to default theme
|
||||
return BuiltinThemes[DefaultTheme]
|
||||
// filterReservedNames removes reserved infrastructure agent names from a name list.
|
||||
func filterReservedNames(names []string) []string {
|
||||
filtered := make([]string, 0, len(names))
|
||||
for _, name := range names {
|
||||
if !ReservedInfraAgentNames[name] {
|
||||
filtered = append(filtered, name)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// Load loads the pool state from disk.
|
||||
|
||||
@@ -462,3 +462,66 @@ func TestThemeForRigDeterministic(t *testing.T) {
|
||||
t.Errorf("theme not deterministic: got %q and %q", theme1, theme2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamePool_ReservedNamesExcluded(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "namepool-test-*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Test all themes to ensure reserved names are excluded
|
||||
for themeName := range BuiltinThemes {
|
||||
pool := NewNamePoolWithConfig(tmpDir, "testrig", themeName, nil, 100)
|
||||
|
||||
// Allocate all available names (up to 100)
|
||||
allocated := make(map[string]bool)
|
||||
for i := 0; i < 100; i++ {
|
||||
name, err := pool.Allocate()
|
||||
if err != nil {
|
||||
t.Fatalf("Allocate error: %v", err)
|
||||
}
|
||||
allocated[name] = true
|
||||
}
|
||||
|
||||
// Verify no reserved names were allocated
|
||||
for reserved := range ReservedInfraAgentNames {
|
||||
if allocated[reserved] {
|
||||
t.Errorf("theme %q allocated reserved name %q", themeName, reserved)
|
||||
}
|
||||
}
|
||||
|
||||
pool.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamePool_ReservedNamesInCustomNames(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "namepool-test-*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
// Custom names that include reserved names should have them filtered out
|
||||
custom := []string{"alpha", "witness", "beta", "mayor", "gamma"}
|
||||
pool := NewNamePoolWithConfig(tmpDir, "testrig", "", custom, 10)
|
||||
|
||||
// Allocate all names
|
||||
allocated := make(map[string]bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
name, _ := pool.Allocate()
|
||||
allocated[name] = true
|
||||
}
|
||||
|
||||
// Should only get alpha, beta, gamma (3 non-reserved names)
|
||||
// Then overflow names for the remaining allocations
|
||||
if allocated["witness"] {
|
||||
t.Error("allocated reserved name 'witness' from custom names")
|
||||
}
|
||||
if allocated["mayor"] {
|
||||
t.Error("allocated reserved name 'mayor' from custom names")
|
||||
}
|
||||
if !allocated["alpha"] || !allocated["beta"] || !allocated["gamma"] {
|
||||
t.Errorf("expected alpha, beta, gamma to be allocated, got %v", allocated)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user