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>
5.8 KiB
5.8 KiB
req-081: 슬롯 occupancy_seq 정합성 가드 + close 시 strategy_state 삭제 불변식
- Status: Implemented
- Type: Data
- Priority: High
- Owner: project maintainers
Intent
- 영구 슬롯이 재사용될 때(점유 전환) 옛 점유가 계산한 strategy_state 가 새 점유에 바인딩되는 ABA 누수를 구조적으로 차단하고, 슬롯 close 시 strategy_state 를 자동 삭제해 데몬 cleanup 책임을 없앤다. occupancy_seq 경량 가드(컬럼 1개)로 full 3계층 분할 없이 정합성 임계부만 선취한다. (dcy-028 FR-2b/FR-3, R-1, issue #26 occupancy race #4705990067)
Requirement
Slot도메인에 monotonicoccupancy_seq:int필드를 추가하고EXPECTED_SLOT_FIELDS계약과 PG 스키마(daily_slot, 레거시 명 — 실제 영구 자산 슬롯)에 마이그레이션으로 반영한다. 기본값 0(또는 점유 없음 표시).- 새 점유 시작 전이(
inactive → pending_buy)에서occupancy_seq를 ++ 한다. 이 값은 한 점유 구간 동안 안정적이고 직전 점유와 달라야 한다(monotonic, 실패한 매수 롤백으로 번호가 건너뛰어도 무방). occupancy_seq를 슬롯 행에 노출해 C-1 read(REQ-073/074)·write CAS(REQ-079/080)가 점유 식별에 사용하게 한다.- 슬롯이 어떤 경로로든 close(
→INACTIVE: 전략 매도 체결/safety-sell/forced-close/operator)되면 단일 전이 지점(service.pyINACTIVE 분기, position 필드 clear 와 동일 위치)에서 해당 slot_id 의 모든 strategy_state 를 삭제한다(REQ-079 store). 행 삭제가 아니라 영구 슬롯→INACTIVE전이 훅이다(dcy-020 정합). - 재사용 슬롯은 새 occupancy_seq + 빈 strategy_state(version 없음)로 시작한다.
Acceptance Criteria
- Given
Slot도메인, When 필드 계약 검사, Thenoccupancy_seq가EXPECTED_SLOT_FIELDS에 포함되고 PG daily_slot 에 컬럼이 존재한다. - Given inactive 슬롯, When
inactive→pending_buy전이, Thenoccupancy_seq가 직전보다 증가하고 해당 점유 구간(pending_buy→holding→pending_sell) 동안 동일 값으로 유지된다. - Given holding 슬롯의 strategy_state 존재, When 슬롯이 임의 close 경로로
→INACTIVE, Then 해당 slot_id 의 모든 strategy_state 가 삭제된다(전략 매도/safety-sell/forced-close 모두 커버). - Given close 후 재매수된 슬롯, When 조회, Then 새 occupancy_seq + 빈 strategy_state(version 없음)로 시작한다.
- Given 점유 전환 ABA 시나리오(옛 점유 기준 occupancy_seq 로 write), When set, Then REQ-080 가
occupancy_changed로 reject 해 stale 상태가 새 점유에 바인딩되지 않는다(R-1 차단).
Impacted Area
- Docs: docs/data-model.md(occupancy_seq 필드), docs/runtime-flows.md(점유 가드·close 삭제 흐름 — REQ-082)
- Modules: trex_core/domain/slot/models.py(
occupancy_seq필드 + EXPECTED_SLOT_FIELDS), trex_core/domain/slot/service.py(inactive→pending_buy bump + →INACTIVE strategy_state 삭제 훅), trex_core/adapters/persistence/postgresql.py(컬럼 + 마이그레이션 SQL), trex_core/application/portfolio.py(slot_to_dict occupancy_seq 노출) - Tests: tests/domain/slot/(occupancy_seq bump·계약 가드), tests/(각 close 경로 후 strategy_state 부재 + ABA reject S-4)
Notes
- 저장·CAS 의미는 REQ-079, write RPC 는 REQ-080 이 소유한다 — 본 REQ 는 슬롯 측 occupancy_seq 부여·bump 와 close 삭제 훅(lifecycle)을 소유한다.
- full 3계층(별도 occupancy 테이블 + strategy_state 를 occupancy_id 키로 전환)은 dcy-028 Out of Scope — 후속 "영구 슬롯 구조 정합" Discovery. 본 REQ 는 컬럼 1개 경량 가드.
- 중장기 영구 슬롯은 점유 회전이 드물어 full 분할이 과하고, intraday(trex-tsl Mode A) 정합성은 본 가드로 충족(dcy-028 OQ-4).
- 출처: dcy-028 FR-2b(C-2b)/FR-3(C-3), R-1.
Change Log
CHG-20260615-03
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-042 verification —
Slot.occupancy_seq(+EXPECTED_SLOT_FIELDS, 마이그 014) +inactive→pending_buybump +→INACTIVEstrategy_state delete 훅(service). AC-1~5 evidence:tests/domain/slot/test_occupancy_seq_and_close_delete.py(bump/안정성/모든 close 경로 삭제/재사용 빈 시작) +test_strategy_state_store.py::TestAbaGuard(S-4 ABA reject) +test_contract(계약 가드). 479 passed, ruff clean. Blocking Issues 없음.
CHG-20260615-02
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Proposed → Approved (confirm-req). 필수 필드·구체 AC(5개) 충족, source dcy-028(FR-2b/FR-3, R-1 완화) 정합. occupancy_seq 경량 가드로 점유 ABA 구조적 차단. blocker 없음.
CHG-20260615-01
- Date: 2026-06-15
- Author: Justin Ko
Change Summary
- dcy-028 FR-2b/FR-3 로부터 최초 생성(Proposed). occupancy_seq 슬롯 필드+bump+노출 + close 시 strategy_state 삭제 불변식.
Intent
- 점유 전환 ABA 누수(R-1) 구조적 차단 + close cleanup 자동화.
Acceptance Criteria Delta
- Added: 필드 계약/bump 안정성/close 삭제 모든 경로/재사용 빈 시작/ABA reject 5개 기준
- Updated: 없음
- Removed: 없음
Impacted Area Delta
- Docs: data-model.md, runtime-flows.md(REQ-082)
- Modules: models.py, service.py, postgresql.py, portfolio.py
- Tests: occupancy_seq bump·계약, close 경로 삭제, ABA reject
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-079/080/082 + REQ-073/074 CHG 동일 batch)
Validation Plan
- occupancy_seq bump·계약 가드 테스트 + 각 close 경로 후 strategy_state 부재 테스트 + ABA reject 테스트(S-4)로 검증.