252dba1a57
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>
406 lines
10 KiB
Markdown
406 lines
10 KiB
Markdown
# 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.
|