Hermes Agent
4699de61cc
feat(strategy-state): persist instance-scoped slot maps
2026-08-29 15:11:43 +09:00
copilot-swe-agent[bot] and genichin
21f8fdd4b6
fix(ac-0024): injective C identity via SHA-256 length-prefix digest + PostgreSQL migration/round-trip tests
...
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com >
2026-08-26 00:38:02 +00:00
copilot-swe-agent[bot] and genichin
48dfc3e76f
fix: harden skipped ledger resolution paths
...
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com >
2026-08-24 13:38:04 +00:00
copilot-swe-agent[bot] and genichin
76cde2edd0
feat: persist skipped ledger fills
...
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com >
2026-08-24 13:23:06 +00:00
Hermes Agent
9da8c27e52
fix(ledger): retain SOR fills with unknown venue
2026-08-24 09:47:21 +09:00
Hermes Agent
359ea098ff
fix: enforce actual venue persistence contract
2026-08-19 12:53:56 +09:00
Hermes Agent
7366cadf03
fix: preserve SOR execution venue separately
2026-08-19 12:48:05 +09:00
Hermes Agent
15aeae6930
fix: converge broker failures without retry
2026-08-19 11:29:26 +09:00
Hermes Agent
843df1d6f1
fix(execution): fail closed on unresolved orders
2026-08-14 15:29:31 +09:00
Hermes Agent
147873cb5d
feat(execution): reconcile timed-out orders safely
2026-08-14 15:15:52 +09:00
Hermes Agent
c0f36946a3
test: cover KIS pagination consumer seams
2026-08-10 00:27:10 +09:00
Hermes Agent
0fa8f39be9
feat: paginate KIS balance inquiries
2026-08-10 00:11:04 +09:00
jordan
56b35b257b
feat: own current KIS daily fill contract in Core
2026-07-29 21:46:42 +09:00
jordan
611805dcec
fix: close broker uncertainty audit gaps
2026-07-29 17:53:39 +09:00
jordan
0266992238
feat: add bounded KIS account read recovery
2026-07-29 17:40:01 +09:00
jordan
3dd8eefc92
fix: persist uncertain cancel outcomes
2026-07-29 17:17:14 +09:00
jordan
a656350a35
feat: resolve and persist actual order venue
2026-07-29 17:10:32 +09:00
jordan
479cb39a7e
feat: propagate intent venue through execution
2026-07-29 16:55:20 +09:00
jordan
d6c2e2d28a
fix: reconcile KIS exchange rejections
2026-07-28 13:29:43 +09:00
jordan
24c42d1c92
fix: reconcile ambiguous KIS order submissions
2026-07-28 11:17:06 +09:00
jordan
b72bf9f394
feat: isolate strategy-owned KIS balances
2026-07-27 11:39:07 +09:00
Hermes Agent
81a853a314
feat(reconcile): safely seed canonical cost basis
2026-07-17 09:57:08 +09:00
Hermes Agent
e95bd4f8b2
test(reconciliation): verify repository lookup parity
2026-07-15 08:18:32 +09:00
Hermes Agent
216e462df4
fix(broker): enforce operator broker truth boundary
2026-07-15 08:07:21 +09:00
genichin and Claude Fable 5
ee3dc83a93
feat(broker): KIS venue parameterization — OrderRequest.venue + EXCG_ID_DVSN_CD (REQ-117/118, BAT-056)
...
- OrderRequest.venue: str = "KRX" additive 추가 (기존 위치 인수 순서 불변)
- BrokerPort.cancel_order: venue: str = "KRX" 파라미터 추가
- BrokerPort.get_current_price: market: str = "J" 파라미터 추가
- KISBroker.submit_order: EXCG_ID_DVSN_CD=req.venue 항상 명시 전송
- KISBroker.cancel_order: EXCG_ID_DVSN_CD=venue 항상 명시 전송
- KISBroker.get_current_price: FID_COND_MRKT_DIV_CODE=market 파라미터화
- PaperBroker: cancel_order/get_current_price 시그니처 정합 (venue/market 수신·무시)
- poll_fill TR 유지 (TTTC8001R) — NXT 체결 포함 여부 미확인 open item (코드 주석 기록)
- tests/adapters/broker/test_venue.py: REQ-117 AC-1~5 + REQ-118 AC-1~8 신규 17개
- docs: interface-contract.md OrderRequest/BrokerPort 섹션 + change log 추가
- docs: runtime-flows.md venue 전달 경로 명시 + change log 추가
결과: 794 passed, 47 skipped (기존 777+47 대비 신규 17개 추가 전부 통과)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-07-06 23:24:51 +09:00
genichin and Claude Fable 5
690071afad
feat(slots): additive strategy fields + filter (REQ-116, BAT-055)
...
trex.slots.req wire 계약 additive 확장 — 기존 소비자(orb/tsl) backward compatible.
- PortfolioItem: strategy_name(Optional[str]) + markets(list) 필드 추가
- hub_read.py: get_portfolios()에서 strategy_name/markets 파싱 추가 (safe default)
- slot_to_dict(): strategy_name/strategy_params/markets 3필드 row에 추가 (SnapshotStore→PortfolioItem 경유)
- make_slots_rpc_handler(): strategy 요청 파라미터 → Python 레벨 후처리 필터 (available_slots 계산 이후, REQ-073 AC-6 불변)
- 테스트: AC-1~8 전수 + hub_read 파싱 + 회귀 갱신 (777 passed, 47 skipped)
- docs/interface-contract.md: 요청 파라미터·응답 행 스키마·소스 테이블·REQ-074 AC-5 주석 갱신
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-07-04 11:10:01 +09:00
genichin and Claude Sonnet 4.6
e4e5c70422
feat(bat-053): 그날-시작 KIS 인증정보 fetch + fail-safe 로드 (REQ-112~115)
...
REQ-112: BrokerCredentialPayload/TradingContext 데이터클래스 + PortfolioHubReadPort.fetch_broker_credential() 포트 메서드 + hub_read 어댑터(_fetch_user_info 헬퍼 추출) + stub_read 결정론 stub
REQ-113: DaemonInstanceConfig/DaemonConfig.credential_fetch_enabled opt-in(기본 False) + TOML 파싱 + break-glass(TREX_KIS_BROKER_BREAK_GLASS) 감지
REQ-114: SnapshotScheduler._maybe_fetch_credential() — fail-closed 3조건(unavailable/broker-null/trading_disabled) + CRITICAL 알람 DAY_START_LOAD_FAILED + IntentService entry_allowed_fn 게이트(BuyIntent 차단, SellIntent 통과)
REQ-115: 그날 고정 캐시(_cached_credential/_credential_date) — 동일 날짜 재fetch 방지 + app_secret 메모리 한정(Redis 미기록)
스텁 기반 구현: 실 portfolio-hub/네트워크 없이 AC 전부 단위 테스트.
회귀: credential_fetch_enabled=False(기본) 경로 byte-for-byte 보존.
745 passed, 47 skipped (0 failed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-28 11:00:18 +09:00
genichin and Claude Sonnet 4.6
73d3b35ab2
feat(bat-052): WAC 실현손익 리포트 통합 (REQ-109/110/111, dcy-035)
...
- portfolio.py: RealizedPnlItem/RealizedPnlResult 데이터클래스 추가;
PortfolioHubReadPort에 get_realized_pnl 포트 메서드 추가
- hub_read.py: GET /v1/portfolios/{id}/pnl/realized 어댑터 구현
(from/to/symbol query, 비2xx/네트워크→PortfolioHubUnavailableError)
- stub_read.py: get_realized_pnl 고정 결과 stub 추가 (무네트워크)
- operator_report.py: OperatorReport에 WAC 4필드+degrade 2필드 추가;
apply_wac_to_report/buy_fee_by_asset 헬퍼; render_text/render_json WAC 섹션
- cli.py: _cmd_report에 WAC 경로(portfolio-hub 설정 시) + degrade 경로 통합
(REQ-111: base_url 미설정/Unavailable → 식별가능 에러, 폴백 없음)
- tests: 51개 신규 테스트 (domain sweep, hub_read, stub_read, operator_report,
cli_report_wac); 전체 717 passed, 47 skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-26 20:35:17 +09:00
genichin and Claude Opus 4.8
d4c5fcbba1
feat(alarm): trex-core 알람 emitter + trex.alerts exchange (dcy-033 BAT-049, Implemented)
...
AlarmEmitter(application, best-effort 비차단)+trex.alerts topic exchange 가산·격리+8 CRITICAL code 배선. 608 passed, opus QC PASS, 팀장 e2e(텔레그램 HTTP200) 통과. REQ-098~101 Implemented.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-21 19:25:55 +09:00
genichin and Claude Opus 4.8
d182464b7a
feat(messaging): OPS-005 이벤트 발행 연결 신뢰성 (BAT-047)
...
발행 전용 연결의 idle heartbeat 사망 후 첫 발행 유실 결함 제거.
- REQ-091 발행 재시도 + 강제 재연결(_force_reconnect, is_open 불신)
- REQ-092 idle keepalive(execution-loop 단일스레드 틱, process_data_events time_limit=0)
- REQ-093 DLQ 가시성 + emit 실패 ERROR 경보(구조화 로그, dcy-029 재사용)
- REQ-094 baseline 문서 정합(runtime-flows/operations/project-structure)
독립 opus QC PASS-WITH-NOTES → 시정 2건(ruff F401, AC-3 프로덕션 경로) 완료.
554 passed/47 skipped/회귀 0/ruff clean. NFR-1 wire 무회귀(interface-contract diff 0).
BAT-047 release-candidate, REQ-091~094 Implemented. dcy-031. M2 트랙B.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-19 22:39:43 +09:00
genichin and Claude Opus 4.8
e0d4e71304
feat(slot,intent): slot strategy-state 저장소 (dcy-028) + sell retryable 플래그 (issue #27 )
...
BAT-042 (dcy-028 / issue #26 C-1/C-2/C-2b/C-3, REQ-079~082 + REQ-073/074 CHG):
- slot_strategy_state 별도 테이블 + StrategyStateStore(in-memory+PG) + occupancy_seq·version CAS + opaque UTF-8 data + 2단 size cap (REQ-079)
- trex.slots.strategy_state.set write RPC — reject reason 집합, 멱등 (REQ-080)
- Slot.occupancy_seq 필드 + inactive→pending_buy bump + →INACTIVE close 삭제 훅 → 점유 전환 ABA 구조적 차단 (REQ-081)
- slots.req 응답 행에 strategy_state 맵(batched 조립)·occupancy_seq additive (REQ-073 AC-7/REQ-074 AC-6)
- 마이그레이션 014(occupancy_seq)/015(slot_strategy_state), baseline 문서 정합 (REQ-082)
BAT-043 (issue #27 / REQ-007 CHG):
- rejected SellIntent 응답에 additive retryable: bool (core 소유 reason→retryable 매핑, 미인식 기본 true, bad_request* false) — 손절매 재시도 안전 경로 decoupling
검증: 487 passed, 47 skipped (신규 41: store CAS 6+ABA, occupancy bump/close 4경로, set RPC 9, slots read 5, retryable 8, PG 게이트), ruff clean.
REQ-079·080·081·082·073·074·007 → Implemented. issue #27 close. PG 경로 실 DB 검증은 release 위임.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-15 19:27:57 +09:00
genichin and Claude Opus 4.8
d737467d70
perf(slots): BAT-040 — slots RPC DB-level status 필터 (REQ-002/006/073, issue #25 )
...
REQ-002/006 change-req(CHG-20260612-01)→구현→confirm-req-implemented,
REQ-073 change-req(CHG-20260612-02, 관찰 계약 불변 Implemented 유지) 전체 delivery.
- repository.py/in_memory_repository.py: SlotRepository.list_slots(instance_key,
status_filter=None) — status 값 집합 필터, None=전체(기존 호출자 불변).
- postgresql.py: list_slots DB-level WHERE status = ANY(%s) (full scan + Python
필터 제거). 스키마/마이그레이션 변경 없음.
- messaging_handlers.py: _FILTER_STATUS 매핑으로 filter→status 집합 위임,
watchdog 갱신용 holding 조회를 all/holding fetch 결과에서 재사용(2nd 커넥션 생략).
- 관찰 가능한 RPC 계약(REQ-073 AC-1~6) 불변 — 동작 보존 최적화.
- tests: in-memory status_filter 5종 + PG 게이트 1종. 439 passed (+5), ruff clean.
REQ-002·006 Approved→Implemented, REQ-073 Implemented 유지, BAT-040 release-candidate.
issue #25 close.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-12 19:27:51 +09:00
genichin and Claude Opus 4.8
9871008bb6
fix(paper): BAT-039 — paper order seq Redis 영속화 (재시작 멱등 키 충돌 방지, REQ-011/issue #4 )
...
REQ-011 change-req(CHG-20260612-01)→구현→confirm-req-implemented(CHG-20260612-02)
전체 delivery. paper 한정 결정성 버그(프로덕션 무관).
- seq_store.py 신규: SeqStore 포트 + RedisSeqStore(원자 INCR, 재시작 단조·영속)
+ InMemorySeqStore(폴백/테스트). REQ-016 token_cache 패턴 재사용.
- paper.py: optional seq_store 주입. 미주입 시 기존 in-memory 동작 byte-for-byte 유지.
- config.py/daemon.py: TREX_PAPER_REDIS_URL → RedisSeqStore wiring
(key=trex:broker:paper:{instance_key}:order-seq).
- 런타임 Redis 오류는 전파(silent in-memory 폴백 금지 — 버그 재현 방지).
- tests: 재시작 단조성/correlation_id 비충돌/in-memory 폴백/fake redis INCR (5).
434 passed (+5), ruff clean.
REQ-011 Approved→Implemented, BAT-039 release-candidate. issue #4 close.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-12 18:16:11 +09:00
genichin and Claude Sonnet 4.6
24a6017457
fix(reconcile): symbol을 슬롯 생성 시 함께 저장 + NULL 슬롯 backfill
...
reconcile_universe 시그니처를 set[str] → dict[str, str] (portfolio_id→symbol)로 변경.
기존 symbol=NULL 슬롯은 다음 reconcile 실행 시 자동 backfill.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-11 21:08:46 +09:00
genichin and Claude Opus 4.8
f0ad37747b
feat(rel-007): dcy-025/024 + BAT-035/036 — slots.req 즉시 교체 + safety_sell_enabled
...
BAT-035 (dcy-025): trex.snapshot.req → trex.slots.req 즉시 교체
- topology: SNAPSHOT_REQ_QUEUE 제거, SLOTS_REQ_QUEUE = "trex.slots.req" 추가
- portfolio.py: View/build_snapshot_envelope/SnapshotEnvelope/_asset_to_dict 제거;
slot_to_dict 시그니처 확장(snapshot_store/watchdog_store/pause_store/watchdog_timeout_sec)
— asset_quantity(hub)/cash_balance/cash_estimated/warned/watchdog{}/paused 병합 (REQ-074)
- messaging_handlers.py: make_snapshot_rpc_handler 제거, make_slots_rpc_handler 추가
— filter(all/inactive/pending/holding/error) + spy(bool) 처리; strategy 필드 제외 (REQ-073/074)
- daemon.py: _snapshot_rpc_loop → _slots_rpc_loop, make_slots_rpc_handler 연결
- cli.py: universe/slots → slots_queue + spy=True + server-side filter; buyable→inactive 매핑 (REQ-063)
- rabbitmq.py: snapshot_queue → slots_queue
- docs: interface-contract.md + runtime-flows.md slots.req 계약으로 업데이트 (REQ-075)
- REQ-028: Implemented → Deprecated (코드 삭제 완료)
- 테스트: test_snapshot_handler/selection/rpc_watchdog/messaging_snapshot_consumer 삭제;
test_slots_handler.py(신규, 13 cases), test_killswitch_masking_resume 재작성,
test_ledger_option_d._apply_cash_estimate → slots handler 경유, test_topology/cli_operator 갱신
BAT-036 (dcy-024): per-instance safety_sell_enabled 플래그
- config.py: DaemonInstanceConfig + DaemonConfig 에 safety_sell_enabled: bool = True 추가;
from_toml 파싱, from_config 전파
- daemon.py: start() workers 조건부 — safety_sell_enabled=false 시 trex-safety-sell 미기동 + WARNING
- tests: test_instance_config.py 에 safety_sell_enabled 파싱 3개 케이스 추가
REQ: 073/074/075/021/034/063/048/005 Approved → Implemented
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-11 14:45:45 +09:00
genichin and Claude Opus 4.8
7d727824dc
feat(slot): BAT-030 — 자산 중심 cutover 완성 (dcy-020 BAT-δ, REQ-056·057·062·064·065)
...
M1 literal inactive 전면화: SlotState 5-state(idle/closed 별칭 제거),
마이그레이션 010(CHECK 교체+행 rewrite), ops_checks 를 transition_log 기반 재작성.
M2 집행 매도 수량 브로커 정본(D3): dispatch 매도 qty=broker hldg_qty,
미러 fallback 없음, 브로커 0 → skip+WARN, 리스트 기반 dispatch(head-block 방지).
M3 컬럼 drop + legacy pool 제거: 마이그레이션 011(trading_date·entry_count DROP),
repo 계약 instance 스코프 개편(집행 큐 포함), preallocation 폐기(데몬 7스레드),
admission 자산 중심 단일 경로(slot_id 정본), capacity 재정의(available=M−active),
daily_symbol_entries 코드 경로 제거.
M4 cutover 도구(D1·D4): trex-core-cutover(전체 rebuild, preflight/브로커 carry-over/
--allow-unmapped/--promote-unique/dry-run) + PG 리허설 테스트 8건.
M5 baseline 마감: data-model/runtime-flows/project-structure/interface-contract
자산 중심 최종 갱신 + run-trex-core-daemon 스킬 정합.
검증: 단위 367 passed + ruff clean; PG-gated 29 passed(010/011 round-trip·드리프트
가드·cutover 리허설); RabbitMQ 21 passed; run-the-app e2e(test DB+실 MQ, M=1):
reconcile 슬롯 생성→slot_id 매수→dedup→capacity_full→fill→already_active→
매도→inactive(자산 바인딩 보존)→영구 슬롯 재활성 전 구간 green.
실 cutover 는 운영자 실행(REL 단계, D4).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 15:16:15 +09:00
genichin and Claude Opus 4.8
8a377e6fb3
feat(slot): BAT-028 M2/M3 — universe reconcile + 자산 중심 admission (dcy-020/REQ-058·059)
...
config 게이트 이중 경로(max_active_slots 설정 시 자산 중심, 미설정 시 legacy pool).
운영 데몬은 cutover(BAT-δ) 전까지 pool 무중단.
- repository: find_slot_by_portfolio·count_active(holding+pending_buy+pending_sell)·
reconcile_universe(생성 멱등/soft-retire/tombstone, allow_retire 가드) — protocol+in_memory+PG
(PG: ON CONFLICT (instance_key, portfolio_id) WHERE portfolio_id IS NOT NULL)
- snapshot_scheduler: run_once swap 직후 _reconcile_slots(빈 universe skip, ≥50%↓ retire 보류)
- intents: _admit_buy 모드 분기 + _admit_buy_asset_centric(활성화/already_active/
capacity_full/unknown_portfolio/over-cap, 인스턴스 lock)
- daemon: instance_key·max_active_slots·reconcile_enabled·trading_date_fn 배선
- 신규 테스트: test_universe_reconcile(6), test_asset_centric_admission(6), PG reconcile(1)
검증: 단위 387 passed / 35 skipped, PG-gated 17 passed, ruff clean. legacy 무파손.
REQ-058/059/060 은 Approved 유지(자산 중심 경로 도입 검증; default 전환·cutover 는 BAT-δ).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 11:14:50 +09:00
genichin and Claude Opus 4.8
017b8185e0
feat(slot): BAT-027 M2/M3 — 상태머신 inactive 재정의 + 인스턴스 스코프 advisory lock (dcy-020/REQ-057)
...
안 B 점진의 2/3단계. runtime 무변경(idle/closed 별칭 흡수)으로 cascade 통제.
- state.py: SlotState.INACTIVE 추가 + idle/closed 별칭 normalize_state(); 전이 집합
inactive 기준 재정의(inactive↔pending_buy↔holding↔pending_sell), closed→idle 제거;
is_allowed_transition 양쪽 정규화; slot_advisory_lock_id(instance_key) 헬퍼
- service.py: SlotService(instance_key) + advisory lock 인스턴스 스코프(self._lock_id)
- __init__: normalize_state/slot_advisory_lock_id export; daemon: instance_key 전달
- 테스트 갱신: test_state(전이/멤버7/락/size12), test_service(closed→idle 제거→reallocation),
test_slot_entry_count, test_postgresql_repository(closed→idle 거부+reallocation)
검증: 단위 375 passed / 35 skipped, PG-gated(trex_core_test) 8 passed
(마이그레이션 009 드리프트 + lifecycle/reallocation), ruff clean.
REQ-056/057 은 토대만 충족 → Approved 유지(entry_count/trading_date drop·literal
inactive 전면 전환은 BAT-δ; confirm-req-implemented 는 dcy-020 후속 배치 완료 후).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 10:53:39 +09:00
genichin and Claude Opus 4.8
2bfecd59a8
feat(ledger): dcy-018 option D cash/position write-back + 추정 현금 (BAT-023)
...
ledger write 응답의 portfolio-hub 권위 cash/quantity 를 스냅샷에 write-back 해
매수/매도 직후 "수량 live·현금 stale" 비대칭 제거(option D 활성화). portfolio-hub#8
(*_after 응답) 동작 중 확인으로 그간 deferred 됐던 REQ-030 을 닫음.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-018 OQ-3 a).
- REQ-017: record_trade → LedgerWriteOutcome{result, cash_balance_after,
asset_quantity_after}. 어댑터가 응답 root flat *_after 파싱(new+duplicate, 누락 None)
- REQ-019: LedgerWriter 에 SnapshotStore 주입 → new+duplicate write-back
(best-effort, *_after 절대값이라 멱등). LedgerOutbox.pending_cash_delta()
- REQ-029: 추정 현금 오버레이(_apply_cash_estimate, cash_estimated 라벨, OQ-4 i)
+ 슬롯 오버레이 유지(OQ-1 B). 미정산 outbox delta 기반, write-back 수렴
- REQ-030: option D 활성화 → Approved→Implemented
best-effort 격리(NFR-1): write-back/추정 실패가 ledger 멱등·청산 무차단.
배치 번호: 동시 커밋된 BAT-022(slot-state, dcy-016)와 충돌해 BAT-023 으로 배정.
검증: 단위 350 passed/35 skipped, 인프라 게이트(PG+RabbitMQ) 385 passed, ruff clean.
신규 test_ledger_option_d + adapter/PG 테스트. BAT-023 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 21:50:56 +09:00
genichin and Claude Opus 4.8
b851b927ee
fix(ledger): dcy-015 outbox 영속 오류 분류 + 백오프/dead-letter (BAT-019)
...
portfolio-hub 404(미등록 포트폴리오)가 retryable 로 분류되어 백오프·상한 없이
초당 영구 재시도되던 버그(issue #13 , 실측 930회) 정정.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-015 OQ-3; 백오프 env 는 REQ-019 흡수).
- REQ-017: 404/400/422 → LedgerPermanentError 분류 (409 conflict / 408·429·5xx·
network retryable 불변). LedgerPort 에 permanent 타입 추가
- REQ-019: 영속 → 터미널 delivery_failed 즉시(재시도 0). retryable 지수 백오프
+jitter+next_retry_at, max_attempts 초과 시 dead-letter delivery_failed.
list_pending 이 백오프 행 스킵(head-of-line 보호). 마이그레이션 007(status enum
+next_retry_at). 백오프 env(base/cap/max-attempts)
- REQ-018: 터미널/dead-letter WARN + WriterStats.delivery_failed 카운터 가시화
- REQ-020: runtime-flows/data-model/interface-contract 정합
단일 터미널 delivery_failed(permanent/dead-letter, last_outcome 로 사유 구분) —
conflict_blocked 패턴과 동형. dead-letter 는 운영자 재처리 가능 상태.
검증: 단위 311 passed/34 skipped, 인프라 게이트(PG+RabbitMQ) 345 passed, ruff clean.
신규 test_ledger_outbox_backoff + adapter/PG 테스트, 기존 retryable 백오프 정합.
BAT-019 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 16:12:17 +09:00
genichin and Claude Opus 4.8
4746f74aae
fix(broker): dcy-013 KIS 외부 취소 감지 + 부분 체결 회계 + stale 워치독 (BAT-017)
...
KIS 계좌에서 직접 매도 주문을 취소하면 poll_fill 이 cncl_yn 을 파싱하지 않아
슬롯이 pending_sell 에 영구히 갇히고 죽은 주문을 무한 폴링하던 버그(issue #9 )
정정.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-013 OQ-3).
- REQ-012: KIS poll_fill cncl_yn 파싱 → 외부 취소 감지. FillStatus.cancelled
/is_partial_cancel 추가. 체결 0 취소→cancelled, 부분 체결 후 취소→partial+cancelled
- REQ-013: 집행 _on_partial_cancel — 체결분 원장 1회 + qty 차감(매도 잔여/매수 체결분)
+ holding 복귀 (OQ-1 A안). 전량 취소는 기존 롤백 경로 재사용
- REQ-018: 부분 체결분 원장 1회 기록 (_record_ledger 재사용)
- REQ-031: 잔여 포지션 정합 연계 (slot.qty ↔ 실 잔고, 과매도 방지)
- REQ-014: pending stale 워치독 Alert-only (TREX_PENDING_STALE_THRESHOLD,
WARN+카운터, 상태 미변경) — 취소 감지 누락 backstop
- REQ-015: interface-contract/runtime-flows 정합
전량 취소는 holding 자동 복구(limit_price clear→재매도 시장가, dcy-012 연계).
KIS cncl_yn 실 규약은 운영 검증(미지 값 보수 처리 + 워치독 backstop).
검증: 단위 294 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 326 passed, ruff clean.
신규 test_kis_cancel(httpx stub) + test_execution_cancel(programmable broker).
BAT-017 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 14:11:49 +09:00
genichin and Claude Opus 4.8
aee3512383
feat(intents): dcy-011 buy intent portfolio_id 필수 계약 + ledger skip 가시화 (BAT-015)
...
dcy-011 전 주기 delivery. issue #6(buy 식별자 정정) + issue #11(ledger silent skip) 흡수.
거버넌스: 기존 Implemented REQ는 change-req, 신규 기능만 신규 REQ(OQ-3).
- REQ-007 (change-req): buy admission portfolio_id 필수화 + SnapshotStore symbol
resolve + unknown_portfolio 거부 (hard cutover, OQ-1/OQ-2)
- REQ-021 (change-req): buy 메시지 payload symbol 제거
- REQ-018 (change-req): _record_ledger skip 가시화 (WARN + ledger_skipped 카운터)
- REQ-055 (신규): closed↔ledger_outbox anti-join 운영 점검 find_ledger_gap_slots
코드: intents.py(BuyIntent portfolio_id 필수 + resolve_symbol 주입 + _admit_buy
reject 분기), messaging_handlers.py, runtime/daemon.py(_resolve_symbol 배선),
execution.py(skip WARN 로그), adapters/persistence/ops_checks.py(신규 anti-join).
검증: 단위 282 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 314 passed, ruff clean.
BAT-015(standard) release-candidate. srs/index Next ID → REQ-056.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 12:57:51 +09:00
genichin and Claude Opus 4.8
9f83c64a40
feat(multi-instance): dcy-009 BAT-013 — RabbitMQ 다중 인스턴스 토폴로지 (REQ-048~051)
...
dcy-009(다중 인스턴스 RabbitMQ 토폴로지) 전체 SDLC: draft-req → confirm-req →
draft-batch(BAT-013) → run-batch-delivery → confirm-req-implemented.
- REQ-048 (Configuration): DaemonInstanceConfig.from_toml + DaemonConfig.from_config
(env 병합, portfolio_hub_token 주입) + 데몬 --config 필수 argparse + .gitignore 인스턴스
TOML + config/instance.example.toml
- REQ-049 (Interface): topology 동적 큐명 빌더 intent/snapshot/control_queue(instance_key)
— default=리터럴 큐명(하위호환), named=`{base}.{instance_key}` + daemon per-instance 구독
- REQ-050 (Integration): trex.direct(topic)/trex.broadcast(fanout) exchange +
declare_topology(instance_key) per-instance binding + control dual binding + direct_routing_key
- REQ-051 (Documentation): interface-contract/runtime-flows/project-structure 정합
하위호환: instance_key="default" → 기존 리터럴 큐명·RPC 경로 무회귀(FR-5).
split-brain 방지(NFR-3): 인스턴스 전용 큐. 민감값(NFR-4): TOML + gitignore.
검증: 신규 9 단위 + RabbitMQ 라우팅 2, 단위 271 passed,
인프라 게이트 301 passed(directed 격리 S-2 + broadcast dual S-3 + default 무회귀 S-4),
ruff clean. REQ-048~051 Implemented, BAT-013 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-07 15:10:36 +09:00
genichin
7e23648489
feat: add kill-switch control flow
2026-06-07 14:00:20 +09:00
genichin and Claude Sonnet 4.6
0082d3b5da
fix(kis): REQ-038 현재가 tr_id 정정 + REL-003 확정 + dcy-008 kill-switch Discovery
...
## REQ-038 CHG-04/05: KIS 시세 tr_id 정정 (FHKST01010100)
- kis.py _tr_price(): TTTC8397R/VTTC8397R → FHKST01010100 (실전/모의 공용)
배포 전 실 KIS LIVE 진단에서 구 tr_id가 rt_cd=1 "없는 서비스 코드"로 거부됨을
확인 — stop-loss/take-profit이 LIVE에서 조용히 미발동하는 결함이었음.
FHKST01010100으로 정정 후 get_current_price('005930')=329000(rt_cd=0) 확인.
- test_kis_price.py: AC-7 테스트 정정 (FHKST01010100 공용 검증)
- REQ-038: CHG-04/05 Change Log 추가, Requirement/AC-7/Notes 정정
- BAT-011 implementation.md: LIVE 검증 및 tr_id 정정 이력 추가
- BAT-011 verification.md: AC-7 evidence를 CHG-04 정정 버전으로 갱신
- docs/srs/index.md: CHG-04/05 Change Log 항목 추가
## REL-003: core 자율 안전 매도 release 문서 생성
- docs/releases/rel-003_20260607_core-autonomous-safety-sell.md 신규 생성
(BAT-010 + BAT-011, app-service profile, Status: confirmed)
- docs/releases/index.md: REL-003 행 추가
## dcy-008: 비상 정지/강제 청산(kill-switch) Discovery 초안
- docs/discovery/dcy-008_20260607_emergency-stop-kill-switch.md 신규 생성
GitHub #3 기반; SlotService.sell() 재사용, 당일 전략 제외 day-scoped
FR 6개, NFR 3개, OQ 4개 (트리거 표면/영속 방식/수동 해제 결정 필요)
- docs/discovery/index.md: dcy-008 행 추가
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 10:17:36 +09:00
genichin and Claude Opus 4.8
a30efa8f3b
feat(safety-sell): dcy-007 core 자율 안전 매도 — BAT-010 기반 + BAT-011 트리거
...
dcy-007(core 자율 안전 매도) 전체 delivery. BAT-010 기반 인프라가 미커밋
상태였고 BAT-011 트리거 레이어와 공유 파일에서 섞여 있어 한 커밋으로 묶음.
BAT-010 (REQ-034/035/036/041, release-candidate):
- WatchdogStore(application/watchdog.py) + snapshot RPC 워치독 갱신
- Slot stop_loss_price/take_profit_price 필드 + 004_add_price_thresholds.sql
- SlotService.sell() 자율 매도 내부 경로 + idempotency
- SafetySellConfig env 5종 파싱
BAT-011 (REQ-037/038/039/040/042, release-candidate):
- SafetySellService(application/safety_sell.py): forced_close 만기 / stop-loss·
take-profit KIS polling / 장 마감 강제 청산 + trex-safety-sell 7번째 스레드
- BrokerPort.get_current_price + KIS inquire-price(TTTC8397R/VTTC8397R, stck_prpr)
+ paper stub
- SlotService.update_thresholds() + intent RPC update_thresholds 액션
(부분 갱신/null 해제, 워치독 last_seen_at 리셋)
- baseline 3문서 정합(interface-contract/runtime-flows/project-structure)
거버넌스: REQ-034~042 Implemented 동기화, BAT-010/011 release-candidate,
dcy-007 discovery 포함.
검증: 신규 38 테스트 green, 단위 236 passed/23 skipped,
인프라 게이트(PG+RabbitMQ) 259 passed(마이그레이션 001~004 round-trip 포함),
ruff clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-07 08:32:30 +09:00
genichin and Claude Opus 4.7
9e64a24441
fix: align portfolio-hub ledger write adapter to live API contract
...
REQ-017 CHG-20260606-01. Live portfolio-hub returned 404 for the
trex-orbit-assumed POST /v1/assets/{asset_id}/ledger/trades. Correct to
POST /v1/portfolios/{portfolio_id}/ledger/trades with body keys
quantity/fee_amount/tax_amount (was qty/fee/tax), success 201. Reverified
with live e2e (201 Created, outbox COMPLETED) + durability drain of the
prior 404'd item. Resolves the REL-001 ledger-write release blocker.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-06 11:27:30 +09:00
genichin and Claude Opus 4.7
43bad2424e
fix: align portfolio-hub read adapter to live API contract
...
whoami now hits GET /v1/user_info (the live endpoint; /v1/auth/whoami
does not exist), get_portfolios parses the {portfolios:[...],total} envelope
and filters by managed_by_daemon_id client-side (the list endpoint is
token-scoped, no such query param), and a missing URL scheme now defaults
to http:// so a bare host can't silently degrade the daemon.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-06 10:34:35 +09:00
genichin
ca757009f5
feat: add portfolio snapshot read layer
2026-06-06 09:33:00 +09:00
genichin
6c7a1cf6f6
feat: add messaging transport rollout
2026-06-06 00:02:52 +09:00