Files
KArtSell.Aegis/GATE_3_SETUP_SCRIPTS.md
T
kjh2064 252dba1a57 Gate 3: Comprehensive Preparation Toolkit
Creates three detailed guides for production-ready shadow run execution:

1. GATE_3_PREFLIGHT_CHECKLIST.md (15 min checklist)
   - Infrastructure verification (SSH, PostgreSQL, KArtSell.Host)
   - Schema validation (all tables present)
   - Market data availability (KRX API or stub)
   - Execution readiness (model selection, date range)
   - Success criteria understanding
   - Troubleshooting for common pre-flight issues

2. GATE_3_SETUP_SCRIPTS.md (Automated preparation)
   - SQL scripts: Create test model, clean state
   - PowerShell: Check market data, test API, monitor jobs
   - Reusable monitoring script with timeout/retry logic
   - SQL validation queries for post-execution analysis
   - Save/reference environment variables

3. GATE_3_RESULTS_VALIDATION.md (Post-execution verification)
   - Validation gates breakdown (PBO, DSR, Cost2x)
   - SQL queries to verify each gate
   - Phase analysis interpretation (Bull/Bear/Sideways)
   - Audit trail verification (CorrelationId tracing)
   - Decision matrix (what to do if gates pass/fail)
   - Troubleshooting post-execution issues

Features:
✓ Step-by-step execution paths
✓ Copy-paste SQL queries for validation
✓ PowerShell scripts for automation
✓ Clear success/failure criteria
✓ Escalation paths (who to contact if gates fail)
✓ Post-execution approval workflow integration

Preparation level: PRODUCTION-READY
Next: Run checklist, execute shadow run, validate results

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-02 13:27:25 +09:00

10 KiB

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

-- 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:

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

-- 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:

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

# 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:

.\gate3_check_market_data.ps1

4. Test API Connectivity (PowerShell)

File: gate3_test_api.ps1
Purpose: Verify KArtSell.Host API is responding

# 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:

$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

# 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:

$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

-- 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 APIgate3_test_api.ps1

    • Confirms KArtSell.Host is running
    • Checks Hangfire dashboard
  2. Check Market Datagate3_check_market_data.ps1

    • Verifies KRX API or stub mode ready
  3. Create Modelgate3_create_model.sql

    • Run if no active models exist
    • Save returned model ID
  4. Clean Stategate3_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
$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.