feat(bat-054): 그날-시작 KIS 인증정보 양의 경로 주입 — KISBroker reinitialize (REQ-113 AC-2/AC-4, REQ-115 AC-1)

BAT-053 스캐폴드에서 연기된 양의 경로 완성:
- KISBroker.reinitialize(credential): app_key/app_secret/account_ref 교체 + L1 token 무효화
- SnapshotScheduler에 kis_reinit_callback 주입 지점 추가; 그날-시작 성공 시 callback 호출
- daemon.py에 _build_kis_reinit_callback() 헬퍼 + SnapshotScheduler 조립 수정
- 신규 테스트 12개 추가: 757 passed / 47 skipped (기존 745 대비 +12, 회귀 0)

안전 불변식 유지:
- credential_fetch_enabled=False(기본) 경로 byte-for-byte 보존
- fail-closed 불변식 미파괴 (reinit 실패 시 entry_allowed 유지)
- AMQP wire 계약 변경 없음

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
2026-06-28 19:51:48 +09:00
co-authored by Claude Sonnet 4.6
parent a50b5e34a2
commit 6b066e19cb
10 changed files with 733 additions and 1 deletions
@@ -50,6 +50,7 @@ class SnapshotScheduler:
alarm_emitter: Optional[AlarmEmitter] = None,
warn_store: Optional[ReconcileWarningStore] = None,
credential_fetch_enabled: bool = False,
kis_reinit_callback: Optional[Callable[[BrokerCredentialPayload], None]] = None,
) -> None:
self._read = read_port
self._store = store
@@ -72,6 +73,10 @@ class SnapshotScheduler:
# dcy-036 / REQ-113/114/115: credential fetch opt-in + break-glass detection.
# credential_fetch_enabled=False (default) → env-only, no portfolio-hub fetch.
self._credential_fetch_enabled: bool = credential_fetch_enabled
# dcy-036 / REQ-113 AC-2 / REQ-115 AC-1: optional callback to reinitialize
# KISBroker with the fetched day-start credential. None = no reinit (paper
# broker or credential_fetch_enabled=False). Set by daemon.py assembly.
self._kis_reinit_callback: Optional[Callable[[BrokerCredentialPayload], None]] = kis_reinit_callback
# REQ-113: detect break-glass at init time (env var set by operator).
self._break_glass: bool = (
os.environ.get("TREX_KIS_BROKER_BREAK_GLASS", "").lower()
@@ -206,6 +211,26 @@ class SnapshotScheduler:
ctx.broker.credential_version,
self._instance_key,
)
# dcy-036 / REQ-113 AC-2 / REQ-115 AC-1: reinitialize KISBroker with
# fetched credential so intraday KIS API calls use the day-start creds.
# Failure does NOT flip entry_allowed — the broker runs on existing env
# credentials until next checkpoint (graceful degrade, not fail-closed).
if self._kis_reinit_callback is not None:
try:
self._kis_reinit_callback(ctx.broker)
_log.info(
"DAY_START KISBroker reinitialized with fetched credential "
"(account_ref=%s, instance=%s)",
ctx.broker.account_ref,
self._instance_key,
)
except Exception as exc: # noqa: BLE001
_log.error(
"DAY_START KISBroker reinitialize failed: %s (instance=%s) "
"— trading continues with existing env credential",
exc.__class__.__name__,
self._instance_key,
)
def _emit_day_start_alarm(self, *, reason: str) -> None:
"""Publish CRITICAL DAY_START_LOAD_FAILED alarm (REQ-114)."""