Files
trex-core/docs/releases/rel-004_20260608_safety-cooldown-bugfix-hardening-cli.md
T
genichinandClaude Opus 4.8 fec9411d33 docs(release): REL-004 에 BAT-022/023 편입 + 재-confirm (confirmed)
릴리즈되지 않은 release-candidate 배치(BAT-022 슬롯 상태 가시화,
BAT-023 ledger 현금/포지션 write-back·option D)를 REL-004 범위에 추가.
확장 범위 증거(BAT-022 실 인프라 운영 재현, BAT-023 인프라 게이트
385 passed) 반영 후 confirm-release 게이트 통과 → Status confirmed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 08:52:12 +09:00

11 KiB

REL-004: safety-sell 쿨다운 + 운영 버그픽스/하드닝 + 운영자 CLI + 슬롯 가시화·현금 write-back 통합 릴리즈

  • Status: confirmed
  • Profile: app-service
  • Included Batch: BAT-014, BAT-015, BAT-016, BAT-017, BAT-018, BAT-019, BAT-020, BAT-021, BAT-022, BAT-023

Scope

  • Included:
    • BAT-014 (dcy-010 / REQ-052~054): safety-sell per-slot 재시도 쿨다운 + 영속 거부 경고
    • BAT-015 (dcy-011 / REQ-007·018·021 change-req + REQ-055): buy intent portfolio_id 필수화 + symbol 서버 resolve + ledger skip 가시화 + closed↔outbox anti-join 점검
    • BAT-016 (dcy-012 / REQ-002·003·006·007·013·015·036 change-req): 매도 가격 버그 정정 — 슬롯 entry_price→limit_price rename(+마이그레이션 006) + dispatch 단일 필드 + sell optional 가격
    • BAT-017 (dcy-013 / REQ-012·013·014·015·018·031 change-req): KIS 외부 취소 감지(cncl_yn) + 부분 체결 회계 + pending stale 워치독(Alert-only)
    • BAT-018 (dcy-014 / REQ-005·009·048 change-req): trading_date 설정 타임존(KST) 분리 + 일자 경계 일일 preallocation
    • BAT-019 (dcy-015 / REQ-017·018·019·020 change-req): ledger outbox 영속 오류 분류 + 지수 백오프/dead-letter(+마이그레이션 007)
    • BAT-020 (dcy-016 / REQ-021·022·026·032·034 change-req): 운영자 CLI 확장(universe/slots/enter/exit, 데몬 RPC 통일) + 워치독 억제 읽기
    • BAT-021 (dcy-017 / REQ-021·032·034·037·038·039·042 change-req): 워치독 소유권 가시화(snapshot 워치독 상태 + safety-sell 발동 로깅)
    • BAT-022 (dcy-016 후속 / REQ-028·032 change-req): trex-core slots 가 universe assets[] 대신 실제 슬롯 상태를 표시 — snapshot envelope 에 read-only slots[](slot_id/status/symbol/qty/limit_price/avg_price/portfolio_id) additive 추가, universe/slots 표면 분리
    • BAT-023 (dcy-018 / REQ-017·019·029·030 change-req, REQ-030 Approved→Implemented): ledger write 응답 cash/position write-back(option D 활성화) — portfolio-hub#8 응답 cash_balance_after/asset_quantity_after 파싱 후 SnapshotStore write-back(best-effort), 체결~write-back 공백은 추정 현금 오버레이(cash_estimated)로 메움. "수량 live·현금 stale" 비대칭 제거
  • Excluded:
    • BAT-001~013 (REL-001/002/003 에서 이미 released)
    • dcy-018 이후 후속 주제, Redis projection·push 알림(dcy-017 OQ-1 미채택), dead-letter 재처리 트리거(dcy-015 후속), 슬롯 오버레이 제거(dcy-018 OQ-1 B 로 유지 확정)

Rollout Plan

  1. 배포 전: 대상 인스턴스 데몬 정지(또는 거래 세션 외 시간), 현재 리비전 SHA 기록.
  2. DB 마이그레이션 적용(멱등): 006_rename_entry_price_to_limit_price.sql(daily_slot 컬럼 rename) + 007_ledger_outbox_delivery_failed_and_backoff.sql(status enum/next_retry_at). 데몬 기동 시 apply_migrations 가 자동 적용하나, 운영 trex_core DB 에 최초 적용되므로 사전 백업 권장.
  3. 신 리비전(6d7bca1 또는 그 이후 main HEAD) 배포 + 데몬 재기동(--config <inst>.toml). 기동 로그에서 RUNNING/비-degraded 확인.
  4. 스냅샷 RPC degraded=false·available_slots·asset_count 확인. snapshot envelope 에 slots[](per-slot 상태)·watchdog[] 노출 확인(BAT-022). trading_date 가 KST 당일과 일치하는지 확인.
  5. 운영자 CLI 스모크: trex-core universe(=assets[])/slots(=실제 슬롯 상태·status·워치독 표시, BAT-022) — paper 또는 비거래 시간.
  6. (가능 시) paper buy/sell 1회 후 trex-core universe 에서 cash_balance·asset_quantity 가 함께 갱신(write-back) 또는 cash_estimated 추정 라벨 노출 확인(BAT-023).
  7. 거래 세션 재개.

