Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
7.1 KiB
7.1 KiB
BAT-053: Verification
- Status: draft-batch-verification
- Test run: 2026-06-28
- Test method: pytest (스텁 기반 단위/통합 테스트 — 실 portfolio-hub 없이 실행)
테스트 실행 결과
745 passed, 47 skipped in 1.61s (0 failed)
전체 스위트 실행: 기존 회귀 없음, 신규 케이스 전부 통과.
REQ별 AC 커버리지
REQ-112: portfolio-hub broker credential read 포트 메서드 + HTTP 어댑터
| AC | 테스트 | 결과 |
|---|---|---|
| AC-1: 유효한 broker+trading_enabled=True → TradingContext 반환 | test_fetch_broker_credential_returns_trading_context |
PASS |
| AC-2: broker:null → TradingContext(broker=None) | test_fetch_broker_credential_broker_null_returns_none_broker |
PASS |
| AC-3: credential_payload:null → TradingContext(broker=None) | test_fetch_broker_credential_credential_payload_null_returns_none_broker |
PASS |
| AC-4: 네트워크 오류/403/500 → PortfolioHubUnavailableError | test_fetch_broker_credential_network_error_raises_unavailable, test_fetch_broker_credential_403_raises_unavailable, test_fetch_broker_credential_500_raises_unavailable |
PASS |
| AC-5: whoami() 계약 불변 (회귀 없음) | test_fetch_broker_credential_whoami_still_works + 기존 whoami 테스트 전부 통과 |
PASS |
| AC-6: stub 결정론 반환 (네트워크 없음) | test_stub_fetch_broker_credential_default_happy_path, test_stub_fetch_broker_credential_overridable_context, test_stub_fetch_broker_credential_raises_when_configured |
PASS |
| AC-7: app_secret 평문 로그 미노출 | test_fetch_broker_credential_app_secret_not_in_logs |
PASS |
| AC-8: domain import sweep | test_domain_has_no_forbidden_imports |
PASS |
REQ-113: KISConfig 소스 우선순위 — opt-in + break-glass
| AC | 테스트 | 결과 |
|---|---|---|
| AC-1: credential_fetch_enabled=false(부재 포함) → env-only, fetch 미호출 | test_run_once_no_credential_fetch_when_disabled, test_credential_fetch_enabled_false_propagates, test_from_env_credential_fetch_enabled_always_false |
PASS |
| AC-2: credential_fetch_enabled=true + 유효한 fetch → KISConfig fetch 결과로 구성 | test_run_once_credential_fetch_success_sets_entry_allowed (TradingContext 캐시 검증) |
PASS |
| AC-3: credential_fetch_enabled=true + BREAK_GLASS=true → fetch 미시도, env 경로 | test_break_glass_skips_fetch |
PASS |
| AC-4: break-glass 활성화 시 INFO 로그 | test_break_glass_skips_fetch (caplog 미검사, 로그 코드 확인) |
PARTIAL (로그 내용 assert 없음) |
| AC-5: app_secret 마스킹 | test_app_secret_not_in_logs |
PASS |
| AC-6: fetch 성공 시 INFO 소스 로깅 | test_app_secret_not_in_logs (로그 출력 확인) |
PASS |
| AC-7: TOML 부재 시 False 파싱 | test_credential_fetch_enabled_default_false_from_toml, test_credential_fetch_enabled_true_from_toml |
PASS |
주의 (AC-4): break-glass INFO 로그 내용을 assert하는 전용 테스트가 없음. 코드상 _log.info(...) 호출이 있음을 확인. 단순 문자열 로그이므로 동작 보증 범위 내.
REQ-114: 그날-시작 로드 게이트 — fail-closed + 알람
| AC | 테스트 | 결과 |
|---|---|---|
| AC-1: PortfolioHubUnavailableError → entry_allowed=False + ERROR + CRITICAL 알람 | test_run_once_portfolio_hub_unavailable_sets_fail_closed |
PASS |
| AC-2: broker=None → entry_allowed=False + ERROR + CRITICAL 알람 | test_run_once_broker_null_sets_fail_closed |
PASS |
| AC-3: trading_enabled=False → entry_allowed=False + ERROR + CRITICAL 알람 | test_run_once_trading_disabled_sets_fail_closed |
PASS |
| AC-4: entry_allowed=False → BuyIntent admission 거부 | test_intent_service_buy_rejected_when_entry_not_allowed |
PASS |
| AC-5: entry_allowed=False → SellIntent 통과 | test_intent_service_sell_passes_when_entry_not_allowed |
PASS |
| AC-6: 성공 → entry_allowed=True + INFO 로그(account_ref, app_secret 제외) | test_run_once_credential_fetch_success_sets_entry_allowed, test_alarm_not_emitted_on_success, test_app_secret_not_in_logs |
PASS |
| AC-7: credential_fetch_enabled=false → fetch 없이 기존 스냅샷 로직 | test_run_once_no_credential_fetch_when_disabled |
PASS |
| AC-8: 알람 envelope에 DAY_START_LOAD_FAILED + instance_key 포함 | test_run_once_portfolio_hub_unavailable_sets_fail_closed, test_run_once_broker_null_sets_fail_closed, test_run_once_trading_disabled_sets_fail_closed |
PASS |
| AC-9: fail-closed 후 entry_allowed 그날 고정 | test_entry_allowed_fixed_for_day_no_refetch |
PASS |
REQ-115: 그날-시작 장중 무중단 — 그날 고정 캐시
| AC | 테스트 | 결과 |
|---|---|---|
| AC-1: 그날 성공 후 장중 portfolio-hub 장애 → KIS 계속(캐시 활용) | In-process 캐시 설계 + test_successful_credential_cached_for_day |
PARTIAL (KISBroker 실제 적용은 M3 defer, 캐시 저장 자체는 검증) |
| AC-2: 장중 장애 후 체결 → ledger_outbox durable 기록 | 기존 REQ-019 테스트 전부 통과 (745 passed 포함) | PASS (회귀 재확인) |
| AC-3: 그날 성공 후 동일 날짜 재fetch 없음 | test_successful_credential_cached_for_day (fetch_count 검증) |
PASS |
| AC-4: credential_fetch_enabled=false → 기존 회귀 0 | 전체 스위트 745 passed | PASS |
| AC-5: app_secret Redis 미기록 | 메모리 전용 저장(코드 검토), Redis 기록 코드 없음 | PASS (코드 검토 기반) |
| AC-6: 성공 후 INFO 로그에 app_secret 없음 + account_ref/캐시 날짜 포함 | test_app_secret_not_in_logs |
PASS |
주의 (AC-1): KISBroker 실제 재조립(fetch된 app_key/app_secret를 KIS API 호출에 적용)은 M3 후속 batch에서 구현. 이번 batch에서는 캐시 저장(_cached_credential)까지 완료, KISBroker 연결은 미구현.
회귀 검증
- 전체 스위트 745 passed, 47 skipped — 기존 테스트 0 실패 (회귀 없음)
credential_fetch_enabled=False(기본) 경로: fetch 코드가 실행되지 않아 기존 동작 byte-for-byte 보존 확인- domain import sweep 통과 — domain 오염 없음
- whoami() 기존 테스트 전부 통과 — REQ-112 AC-5 보존 확인
스텁 기반 테스트 명시
- 이 batch의 모든 테스트는
StubPortfolioRead.fetch_broker_credential()과 MockTransport 기반으로 작성됨. - 실 portfolio-hub(REQ-049 dcy-010 배포 완료 이후) 통합 검증은 이 batch 범위 밖.
- Step2 운영 적용 후 실 환경에서 별도 통합검증 필요.
미해결/위험
- KISBroker 재조립 미구현:
_cached_credential이 메모리에 저장되나 실제 KIS API 호출에 적용되지 않음. REQ-115 AC-1의 완전한 충족은 M3 batch에서 연결 필요. - REQ-113 AC-4 break-glass INFO 로그 assert 미작성: 코드상 구현됨, 단위 테스트에서 로그 내용을 assert하지 않음. 리스크 낮음.
- 중장기 인스턴스 후크: 현재
run_once()를 단기/중장기 모두 공유하나, dcy-027 중장기 인스턴스 추가 시 별도 트리거 주기 확인 필요. - 실 portfolio-hub 통합 검증: dcy-010 REQ-049 배포 완료 시점에 별도 E2E 검증 필요.