ai-code-battle/cmd/acb-evolver/internal/db/db.go
jedarden 5669688984 Add validation pipeline, sandbox, and evolution DB layer (Phase 7)
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>
2026-03-26 22:45:13 -04:00

44 lines
1.7 KiB
Go

// Package db provides database access for the evolution pipeline.
package db
import (
"context"
"database/sql"
)
// schemaSQL creates the programs and validation_log tables with their indexes.
const schemaSQL = `
CREATE TABLE IF NOT EXISTS programs (
id BIGSERIAL PRIMARY KEY,
code TEXT NOT NULL,
language VARCHAR(32) NOT NULL,
island VARCHAR(16) NOT NULL,
generation INTEGER NOT NULL DEFAULT 0,
parent_ids JSONB NOT NULL DEFAULT '[]',
behavior_vector DOUBLE PRECISION[] NOT NULL DEFAULT '{}',
fitness DOUBLE PRECISION NOT NULL DEFAULT 0.0,
promoted BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_programs_island ON programs(island);
CREATE INDEX IF NOT EXISTS idx_programs_island_fitness ON programs(island, fitness DESC);
CREATE TABLE IF NOT EXISTS validation_log (
id BIGSERIAL PRIMARY KEY,
island VARCHAR(16) NOT NULL,
language VARCHAR(32) NOT NULL,
stage VARCHAR(16) NOT NULL, -- last stage attempted: syntax / schema / sandbox
passed BOOLEAN NOT NULL,
error_text TEXT NOT NULL DEFAULT '',
llm_output TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_validation_log_island ON validation_log(island);
CREATE INDEX IF NOT EXISTS idx_validation_log_island_passed ON validation_log(island, passed);
`
// EnsureSchema creates the programs table if it does not already exist.
func EnsureSchema(ctx context.Context, db *sql.DB) error {
_, err := db.ExecContext(ctx, schemaSQL)
return err
}