Rollback Plan

  • 조건: 기동 실패, 마이그레이션 오류, buy/sell admission·집행 회귀, ledger 전송 비정상, safety-sell 오작동.
  • 절차: 신 리비전 → 직전 released 리비전(REL-003 시점)으로 롤백 + 데몬 재기동.
  • 주의: 마이그레이션 006(컬럼 rename)은 비가역적 rename 이다 — 롤백 시 구 코드는 entry_price 컬럼을 기대하므로, 코드 롤백과 함께 역마이그레이션(limit_price→entry_price rename) 또는 컬럼 alias 가 필요하다. 007 은 additive(컬럼/enum 추가)라 구 코드와 공존 가능. 배포 전 역마이그레이션 스크립트를 준비한다.
  • 데이터: 마이그레이션은 순수 rename/additive 라 행 데이터 보존. ledger_outbox delivery_failed 행은 롤백 후 구 코드가 모르는 status 이므로 list_pending 에서 자연 제외(무해).

Verification Checklist

  • 배포 전:
    • 전체 인프라 게이트 테스트 green (PG trex_core_test + RabbitMQ): BAT-023 verification 시점(main HEAD 2bfecd5, BAT-022 63da87c 포함) 385 passed(pending_cash_delta SQL 포함) — 확장 범위 반영 완료. (참고: 최초 confirm 시점 BAT-014~021 범위는 369 passed)
    • ruff check trex_core tests All passed (BAT-022/023 변경 파일 포함).
    • 마이그레이션 006/007 idempotent 재적용 확인(컬럼 계약 가드 green). BAT-022/023 은 신규 마이그레이션 없음(snapshot 필드 additive + 코드-only write-back).
    • 역마이그레이션(006 rename 되돌리기) 스크립트 준비.
  • 배포 후:
    • 데몬 RUNNING + 비-degraded, 8개 백그라운드 스레드 기동(trex-preallocation 포함).
    • trading_date == KST 당일, 슬롯 preallocation 정상.
    • 스냅샷 RPC envelope(assets/available_slots/degraded) 정상 + watchdog·slots[] 필드 노출(BAT-022).
    • trex-core universe(assets[])/slots(실제 슬롯 상태·status·워치독 소유 표시) 응답 정상.
    • (가능 시) paper buy/sell 1회 e2e: portfolio_id 기반 admission → 체결 → ledger 기록 → cash_balance·asset_quantity write-back(또는 cash_estimated 추정 라벨) 확인(BAT-023).

Pre-Release Run Evidence (operator-facing smoke)

confirm-release 전 "운영자가 쓰는 프로그램이 실제로 동작한다"는 run-the-app 증거. 테스트 통과(369 passed)와 별개로 실 데몬 기동 + trex-core CLI 구동을 검증했다.

주: 아래 base run 증거는 BAT-014~021 범위(REL-004 최초 confirm) 시점의 것이다. BAT-022·BAT-023 편입 범위의 run/test 증거는 바로 아래 "확장 범위 증거(BAT-022/023)"에 추가했다.

