ai-code-battle/cmd/acb-evolver/internal/db/db.go
jedarden 76e8791e4d Add evaluation arena, promotion gate, and retirement policy (Phase 7)
- arena/arena.go: 10-match mini-tournament running candidate as a local
  subprocess against diverse live opponents sampled across the rating
  distribution; AES-GCM secret decryption for opponent auth
- arena/psro.go: Nash equilibrium computation for the 1×K meta-game;
  FictitiousPlayNash included for future K×K support
- arena/winrate.go: Wilson-score 95% CI for win-rate calculation; draws
  counted as 0.5 wins
- arena/gate.go: two-part promotion gate — Nash value ≥ threshold AND
  MAP-Elites niche fill or improvement; detailed reason strings
- promoter/promoter.go: full promotion pipeline — bot source + Dockerfile
  + K8s Secret/Deployment/Service manifests, docker build, git commit/push
  (ArgoCD sync), kubectl readiness poll, bots-table INSERT, programs-table
  update; RetireBot and EnforcePolicy (rating threshold + population cap 50)
- db/db.go: add bot_name / bot_secret migration columns
- db/programs.go: ListPromoted, SetBotNameAndSecret, UnsetPromoted,
  GetByBotID, PromotedCount helpers for promotion/retirement lifecycle
- main.go: evaluate and retire subcommands wiring arena + gate + promoter;
  remove unused island flag from evaluate
- arena/arena_test.go: 21 unit tests covering Nash, Wilson CI, Gate logic,
  and selectDiverse opponent sampling
- promoter/promoter_test.go: tests for Dockerfiles, bot-ID/secret generation,
  AES-GCM helpers, and K8s manifest templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 23:32:37 -04:00

57 lines
2.2 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,
bot_id VARCHAR(16),
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);
`
// migrationSQL holds additive migrations run after the base schema is ensured.
// Each statement is idempotent (ALTER TABLE … ADD COLUMN IF NOT EXISTS).
const migrationSQL = `
ALTER TABLE programs ADD COLUMN IF NOT EXISTS bot_id VARCHAR(16);
ALTER TABLE programs ADD COLUMN IF NOT EXISTS bot_name VARCHAR(64);
ALTER TABLE programs ADD COLUMN IF NOT EXISTS bot_secret TEXT;
`
// EnsureSchema creates the programs and validation_log tables if they do not
// already exist, then applies any pending additive migrations.
func EnsureSchema(ctx context.Context, db *sql.DB) error {
if _, err := db.ExecContext(ctx, schemaSQL); err != nil {
return err
}
_, err := db.ExecContext(ctx, migrationSQL)
return err
}