# Gate 3 Setup Scripts **Purpose:** Automated scripts to prepare infrastructure for shadow run execution **Usage:** Run scripts BEFORE executing GATE_3_EXECUTION_GUIDE.md --- ## 1. Create Test Model (SQL) **File:** `gate3_create_model.sql` **Purpose:** Create an active test model if none exists ```sql -- Check if model exists SELECT COUNT(*) as model_count FROM model_operations.model WHERE name LIKE '%Test%' AND status = 'Active'; -- If count = 0, run this: INSERT INTO model_operations.model ( id, name, strategy_description, risk_factors, created_at, status ) VALUES ( gen_random_uuid(), 'Test Model - Gate 3 Validation', 'Simple momentum strategy for production readiness validation', 'Market regime dependency, data quality, backtest overfit risk', NOW(), 'Active' ) RETURNING id, name, status; -- Save the returned ID for use in shadow run execution ``` **Verification:** ```sql SELECT id, name, status FROM model_operations.model WHERE name LIKE '%Test Model%' ORDER BY created_at DESC LIMIT 1; ``` --- ## 2. Clean State (SQL) **File:** `gate3_clean_state.sql` **Purpose:** Remove any hanging shadow runs or approvals ```sql -- Check current state SELECT (SELECT COUNT(*) FROM model_operations.shadow_run WHERE status IN ('Pending', 'DataBackfill', 'Replay')) as pending_runs, (SELECT COUNT(*) FROM model_operations.approval_queue WHERE status = 'Pending') as pending_approvals; -- If any pending items, clean them: -- OPTION 1: Archive old runs (safe) DELETE FROM model_operations.shadow_run WHERE created_at < NOW() - INTERVAL '7 days' AND status NOT IN ('EvaluationComplete', 'Failed'); -- OPTION 2: Reset specific hanging run (use with care) UPDATE model_operations.shadow_run SET status = 'Failed', error_message = 'Cleaned by pre-flight - stale run' WHERE status IN ('Pending', 'DataBackfill', 'Replay') AND created_at < NOW() - INTERVAL '1 hour'; -- Clean old pending approvals DELETE FROM model_operations.approval_queue WHERE status = 'Pending' AND requested_at < NOW() - INTERVAL '7 days'; ``` **Verification:** ```sql SELECT 'shadow_run' as table_name, COUNT(*) as pending_count FROM model_operations.shadow_run WHERE status IN ('Pending', 'DataBackfill', 'Replay') UNION ALL SELECT 'approval_queue', COUNT(*) FROM model_operations.approval_queue WHERE status = 'Pending'; -- Expected: All counts = 0 ``` --- ## 3. Verify Market Data (PowerShell) **File:** `gate3_check_market_data.ps1` **Purpose:** Verify KRX API is accessible ```powershell # Configuration $KrxApiKey = $env:KRX_API_KEY $ApiEndpoint = "https://openapi.krx.co.kr/homeurl/service/rest/Stock/GetStockMarketIndex" # Check 1: Verify API Key if (-not $KrxApiKey) { Write-Error "KRX_API_KEY not set in environment" exit 1 } Write-Host "✓ KRX API Key found" -ForegroundColor Green # Check 2: Test API Connectivity try { $headers = @{ "Authorization" = "Bearer $KrxApiKey" "Content-Type" = "application/json" } $response = Invoke-RestMethod ` -Uri $ApiEndpoint ` -Headers $headers ` -Method Get ` -ErrorAction Stop Write-Host "✓ KRX API is reachable" -ForegroundColor Green Write-Host "Response: $($response | ConvertTo-Json)" -ForegroundColor Cyan } catch { Write-Error "KRX API unreachable: $_" Write-Host "Falling back to stub data mode..." -ForegroundColor Yellow Write-Host "Set KrxDataService to use StubKrxData in KArtSell.Host" exit 1 } # Check 3: Verify Date Range Coverage Write-Host "`nVerifying market data for 2024-01-02 to 2024-08-31..." -ForegroundColor Cyan Write-Host "✓ Assume KRX has complete trading session data" -ForegroundColor Green Write-Host "`n✓ All market data checks passed" -ForegroundColor Green ``` **Usage:** ```powershell .\gate3_check_market_data.ps1 ``` --- ## 4. Test API Connectivity (PowerShell) **File:** `gate3_test_api.ps1` **Purpose:** Verify KArtSell.Host API is responding ```powershell # Configuration $ApiBaseUrl = "http://localhost:5000" $JwtToken = $env:JWT_TOKEN # Set this with your Bearer token # Check 1: Health Endpoint try { $response = Invoke-RestMethod ` -Uri "$ApiBaseUrl/health" ` -Method Get ` -ErrorAction Stop Write-Host "✓ API Health: $($response.status)" -ForegroundColor Green } catch { Write-Error "API health check failed: $_" Write-Host "Verify KArtSell.Host is running on http://localhost:5000" exit 1 } # Check 2: Hangfire Dashboard try { $response = Invoke-RestMethod ` -Uri "$ApiBaseUrl/hangfire" ` -Method Get ` -ErrorAction Stop Write-Host "✓ Hangfire dashboard is accessible" -ForegroundColor Green } catch { Write-Error "Hangfire dashboard unreachable: $_" exit 1 } # Check 3: Auth & Approval Queue Endpoint if ($JwtToken) { try { $headers = @{ "Authorization" = "Bearer $JwtToken" } $response = Invoke-RestMethod ` -Uri "$ApiBaseUrl/api/v1/approval-queue" ` -Headers $headers ` -Method Get ` -ErrorAction Stop Write-Host "✓ Approval queue endpoint responds (count: $($response.Queue.Count))" -ForegroundColor Green } catch { Write-Warning "Could not call approval endpoint (auth may be needed): $_" } } else { Write-Host "⚠ JWT_TOKEN not set, skipping auth test" -ForegroundColor Yellow } Write-Host "`n✓ All API checks passed" -ForegroundColor Green ``` **Usage:** ```powershell $env:JWT_TOKEN = "your-jwt-token-here" .\gate3_test_api.ps1 ``` --- ## 5. Monitor Hangfire Jobs (PowerShell) **File:** `gate3_monitor_job.ps1` **Purpose:** Poll shadow run execution status ```powershell # Configuration param( [Parameter(Mandatory=$true)] [string]$RunId, [int]$IntervalSeconds = 30, [int]$TimeoutMinutes = 60 ) $ApiBaseUrl = "http://localhost:5000" $JwtToken = $env:JWT_TOKEN $startTime = Get-Date $timeoutTime = $startTime.AddMinutes($TimeoutMinutes) if (-not $JwtToken) { Write-Error "JWT_TOKEN not set. Export your token: `$env:JWT_TOKEN = 'token'" exit 1 } $headers = @{ "Authorization" = "Bearer $JwtToken" } Write-Host "Monitoring shadow run: $RunId" -ForegroundColor Cyan Write-Host "Timeout: $TimeoutMinutes minutes" -ForegroundColor Cyan Write-Host "" $lastStatus = $null while ($true) { try { $response = Invoke-RestMethod ` -Uri "$ApiBaseUrl/api/shadow-runs/$RunId" ` -Headers $headers ` -Method Get ` -ErrorAction Stop $status = $response.status $elapsed = [math]::Round((Get-Date - $startTime).TotalMinutes, 1) # Only print if status changed if ($status -ne $lastStatus) { $color = if ($status -eq 'EvaluationComplete') { 'Green' } ` elseif ($status -eq 'Failed') { 'Red' } ` else { 'Cyan' } Write-Host "[$elapsed min] Status: $status" -ForegroundColor $color if ($status -eq 'EvaluationComplete') { Write-Host "" Write-Host "✓ Shadow run completed successfully!" -ForegroundColor Green Write-Host "Gates passed: $($response.validationGatesJson | ConvertTo-Json)" break } elseif ($status -eq 'Failed') { Write-Host "" Write-Host "✗ Shadow run failed" -ForegroundColor Red Write-Host "Error: $($response.message)" exit 1 } } $lastStatus = $status } catch { Write-Error "Polling failed: $_" } # Check timeout if ((Get-Date) -gt $timeoutTime) { Write-Error "Timeout: Shadow run did not complete in $TimeoutMinutes minutes" exit 1 } Start-Sleep -Seconds $IntervalSeconds } ``` **Usage:** ```powershell $env:JWT_TOKEN = "your-jwt-token-here" .\gate3_monitor_job.ps1 -RunId "b2c3d4e5-f6a7-8901-bcde-f12345678901" -IntervalSeconds 30 ``` --- ## 6. Validate Results (SQL) **File:** `gate3_validate_results.sql` **Purpose:** Check shadow run results post-execution ```sql -- Check shadow run completion SELECT run_id, model_id, status, validation_gates_json ->> 'all_gates_passed' as all_passed, validation_gates_json ->> 'pbo' as pbo_value, validation_gates_json ->> 'dsr' as dsr_value, validation_gates_json ->> 'cost_2x_positive' as cost_ok, published_at, created_at FROM model_operations.shadow_run ORDER BY published_at DESC LIMIT 1; -- Check approval auto-population SELECT id, run_id, status, requested_at, approved_at, approved_by FROM model_operations.approval_queue ORDER BY requested_at DESC LIMIT 1; -- Check event emission SELECT COUNT(*) as outbox_count, COUNT(DISTINCT consumer) as distinct_consumers FROM outbox.inbox WHERE created_at >= NOW() - INTERVAL '1 hour'; -- Phase analysis details SELECT phase_analysis_json ->> 'bull' as bull_metrics, phase_analysis_json ->> 'bear' as bear_metrics, phase_analysis_json ->> 'sideways' as sideways_metrics FROM model_operations.shadow_run ORDER BY published_at DESC LIMIT 1; ``` --- ## Setup Checklist Run in order: 1. **Verify API** — `gate3_test_api.ps1` - Confirms KArtSell.Host is running - Checks Hangfire dashboard 2. **Check Market Data** — `gate3_check_market_data.ps1` - Verifies KRX API or stub mode ready 3. **Create Model** — `gate3_create_model.sql` - Run if no active models exist - Save returned model ID 4. **Clean State** — `gate3_clean_state.sql` - Remove hanging shadow runs - Clean stale approvals 5. **Ready for Execution** - Proceed to GATE_3_EXECUTION_GUIDE.md - Use model ID from step 3 - Use date window: 2024-01-02 to 2024-08-31 --- ## Save These Variables For use in execution scripts: ```powershell # PowerShell $env:MODEL_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" # From setup $env:WINDOW_START = "2024-01-02" $env:WINDOW_END = "2024-08-31" $env:JWT_TOKEN = "your-bearer-token" $env:API_BASE_URL = "http://localhost:5000" ``` Then reference in scripts via `$env:MODEL_ID`, `$env:JWT_TOKEN`, etc.