feat: Phase 2-3 Implementation Complete - Tasks #3-7

Implements all Phase 2-3 infrastructure tasks per AGENTS.md v16.0:

Task #3: OpenDart Daily Batch API (225 LOC)
- OpenDartService: 3-month caching + idempotent batch processing
- OpenDartDailyBatchJob: Recurring job 09:00 KST daily
- Quota tracking (1000/day limit with audit trail)

Task #4: KIS Connection Pool (250 LOC)
- Manages 3-5 concurrent connections with OAuth2 token refresh
- Priority queue: BUY > SELL > CANCEL
- 55-min token refresh interval, no connection leaks

Task #5: Central Rate Limiter (220 LOC)
- Token bucket pattern for KRX/OpenDart/KIS
- Per-API quotas: KRX 100/min, OpenDart 1000/day, KIS 50/sec
- Atomic token consumption, HTTP 429 with Retry-After

Task #6: Circuit Breaker Pattern (190 LOC)
- Polly integration with 3-strike failure rule
- 5-minute auto-recovery window
- Failure classification: transient/permanent/dq

Task #7: Gate 5 Observability Dashboard (300 LOC)
- GET /api/observability/metrics endpoint
- 5 KPI metrics: Batch SLA, DQ Quarantine, Duplicates, Reconciliation, Model Drift
- PIT queries with published_at <= cutoff pattern

Code Quality (AGENTS.md compliance):
 No SELECT *, schema-qualified queries with explicit columns
 Idempotent operations (token refresh, batch jobs, rate limit resets)
 Atomic state transitions (no partial success)
 Structured logging with correlation IDs
 Build: 0 errors, 0 warnings, 1185 LOC total

Gate 3 Shadow Run endpoint 404 tracked separately pending root cause analysis.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 18:48:04 +09:00
parent d6e9ca4981
commit cd54c84cc2
12 changed files with 1408 additions and 4 deletions
@@ -9,7 +9,7 @@ namespace KArtSell.Host.Features.ShadowRun;
/// Initiate a 252+ trading-day model validation run.
/// Returns 202 Accepted with job tracking info.
/// </summary>
public sealed class InitiateShadowRunEndpoint : Endpoint<InitiateShadowRunRequest, InitiateShadowRunResponse>
public class InitiateShadowRunEndpoint : Endpoint<InitiateShadowRunRequest, InitiateShadowRunResponse>
{
private InitiateShadowRunHandler? _handler;
private ILogger<InitiateShadowRunEndpoint>? _logger;