Hermes Agent
15aeae6930
fix: converge broker failures without retry
2026-08-19 11:29:26 +09:00
Hermes Agent
147873cb5d
feat(execution): reconcile timed-out orders safely
2026-08-14 15:15:52 +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
genichin and Claude Opus 4.8
e4be4d60c2
feat(slot): dcy-021 포지션 사이징 — 보유 슬롯 증액·부분 매도 (BAT-031)
...
자산 영구 슬롯(dcy-020)의 수량 가변 전제 위에 보유 포지션 수량 조정 구현.
명령형 계약(전략이 cash+quantity 로 qty+price 계산), core 는 실행 substrate,
수량 정본 = 브로커 잔고 재동기화로 "주문 수량 vs 보유 수량" 충돌 해소(별도 필드 없음).
- state.py: holding→pending_buy 전이 추가(증액) → 13 transitions (REQ-057)
- service.py: PENDING_SELL 진입 qty=caller as-is(None=전량 sentinel, 값=부분 주문) (REQ-062)
- intents.py: 증액 admission(holding 슬롯 매수=increase, M 캡 미적용), SellIntent.qty 부분 매도 (REQ-061)
- execution.py: _balance_map; 매도 dispatch=브로커잔고(전량)/min(주문,잔고)(부분);
매수 체결 avg_price 가중평균+브로커 정본 resync; 매도 체결 잔고>0→holding/0→inactive;
증액 롤백 holding 복귀 (REQ-066/062)
- messaging_handlers.py: sell payload qty 파싱(부분 매도)
- baseline 4문서(data-model/runtime-flows/interface-contract/project-structure) 정합 (REQ-067)
검증: 단위 378 / 통합(PG+RabbitMQ) 422 passed, ruff clean. run-the-app 사이징 e2e:
매수 10@1000 → 증액 +5@1200 → 15@1066.67 (가중평균) → 부분 매도 6 → 9@1066.67 (cost basis) → 전량→inactive.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 18:53:37 +09:00
genichin and Claude Opus 4.8
c04fd276b3
feat(reset): cutover 도구 폐기 → trex-core-reset(DB 재초기화) 대체 (REQ-064 CHG-20260610-03)
...
실 DB 점검 중 마이그레이션 009 부분 유니크 인덱스가 legacy 풀 데이터(같은
자산이 closed+재진입 holding 으로 portfolio_id 중복)에 적용 불가 → cutover·
데몬 부팅 모두 차단되는 결함 확인. 데이터 보존 cutover 를 폐기하고 DB wipe +
자산 중심 재초기화로 전환(사용자 결정). 빈 테이블에는 009 인덱스가 정상
생성되고 자산 중심에서 (instance_key, portfolio_id)는 설계상 유일.
- trex_core/runtime/reset.py 신규(trex-core-reset): slot-core 7테이블 wipe +
apply_migrations 재적용 → 자산 중심 스키마 착지 검증. dry-run 기본/--yes 적용,
파괴적·DB 전역. 보유 carry-over 없음(재초기화 후 reconcile_core_holdings 재편입).
- runtime/cutover.py + trex-core-cutover console script + test_cutover_rehearsal.py 삭제.
- pyproject: trex-core-reset 등록.
- tests/runtime/test_reset.py 신규 5건(PG-gated): wipe+착지·dry-run 무변경·멱등·
wipe 후 admission·테이블 커버리지.
- change-req REQ-064 CHG-20260610-03(cutover→재초기화 재정의) + srs index 갱신.
- baseline 4문서(data-model/runtime-flows/project-structure/interface-contract)
+ BAT-030 design/planning/index/implementation/verification 도구 서술 reset 으로 교체.
검증: ruff clean, 단위 367 passed, PG+RabbitMQ 통합 411 passed/1 skip(KIS sandbox).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 16:08:05 +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
6e8e79660c
feat(slot): slot entry_count + closed-slot reallocation (dcy-019, BAT-025) + REL-005
...
dcy-019/issue #18 : slot 자원을 진입 횟수 기준으로 고르게 재사용하고 idle 소진 시
closed 슬롯을 직접 재할당한다. 거버넌스는 전부 change-req(신규 REQ 없음).
- 도메인(REQ-002): Slot.entry_count(기본 0) + EXPECTED_SLOT_FIELDS, 상태 머신
closed→pending_buy 신규 전이(base 8→9, ALLOWED_TRANSITIONS 14→15),
_apply_transition_fields closed→pending_buy clean-slate + →pending_buy 시 +1
- 영속화(REQ-006): 멱등 마이그레이션 008(entry_count), flat 매핑,
find_allocatable_slot(idle∪closed, entry_count→updated_at→slot_id) + in-memory 동등
- admission(REQ-007): _admit_buy find_idle_slot→find_allocatable_slot + from_state=slot.status
- 테스트(REQ-003): 전이 카운트/계약 가드 정합 + test_slot_entry_count.py / test_buy_admission_reallocation.py
- 문서(REQ-009): data-model.md / runtime-flows.md 정합
- 기존 daily_symbol_entries(symbol-scoped) 분리·미변경
BAT-025(release-candidate) delivery + change-req REQ-002/003/006/007/009(CHG-20260609-01).
REL-005(confirmed, app-service): BAT-024+BAT-025 묶음. operator-facing run-the-app
스모크로 enter --forced-close-at(BAT-024)·closed 재할당(BAT-025) 실 데몬 검증
(실 PG 마이그레이션 008 round-trip 포함).
검증: 단위 366 passed / 35 skipped(KIS sandbox 1건 deselect — live .env 환경 의존), ruff clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-09 14:49:22 +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
0b7db66463
feat(runtime): dcy-014 trading_date KST 타임존 분리 + 일일 슬롯 preallocation (BAT-018)
...
데몬이 시스템 UTC 날짜로 슬롯을 1회만 preallocate 해 trading_date 가 KST 캘린더와
어긋나고 재시작 없이는 다음날 슬롯이 안 생기던 문제(issue #14 ) 정정.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-014 OQ-3; 스케줄러는 REQ-030 패턴 준용).
- REQ-005: trading_date 를 설정 타임존(기본 Asia/Seoul) 기준 계산(timestamp 는 UTC
유지). DailyPreallocationScheduler 신규 — TZ 일자당 1회 멱등 fire, 재시작 없이
다음날 슬롯 자동 생성. setup() 배선 + trex-preallocation 스레드
- REQ-048: TOML trading_timezone/daily_preallocation_time 키 + from_config 전파
- REQ-009: runtime-flows/data-model 정합 + instance.example.toml
OQ-1 기본 00:00(TZ 자정, TOML 설정 가능) / OQ-2 매 캘린더일 생성(거래일 캘린더 후속).
멱등 preallocate 로 중복 tick·다중 인스턴스 중복 생성 0.
검증: 단위 302 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 334 passed, ruff clean.
신규 test_preallocation_scheduler(고정 clock) + test_instance_config 확장.
BAT-018 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 15:39:04 +09:00
genichin and Claude Opus 4.8
cc28e1fba5
fix(execution): dcy-012 매도 가격 버그 정정 — slot entry_price→limit_price rename (BAT-016)
...
매도(sell) 주문이 현재가가 아닌 매수가(entry_price) 지정가로 나가던 버그(issue #10 )
정정. 슬롯의 매수 전용 entry_price 를 side 무관 "현재 pending 주문 지정가"
limit_price 로 내부 rename 하고, pending 이탈(→holding/→closed) 시 clear 해
매수 지정가가 매도로 누수되는 경로를 구조적으로 제거.
거버넌스: 전부 change-req (신규 REQ 없음, dcy-012 OQ-3).
- REQ-002: Slot entry_price→limit_price rename + clear-on-exit 생애주기
- REQ-006: daily_slot 컬럼 rename 마이그레이션 006 (idempotent) + persistence 매핑
- REQ-013: _dispatch 가 slot.limit_price 단일 필드로 가격/주문유형 결정
- REQ-007: SellIntent/sell payload optional limit_price + _admit_sell 운반
- REQ-036: SlotService.sell optional 가격 → 자율 매도(safety-sell/kill-switch) 시장가
- REQ-003: 컬럼 계약/드리프트 가드 limit_price 반영
- REQ-015: runtime-flows/interface-contract/data-model 정합
매도 정책(OQ-1 하이브리드): 가격 지정→지정가("00"), 미지정→시장가("01").
자율 매도는 가격 미전달 → 항상 시장가 (손절 미체결 pending_sell 갇힘 방지, issue #9 연계).
검증: 단위 286 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 318 passed, ruff clean.
신규 test_sell_pricing(recording broker)로 지정가 매수 슬롯의 매도가 매수가
재사용 안 함을 직접 검증. BAT-016 release-candidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-08 13:41:46 +09:00
genichin
aed54911d4
chore: commit current workspace changes
2026-06-04 23:38:42 +09:00
genichin and Claude Opus 4.8
97d58318db
Deliver BAT-004: broker execution + KIS adapter + durable handoff
...
Implement REQ-011~015 (dcy-003): the order-execution layer on top of the
BAT-002 slot-core daemon, connecting intents to real orders.
- application: BrokerPort (submit/poll_fill/cancel) + ExecutionService
(claim -> submit -> poll -> transition -> rollback -> reconcile)
- adapters/broker: PaperBroker (deterministic async double) and KISBroker
(KIS Open API: token, order-cash, inquire-daily-ccld, cancel; VTS sandbox
tr_ids; live account gated behind allow_live)
- persistence: option-A execution queue (find_pending_for_dispatch FOR
UPDATE SKIP LOCKED, mark_dispatched idempotency guard, clear_dispatch)
- runtime: background execution loop in the daemon lifespan + startup
reconcile; config selects paper|kis
Verification (real KIS VTS 모의투자 + PostgreSQL): 92 passed, ruff clean,
domain import sweep shows zero broker/web/db deps, buy->holding /
sell->closed / reject->idle, idempotent dispatch (exactly one order),
reconcile after crash creates no duplicate order, KIS sandbox token+submit
round-trip, and a daemon E2E through the background loop. Align the four
baseline docs. BAT-004 -> release-candidate; REQ-011~015 -> Implemented.
KIS live-account go-live, partial-fill accrual, option-B outbox, connection
pooling, and the safety floor remain deferred to follow-up Discoveries.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 17:46:17 +09:00
genichin and Claude Opus 4.8
a4e263c8e7
Deliver BAT-002: slot-core daemon + HTTP intent API + PostgreSQL
...
Implement REQ-005~009 (dcy-002 slice 1) as an onion stack on top of the
BAT-001 pure domain:
- application: IntentService (admission + single-writer transition +
intent_id idempotency via durable intent_log)
- adapters/persistence: PostgreSQLSlotRepository + PostgreSQLIntentStore +
trex-core-owned migrations (daily_slot per Appendix A, daily_symbol_entries,
slot_transition_log, intent_log) + in-memory intent store
- adapters/api: FastAPI /v1 (healthz, intents/buy|sell|{id}, slots, capacity)
- runtime: trex-core-daemon entrypoint with lifespan migrate+preallocate
Verification (against local PostgreSQL 18): 74 passed, ruff clean, domain
import sweep shows zero web/db deps (NFR-1), 20-thread concurrency admits
exactly the idle count (NFR-2), idempotent resubmit causes no double
transition (NFR-3), EXPECTED_SLOT_FIELDS<->information_schema drift test
(realizes dcy-001 OQ-2's deferred DB-side check), and a daemon E2E smoke.
Align all four baseline docs to the new daemon/API/persistence layers.
BAT-002 -> release-candidate; REQ-005~009 -> Implemented. Full async outbox,
broker execution, safety floor, and strategy daemons remain deferred to a
follow-up Discovery.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 13:46:08 +09:00
genichin and Claude Opus 4.8
b40e569537
Bootstrap StagePilot baseline for slot domain migration
...
Initialize baseline seed, four baseline docs (project-structure,
runtime-flows, interface-contract, data-model), and the active
discovery/srs/batches/releases indexes. Content derived from the
trex-orbit slot pure-domain migration plan (trex-core as a new base,
pure domain only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-03 09:47:14 +00:00