fix(hyperopt): Fix PSO budget calculation for sequential execution

PROBLEM:
- PPO/DQN/TFT/MAMBA2 hyperopt stopped at 23/50 trials (46% completion)
- Root cause: Optimizer incorrectly divided remaining trials by n_particles
- Sequential execution (mutex-locked models) means 1 eval per iteration, not n_particles

FIX:
- Remove division by n_particles in PSO budget calculation
- Each iteration now evaluates exactly 1 trial (sequential execution)
- Expected: 3 initial + 47 PSO iterations = 50 trials total 

IMPACT:
- All hyperopt runs will now complete full trial count
- No performance impact (same execution pattern)
- Fixes PPO, DQN, TFT, and MAMBA2 hyperopt early termination

Files modified:
- ml/src/hyperopt/optimizer.rs: Fix budget calculation (lines 320-328)
- scripts/validate_gitlab_cicd.sh: Add CI/CD configuration validator
- scripts/build_docker_images.sh: Fix entrypoint override for validation

Testing:
- Code compiles successfully (2m 27s build time)
- GitLab CI/CD validator passes all checks
- Will be validated in CI/CD pipeline

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2025-11-02 19:37:32 +01:00
parent a0b9f4db0a
commit 9cd2a9f7ca
3 changed files with 399 additions and 8 deletions

View File

