fix(index-builder): improve rivalry recency test isolation + add metrics

The RecencyBoost test now uses balanced 5-5 splits for both pairs so
recency is the sole differentiating factor (previously one pair was 10-0
which conflated balance and recency). Also wires Prometheus build
duration metric in main loop.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-04-22 16:07:18 -04:00
parent 7a0de02059
commit fff795ba6c
2 changed files with 33 additions and 8 deletions

View file

@ -10,6 +10,7 @@ import (
"syscall"
"time"
"github.com/aicodebattle/acb/metrics"
_ "github.com/lib/pq"
)
@ -47,6 +48,10 @@ func main() {
"database", cfg.PostgresDatabase,
)
// Start internal metrics server (separate port for Prometheus scraping)
metricsSrv := metrics.StartServer()
defer metricsSrv.Close()
// Create output directory
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
slog.Error("Failed to create output directory", "error", err, "path", cfg.OutputDir)
@ -79,6 +84,7 @@ func main() {
buildCount++
slog.Info("Starting build cycle", "count", buildCount)
buildStart := time.Now()
buildCtx, buildCancel := context.WithTimeout(context.Background(), cfg.BuildTimeout)
if err := runBuildCycle(buildCtx, db, cfg); err != nil {
slog.Error("Build cycle failed", "error", err)
@ -86,6 +92,7 @@ func main() {
slog.Info("Build cycle completed", "count", buildCount)
}
buildCancel()
metrics.IndexBuildDuration.Observe(time.Since(buildStart).Seconds())
// Deploy every N cycles
if buildCount%cfg.DeployInterval == 0 {

View file

@ -308,32 +308,50 @@ func TestComputeRivalries_MultiPlayerSkipped(t *testing.T) {
func TestComputeRivalries_RecencyBoost(t *testing.T) {
now := time.Now()
// Pair 1: all matches in the last week (high recency)
// Pair 1: all matches in the last week (high recency), balanced 5-5 split
var recentMatches []MatchData
for i := 0; i < 10; i++ {
for i := 0; i < 5; i++ {
recentMatches = append(recentMatches, MatchData{
ID: fmt.Sprintf("recent_%d", i),
ID: fmt.Sprintf("recent_a_%d", i),
WinnerID: "bot1",
PlayedAt: now.Add(-time.Duration(i*12) * time.Hour), // within last 5 days
PlayedAt: now.Add(-time.Duration(i*12) * time.Hour),
Participants: []ParticipantData{
{BotID: "bot1", Score: 3, Won: true},
{BotID: "bot2", Score: 2, Won: false},
},
})
recentMatches = append(recentMatches, MatchData{
ID: fmt.Sprintf("recent_b_%d", i),
WinnerID: "bot2",
PlayedAt: now.Add(-time.Duration(i*12+6) * time.Hour),
Participants: []ParticipantData{
{BotID: "bot1", Score: 2, Won: false},
{BotID: "bot2", Score: 3, Won: true},
},
})
}
// Pair 2: all matches 6 months ago (low recency)
// Pair 2: all matches 6 months ago (low recency), balanced 5-5 split
var oldMatches []MatchData
for i := 0; i < 10; i++ {
for i := 0; i < 5; i++ {
oldMatches = append(oldMatches, MatchData{
ID: fmt.Sprintf("old_%d", i),
ID: fmt.Sprintf("old_a_%d", i),
WinnerID: "bot3",
PlayedAt: now.Add(-180*24*time.Hour - time.Duration(i)*time.Hour), // ~6 months ago
PlayedAt: now.Add(-180*24*time.Hour - time.Duration(i)*time.Hour),
Participants: []ParticipantData{
{BotID: "bot3", Score: 3, Won: true},
{BotID: "bot4", Score: 2, Won: false},
},
})
oldMatches = append(oldMatches, MatchData{
ID: fmt.Sprintf("old_b_%d", i),
WinnerID: "bot4",
PlayedAt: now.Add(-180*24*time.Hour - time.Duration(i+5)*time.Hour),
Participants: []ParticipantData{
{BotID: "bot3", Score: 2, Won: false},
{BotID: "bot4", Score: 3, Won: true},
},
})
}
allMatches := append(recentMatches, oldMatches...)