확장 범위 증거 (BAT-022 / BAT-023, 재-confirm)

  • BAT-022 (슬롯 상태 가시화) — 실 인프라 운영 재현 PASS: 신규 코드 데몬 재기동(trex-core-daemon --config config/test.toml, PID 2965049) 후 trex-core slots → instance=test status=all count=10 으로 10개 슬롯 각각 status(idle)·slot_id·qty·limit·avg·pid 표시(이전 갭: universe 1개·status 없음 해소). slots --status holding → count=0(필터 동작). trex-core universe → assets=1(universe 유지, slots↔universe 분리 실증). DB daily_slot (2026-06-08,'idle',10) 와 정확히 일치. 요청은 actor=operator/touch_watchdog=false(비침습). 단위 회귀 338 passed.

  • BAT-023 (현금/포지션 write-back, option D) — 인프라 게이트 PASS: PG trex_core_test + RabbitMQ 인프라 게이트 385 passed(option D write-back 11 + adapter *_after 파싱 + pending_cash_delta SQL 포함), 단위 350 passed / 35 skipped, ruff clean. write-back(new/duplicate 멱등)·*_after 누락 skip·best-effort 무차단·추정 현금 오버레이(cash_estimated) 수렴 전부 green.

  • 한계(운영 배포 검증으로 이월): BAT-023 의 실 portfolio-hub#8 full-stack option D e2e(실 *_after 응답 → 스냅샷 cash/quantity 갱신)는 paper/단위로 커버했고, LIVE full-stack 은 아래 Release Execution Evidence(실 배포)에서 확인한다. BAT-022 의 pytest 인프라 게이트 미실행은 verification Human Approval Memo 로 수용된 잔여(실 인프라 운영 재현이 동등 이상 경로 커버).

  • 환경: paper 브로커 + 테스트 PostgreSQL(trex_core_test) + 테스트 RabbitMQ, portfolio-hub stub(universe 2종), --config <inst.toml>(instance_key=rel004-smoke), revision = main HEAD(수정 후).

  • 데몬 기동: trex-core-daemon --config ... → 마이그레이션 적용(006/007 포함), RabbitMQ 연결, snapshot scheduler boot(stub universe swap), preallocation, 8 스레드 기동, RUNNING. 기동 후 에러 로그 없음.

  • 운영자 CLI(데몬 RPC 통일) 구동 결과:

    • trex-core universe → snapshot RPC, assets 출력, degraded=false (BAT-020).
    • trex-core slots / slots --status held --json → 보유 슬롯 + watchdog 필드(slot_id/expired/last_seen) 노출 (BAT-021/dcy-016).
    • trex-core enter pf-005930 --capital ... --yes → status=admitted slot_id=... → paper 체결 → holding (BAT-015/018).
    • trex-core enter ... --dry-run → 미제출 미리보기(안전장치), --json+enter 는 --yes 강제 (BAT-020).
    • trex-core exit <slot_id> --yes → status=admitted → 시장가 매도 체결 → closed(held count 0) (BAT-016).
    • ledger_outbox: buy/sell 모두 status=completed(outbox durability + writer drain, BAT-019 경로 정상).
  • 검출·수정한 결함(이 run 이 아니었으면 release 에 포함됐을 버그): Daemon._resolve_symbol 이 SnapshotAsset.symbol(존재하지 않음)을 접근해 데몬 buy admission 이 매 요청 AttributeError → intent RPC 타임아웃. 실 데몬 buy 가 전면 불능이었으나 단위 테스트는 stub resolver 를 주입해 미검출(369 passed). asset.item.symbol 로 수정 + 회귀 테스트(tests/runtime/test_daemon_resolve_symbol.py) 추가 → 재기동 후 buy/sell e2e 정상(REQ-007 CHG-20260608-03). 수정 후 단위 337 passed.

  • 한계: 실계좌(LIVE KIS) 주문은 미검증(paper 한정) — LIVE full-stack 은 운영자 배포 evidence(아래)에서 확인.

Release Execution Evidence

  • Release Status Transition Target: released

Deployment Facts

  • Executed At:
    • <배포 시작 시각>
  • Completed At:
    • <배포 완료 시각>
  • Environment:
    • <배포 대상 환경 (예: 운영 trex_core DB + 대상 instance_key)>
  • Operator:
    • <배포 수행자>
  • Revision or Artifact:
    • <커밋 SHA (main HEAD)>
  • Commands or Procedure:
    • <마이그레이션 적용 + 데몬 재기동 절차 요약>

Profile-Specific Checks

  • app-service:
    • Health Endpoint:
      • <스냅샷 RPC degraded 상태/available_slots/asset_count + 확인 시각>
    • Startup Log Fields:
      • <기동 로그 RUNNING/instance_key/8 스레드 확인>
    • Request Log Fields:
      • <correlation_id 포함 RPC 처리 로그 확인>
    • Smoke or Manual Verification:
      • <CLI universe/slots + (가능 시) paper buy/sell e2e 결과>

Rollback Outcome

  • Rollback Required:
    • <yes 또는 no>
  • Rollback Trigger:
    • <발생 시 원인, 없으면 none>
  • Rollback Action:
    • <수행한 조치, 없으면 none>

Release Decision Evidence

  • Released Decision:
    • <released 전환 여부>
  • Rationale:
    • <released 전환 판단 근거>
  • Recorded By:
    • <기록자>
  • Recorded At:
    • <기록 시각>

Feedback Handoff

  • Observation Summary:
    • <운영 관찰 사실 요약 또는 없음>
  • Discovery Input:
    • <후속 discovery 후보 (예: WatchdogStore 영속 승격, Redis projection/push 알림, dead-letter 재처리 트리거)>
  • REQ Input:
    • <후속 req 후보>
  • Change Request Input:
    • <기존 req 변경 후보 (예: buy/sell 외부 payload entry_price 필드명 rename, snapshot envelope slot_id 노출)>