@@ -279,7 +279,8 @@ validate_binaries() {
local missing_binaries=()
for binary in "${EXPECTED_BINARIES[@]}"; do
if ! docker run --rm "$image_tag" test -f "/usr/local/bin/$binary"; then
# Override entrypoint to bypass self-termination wrapper during validation
if ! docker run --rm --entrypoint="" "$image_tag" test -f "/usr/local/bin/$binary"; then
print_error "Binary not found: /usr/local/bin/$binary"
missing_binaries+=("$binary")
else
@@ -294,7 +295,7 @@ validate_binaries() {
# Check CUDA libraries
print_info "Checking CUDA libraries..."
if ! docker run --rm "$image_tag" test -d /usr/local/cuda; then
if ! docker run --rm --entrypoint="" "$image_tag" test -d /usr/local/cuda; then
print_error "CUDA directory not found in image"
return 1
fi
@@ -302,7 +303,7 @@ validate_binaries() {
# Check cuDNN libraries
print_info "Checking cuDNN libraries..."
if ! docker run --rm "$image_tag" sh -c 'ldconfig -p | grep -q libcudnn'; then
if ! docker run --rm --entrypoint="" "$image_tag" sh -c 'ldconfig -p | grep -q libcudnn'; then
print_warning "cuDNN library not found (may be OK if using base image)"
else
print_success "cuDNN library present"
@@ -311,7 +312,7 @@ validate_binaries() {
# Check GLIBC version (should be 2.35 for Ubuntu 22.04)
print_info "Checking GLIBC version..."
local glibc_version
glibc_version=$(docker run --rm "$image_tag" ldd --version | head -n1 | grep -oP '\d+\.\d+' | head -n1)
glibc_version=$(docker run --rm --entrypoint="" "$image_tag" ldd --version | head -n1 | grep -oP '\d+\.\d+' | head -n1)
print_success "GLIBC version: $glibc_version"
print_success "Image validation complete"

387
scripts/validate_gitlab_cicd.sh Executable file
View File

@@ -0,0 +1,387 @@
#!/bin/bash
# =============================================================================
# GitLab CI/CD Configuration Validator
# =============================================================================
# Purpose: Validate .gitlab-ci.yml configuration and check prerequisites
# Usage: ./scripts/validate_gitlab_cicd.sh
# =============================================================================
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
print_header() {
echo -e "\n${CYAN}==============================================================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}==============================================================================${NC}\n"
}
print_success() {
echo -e "${GREEN}[✓]${NC} $1"
}
print_error() {
echo -e "${RED}[✗]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_info() {
echo -e "${BLUE}[i]${NC} $1"
}
# =============================================================================
# Validation Functions
# =============================================================================
validate_gitlab_ci_file() {
print_header "1. Validating .gitlab-ci.yml Syntax"
if [ ! -f .gitlab-ci.yml ]; then
print_error ".gitlab-ci.yml not found in current directory"
return 1
fi
print_success ".gitlab-ci.yml file exists"
# Check if gitlab-ci-local is installed for local validation
if command -v gitlab-ci-local &> /dev/null; then
print_info "Validating syntax with gitlab-ci-local..."
if gitlab-ci-local --list 2>&1 | grep -q "build:docker"; then
print_success "Syntax validation passed"
else
print_error "Syntax validation failed"
return 1
fi
else
print_warning "gitlab-ci-local not installed (optional, for local validation)"
print_info "Install: npm install -g gitlab-ci-local"
fi
# Check required stages
print_info "Checking required stages..."
for stage in "build" "test" "deploy"; do
if grep -q "\- $stage" .gitlab-ci.yml; then
print_success "Stage '$stage' defined"
else
print_error "Stage '$stage' missing"
return 1
fi
done
return 0
}
validate_docker_config() {
print_header "2. Validating Docker Configuration"
# Check Docker availability
if ! command -v docker &> /dev/null; then
print_error "Docker is not installed"
return 1
fi
print_success "Docker installed: $(docker --version)"
# Check Docker daemon
if ! docker info &> /dev/null; then
print_error "Docker daemon is not running"
return 1
fi
print_success "Docker daemon running"
# Check BuildKit support
if docker buildx version &> /dev/null; then
print_success "BuildKit available: $(docker buildx version | head -n1)"
else
print_warning "BuildKit not available (will use legacy builder)"
fi
# Check Dockerfile
if [ -f Dockerfile.foxhunt-build ]; then
print_success "Dockerfile.foxhunt-build exists"
else
print_error "Dockerfile.foxhunt-build not found"
return 1
fi
return 0
}
validate_docker_hub_config() {
print_header "3. Validating Docker Hub Configuration"
# Check if Docker Hub credentials are set (for local testing)
if [ -n "${DOCKER_HUB_USERNAME:-}" ] && [ -n "${DOCKER_HUB_PASSWORD:-}" ]; then
print_success "Docker Hub credentials found in environment"
# Test Docker Hub login
print_info "Testing Docker Hub authentication..."
if echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin docker.io &> /dev/null; then
print_success "Docker Hub authentication successful"
else
print_error "Docker Hub authentication failed"
return 1
fi
else
print_warning "Docker Hub credentials not set in environment (OK for GitLab CI/CD)"
print_info "For GitLab CI/CD, set these in: Settings → CI/CD → Variables"
print_info " - DOCKER_HUB_USERNAME (your Docker Hub username)"
print_info " - DOCKER_HUB_PASSWORD (Docker Hub access token, NOT password)"
fi
# Check Docker Hub repository
print_info "Checking Docker Hub repository configuration..."
REPO=$(grep "DOCKER_HUB_REPO:" .gitlab-ci.yml | awk '{print $2}')
if [ -n "$REPO" ]; then
print_success "Docker Hub repository: $REPO"
else
print_error "DOCKER_HUB_REPO not defined in .gitlab-ci.yml"
return 1
fi
return 0
}
validate_build_artifacts() {
print_header "4. Validating Build Artifacts"
# Check if hyperopt binaries exist
print_info "Checking for hyperopt binaries..."
local binaries=(
"hyperopt_mamba2_demo"
"hyperopt_dqn_demo"
"hyperopt_ppo_demo"
"hyperopt_tft_demo"
)
local missing_count=0
for binary in "${binaries[@]}"; do
if [ -f "target/release/$binary" ]; then
print_success "$binary exists ($(du -h "target/release/$binary" | cut -f1))"
else
print_warning "$binary not found (will be built in CI/CD)"
((missing_count++))
fi
done
if [ $missing_count -eq ${#binaries[@]} ]; then
print_warning "No hyperopt binaries found locally (expected for clean checkout)"
print_info "Binaries will be built during Docker image build"
fi
return 0
}
validate_gitlab_runner() {
print_header "5. Validating GitLab Runner Configuration"
# Check if gitlab-runner is installed
if command -v gitlab-runner &> /dev/null; then
print_success "GitLab Runner installed: $(gitlab-runner --version | head -n1)"
# Check registered runners
print_info "Checking registered runners..."
if gitlab-runner list 2>&1 | grep -q "Executor"; then
print_success "GitLab Runner registered"
gitlab-runner list 2>&1 | grep "Executor" | while read -r line; do
print_info " $line"
done
else
print_warning "No GitLab Runners registered locally"
fi
else
print_warning "GitLab Runner not installed locally (OK if using GitLab.com shared runners)"
print_info "For self-hosted runner: https://docs.gitlab.com/runner/install/"
fi
# Check .gitlab-ci.yml for runner tags
print_info "Checking runner tags in .gitlab-ci.yml..."
if grep -q "tags:" .gitlab-ci.yml; then
grep "tags:" .gitlab-ci.yml | while read -r line; do
print_info " $line"
done
print_success "Runner tags configured"
else
print_warning "No runner tags specified (will use any available runner)"
fi
return 0
}
validate_ci_variables() {
print_header "6. Validating CI/CD Variables"
print_info "Required GitLab CI/CD Variables (set in GitLab UI):"
print_info " - DOCKER_HUB_USERNAME (required)"
print_info " - DOCKER_HUB_PASSWORD (required, use access token)"
print_info ""
print_info "Optional CI/CD Variables:"
print_info " - SLACK_WEBHOOK_URL (for notifications)"
print_info " - DISCORD_WEBHOOK_URL (for notifications)"
# Check if variables are referenced in .gitlab-ci.yml
if grep -q "DOCKER_HUB_USERNAME" .gitlab-ci.yml && grep -q "DOCKER_HUB_PASSWORD" .gitlab-ci.yml; then
print_success "Required variables referenced in .gitlab-ci.yml"
else
print_error "Required variables not referenced in .gitlab-ci.yml"
return 1
fi
return 0
}
validate_deployment_config() {
print_header "7. Validating Deployment Configuration"
# Check deployment stages
if grep -q "deploy:runpod:" .gitlab-ci.yml; then
print_success "RunPod deployment stage configured"
else
print_warning "RunPod deployment stage not found"
fi
if grep -q "deploy:runpod-staging:" .gitlab-ci.yml; then
print_success "Staging deployment stage configured"
else
print_warning "Staging deployment stage not found"
fi
# Check manual approval for production
if grep -q "when: manual" .gitlab-ci.yml; then
print_success "Manual approval configured for production deployment"
else
print_warning "No manual approval for production (all deployments automatic)"
fi
# Check environment configuration
if grep -q "environment:" .gitlab-ci.yml; then
print_success "Environment configuration present"
else
print_warning "No environment configuration"
fi
return 0
}
simulate_local_build() {
print_header "8. Simulating Local Build (Optional)"
read -p "Run local Docker build simulation? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Skipping local build simulation"
return 0
fi
print_info "Building Docker image locally (this may take 5-10 minutes)..."
export DOCKER_BUILDKIT=1
export GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
export BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
if docker build \
-f Dockerfile.foxhunt-build \
-t jgrusewski/foxhunt:test-local \
--build-arg GIT_COMMIT="$GIT_COMMIT" \
--build-arg BUILD_DATE="$BUILD_DATE" \
. 2>&1 | tail -20; then
print_success "Local Docker build completed"
# Validate binaries in image
print_info "Validating binaries in image..."
local binaries=(
"hyperopt_mamba2_demo"
"hyperopt_dqn_demo"
"hyperopt_ppo_demo"
"hyperopt_tft_demo"
)
for binary in "${binaries[@]}"; do
if docker run --rm --entrypoint="" jgrusewski/foxhunt:test-local test -f "/usr/local/bin/$binary"; then
print_success "$binary exists in image"
else
print_error "$binary missing in image"
return 1
fi
done
# Show image size
local size=$(docker image inspect jgrusewski/foxhunt:test-local --format='{{.Size}}' | awk '{ sum=$1; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; for (x=1024**3; x>=1024; x/=1024) { if (sum>=x) { printf "%.2f %s", sum/x, hum[x]; break } }}')
print_info "Image size: $size"
else
print_error "Local Docker build failed"
return 1
fi
return 0
}
# =============================================================================
# Main Execution
# =============================================================================
main() {
print_header "GitLab CI/CD Configuration Validator"
print_info "Current directory: $(pwd)"
print_info "Git repository: $(git remote get-url origin 2>/dev/null || echo 'Not a git repository')"
print_info "Git branch: $(git branch --show-current 2>/dev/null || echo 'Unknown')"
print_info "Git commit: $(git rev-parse --short HEAD 2>/dev/null || echo 'Unknown')"
local exit_code=0
# Run all validations
validate_gitlab_ci_file || exit_code=1
validate_docker_config || exit_code=1
validate_docker_hub_config || exit_code=1
validate_build_artifacts || exit_code=1
validate_gitlab_runner || exit_code=1
validate_ci_variables || exit_code=1
validate_deployment_config || exit_code=1
# Optional: simulate local build
if [ $exit_code -eq 0 ]; then
simulate_local_build || exit_code=1
fi
# Final summary
print_header "Validation Summary"
if [ $exit_code -eq 0 ]; then
print_success "All validations passed!"
print_info ""
print_info "Next steps:"
print_info " 1. Set GitLab CI/CD variables in GitLab UI (if not already set)"
print_info " Settings → CI/CD → Variables"
print_info " - DOCKER_HUB_USERNAME"
print_info " - DOCKER_HUB_PASSWORD (Docker Hub access token)"
print_info ""
print_info " 2. Push to main branch to trigger pipeline:"
print_info " git push origin main"
print_info ""
print_info " 3. Monitor pipeline in GitLab:"
print_info " Project → CI/CD → Pipelines"
print_info ""
print_info " 4. Manual approval required for production deployment"
print_info ""
else
print_error "Some validations failed"
print_info ""
print_info "Please fix the issues above before enabling GitLab CI/CD"
print_info ""
fi
exit $exit_code
}
# Run main function
main "$@"