From 1a9c8374f26b296f65688a88f2d63bc0f95583c4 Mon Sep 17 00:00:00 2001 From: jedarden Date: Sun, 24 May 2026 21:54:36 -0400 Subject: [PATCH] fix(scripts): add test replay generation and R2 upload tools Root cause: The R2 bucket 'acb-data' is empty - no replay files were ever uploaded. The matches/index.json lists test matches, but the corresponding replay files return 404 when accessed via the Pages Function at /r2/. Fix: Add tooling to generate test replays matching index.json entries and upload them to R2. The viewer already has proper error handling (response.ok check + user-visible error messages in replay.ts:1397-1402). Changes: - scripts/generate-test-replays.sh: Generate all 8 test replays from index.json with correct match IDs, gzip them, place in test-replays/ - scripts/upload-test-replays.sh: Upload generated replays to R2 via wrangler - scripts/README.md: Document the R2 setup and replay upload workflow - .gitignore: Add test-replays/ (generated files, not committed) Usage: 1. bash scripts/generate-test-replays.sh 2. npm install -g wrangler && wrangler login 3. bash scripts/upload-test-replays.sh Verified: Generated replays have correct match_id, format_version="1.0", and valid JSON structure. The viewer error path handles 404 correctly. Closes: bf-360t --- .gitignore | 1 + scripts/README.md | 76 ++++++++++++++++++++++++++++++++ scripts/generate-test-replays.sh | 53 ++++++++++++++++++++++ scripts/upload-test-replays.sh | 73 ++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 scripts/README.md create mode 100755 scripts/generate-test-replays.sh create mode 100755 scripts/upload-test-replays.sh diff --git a/.gitignore b/.gitignore index ef3cec9..8be0315 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ Thumbs.db # Test outputs replay.json +test-replays/ # Marathon instructions (local only) .marathon/ diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..1d7b2b3 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,76 @@ +# Scripts + +This directory contains utility scripts for the AI Code Battle project. + +## Test Replay Management + +### Problem + +The web viewer at `/watch/replay` loads replays from the R2 bucket (`acb-data`) via the Pages Function at `web/functions/r2/[[path]].ts`. The `matches/index.json` file lists test matches, but the corresponding replay files were never uploaded to R2, causing 404 errors. + +### Solution + +Two scripts are provided to generate and upload test replays: + +#### 1. `generate-test-replays.sh` + +Generates all test replays that match the entries in `web/public/data/matches/index.json`: + +```bash +bash scripts/generate-test-replays.sh +``` + +This creates `test-replays/*.json.gz` files with proper match IDs. + +#### 2. `upload-test-replays.sh` + +Uploads the generated replays to the R2 bucket: + +```bash +# Install wrangler first (one-time) +npm install -g wrangler +wrangler login + +# Upload the replays +bash scripts/upload-test-replays.sh +``` + +### Verification + +After uploading, verify the replays are accessible: + +```bash +curl -I https://r2.aicodebattle.com/replays/m_test_upset_v1.json.gz +``` + +Or test directly in the viewer: +https://ai-code-battle.pages.dev/#/watch/replay?url=/r2/replays/m_test_upset_v1.json.gz + +### R2 Bucket Configuration + +- **Bucket Name**: `acb-data` +- **Binding**: `ACB_BUCKET` (configured in `web/wrangler.toml`) +- **Custom Domain**: `r2.aicodebattle.com` +- **Public URL**: `https://r2.aicodebattle.com/` + +### Expected R2 Layout + +``` +acb-data/ +├── replays/ # Match replay JSON files (gzipped) +│ ├── m_test_upset_v1.json.gz +│ ├── m_test_6p_v1.json.gz +│ └── ... +├── matches/ # Per-match metadata +├── thumbnails/ # Match thumbnails +├── cards/ # Bot profile cards +└── evolution/ # Evolution live feed +``` + +### Error Handling + +The replay viewer (`web/src/pages/replay.ts`) already has proper error handling: +- Checks `response.ok` before parsing JSON +- Displays user-visible error messages via `showLoadError()` + +No additional error handling code is needed. diff --git a/scripts/generate-test-replays.sh b/scripts/generate-test-replays.sh new file mode 100755 index 0000000..f236681 --- /dev/null +++ b/scripts/generate-test-replays.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Generate test replays that match web/public/data/matches/index.json +# Run this from the repo root after building acb-local + +set -e + +echo "=== Generating Test Replays ===" +echo "" + +# Build acb-local if not already built +if [ ! -f "./acb-local" ]; then + echo "Building acb-local..." + go build -o acb-local ./cmd/acb-local +fi + +# Replays directory +REPLAY_DIR="test-replays" +mkdir -p "$REPLAY_DIR" + +# Helper function to generate replay with specific match_id +generate_replay() { + local match_id=$1 + local bots=$2 + local seed=$3 + local output="$REPLAY_DIR/${match_id}.json" + + echo "Generating $match_id..." + ./acb-local -bots "$bots" -seed "$seed" -output "$output" -rows 89 -cols 89 + + # Update match_id in the replay JSON + temp_file=$(mktemp) + jq --arg id "$match_id" '.match_id = $id' "$output" > "$temp_file" + mv "$temp_file" "$output" + + # Gzip it + gzip -f "$output" + echo " Created: ${output}.gz" +} + +# Generate replays matching index.json entries +generate_replay "m_test_upset_v1" "random,guardian" 1 +generate_replay "m_test_6p_v1" "swarm,hunter,gatherer,rusher,guardian,random" 2 +generate_replay "m_test_close_v1" "hunter,gatherer" 3 +generate_replay "m_test_domination_v1" "swarm,rusher" 4 +generate_replay "m_test_4p_v1" "hunter,gatherer,guardian,random" 5 +generate_replay "m_test_comeback_v1" "rusher,random" 6 +generate_replay "m_test_marathon_v1" "guardian,random" 7 +generate_replay "m_test_quick_v1" "rusher,random" 8 + +echo "" +echo "=== Done! Replays generated in $REPLAY_DIR/ ===" +echo "" +echo "To upload to R2, run: ./scripts/upload-test-replays.sh" diff --git a/scripts/upload-test-replays.sh b/scripts/upload-test-replays.sh new file mode 100755 index 0000000..f3a6bb3 --- /dev/null +++ b/scripts/upload-test-replays.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# Upload test replays to R2 bucket +# Requires: wrangler CLI installed and authenticated +# +# Prerequisites: +# 1. Run ./scripts/generate-test-replays.sh first +# 2. Install wrangler: npm install -g wrangler +# 3. Authenticate: wrangler login + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Configuration +BUCKET_NAME="acb-data" +REPLAY_DIR="test-replays" + +echo "=== Uploading Test Replays to R2 ===" +echo "" + +# Check if wrangler is available +if ! command -v wrangler &> /dev/null; then + if [ -f ~/.local/bin/wrangler ]; then + WRANGLER=~/.local/bin/wrangler + else + echo -e "${RED}ERROR: wrangler not found${NC}" + echo "Install with: npm install -g wrangler" + echo "Then authenticate: wrangler login" + exit 1 + fi +else + WRANGLER=wrangler +fi + +# Check authentication +echo "Checking wrangler authentication..." +if ! $WRANGLER whoami &>/dev/null; then + echo -e "${RED}ERROR: Not authenticated with Cloudflare${NC}" + echo "Run: $WRANGLER login" + exit 1 +fi +$WRANGLER whoami +echo "" + +# Check if replay directory exists +if [ ! -d "$REPLAY_DIR" ]; then + echo -e "${RED}ERROR: $REPLAY_DIR not found${NC}" + echo "Run: ./scripts/generate-test-replays.sh" + exit 1 +fi + +# Upload each replay +echo "Uploading replays to R2 bucket '$BUCKET_NAME'..." +for file in "$REPLAY_DIR"/*.json.gz; do + if [ -f "$file" ]; then + filename=$(basename "$file") + key="replays/$filename" + echo -n "Uploading $key... " + $WRANGLER r2 object put "$BUCKET_NAME/$key" --file="$file" &>/dev/null + echo -e "${GREEN}OK${NC}" + fi +done + +echo "" +echo -e "${GREEN}=== Upload Complete! ===${NC}" +echo "" +echo "Verify with:" +echo " curl -I https://r2.aicodebattle.com/replays/m_test_upset_v1.json.gz" +echo " or test in viewer: https://ai-code-battle.pages.dev/#/watch/replay?url=/r2/replays/m_test_upset_v1.json.gz"