# Direct Invocation Testing & Verification

## Quick Start

### 1. Call Direct API
```powershell
$headers = @{ "Content-Type" = "application/json" }
$body = @{
    modelId = "00000000-0000-0000-0000-000000000004"
    windowStart = "2026-05-01"
    windowEnd = "2026-05-31"
    phaseFilter = "All"
} | ConvertTo-Json

$response = Invoke-WebRequest -Uri "http://127.0.0.1:5002/api/test/shadow-run-direct" `
    -Method POST -Headers $headers -Body $body

$response.Content | ConvertFrom-Json
```

Returns:
```json
{
  "Success": true,
  "RunId": "af5a7555-7673-43ac-9701-d5978fcbcf83",
  "CorrelationId": "...",
  "DurationMs": 1668.3,
  "Message": "Shadow run executed successfully. Check database for persisted results."
}
```

### 2. Verify Database Results

**Using psql:**
```bash
psql -h 127.0.0.1 -U kartsell -d kartselldb -c "
SELECT 
  run_id, 
  model_id,
  window_start,
  window_end,
  status,
  (metrics_json->>'TotalReturn')::numeric as total_return,
  (metrics_json->>'SharpeRatio')::numeric as sharpe,
  (metrics_json->>'ProbOfBacktestOverfit')::numeric as pbo,
  (metrics_json->>'DailySharePercentile')::numeric as dsr,
  created_at
FROM model_operations.shadow_run
WHERE model_id = '00000000-0000-0000-0000-000000000004'
ORDER BY created_at DESC
LIMIT 5;
"
```

**Using .NET DbMigrator (E2E):**
```bash
dotnet test tests/KArtSell.Integration.Tests -c Release --filter "ShadowRunDirectInvocation"
```

## Performance Characteristics

| Window | Duration | Metrics Calculated |
|--------|----------|-------------------|
| **252 days** (2025-08-12 ~ 2026-08-12) | 8.6s | ✅ Full year |
| **90 days** (2026-05-15 ~ 2026-08-12) | 2.3s | ✅ Q2-Q3 |
| **30 days** (2026-04-01 ~ 2026-04-30) | 1.6s | ⚠️ Insufficient (needs 252+ days) |

## Key Improvements

✅ **No Queue Wait** - Direct synchronous execution  
✅ **Stub API Data** - No external API calls (KRX_OPENAPI not set → stub)  
✅ **Fast Feedback** - 2-3 min vs 7+ min with Hangfire  
✅ **Persistence Verified** - Results saved to model_operations.shadow_run

## Architecture

```
API Request
  ↓
ShadowRunJob.ExecuteAsync (direct, no queue)
  ├─ Phase 1: DataBackfiller.BackfillOhlcvAsync
  │    └─ Uses StubKrxData (no real API call)
  ├─ Phase 2: ReplayEngine.ReplayAsync
  ├─ Phase 3: MetricsCalculator.CalculateAsync
  ├─ Phase 4: PhaseSegmentation.Segment
  └─ InsertShadowRunAsync (DB persist)
       └─ Outbox event emitted
           └─ Inbox consumer processes async
```

## Testing Notes

- **Unit Tests**: `ShadowRunDirectInvocationTests` (2/2 passing)
- **Integration Tests**: `ShadowRunTests` (all passing)
- **E2E Gateway Tests**: `ShadowRunGate3Tests` (via Hangfire queue)

## Next Steps

1. ✅ Direct invocation endpoint implemented
2. ✅ DB persistence verified
3. ⏳ **TODO**: Isolate API mock for faster unit tests (separate from integration tests)
4. ⏳ **TODO**: Add performance benchmarks (target <3s for 90-day windows)
