19 KiB
19 KiB
0. 문서 상태
- 상태: confirmed
- 문서 ID: dcy-037_20260714_operator-broker-truth-and-managed-slot-divergence-hotfix
- 이슈명: HOTFIX — fetched credential 운영자 broker truth 정합 및 managed non-holding divergence 분리 (#39, #40, #41)
- 작성 시각(KST): 2026-07-14 21:52:01 KST
- 마지막 갱신 시각(KST): 2026-07-14 22:24:41 KST (draft-req)
- 대체됨: 없음
- 후속 Discovery 참조:
dcy-038_20260716_cost-basis-response-contract-and-safe-sync-seeding— portfolio-hub cost-basis canonical response parsing 및 안전한 sync avg_price seed P1 follow-up - 생성된 REQ 참조: REQ-119, REQ-120, REQ-121, REQ-122
1. 계획 상태 요약
- 연계 문서 현황:
- 해석:
credential_fetch_enabled=true인genichin-longterm에서 daemon, operator CLI, broker token lifecycle이 같은 계좌 잔고 truth를 보장하지 못하여sync/verify결과를 운영 복구 판단에 사용할 수 없다.- 이 HOTFIX는 잘못된 broker truth를 빈 잔고로 해석하는 경로를 차단하고, 이미 관리되는 inactive/error 슬롯을 진짜 unmanaged position과 구분해 안전한 운영자 triage와 이후 sync를 가능하게 한다.
2. 요구사항 판정 결과
- 판정: 신규
- 근거
dcy-034/REQ-105·106은sync/verify의 상태 동기화 의미론을 정의했지만, fetched credential 모드에서 CLI가 daemon과 동일한 credential source 및 token lifecycle을 사용해야 한다는 운영 불변식은 정의하지 않았다.dcy-036/REQ-113·115는 day-start fetched credential과 fail-safe entry gate를 다루지만, direct-DB operator CLI의 credential 재해석·token throttle 및 inactive 슬롯의 reconcile 분류는 후속 운영 환류로 독립 추적하는 편이 명확하다.
3. 문제점의 요약
- 현재 상태
- issue #39 재현에서 daemon은 portfolio-hub fetched credential로 계좌 A를 사용하지만,
sync/verify는_build_broker(cfg)로 env/config 계좌 B를 생성했다. 동일 instance의005930은 daemon broker truth에서 qty=5이나 CLI dry-run은broker_qty_zero로 skip했다. 계좌 식별자는 문서·로그에서 안전하게 마스킹한다. - issue #40의
KISBroker.get_balance()는 token/auth HTTP 오류를 잡아[]로 반환한다. fresh fetched-credential broker가 KIS token throttle(EGW00133)을 받으면 실제 보유가 없는 것처럼 보이며,broker_qty_zero같은 상태 판단으로 이어질 수 있다. - issue #41의
reconcile_core_holdings()는list_holding_slots(instance_key)만 대조한다. 따라서 broker가 보유한 symbol에 대해 같은 instance의 managed slot이inactive또는error로 존재해도unmanaged position으로 로그를 남긴다.
- issue #39 재현에서 daemon은 portfolio-hub fetched credential로 계좌 A를 사용하지만,
- 기대 상태
- fetched credential 모드에서 daemon과
sync/verify는 동일한 portfolio-hub credential source와 명시적인 token/broker lifecycle 정책으로 broker truth를 조회하며, 인증·token 실패는 empty balance와 절대 동치가 아니다. - reconciliation은
slot 없음의 true unmanaged position과slot 존재 + non-holding의 managed state divergence를 별도 code/log/운영 조치로 구분한다.
- fetched credential 모드에서 daemon과
- 이해관계자
- 사장님: hotfix 범위·production 배포 및 실계좌
sync --live최종 승인자 - 팀장: Discovery/REQ/Batch 및 release gate 관리
- trex-core-dev: broker 구성, reconciliation, CLI 및 회귀 테스트 delivery 담당
- qc-reviewer: credential source, throttle fail-closed, divergence 분류의 독립 검증 담당
- 운영자: dry-run 검증 후 승인된 live sync를 수행하는 주체
- 사장님: hotfix 범위·production 배포 및 실계좌
- 제약사항
- app key/app secret/token 및 raw credential payload는 로그, JSON 출력, 테스트 fixture에 기록하지 않는다.
sync --live는 외부 실계좌/DB 상태를 변경하므로 본 HOTFIX 배포 후에도 별도 운영 승인 없이는 실행하지 않는다.- 기존
credential_fetch_enabled=falseenv-only instance와 AMQP wire 계약은 회귀 없이 유지한다.
주요 사용자 시나리오
- 운영자가
genichin-longterm의 inactive slot과 broker-held005930을 확인한다.sync --dry-run은 fetched credential source로 broker qty=5를 확인하고, token 오류가 나면 0 보유로 판단하지 않고 비0 종료와 안전한 오류를 반환한다. - daemon reconcile이
inactivemanaged slot + broker qty>0을 발견하면managed_non_holding_divergence로 구조화해 경고한다. slot이 전혀 없는 broker-held symbol만 기존unmanaged_position경로를 탄다. - hotfix QC와 release 검증 후 운영자가 dry-run 결과, portfolio-hub 장부, broker truth를 교차 확인하고 명시 승인된 단일 대상에만
sync --live --yes를 실행한다.
4. 이번에 정의할 변경
- 변경 1 — daemon/CLI 공통 broker truth 해석:
credential_fetch_enabled=true일 때 operator CLI도 portfolio-hub fetched credential을 사용하고, raw env/config credential은 명시적인 break-glass 정책 외에는 조용히 fallback하지 않는다. - 변경 2 — token/auth 실패 fail-loud:
get_balance()와 operator 표면에서 token issuance/auth/transport 실패를 actual empty holdings와 분리하고, 반복 조회에 대한 broker/token 재사용 정책을 명확히 한다. - 변경 3 — managed non-holding divergence 분류: holding-only 수량 대조는 보존하되, 미매칭 broker symbol에 대해 전체 slot 존재를 확인해
unmanaged_position과managed_non_holding_divergence를 구분한다. - 변경 4 — baseline/운영 문서 정합: credential source, error semantics, reconcile decision code, dry-run 및 live remediation gate를
docs/runtime-flows.md,docs/interface-contract.md,docs/operations.md에 실제 구현과 일치하게 반영한다.
영향 범위
- 코드 영향:
trex_core/runtime/daemon.py,trex_core/runtime/cli.py,trex_core/application/snapshot_scheduler.py또는 공통 broker factory: fetched credential source 및 CLI broker 생성 경로.trex_core/adapters/broker/kis.py: token/auth failure와 actual empty balance의 구분, KIS token lifecycle.trex_core/application/reconciliation.py, SlotRepository protocol 및 PostgreSQL/InMemory 구현: non-holding managed-slot existence check와 구조화 classification.
- 문서 영향:
docs/runtime-flows.md,docs/interface-contract.md,docs/operations.md, 신규 REQ/Batch/verification 문서.dcy-034,dcy-036: 본 HOTFIX follow-up 관계 기록.
- 운영 영향:
- 배포 전 dry-run에서 credential source·account reference masking·broker query 결과·분류 code를 확인한다.
- 배포 후 live sync는 single portfolio/slot 대상, 사전 dry-run 및 사장님 승인으로 제한한다.
5. 요구사항 목록
기능 요구사항
- FR-1:
credential_fetch_enabled=trueinstance의 daemon,sync,verify및 해당 operator broker-read 경로는 동일한 portfolio-hub fetched credential source를 해석해야 한다. fetch 실패 시 명시적 break-glass가 활성화되지 않은 한 env/config credential로 조용히 fallback하지 않는다. - FR-2: token issuance, auth, HTTP transport 또는 malformed broker response 실패는
get_balance()==[]로 변환하지 않는다. operator CLI는 안전하게 sanitize된 오류와 비0 종료로 중단하며,broker_qty_zero/sync skip/verify 결과를 만들지 않는다. - FR-3: repeated fetched-credential broker read는 구현된 token/broker lifecycle 정책에 따라 안정적으로 동작해야 하며, fresh object 생성으로 인한 token throttle을 실제 빈 계좌로 오판하지 않아야 한다.
- FR-4:
reconcile_core_holdings()는 broker-held symbol이 holding slot에 매칭되지 않을 때 (a) instance에 어떤 slot도 없는unmanaged_position, (b) slot은 있으나inactive/error등 non-holding인managed_non_holding_divergence를 구분해 구조화 로그/decision code를 남겨야 한다. - FR-5:
managed_non_holding_divergence는 자동 slot 전이, 자동 warning 해제, 자동 매매 또는 자동 청산을 유발하지 않는다. 상태 수렴은 검증된sync와 기존 운영 gate를 통해서만 수행한다. - FR-6: runtime/interface/operations baseline은 credential source 우선순위, safe error semantics, reconciliation 분류 및 operator remediation 절차를 구현과 동기화해야 한다.
비기능 요구사항
- NFR-1 (안전성): credential, access token, app secret, raw account number 및 HTTP authorization payload는 로그·CLI JSON·테스트 artifact에 노출되지 않는다. account reference가 필요한 운영 식별은 마스킹 또는 비밀이 아닌 stable label을 사용한다.
- NFR-2 (회귀안전):
credential_fetch_enabled=falseenv-only instance, 정상 holding match, holding qty mismatch, slot 없는 unmanaged position, 기존sync/verifylive double-ack 의미론은 보존한다. - NFR-3 (관측성): source mode, safe failure code, reconciliation decision code, slot_id/portfolio_id/symbol/status가 구조화 로그로 추적 가능해야 한다.
- NFR-4 (검증): unit/integration/CLI regression에 #39·#40·#41 재현 조건과 existing reconciliation/sync/verify 경로를 포함하고, independent QC가 실제 suite를 재실행한다.
범위 경계
- In Scope
- #39 fetched credential source mismatch, #40 token throttle/empty balance masking, #41 managed non-holding divergence 분류 및 이들의 tests/docs.
- operator dry-run evidence 및 post-release single-target remediation runbook.
- Out of Scope
- portfolio-hub credential API 계약 또는 credential 저장 모델의 재설계; 필요한 계약 변화가 발견되면 cross-service gate로 중단한다.
sync --live의 자동 실행, 전역 bulk sync, unmanaged broker position 자동 slot 생성, automatic remediation/trading.- TVR 전략 로직 변경 또는 TVR 재배포. TVR은 core truth/slot 상태가 정합된 뒤 기존
inactive,holdingread 의미론으로 재평가한다.
6. 리스크/가정 목록
리스크
- R-1 (High): credential source 또는 account identity를 잘못 연결하면 다른 실계좌의 broker truth를 기준으로 sync 판단을 할 수 있다.
- 완화 방안: fetched mode CLI source를 daemon과 공통화하고, dry-run에서 비밀 없는 source/account fingerprint 일치 assertion을 테스트한다. live sync는 사전 dry-run과 명시적 승인 없이는 실행하지 않는다.
- R-2 (High): auth/token 오류를 empty balance로 취급하면 false zero 기반의 잘못된 상태 수렴이 발생할 수 있다.
- 완화 방안: typed/sanitized failure를 도입하고 balance가 성공적으로 조회된 경우에만 qty=0 판단을 허용한다. throttling 재현 테스트를 추가한다.
- R-3 (Medium): non-holding slot existence check가 holding 수량 mismatch 또는 true unmanaged warning 의미론을 바꿀 수 있다.
- 완화 방안: primary holding compare를 유지한 뒤 unmatched broker symbols에만 second-pass existence lookup을 적용하고, 4-case regression matrix를 고정한다.
- R-4 (Medium): HOTFIX 배포 직후 운영자가 빠르게 live sync를 실행하면서 장부/브로커/slot 증거 교차 확인을 건너뛸 수 있다.
- 완화 방안: release runbook에 dry-run → broker/ledger cross-check → single-target explicit approval → live sync → re-reconcile 순서를 필수 gate로 기록한다.
가정
- A-1: portfolio-hub fetched credential path는 daemon의 현재 정상 운행에서 authority source로 사용 가능하며, service-token 접근 계약은 변경하지 않는다.
- A-2:
sync는 REQ-105의 기존 원칙대로 managed slot만 브로커 truth에 수렴시키며, slot 없는 broker holdings를 자동 편입하지 않는다. - A-3:
genichin-longterm의005930사례는 generic regression fixture로 추상화할 수 있고, 실제 계좌 식별값/credential은 test data에 포함하지 않는다.
오픈 질문
- OQ-1: #39, #40, #41을 하나의 emergency delivery batch로 묶어 single release candidate로 배포할지, credential hotfix(#39/#40)와 telemetry 분류(#41)를 분리할지?
- 상태: Answered (2026-07-14, 사장님)
- 결정: #39·#40·#41을 하나의 emergency batch로 확정한다. #41은 자동 state write가 없는 additive classification으로 유지해 rollback blast radius를 제한한다.
- 종료 근거: 사장님이 2026-07-14에 단일 emergency batch를 명시 승인했다.
- OQ-2: operator CLI의 fetched credential broker/token lifecycle을 process-local reuse, shared token cache, 또는 다른 공통 provider 중 무엇으로 고정할지?
- 상태: Deferred to REQ
- 처리 방안: delivery-runner/trex-core-dev가 current KISBroker token cache·daemon reinitialization·CLI process lifetime을 분석해 secret-safe alternatives와 retry/throttle behavior를 REQ draft에 제시한다.
- 인계 조건: REQ가 token lifecycle ownership, error type, retry/no-retry policy 및 regression test seam을 명시한다. 이는 구현 설계 선택이며 Discovery 범위·성공 기준을 바꾸지 않는다.
- OQ-3: hotfix release 뒤
genichin-longterm의 live sync 실행 대상을005930단일 slot으로 확정할지?- 상태: Deferred to release gate
- 처리 방안: hotfix deployment와 dry-run 결과 후 사장님이 broker/ledger/slot cross-check evidence를 보고 승인한다.
- 인계 조건: release approval에 target portfolio/slot, executed command class, before/after evidence, rollback/hold plan이 기록된다. 본 Discovery는 live sync 실행을 승인하지 않는다.
7. 초기 성공 기준
- S-1: fetched credential enabled fixture에서 daemon-equivalent path와
sync --dry-run/verify가 동일한 masked source identity와 동일 broker holding set을 사용한다. - S-2: KIS token throttle/auth failure fixture에서 CLI가 non-zero failure와 sanitized code를 반환하고, empty balance/
broker_qty_zero/state write를 만들지 않는다. - S-3: 4-case reconciliation regression이 통과한다: slot 없음→unmanaged, inactive slot+broker holding→managed_non_holding_divergence, matching holding→ok, holding qty mismatch→기존 mismatch path.
- S-4: 실제 deployed hotfix에서 approved dry-run이
genichin-longterm대상 broker truth와 divergence classification을 확인하며, live sync 전에는 DB 상태가 변경되지 않는다.
측정 방식 및 데이터 출처
- S-1 측정 방식: daemon/CLI 공통 provider와 mocked fetched credential/broker fixture의 account fingerprint·balance 결과 비교 테스트 / 데이터 출처: 신규 runtime CLI 및 broker factory tests.
- S-2 측정 방식: token issuance error를 주입한
get_balance/CLI test에서 exit code, sanitized error, no-write assertion 확인 / 데이터 출처: KIS adapter 및 CLI tests. - S-3 측정 방식:
reconcile_core_holdingsapplication tests와 PostgreSQL/InMemory repository parity tests 실행 / 데이터 출처:tests/application/test_holding_divergence.py및 추가 regression tests. - S-4 측정 방식: release runbook에 따른 production dry-run command output, broker/ledger/slot readback, audit logs 확인 / 데이터 출처: deployment evidence 및 운영자 기록. 실계좌 write는 승인 후 별도 증거로만 수행한다.
8. REQ로 넘기기 전 확인 체크
- 범위(In Scope/Out of Scope) 확정
- 근거: 사장님이 2026-07-14 #39/#40/#41 단일 emergency batch를 승인했고, cross-service 계약 변경은 발견 시 별도 gate로 중단한다.
- 성공 지표의 측정 방식/데이터 출처 확정
- 근거: S-1~S-4에 test seam, safe production dry-run evidence, independent QC 재실행 요구가 명시되었다. runtime 계측값은 REQ/release evidence로 수집한다.
- High 영향 리스크 우선순위 및 해소 책임자 지정
- 근거: R-1/R-2 delivery owner=delivery-runner/trex-core-dev, independent verifier=qc-reviewer, live operation approver=사장님으로 고정한다.
- 모든 오픈 질문(OQ)
Open상태 없음 확인- 근거: OQ-1 Answered, OQ-2는 REQ 설계로 Deferred, OQ-3은 release approval gate로 Deferred 상태다.
- Freeze 확정 담당자(CONFIRMED_BY) 지정
- 근거: 사장님(genichin)이 2026-07-14 HOTFIX scope를 confirm-discovery에서 승인했다. live sync 실행은 별도 release approval 대상이다.
9. 파일 처리 결과
- 처리 결과: 생성
- 생성 경로:
docs/discovery/dcy-037_20260714_operator-broker-truth-and-managed-slot-divergence-hotfix.md - 참조 문서:
docs/discovery/dcy-034_20260625_slot-account-blocking-reconcile-sync-coldstart.mddocs/discovery/dcy-036_20260628_daystart-credential-fetch-failsafe-trading-load.md- GitHub issues #39, #40, #41;
trex_core/runtime/daemon.py,trex_core/runtime/cli.py,trex_core/adapters/broker/kis.py,trex_core/application/reconciliation.py .stage-pilot/templates/runtime-flows.md,.stage-pilot/templates/project-structure.md
10. 사용자 결정 필요 항목 요약
확정된 결정
- HOTFIX delivery boundary: #39·#40·#41을 하나의 emergency batch로 구현·검증해 single release candidate로 관리한다 (2026-07-14, 사장님 승인).
- Production safety gate: hotfix 배포 뒤
sync --live는 dry-run 및 broker/ledger/slot cross-check evidence가 준비된 경우에도 사장님 명시 release approval이 있어야만 실행한다. - Post-deploy evidence: target instance의 masked credential source, broker holdings, slot 상태, portfolio-hub ledger readback은 REQ verification 및 release gate에서 수집한다. 현재는 구현 전이므로 실제 운영 데이터는 없다.
11. Discovery Freeze
섹션 참조
- 범위: # 5. 요구사항 목록 > 범위 경계
- 리스크/오픈 질문: # 6. 리스크/가정 목록
- 성공 기준: # 7. 초기 성공 기준
- 인계 전 확인: # 8. REQ로 넘기기 전 확인 체크
- 사용자 결정 필요: # 10. 사용자 결정 필요 항목 요약
Freeze 플래그
- Handoff Decision: 승인
- Handoff Rationale: 사장님이 #39/#40/#41 단일 emergency batch scope를 승인했다. OQ-2는 REQ에서 구현 설계로 구체화하며, OQ-3은 배포 후 별도 release approval gate이므로 REQ drafting을 막지 않는다.
- Ready for REQ Drafting: true
- Confirmed By: genichin
- Confirmed At (KST): 2026-07-14 22:19:29 KST