# req-115: 그날-시작 장중 무중단 보장 — 그날 고정 인증정보 캐시 + portfolio-hub 장애 비중단 - Status: Approved - Type: Non-Functional - Priority: High - Owner: trex-core-dev ## Intent - dcy-036 C3/FR-3/NFR-1~3에 따라, 그날-시작 로드 성공 이후 장중 portfolio-hub 장애는 이미 시작된 그날 실행(진입·청산 포함)을 중단시키지 않아야 한다. 그날 인증정보는 캐시로 유지되어 KIS API 호출이 계속되고, 원장 기록은 `ledger_outbox`로 portfolio-hub 복구 후 drain된다. - 또한 기존 env-only 경로(fetch 미활성)에서 이 REQ의 변경이 아무런 회귀를 발생시키지 않아야 한다(NFR-1). ## Requirement - **그날 고정 캐시**: `credential_fetch_enabled = true` 경로에서 그날-시작 체크포인트에 fetch된 `BrokerCredentialPayload`는 그날 동안 메모리 캐시로 유지된다. 장중 portfolio-hub 장애 또는 복구 이벤트가 발생해도 그날 중 자동 재fetch하지 않는다. 다음 그날-시작 체크포인트(다음 날 07:30 KST 또는 중장기 리밸런싱 주기)에서만 새로 fetch한다. - **KIS API 연속성**: 그날 캐시된 인증정보로 KIS broker adapter(`KISBrokerAdapter`)의 주문 제출·체결 조회·토큰 갱신이 장중 portfolio-hub 장애와 무관하게 계속된다. - **원장 무손실**: 그날 체결 기록은 `ledger_outbox`(REQ-019)를 통해 durable하게 trex-core PG에 기록되므로 장중 portfolio-hub 장애가 원장 유실로 이어지지 않는다. 이는 기존 구현(REQ-019 Implemented)의 속성을 재확인·명시하는 것이다. - **회귀 없음**: `credential_fetch_enabled = false`(기존 env-only 경로)에서 이 REQ의 변경이 기존 동작에 영향을 주지 않는다. 기존 테스트가 전부 그린을 유지해야 한다. - **보안**: 그날 캐시된 인증정보(특히 `app_secret`)는 메모리에만 유지하며 Redis 또는 다른 외부 저장소에 평문 기록하지 않는다. 캐시 만료(다음날 로드 사이클)까지 메모리 내 보존. ## Acceptance Criteria 1. Given 그날-시작 로드 성공(`credential_fetch_enabled = true`) 후 portfolio-hub를 내려(네트워크 차단) 장중 장애 주입, When BuyIntent 또는 SellIntent를 처리, Then KIS 브로커 어댑터가 캐시된 인증정보로 주문을 처리하고 `PortfolioHubUnavailableError`로 인해 주문이 차단되지 않는다. 2. Given 장중 portfolio-hub 장애 상태에서 체결 발생, When 체결 처리, Then `ledger_outbox`에 durable하게 기록된다 (portfolio-hub 복구 후 drain — 기존 REQ-019 속성 회귀 없음). 3. Given 그날 로드 성공 후 장중 portfolio-hub가 잠시 다운되었다가 복구, When 그날 중 재fetch 트리거 없음, Then 그날 인증정보는 재load 없이 최초 fetch 값 그대로 유지된다 (그날 고정 불변식). 4. Given `credential_fetch_enabled = false`(기존 env-only), When 기존 회귀 테스트 스위트 실행, Then 0 fail — 기존 동작 보존. 5. Given 그날 캐시된 `app_secret`, When Redis 또는 외부 저장소 확인, Then 평문 기록 없음 (메모리 캐시 한정). 6. Given 그날-시작 로드 성공 직후 INFO 로그 확인, When 캐시 상태 기록, Then `app_secret` 평문이 로그에 없고, account_ref 및 캐시 유효 날짜가 기록된다. ## Impacted Area - Docs: 없음 (baseline 문서 갱신은 별도 scope) - Modules: - `trex_core/application/snapshot_scheduler.py` (또는 그날-시작 후크 레이어) — 그날 고정 캐시 저장소(`_cached_credential: BrokerCredentialPayload | None`, `_credential_date: date | None`) 관리, 장중 재fetch 방지 로직 - `trex_core/runtime/config.py` 또는 조립 레이어 — 캐시된 `BrokerCredentialPayload`에서 `KISConfig` 재구성 경로 보장 (장중 KIS adapter 재생성 불필요) - Tests: - `tests/application/test_snapshot_scheduler.py` — AC-1~3: 장중 portfolio-hub 장애 주입 시나리오 (stub fetch_broker_credential + 캐시 상태 검증) - `tests/runtime/test_config.py` (또는 회귀 스위트) — AC-4: 기존 env-only 테스트 그린 유지 - `tests/application/` — AC-5: 캐시가 Redis에 기록되지 않는 검증 (mock Redis 확인) ## Notes - AC-1의 "주문 처리 계속"은 KIS broker adapter가 이미 로컬로 보유한 인증정보를 사용한다는 전제다. KIS token cache(Redis, REQ-016)는 KIS access token(≠ app_key/app_secret)을 저장하며 이는 별개 캐시 계층 — 이 REQ가 다루는 것은 `app_key`/`app_secret`/`account_ref`의 "그날 고정" 보장이다. - `ledger_outbox` 무손실(AC-2)은 REQ-019 Implemented의 기존 속성을 이 컨텍스트에서 재확인·evidence로 명시하는 것이다. 추가 구현은 불필요하나, 테스트에서 outbox 행이 생성됨을 회귀 케이스로 확인한다. - 중장기 인스턴스에서 그날 고정의 "하루" 경계가 다를 수 있다(dcy-027 리밸런싱 주기 단위). AC-3는 단기(07:30 KST 스냅샷) 기준으로 테스트하고, 중장기는 설계 단계에서 확인 후 반영. - 보안(AC-5): KIS access token(REQ-016)은 Redis TTL 캐시가 이미 존재하며 이와 혼동하지 않는다. `app_secret`은 Redis에 별도로 쓰지 않음. - Source: dcy-036 C3, FR-3, NFR-1(회귀안전), NFR-2(보안), NFR-3(관측성 중 캐시 상태 로깅 부분), OQ-2 Answered (그날 고정). ## Change Log ### CHG-20260628-01 - Date: 2026-06-28 - Author: trex-core-dev #### Change Summary - 신규 생성 (Proposed) — dcy-036 C3/FR-3/NFR-1~3 산출물. #### Intent - dcy-036 FR-3(장중 무중단 보장)과 NFR-1~3을 Non-Functional REQ로 정규화한다. 구현 근거 없이 "완료"로 처리하지 않도록 측정 가능한 AC를 명시. #### Acceptance Criteria Delta - Added: - AC-1~6 전체 (신규 초안) - Updated: 없음 - Removed: 없음 #### Impacted Area Delta - Docs: 없음 - Modules: - `snapshot_scheduler.py` 그날 고정 캐시 로직 - `config.py` 조립 레이어 캐시 경로 - Tests: - `test_snapshot_scheduler.py`, `test_config.py` 케이스 추가 #### Delivery Trace Delta - Batches: 미정 (suggest-batch-reqs 대기) - Releases: 미정 #### Revalidation Impact - Reverification Needed: no - Existing Implementation Invalidated: no - Status Recommendation: keep-current - Follow-up Action: confirm-req 후 REQ-112~115 일괄 batch 배정 검토. #### Validation Plan - pytest로 AC-1~6 확인. AC-1(장중 장애 후 주문 처리 계속)은 PortfolioHubReadAdapter를 장중 failure stub으로 교체하는 방식으로 격리. AC-4(기존 회귀)는 전체 테스트 스위트 재실행으로 확인. ### CHG-20260628-02 - Date: 2026-06-28 - Author: 팀장(Claude) - confirm-req: `Proposed` → `Approved`. dcy-036 FR-3/NFR-1~3/OQ-2 추적. 그날 고정 캐시(장중 무재fetch, AC-3)·KIS API 연속성(AC-1)·ledger_outbox 무손실 재확인(AC-2, REQ-019)·app_secret 메모리 한정(AC-5, Redis 미기록)·env-only 회귀보존(AC-4) 적절. KIS access token 캐시(REQ-016)와 구분 명확. blocker 없음. ### CHG-20260628-03 - Date: 2026-06-28 - Author: 팀장(Claude) - 부분 구현 — BAT-053 PR #34 머지(merge commit 01655ab). 그날 고정 캐시 저장(AC-3), app_secret 메모리 한정(AC-5), ledger_outbox 무손실 재확인(AC-2), env-only 회귀보존(AC-4) 구현·머지 완료. **연기: AC-1(캐시된 인증정보를 실 KIS 거래에 주입=KISBroker 런타임 재조립) → M3 후속 batch.** AC-9 전용 테스트 보강도 후속. Status `Approved` 유지(미충족 AC 존재).