new-discovery → review-discovery → confirm-discovery (승인자: Justin Ko). OQ-1~4 전부 Answered: - OQ-1: data = opaque UTF-8 문자열 + 2단 상한(기본 1~2KB / ceiling 4KB), state_too_large reject - OQ-2: write = 별도 RPC trex.slots.strategy_state.set / read = slots.req piggyback - OQ-3: 신규 삭제 이벤트 없음 — 스냅샷 부재 + CAS 의존 (기존 slot_filled_sell 옵션 재사용) - OQ-4: 별도 slot_strategy_state 테이블 + 맵(복합 PK (slot_id, strategy_id)) + slot_id 키 trex-tsl 팀 점유 전환 ABA 누수(High) 지적 반영 → occupancy_seq 경량 가드(C-2b) v1 포함, full 3계층 슬롯 구조 분할은 후속 "영구 슬롯 구조 정합" Discovery로 Deferred. C-4(SellIntent/watchdog)는 기존 계약 확인으로 issue #26 답변 완료. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
28 KiB
0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
- 상태: confirmed
- 문서 ID: dcy-028_20260615_slot-strategy-state-store
- 이슈명: Slot Strategy-State 저장소 (per-strategy opaque state store on trex-core slots, issue #26 C-1/C-2/C-3)
- 작성 시각(KST): 2026-06-15 16:26
- 마지막 갱신 시각(KST): 2026-06-15 17:52
- 대체됨: 없음
- 후속 Discovery 참조: 없음
- 생성된 REQ 참조: 없음
1. 계획 상태 요약
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
- 연계 문서 현황:
- 관련 점수 파일: 미생성
- 관련 TODO/메모: GitHub issue #26 (trex-tsl strategy-daemon 팀 계약 제안), C-4 확인 코멘트·OQ 결정 코멘트(게시 완료), trex-tsl 팀 occupancy race 피드백(#4705990067)
- 해석:
- trex-tsl(매도 전략 데몬)이 TSL trailing stop line 계산에 필요한 **시간 누적 상태(예: entry 이후 peak price)**를 슬롯 수명에 묶어 server-side로 보관할 generic state store를 요청했다(C-1/C-2/C-3).
- 이번 Discovery는 "trex-core가 해석하지 않는 opaque state를
(slot_id, strategy_id)키로 저장/조회/수명관리"하는 범위를 정의한다. OQ-1~4 전부 Answered. trex-tsl 팀이 점유 전환 ABA 누수(High)를 지적해 occupancy_seq 경량 가드(C-2b)를 v1 범위로 추가, full 3계층 분할만 후속 Deferred. C-4(SellIntent/watchdog)는 기존 계약 확인 항목으로 답변 완료. - trex-tsl-v1 운영 모드 = intraday,
safety_sell_enabled=true(core SL/TP watchdog backup + market_close EOD backstop 유지, 데몬이 primary 매도). 중장기 프로파일과 무관 — core가 backup으로 남으며 당일 재진입이 잦아 occupancy 가드 필요성이 큼.
2. 요구사항 판정 결과
이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다.
- 판정: 신규
- 근거
docs/discovery/전체에서strategy_state/per-strategy opaque store를 다루는 기존 Discovery가 없다(grep 결과 0건). 가장 가까운 dcy-025(strategy read surface — slots.req 노출면)는 슬롯 메타 read 확장이지 strategy 소유 상태 저장/CAS write/수명 삭제 계약이 아니다.- C-2(version CAS write RPC)·C-3(close 시 삭제 불변식)는 신규 RPC와 신규 도메인 저장 개념을 도입하므로 기존 REQ/batch 산출물의 미세 조정 범위를 넘어선다.
3. 문제점의 요약
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다.
- 현재 상태
- 슬롯 스냅샷 RPC(
trex.slots.req)는trex_core/application/messaging_handlers.py의build_slots_handler+slot_to_dict(trex_core/application/portfolio.py:250)로 슬롯 행을 구성하며, strategy 소유 임의 상태를 실어 나르는 필드가 없다. - 슬롯 도메인(
trex_core/domain/slot/models.pySlot,state.py)에는 position/occupancy 필드만 있고 strategy opaque blob 저장소가 없다. 전략은evaluate()순수성 때문에 상태를 스스로 영속화할 수 없다. - 슬롯 close는 영구 슬롯 모델(dcy-020/REQ-057, BAT-030)에서 행 삭제가 아니라
→ INACTIVE전이다(trex_core/domain/slot/service.py:174— position/occupancy 필드 일괄 clear, asset 정체성 보존). 현재 이 전이에서 정리할 strategy_state 자체가 없다. - 결과적으로 전략 데몬이 peak 등 누적 상태를 데몬 메모리에 두면 재시작/장애/failover 시 유실되어 stop line이 느슨해지는 실손실 위험이 있고, 별도 외부 스토어를 쓰면 orphan-cleanup 책임이 발생한다.
- 슬롯 스냅샷 RPC(
- 기대 상태
(slot_id, strategy_id)로 네임스페이스된 opaque state를 trex-core가 저장하고, 슬롯 스냅샷 응답에 round-trip(추가 왕복 없이 read), occupancy_seq + version CAS로 idempotent write, 슬롯 close(→INACTIVE) 시 자동 삭제한다.- 전략/데몬은 cleanup 책임이 없고, 슬롯이 source of truth이자 GC가 된다. 재사용된 슬롯은 새 occupancy_seq + 빈 상태(version 없음)로 시작한다.
- 이해관계자
- trex-tsl 매도 전략 데몬 팀 (제안자/주 소비자)
- trex-core 유지보수자 (계약·구현·검증 책임)
- 운영 담당자 (멀티데이 인스턴스 운영, dcy-027 long-term 프로파일 연계)
- 제약사항
- trex-core는
data를 절대 파싱/검증/해석하지 않는다(opaque). schema는 전략 소유. - 순수 AMQP 계약 통합만 — 데몬은
trex_core를 직접 import 하지 않는다. - 단일 writer 전제(해당 slot·strategy를 운용하는 데몬 1개). version CAS는 재시도/중복 안전용이지 다중 writer 동시성 제어가 아니다.
- 영구 슬롯 모델 정합: 삭제는 행 삭제가 아니라
→INACTIVE전이 훅에서 수행한다(dcy-020).
- trex-core는
주요 사용자 시나리오
사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다.
- TSL 데몬이 매 decision-cycle에
trex.slots.req로 슬롯과 함께strategy_state["tsl_v1"]를 읽어evaluate()의 read-only 입력으로 쓰고, 갱신된 peak 상태를trex.slots.strategy_state.set(expected_version CAS)로 write 한다. - 데몬이 재시작/장애로 메모리 상태를 잃어도 다음 사이클에 슬롯 스냅샷에서 peak를 복원해 stop line이 느슨해지지 않는다.
- 슬롯이 매도 체결로 close(
→INACTIVE)되면 trex-core가 해당 슬롯의 모든 strategy_state를 삭제하고, 같은 슬롯이 재사용되면(occupancy_seq++) 전략은 빈 상태에서 다시 시작한다.
4. 이번에 정의할 변경
이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다.
- C-1: 슬롯 스냅샷 RPC(
trex.slots.req) 응답 각 슬롯 행에 optionalstrategy_state맵을 추가(additive, 하위호환). 미보유 시 omit 또는{}. - C-2: 신규 RPC
trex.slots.strategy_state.set—(slot_id, strategy_id)opaque value를 version CAS로 upsert. 기존 계약 패턴(direct reply-to RPC + JSON +queue_name({base}.{instance_key})) 준수. - C-2b (occupancy_seq 경량 가드): 슬롯 행에 monotonic
occupancy_seq(새 점유 시작 시 ++)를 추가하고 snapshot 행에 노출한다.strategy_state.set은expected_occupancy_seq를 받아 occupancy_seq 일치 + version 일치를 함께 CAS 검증, 점유가 바뀌었으면occupancy_changedreject. 점유 전환(read v0→close→reopen→write v0)의 ABA 누수를 구조적으로 차단(intraday 재진입 안전). full 3계층(occupancy 테이블 분할)은 후속 Deferred — 본 가드는 컬럼 1개로 정합성 임계부만 선취. - C-3: 슬롯 close 시 strategy_state 삭제 불변식 — 영구 슬롯 모델 정합상
→INACTIVE전이(service.py:174)에서 해당 slot_id의 모든 strategy_state 제거. - (baseline)
docs/runtime-flows.md에 strategy-state read/write/삭제 흐름 추가,docs/project-structure.md에 저장소 구조·계약 키 반영.
영향 범위
변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다.
- 코드 영향:
trex_core/application/messaging_handlers.py(build_slots_handler응답에 strategy_state + occupancy_seq 병합, 신규 strategy_state.set 핸들러 + occupancy_seq CAS)trex_core/application/portfolio.py(slot_to_dict에 strategy_state + occupancy_seq round-trip)- 신규 저장 포트/리포지토리(예:
StrategyStateStore)와 PG/in-memory 구현(trex_core/adapters/persistence/postgresql.py,trex_core/domain/slot/in_memory_repository.py또는 별도 모듈) trex_core/domain/slot/models.py·service.py(슬롯에occupancy_seq필드 추가 + 새 점유 시작(inactive→pending_buy) 시 ++ +→INACTIVE전이 시 strategy_state 삭제 훅), 스키마 마이그레이션(occupancy_seq컬럼) 및 데몬 와이어링(trex_core/runtime/daemon.py)
- 문서 영향:
docs/runtime-flows.md(strategy-state 흐름),docs/project-structure.md(저장소/계약 키),docs/srs/index.md(신규 REQ 등록)
- 운영 영향:
- 신규 RPC 라우팅 키/큐 추가 → 데몬·인프라 설정 반영. PG 사용 시 신규 테이블/스키마 마이그레이션.
5. 요구사항 목록
실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다.
기능 요구사항
- FR-1 (C-1):
trex.slots.req응답 각 슬롯 행에 optionalstrategy_state맵({<strategy_id>: {version:int, data:str, updated_at:str}})과 **occupancy_seq(int)**를 추가한다. 미보유 시 omit/{}. 기존 소비자는 unknown 필드 무시로 하위호환. 맵은 별도slot_strategy_state테이블(OQ-4)에서 반환 slot_id들로 batched 조회 후 group by 해 조립한다(슬롯 본체 스키마 불변; occupancy_seq는 슬롯 행 컬럼). - FR-2 (C-2): 신규 RPC
trex.slots.strategy_state.set로(slot_id, strategy_id)opaquedata를 occupancy_seq + version CAS upsert 한다.expected_occupancy_seq가 슬롯 현재 occupancy_seq와 일치하고expected_version이 stored version과 일치 → commit 후 version+1. 점유 불일치 →{ok:false, reason:"occupancy_changed", occupancy_seq:<cur>}(저장 안 함; 데몬 re-read 후 fresh restart). version 불일치 →{ok:false, reason:"version_conflict", version:<cur>}. slot inactive/missing →{ok:false, reason:"slot_inactive"}(저장 안 함). 최초(없음 + expected_version=0, occupancy_seq 일치) → version=1 생성. 동일correlation_id재전송은 부작용 없음.data는 opaque UTF-8 문자열로 받아 (1) 유효 UTF-8 + (2) 크기 상한(NFR-2/OQ-1)만 검증하고 그대로 저장하며, 초과 시{ok:false, reason:"state_too_large"}로 reject 한다(저장 안 함). malformed 페이로드는{ok:false, reason:"bad_request:<detail>"}. reject reason 전체 집합 = {occupancy_changed,version_conflict,slot_inactive,state_too_large,bad_request}, 데몬은 미인식 reason에 fail-closed. - FR-2b (C-2b, occupancy_seq 가드): 슬롯에 monotonic
occupancy_seq필드를 두고 새 점유 시작(inactive→pending_buy) 시 ++, snapshot 행(FR-1)에 노출한다. read v0→close→reopen→write v0 의 ABA 누수를 FR-2 occupancy CAS로 구조적으로 차단한다. (full occupancy 테이블 분할은 Out of Scope — 컬럼 1개로 정합성 임계부만 선취.) - FR-3 (C-3): 슬롯이 어떤 경로로든 close(
→INACTIVE)되면 해당 slot_id의 모든 strategy_state를 삭제한다. 재사용 슬롯은 새 occupancy_seq + 빈 상태(version 없음)로 시작한다. 삭제 즉시성 통지는 신규 이벤트를 만들지 않고(OQ-3 확정), 데몬은 다음slots.req스냅샷의 state 부재(또는 occupancy_seq 변화)로 감지한다; 즉시성이 필요하면 이미 발행되는slot_filled_sell(status=inactive) transition 이벤트를 재사용한다(필요시strategy_state_clearedadditive 플래그). - FR-4 (baseline):
docs/runtime-flows.md에 strategy-state read/write/삭제 흐름·occupancy_seq 가드·영구 슬롯 close 훅 정합을,docs/project-structure.md에 저장소 구조·계약 키를 반영한다.
비기능 요구사항
성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다.
- NFR-1 (불간섭/opaque): trex-core는
data를 파싱/검증/해석하지 않는다. 충돌/만료/해석은 전적으로 trex-core 밖이다. - NFR-2 (인코딩/크기 한계, OQ-1 확정):
data는 core가 해석하지 않는 opaque UTF-8 문자열이다 — JSON/base64를 계약 레벨에서 강제하지 않으며(base64 기본 강제는33% 팽창·무이득), core 검증은 (1) 유효 UTF-8 + (2) 크기 상한(byte 기준) 두 가지뿐이다. 상한은 2단 — TSL 등 알려진 용례 기본 **12KB**, hard ceiling 4KB. 초과 시 명시적 reject(state_too_large). C-1 read piggyback상 스냅샷 응답 크기 ≈max_active_slots × cap이므로 상한은 슬롯당 저장이 아니라 폴링 응답 크기 관점에서 정한다. - NFR-3 (수명 정합): strategy_state는 슬롯 수명 동안만 존재하고 장기 영속/감사 대상이 아니다. read는 기존 스냅샷 RPC에 round-trip 되어 추가 왕복이 없고 watchdog 갱신을 깨지 않는다.
범위 경계
이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다.
- In Scope
- C-1 read 확장(strategy_state 맵 + occupancy_seq), C-2 write RPC, C-2b occupancy_seq 경량 가드, C-3 close 삭제 불변식, baseline 문서 정합
- occupancy_seq + version CAS 의미(occupancy_changed/version_conflict/slot_inactive/state_too_large/bad_request/first-create/idempotent)
- Out of Scope
- 다중 writer 동시성 제어(단일 writer 전제)
- strategy_state 장기 보존/감사/이력 저장(별도 논의)
- C-4(SellIntent/watchdog) 신규 구현 — 기존 계약 확인 항목으로 issue #26 코멘트에서 답변 완료
- full 3계층 슬롯 구조 분할(별도
asset_slot/slot_occupancy테이블, strategy_state를 occupancy_id 키로 전환) — 후속 "영구 슬롯 구조 정합" Discovery로 Deferred.daily_slot네이밍 정합·daily_symbol_entries잔재 제거도 함께. (정합성 임계부인 occupancy_seq 가드는 본 batch 포함 — C-2b. 중장기 영구 슬롯엔 점유 회전이 드물어 full 분할은 과함; 가드 컬럼 1개로 충분.)
6. 리스크/가정 목록
불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다.
리스크
- R-1 (High→완화): 점유 전환 ABA 누수 — read v0→close→reopen→write v0 시 X가 계산한 상태가 새 점유 Y에 바인딩(잘못된 stop line, 안전 관련). version CAS(0 vs 0)·slot_inactive(write 시 Y로 이미 active)로는 못 잡음. intraday Mode A(당일 재진입)에서 실재(trex-tsl 팀 #26 지적).
- 완화 방안: occupancy_seq 경량 가드(C-2b/FR-2b) — 새 점유마다 occupancy_seq ++, write가
expected_occupancy_seq로 점유 일치를 server-side CAS 검증 → 다른 점유면occupancy_changedreject. ABA를 구조적으로 차단. +→INACTIVE단일 전이 지점 삭제 훅(모든 close 경로 커버)·테스트로 보강.
- 완화 방안: occupancy_seq 경량 가드(C-2b/FR-2b) — 새 점유마다 occupancy_seq ++, write가
- R-2 (Medium): write RPC race/중복 전달로 상태 덮어쓰기.
- 완화 방안: occupancy_seq + version CAS +
correlation_id("{slot_id}:{strategy_id}:{expected_version}") idempotency. 단일 writer 전제 문서화.
- 완화 방안: occupancy_seq + version CAS +
- R-3 (Low): PG 스키마 추가/마이그레이션 운영 부담(별도
slot_strategy_state테이블 + 슬롯occupancy_seq컬럼).- 완화 방안: opaque blob 별도 테이블 + occupancy_seq 컬럼 1개의 최소 스키마(JSONB-on-row는 OQ-4에서 기각). in-memory 구현 병행으로 paper/테스트 무중단.
가정
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
- A-1 (OQ-4로 확정): strategy_state는 별도
slot_strategy_state테이블 + 맵(복합 PK(slot_id, strategy_id)) + slot_id 키. 슬롯 본체(daily_slot, 레거시 명 — 실제는 영구 자산 슬롯)에는 정합성 가드용occupancy_seq컬럼 1개만 추가(full 테이블 분할 없음). - A-2 (OQ-2로 확정): read는 기존
trex.slots.req에 piggyback, write는 별도 신규 RPCtrex.slots.strategy_state.set. (가정 → 확정) - A-3: 영구 슬롯 모델(dcy-020) 정합상 삭제는 행 삭제가 아니라
→INACTIVE전이 훅이다(issue #26 코멘트에서 데몬 팀에 이미 고지).
오픈 질문
답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다.
- OQ-1 (OQ-A):
data인코딩을 JSON 문자열로 할지 base64 바이트로 할지, 수용 가능한 크기 상한(제안 4KB)은 얼마인지.- 상태: Answered (2026-06-15, Justin Ko)
- 결정: opaque UTF-8 문자열 + 2단 상한. JSON/base64를 계약 레벨에서 강제하지 않고 core는 유효 UTF-8 + byte 크기 상한만 검증(NFR-1 정합). 상한은 TSL 등 알려진 용례 기본 1~2KB, hard ceiling 4KB(byte 기준). 초과 시
state_too_large명시적 reject. C-1 스냅샷 응답 크기(max_active_slots × cap) 관점에서 상한을 정한다. - 반영 위치: NFR-2(인코딩/크기 한계), FR-2(write 검증·reject 사유).
- OQ-2 (OQ-B): 신규 RPC(
trex.slots.strategy_state.set) vs 기존 메시지(heartbeat/intent) piggyback 중 어느 write 방식을 채택할지.- 상태: Answered (2026-06-15, Justin Ko)
- 결정: write = 별도 RPC
trex.slots.strategy_state.set(C-2), read =trex.slots.reqpiggyback(C-1) 유지. piggyback 기각 근거 — (1) write(거의 매 사이클)와 sell intent(드묾)의 빈도 불일치, (2) trex-core에 dedicated heartbeat 부재 + watchdog는slots.req가 모든 holding 슬롯에 매 사이클 갱신해야 해 조건부 write와 합치면 커버리지 붕괴, (3) read RPC에 write를 얹으면 멱등성·spy의미 붕괴, (4) CAS 응답/재시도 격리, (5) trex-core가 이미 concern별 개별 RPC 패턴이라 추가 비용 낮음. read는 어차피 폴링하는slots.req에 공짜로 얹히므로 비대칭(read piggyback / write 분리)이 의도된 설계. - 반영 위치: FR-1(C-1 read piggyback), FR-2(C-2 별도 write RPC). A-2 가정 → 확정.
- 비고: 사이클당 다중 슬롯 write 시 N개 set RPC 발생 — optional batch 변형은 v1 범위 밖 후속 최적화.
- OQ-3 (OQ-C): close 시 strategy_state 삭제를 slot-transition 이벤트(
trex.events.strategy.*)로 노출할지(데몬 즉시 반응 가능).- 상태: Answered (2026-06-15, Justin Ko)
- 결정: 신규 전용 이벤트 도입하지 않음. 정합성은 (1) 스냅샷 부재(
slots.req에서 strategy_state 없음 → 데몬expected_version=0first-create) + (2) C-2 CAS rule(닫힌 슬롯 write는slot_inactivereject로 부활 차단)가 보장한다. 즉시성이 필요하면 이미 발행되는slot_filled_sell(status=inactive) transition 이벤트를 재사용(모든 매도 close가 execution looppending_sell→INACTIVE경로로 이 이벤트를 emit; best-effort). 정 필요하면 그 payload에strategy_state_cleared: trueadditive 필드만 추가 — 새 event_type/route 아님. 전용 state-cleared 이벤트는 구체적 필요 발생 시 후속 반복으로 Deferred. - 근거: 정합성이 best-effort 이벤트에 의존하지 않도록(source of truth = 스냅샷), 신규 event_type의 라우팅/바인딩/DLQ 비용 회피, transition 이벤트·스냅샷 부재와의 중복 제거.
- 반영 위치: FR-3(삭제 불변식 — 이벤트 노출은 옵션, 기존 transition 이벤트 재사용 명시), NFR-3(수명 정합).
- OQ-4 (OQ-D):
strategy_state를 슬롯당 다중 strategy 맵으로 둘지 단일 객체로 둘지 + 저장 모델(별도 테이블 vs 슬롯 행 JSONB).- 상태: Answered (2026-06-15, Justin Ko)
- 결정: 별도
slot_strategy_state테이블 + 맵 +slot_id키. ① shape = 맵(strategy_id 네임스페이스, 계약 키(slot_id, strategy_id)로 강제) — 한 슬롯이strategy_id(매수)·sell_strategy_id(매도)를 동시 보유 가능하므로 단일 객체는 충돌. ② 저장 = 별도 테이블(JSONB-on-row 기각): CAS가UPDATE ... WHERE version=?rowcount /INSERT ON CONFLICT로 race-safe, hot 슬롯 행(daily_slot) lean 유지, write 경합 분리, C-3 삭제DELETE WHERE slot_id=?한 문장. 테이블 PK = 복합(slot_id, strategy_id), strategy당 1행. C-1 read는 반환 slot_id들로 batched 조회 후 group by 해 맵 조립. in-memory repo는 복합키 dict로 미러. 참조 방향은 strategy_state → slot(테이블이 slot_id를 컬럼으로 보유), slot 본체 스키마 불변. - 키 선택(slot_id vs occupancy_id): strategy_state 테이블은 slot_id 키 유지 + occupancy_seq 경량 가드(C-2b) 추가. (2026-06-15 갱신, trex-tsl #4705990067 지적 반영) 당초 "occupancy 식별자 전면 deferred"는 점유 전환 ABA 누수(R-1)를 못 막음이 확인되어 수정 — 정합성 임계부인 occupancy 식별만 슬롯 행 occupancy_seq 컬럼 1개로 v1에 선취하고, write CAS가
expected_occupancy_seq로 점유 일치를 검증한다. full 3계층(별도 occupancy 테이블 + strategy_state를 occupancy_id 키로 전환)만 Deferred — 중장기 영구 슬롯은 점유 회전이 드물어 full 분할이 과하고, intraday(trex-tsl)가 요구하는 정합성은 가드 컬럼으로 충족. strategy_state 격리 테이블이라 추후 full 분할 시 seq→id 흡수도 contained. - 반영 위치: FR-1(read 맵 조립), FR-2(CAS 저장), FR-2b/C-2b(occupancy_seq 가드, In Scope), FR-3(close 삭제), §4 영향 범위(별도 StrategyStateStore/테이블), 범위 경계(full 3계층만 Out of Scope), A-1 확정.
오픈 질문 처리 기준
Open: 아직 답이 없고 다음 단계 진행에 영향이 있는 상태다. 문서에 유지한다.Answered: 답이 확정된 상태다. 관련 본문/요구사항에 반영한 뒤 오픈 질문 목록에서는 제거하거나 resolved 기록으로 이동한다.Deferred: 지금 단계에서 결정하지 않고 다음 단계 또는 후속 이슈로 넘기는 상태다. 넘길 대상과 이유를 반드시 적는다.Dropped: 더 이상 유효하지 않은 질문이다. 삭제 사유를 짧게 남기고 목록에서 제거한다.- 처리 원칙 1: 질문만 남기지 말고 반드시
상태,처리 방안,종료 조건을 함께 적는다. - 처리 원칙 2: 답이 나온 질문은 본문 반영 없이 단순 삭제하지 않는다. 반영 위치를 먼저 갱신한다.
- 처리 원칙 3: High 영향 질문은
Deferred처리 후 처리 방안에 REQ 인계 추적 방식을 명시한다.
7. 초기 성공 기준
이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다.
- S-1: 데몬이
trex.slots.req로 슬롯과 함께 strategy_state·occupancy_seq를 read하고,trex.slots.strategy_state.set으로 write한 뒤, 같은 슬롯의 다음 스냅샷에서 version+1과 갱신된 data가 보인다. - S-2: CAS 의미(occupancy match+version match commit / version_conflict / occupancy_changed / slot_inactive / state_too_large / first-create)와 idempotent 재전송 무부작용이 테스트로 검증된다.
- S-3: 슬롯이 모든 close 경로(전략 매도 체결/safety-sell/forced-close)로
→INACTIVE전이 시 strategy_state가 삭제되고, 재사용 슬롯이 새 occupancy_seq + 빈 상태(version 없음)로 시작한다. - S-4: 점유 전환 ABA 시나리오(read v0 → close → reopen(occupancy_seq++) → 옛 점유 기준 write) 가
occupancy_changed로 reject 되어 새 점유에 stale 상태가 바인딩되지 않음이 테스트로 검증된다.
측정 방식 및 데이터 출처
각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다.
- S-1 측정 방식: read/write/재read end-to-end 통합 테스트 / 데이터 출처: messaging_handlers 핸들러 테스트, slots.req 응답 페이로드
- S-2 측정 방식: strategy_state.set 핸들러 단위 테스트(6 케이스: occupancy+version commit/version_conflict/occupancy_changed/slot_inactive/state_too_large/first-create + 중복 재전송) / 데이터 출처: 신규 핸들러/스토어 테스트
- S-3 측정 방식: 각 close 경로 후 strategy_state 부재 + occupancy_seq 증가 검증 테스트 / 데이터 출처: slot service
→INACTIVE/inactive→pending_buy전이 테스트, 스토어 상태 - S-4 측정 방식: 점유 전환 race 단위 테스트(occupancy_seq mismatch → occupancy_changed) / 데이터 출처: strategy_state.set 핸들러/스토어 테스트
8. REQ로 넘기기 전 확인 체크
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다.
- 범위(In Scope/Out of Scope) 확정
- 기준: C-1/C-2/C-2b/C-3 + baseline 포함, C-4·다중writer·장기보존·full 3계층 분할 제외 합의 — confirm-discovery 확정.
- 성공 지표의 측정 방식/데이터 출처 확정
- 기준: S-1~S-4 테스트 가능 형태로 확정 (§7 측정 방식 참조)
- High 영향 리스크 우선순위 및 해소 책임자 지정
- 기준: R-1(점유 전환 ABA, High) → occupancy_seq 가드(C-2b/FR-2b)로 완화안 채택 확정. R-2/R-3 Medium/Low.
- 모든 오픈 질문(OQ)
Open상태 없음 확인- 기준: OQ 목록에
Open상태 항목이 0개이거나, 잔여 항목 전부Deferred처리 완료 - 결과: OQ-1~4 전부 Answered (2026-06-15). full 3계층 분할만 후속 Discovery로 Deferred(occupancy_seq 가드는 v1 포함).
- 기준: OQ 목록에
- Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: confirm-discovery 시 승인자 지정 — Justin Ko (2026-06-15)
9. 파일 처리 결과
이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다.
- 처리 결과: 생성
- 생성 경로: docs/discovery/dcy-028_20260615_slot-strategy-state-store.md
- 참조 문서:
- GitHub issue #26 (Slot Strategy-State 계약 제안) + C-4 확인 코멘트 + OQ 결정 코멘트 + occupancy race 피드백/답변(#4705990067, #4706137866)
- docs/discovery/dcy-020_20260610_asset-centric-slot-model.md (영구 슬롯/→INACTIVE 모델)
- docs/discovery/dcy-025_20260611_strategy-read-surface-slots-req.md (slots.req read surface)
- docs/discovery/dcy-027_20260612_long-term-strategy-slot-operation.md (영구 슬롯/long-term 프로파일 연계)
- stage-pilot/templates/project-structure.md, stage-pilot/templates/runtime-flows.md
10. 사용자 결정 필요 항목 요약
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다.
DECIDE
→ 해결됨(2026-06-15): opaque UTF-8 문자열 + 2단 상한(기본 1~2KB / hard ceiling 4KB), 초과 시data인코딩 + 크기 상한 — OQ-Astate_too_largereject. (OQ-1 참조)write 경로(별도 RPC vs piggyback) — OQ-B→ 해결됨(2026-06-15): write = 별도 RPC(C-2), read = slots.req piggyback(C-1) 유지. (OQ-2 참조)슬롯당 다중 strategy 맵 vs 단일 객체 + 저장 모델(테이블 vs JSONB) — OQ-D→ 해결됨(2026-06-15): 별도slot_strategy_state테이블 + 맵(복합 PK(slot_id, strategy_id)) + slot_id 키, occupancy_id 후속 Deferred. (OQ-4 참조)
CONFIRM
close 시 strategy_state 삭제를 slot-transition 이벤트로 노출할지 — OQ-C→ 해결됨(2026-06-15): 신규 이벤트 없음, 스냅샷 부재 + CAS 의존, 기존slot_filled_sell옵션 재사용. (OQ-3 참조)- 삭제 훅을 영구 슬롯
→INACTIVE전이로 두는 설계(행 삭제 아님) — A-3·FR-3로 확정, 데몬 팀 고지 완료. confirm-discovery 승인 시 함께 확정.
DATA
PG 컬럼/메시지 크기 기준 실수용 가능한 data 상한 값→ 확정(OQ-1): 기본 1~2KB / hard ceiling 4KB(byte 기준)
11. Discovery Freeze
REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다.
섹션 참조
- 범위: # 5. 요구사항 목록 > 범위 경계
- 리스크/오픈 질문: # 6. 리스크/가정 목록
- 성공 기준: # 7. 초기 성공 기준
- 인계 전 확인: # 8. REQ로 넘기기 전 확인 체크
- 사용자 결정 필요: # 10. 사용자 결정 필요 항목 요약
Freeze 플래그
- Handoff Decision: 승인
- Handoff Rationale: OQ-1~4 전부 Answered(2026-06-15) — 인코딩(opaque UTF-8+2단 상한)/write 경로(별도 RPC)/삭제 이벤트(신규 없음)/저장 구조(별도 테이블+맵+slot_id 키 + occupancy_seq 경량 가드) 확정. trex-tsl 팀 점유 ABA 지적 반영(C-2b). full 3계층 분할만 후속 Discovery로 Deferred. 범위·성공기준·저장소 사실관계 확인 완료, C유형 placeholder·Open OQ 0개 → REQ 초안 작성 진행 가능.
- Ready for REQ Drafting: true
- Confirmed By: Justin Ko
- Confirmed At (KST): 2026-06-15 17:52