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>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# req-079: Slot strategy-state 저장소 — `slot_strategy_state` 테이블 + StrategyStateStore 포트 + occupancy_seq·version CAS
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Data
|
||||
- Priority: High
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
- 전략 데몬(trex-tsl 등)이 슬롯 점유 동안 누적하는 opaque 상태(예: TSL peak)를 슬롯 수명에 묶어 server-side 영속화할 저장소를 신설한다. trex-core 는 값을 해석하지 않고(opaque) 저장/조회/CAS 만 책임진다. 슬롯이 source of truth 이자 GC 가 되어 데몬은 cleanup 책임이 없다. (dcy-028 FR-2/OQ-1/OQ-4, issue #26 C-2)
|
||||
|
||||
## Requirement
|
||||
- 별도 테이블 `slot_strategy_state` 를 신설한다(슬롯 행 JSONB 미사용 — dcy-028 OQ-4): 복합 PK `(slot_id, strategy_id)`, 컬럼 `version int`, `data text`, `updated_at timestamptz`, 그리고 점유 식별 `occupancy_seq int`(REQ-081 가드 참조). strategy 당 1행.
|
||||
- `StrategyStateStore` 포트(Protocol)를 정의하고 PG 구현과 in-memory 구현(복합키 dict)을 함께 제공한다(paper/테스트 무중단).
|
||||
- CAS upsert 의미:
|
||||
1. occupancy_seq 일치 + version 일치 → commit, version+1 반환.
|
||||
2. occupancy 불일치 → `occupancy_changed` (저장 안 함). version 불일치 → `version_conflict` (저장 안 함). 슬롯 inactive/미존재 → `slot_inactive` (저장 안 함).
|
||||
3. 최초(엔트리 없음 + expected_version=0 + occupancy 일치) → version=1 생성.
|
||||
4. 동일 입력(같은 expected_version) 재적용은 부작용 없음(멱등).
|
||||
- `data` 는 opaque UTF-8 문자열로 저장한다. core 검증은 (1) 유효 UTF-8 + (2) byte 크기 상한뿐 — JSON/base64 를 강제하지 않는다. 상한은 2단(기본 1~2KB / hard ceiling 4KB byte). 초과 시 `state_too_large` 로 저장 거부(REQ-080 RPC 가 reason 운반).
|
||||
- 조회 API 는 slot_id 집합으로 batched 조회를 지원해 C-1 read(REQ-073/074) 가 추가 왕복 없이 행별 맵으로 조립할 수 있어야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 비어 있는 `(slot_id, strategy_id)`, When expected_version=0 + 일치 occupancy_seq 로 set, Then version=1 로 생성되고 같은 키 조회 시 data·version=1 이 반환된다.
|
||||
2. Given version=N 인 엔트리, When expected_version=N + 일치 occupancy_seq 로 set, Then commit + version=N+1. When expected_version≠N 으로 set, Then `version_conflict` 로 저장되지 않고 기존 값이 유지된다.
|
||||
3. Given 슬롯의 현재 occupancy_seq=k, When expected_occupancy_seq≠k 로 set, Then `occupancy_changed` 로 저장되지 않는다. Given inactive/미존재 슬롯, When set, Then `slot_inactive` 로 저장되지 않는다.
|
||||
4. Given 크기 상한 초과 `data`, When set, Then `state_too_large` 로 저장 거부된다. Given 유효 UTF-8 + 상한 이내, Then core 가 내용 해석 없이 그대로 저장한다.
|
||||
5. Given 여러 slot_id, When batched 조회, Then 각 slot_id 별 `{strategy_id: {version,data,updated_at}}` 맵으로 그룹되어 반환된다(C-1 조립 입력).
|
||||
6. Given PG 구현과 in-memory 구현, When 동일 시나리오 테스트, Then 두 구현이 동일한 CAS 의미를 보인다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/data-model.md(`slot_strategy_state` 스키마), docs/project-structure.md(저장소 구조 — REQ-082)
|
||||
- Modules: trex_core/adapters/persistence/postgresql.py(PG StrategyStateStore + 마이그레이션 SQL), trex_core/domain/slot/in_memory_repository.py 또는 신규 모듈(in-memory), 신규 포트 정의(예: trex_core/application/ports.py 또는 strategy_state 모듈)
|
||||
- Tests: tests/adapters/persistence/(PG CAS 게이트), tests/(in-memory CAS 6 케이스 — commit/version_conflict/occupancy_changed/slot_inactive/state_too_large/first-create + 멱등)
|
||||
|
||||
## Notes
|
||||
- occupancy_seq 컬럼은 REQ-081(슬롯 점유 가드)과 짝을 이룬다 — 본 REQ 는 저장·CAS, REQ-081 은 슬롯 측 occupancy_seq 부여·bump·close 삭제를 소유한다.
|
||||
- write RPC 계약(요청/응답 shape, reject reason 운반)은 REQ-080 이 소유한다. 본 REQ 는 저장 의미.
|
||||
- 단일 writer 전제(해당 slot·strategy 데몬 1개). CAS 는 재시도/중복·점유전환 안전용이지 다중 writer 동시성 제어가 아니다.
|
||||
- 출처: dcy-028 FR-2, OQ-1(인코딩/상한), OQ-4(별도 테이블+맵+slot_id 키), R-2/R-3.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260615-03
|
||||
- Date: 2026-06-15
|
||||
- Author: Justin Ko
|
||||
- Type: status
|
||||
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-042(release-candidate) verification — `slot_strategy_state` 테이블(마이그 015) + `StrategyStateStore`/`InMemoryStrategyStateStore`/`PgStrategyStateStore` + occupancy_seq·version CAS + opaque UTF-8·size cap. AC-1~6 evidence: `tests/application/test_strategy_state_store.py`(CAS 6 케이스+ABA+batched+delete) + `test_postgresql_repository.py::test_strategy_state_store_pg`(PG 게이트). 479 passed, ruff clean. Blocking Issues 없음.
|
||||
|
||||
### CHG-20260615-02
|
||||
- Date: 2026-06-15
|
||||
- Author: Justin Ko
|
||||
- Type: status
|
||||
- Summary: Proposed → Approved (confirm-req). 필수 필드·구체 AC(6개) 충족, source dcy-028(confirmed, Open OQ 0건, OQ-1/OQ-4 정합) 일치. blocker 없음. REQ-080/081/082 + REQ-073/074 CHG 와 동일 batch 편성 예정.
|
||||
|
||||
### CHG-20260615-01
|
||||
- Date: 2026-06-15
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- dcy-028 FR-2/OQ-1/OQ-4 로부터 최초 생성(Proposed). slot_strategy_state 저장소 + StrategyStateStore 포트 + occupancy_seq·version CAS + opaque UTF-8 data + 2단 size cap.
|
||||
|
||||
#### Intent
|
||||
- 전략 opaque 상태를 슬롯 수명에 묶어 server-side 영속화 — 데몬 재시작/장애에도 상태 보존, orphan-cleanup 제거.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: first-create/version CAS/occupancy CAS/size cap/batched 조회/PG·in-memory 동등 6개 기준
|
||||
- Updated: 없음
|
||||
- Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: data-model.md, project-structure.md(REQ-082)
|
||||
- Modules: postgresql.py, in-memory store, 신규 포트
|
||||
- Tests: PG CAS, in-memory CAS 6 케이스
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches: none (편성 예정)
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: confirm-req 후 batch 편성(REQ-080/081/082 + REQ-073/074 CHG 와 동일 batch)
|
||||
|
||||
#### Validation Plan
|
||||
- in-memory CAS 6 케이스 + PG 게이트 테스트로 저장 의미 검증. batched 조회는 C-1 조립 테스트(REQ-073/074)와 연계.
|
||||
Reference in New Issue
Block a user