Three-stage fail-fast validator for LLM-generated bot candidates: - syntax.go: language-aware parse (go/parser for Go; py_compile, rustfmt, tsc, javac, php -l for others; brace-balance fallback) - schema.go: regex detection of /health + /turn endpoints and "moves" field - sandbox.go: nsjail-isolated smoke test — builds bot, polls /health, sends 5 signed /turn requests, verifies JSON moves responses - validator.go: orchestrates stages with fail-fast short-circuit DB layer: - programs table + CRUD (create, get, list, updateFitness, setPromoted) - validation_log table with RecordValidation, IslandPassRates, IslandValidationStats for per-island pass-rate tracking - seed.go: 6 generation-0 bots across alpha/beta/gamma/delta islands MAP-Elites grid (mapelites/grid.go): 2-D behavior grid on aggression×economy axes; TryPlace keeps the fittest occupant per niche. acb-evolver CLI gains two new subcommands: validate <file> -lang <lang> [-island <island>] [-nsjail] [-nolog] validation-stats (tabular per-island pass-rate breakdown) cmd/acb-api/db.go: add programs table to API schema so the API can query promoted evolved bots. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
126 lines
2.8 KiB
Go
126 lines
2.8 KiB
Go
package db
|
||
|
||
import (
|
||
"context"
|
||
_ "embed"
|
||
"fmt"
|
||
)
|
||
|
||
//go:embed seeds/gatherer_strategy.go.txt
|
||
var gathererCode string
|
||
|
||
//go:embed seeds/rusher_strategy.rs.txt
|
||
var rusherCode string
|
||
|
||
//go:embed seeds/swarm_strategy.ts.txt
|
||
var swarmCode string
|
||
|
||
//go:embed seeds/guardian_strategy.php.txt
|
||
var guardianCode string
|
||
|
||
//go:embed seeds/hunter_strategy.java.txt
|
||
var hunterCode string
|
||
|
||
//go:embed seeds/random_main.py.txt
|
||
var randomCode string
|
||
|
||
// seedProgram describes a built-in strategy bot used to bootstrap the
|
||
// programs database.
|
||
type seedProgram struct {
|
||
name string
|
||
language string
|
||
island string
|
||
aggression float64 // behavior_vector[0]
|
||
economy float64 // behavior_vector[1]
|
||
code string
|
||
}
|
||
|
||
// seeds is the initial population of 6 built-in strategy bots distributed
|
||
// across all 4 islands. Each bot is assigned a behavior vector that captures
|
||
// its play-style on the aggression × economy axes.
|
||
var seeds = []seedProgram{
|
||
// beta island – economic strategies
|
||
{
|
||
name: "gatherer",
|
||
language: "go",
|
||
island: IslandBeta,
|
||
aggression: 0.1,
|
||
economy: 0.9,
|
||
code: gathererCode,
|
||
},
|
||
{
|
||
name: "guardian",
|
||
language: "php",
|
||
island: IslandBeta,
|
||
aggression: 0.2,
|
||
economy: 0.6,
|
||
code: guardianCode,
|
||
},
|
||
// alpha island – aggressive strategies
|
||
{
|
||
name: "rusher",
|
||
language: "rust",
|
||
island: IslandAlpha,
|
||
aggression: 0.9,
|
||
economy: 0.2,
|
||
code: rusherCode,
|
||
},
|
||
{
|
||
name: "swarm",
|
||
language: "typescript",
|
||
island: IslandAlpha,
|
||
aggression: 0.6,
|
||
economy: 0.5,
|
||
code: swarmCode,
|
||
},
|
||
// gamma island – adaptive / hunting strategies
|
||
{
|
||
name: "hunter",
|
||
language: "java",
|
||
island: IslandGamma,
|
||
aggression: 0.7,
|
||
economy: 0.3,
|
||
code: hunterCode,
|
||
},
|
||
// delta island – baseline / experimental
|
||
{
|
||
name: "random",
|
||
language: "python",
|
||
island: IslandDelta,
|
||
aggression: 0.3,
|
||
economy: 0.4,
|
||
code: randomCode,
|
||
},
|
||
}
|
||
|
||
// SeedPopulation inserts the 6 built-in strategy bots as generation-0
|
||
// programs if the programs table is empty. It is idempotent: a second call
|
||
// is a no-op.
|
||
func SeedPopulation(ctx context.Context, s *Store) (int, error) {
|
||
total, err := s.TotalCount(ctx)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("check existing programs: %w", err)
|
||
}
|
||
if total > 0 {
|
||
return 0, nil
|
||
}
|
||
|
||
inserted := 0
|
||
for _, seed := range seeds {
|
||
p := &Program{
|
||
Code: seed.code,
|
||
Language: seed.language,
|
||
Island: seed.island,
|
||
Generation: 0,
|
||
ParentIDs: []int64{},
|
||
BehaviorVector: []float64{seed.aggression, seed.economy},
|
||
Fitness: 0.0,
|
||
Promoted: false,
|
||
}
|
||
if _, err := s.Create(ctx, p); err != nil {
|
||
return inserted, fmt.Errorf("seed %s: %w", seed.name, err)
|
||
}
|
||
inserted++
|
||
}
|
||
return inserted, nil
|
||
}
|