Files
trex-core/docs/srs/Data/req-081_slot-occupancy-seq-guard-and-close-delete.md
T
genichinandClaude 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

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 도메인에 monotonic occupancy_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.py INACTIVE 분기, position 필드 clear 와 동일 위치)에서 해당 slot_id 의 모든 strategy_state 를 삭제한다(REQ-079 store). 행 삭제가 아니라 영구 슬롯 →INACTIVE 전이 훅이다(dcy-020 정합).
  • 재사용 슬롯은 새 occupancy_seq + 빈 strategy_state(version 없음)로 시작한다.

Acceptance Criteria

  1. Given Slot 도메인, When 필드 계약 검사, Then occupancy_seq 가 EXPECTED_SLOT_FIELDS 에 포함되고 PG daily_slot 에 컬럼이 존재한다.
  2. Given inactive 슬롯, When inactive→pending_buy 전이, Then occupancy_seq 가 직전보다 증가하고 해당 점유 구간(pending_buy→holding→pending_sell) 동안 동일 값으로 유지된다.
  3. Given holding 슬롯의 strategy_state 존재, When 슬롯이 임의 close 경로로 →INACTIVE, Then 해당 slot_id 의 모든 strategy_state 가 삭제된다(전략 매도/safety-sell/forced-close 모두 커버).
  4. Given close 후 재매수된 슬롯, When 조회, Then 새 occupancy_seq + 빈 strategy_state(version 없음)로 시작한다.
  5. 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_buy bump + →INACTIVE strategy_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)로 검증.