feat(intents): dcy-011 buy intent portfolio_id 필수 계약 + ledger skip 가시화 (BAT-015)
dcy-011 전 주기 delivery. issue #6(buy 식별자 정정) + issue #11(ledger silent skip) 흡수. 거버넌스: 기존 Implemented REQ는 change-req, 신규 기능만 신규 REQ(OQ-3). - REQ-007 (change-req): buy admission portfolio_id 필수화 + SnapshotStore symbol resolve + unknown_portfolio 거부 (hard cutover, OQ-1/OQ-2) - REQ-021 (change-req): buy 메시지 payload symbol 제거 - REQ-018 (change-req): _record_ledger skip 가시화 (WARN + ledger_skipped 카운터) - REQ-055 (신규): closed↔ledger_outbox anti-join 운영 점검 find_ledger_gap_slots 코드: intents.py(BuyIntent portfolio_id 필수 + resolve_symbol 주입 + _admit_buy reject 분기), messaging_handlers.py, runtime/daemon.py(_resolve_symbol 배선), execution.py(skip WARN 로그), adapters/persistence/ops_checks.py(신규 anti-join). 검증: 단위 282 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 314 passed, ruff clean. BAT-015(standard) release-candidate. srs/index Next ID → REQ-056. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# req-055: closed 슬롯 ↔ ledger_outbox 누락 운영 점검 쿼리
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Exception
|
||||
- Priority: Medium
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
|
||||
portfolio_id 없는 체결의 ledger silent skip(issue #11)으로 발생하는 회계 누락을 운영자가 탐지·집계할 수 있도록, `closed` 슬롯 중 대응 `ledger_outbox` 행이 없는 케이스를 anti-join 으로 식별하는 읽기 전용 운영 점검을 제공한다(dcy-011 FR-5). `daily_slot` 이 durable 하므로 outbox 마커 행 없이도 영구 탐지가 성립한다(dcy-010 OQ-4 위임).
|
||||
|
||||
## Requirement
|
||||
|
||||
- `find_ledger_gap_slots(dsn, *, trading_date=None)` 읽기 전용 함수를 제공한다(`trex_core/adapters/persistence/ops_checks.py`).
|
||||
- gap 정의: `status='closed'` 슬롯 중 `portfolio_id IS NULL` 이거나 `ledger_outbox` 에 `asset_id = slot.portfolio_id` 행이 없는 슬롯.
|
||||
- 결과는 `slot_id`/`trading_date`/`symbol`/`portfolio_id`/`broker_order_id` 를 포함한다. `trading_date` 인자로 일자 범위를 한정할 수 있다(미지정 시 전체).
|
||||
- 스키마 변경 없음(읽기 전용 SELECT). 주기/온디맨드 실행으로 누락을 탐지·집계할 수 있어야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. Given `closed` 슬롯 중 `portfolio_id IS NULL` 인 슬롯, When `find_ledger_gap_slots`, Then 그 슬롯이 결과에 포함된다(S-4).
|
||||
2. Given `closed` 슬롯 중 portfolio_id 는 있으나 대응 outbox 행이 없는 슬롯, When 호출, Then 결과에 포함된다.
|
||||
3. Given `closed` 슬롯 + 대응 `ledger_outbox` 행(asset_id 일치)이 있는 슬롯, When 호출, Then 결과에 포함되지 않는다(정상 케이스 0건).
|
||||
4. Given `holding` 등 비-closed 슬롯, When 호출, Then 결과에서 제외된다(closed 한정).
|
||||
|
||||
## Impacted Area
|
||||
|
||||
- Docs: `docs/runtime-flows.md`(ledger skip 가시화 + 점검 쿼리 참조)
|
||||
- Modules: `trex_core/adapters/persistence/ops_checks.py`(신규, 읽기 전용)
|
||||
- Tests: `tests/adapters/persistence/test_ops_checks.py`(PG 게이트)
|
||||
|
||||
## Notes
|
||||
|
||||
- OQ-4 결정: outbox 마커 행 미도입 → slots↔outbox anti-join 으로 영구 탐지(REQ-019 outbox 스키마 변경 없음).
|
||||
- 알람/주기 실행 연결은 운영 배포 절차로 다룬다(쿼리/함수가 산출물).
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260608-01
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- dcy-011(confirmed) → REQ-055 생성(draft-req, Proposed). issue #11 제안 ③: closed↔outbox 대조 운영 점검(FR-5). 기존 REQ 가 다루지 않는 신규 기능이라 신규 REQ(OQ-3 결정).
|
||||
|
||||
#### Intent
|
||||
|
||||
- ledger 누락 영구 탐지 수단을 운영자에게 제공.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
|
||||
- Added: AC-1~4 전체
|
||||
|
||||
#### Delivery Trace Delta
|
||||
|
||||
- Batches: BAT-015
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
|
||||
- Reverification Needed: no
|
||||
- Status Recommendation: keep-current
|
||||
|
||||
### CHG-20260608-02
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- Proposed → Approved (confirm-req). 필수 필드·구체 AC·dcy-011 FR-5 정합 확인.
|
||||
|
||||
### CHG-20260608-03
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- Approved → Implemented (confirm-req-implemented, 근거 BAT-015 release-candidate). `find_ledger_gap_slots` 구현 + PG 게이트 단위(gap 탐지/정상 0건) green. 전체 인프라 게이트 314 passed.
|
||||
|
||||
#### Delivery Trace Delta
|
||||
|
||||
- Batches: BAT-015 (release-candidate)
|
||||
- Releases: none
|
||||
@@ -149,3 +149,43 @@
|
||||
- AC-3: 위 buy 테스트가 FillStatus.execution_id/fee/tax 운반 직접 검증.
|
||||
- AC-4: tests/application/test_execution_ledger.py::test_portfolio_id_absent_skips_ledger_but_transitions_slot.
|
||||
- AC-5: tests/domain/test_domain_import_sweep.py + grep 결과(trex_core/application/execution.py 단일 enqueue 지점).
|
||||
|
||||
### CHG-20260608-01
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- (change-req, dcy-011/issue #11) `_record_ledger` 의 ledger skip 을 무성에서 **가시화**로 전환: portfolio_id/execution_id 누락 skip 시 WARN 로그 + `ExecutionResult.ledger_skipped` 카운터 노출(슬롯 전이는 그대로). BAT-015 재구현·재검증 완료 → Implemented 유지.
|
||||
|
||||
#### Intent
|
||||
|
||||
- portfolio_id 없는 체결의 ledger silent skip(회계 누락)을 운영자가 탐지 가능하게(issue #11 제안 ②). OQ-4 결정으로 outbox 마커 행은 도입하지 않고 로그+메트릭만; 영구 탐지는 REQ-055 점검 쿼리에 위임.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
|
||||
- Updated:
|
||||
- AC-4: skip 시 무성 반환 → WARN 로그 + 카운터 가시화(두 skip 경로 모두).
|
||||
|
||||
#### Impacted Area Delta
|
||||
|
||||
- Modules: `trex_core/application/execution.py`(`_record_ledger` 로그 + `_log` 추가)
|
||||
- Docs: `docs/runtime-flows.md`
|
||||
- Tests: tests/application/test_execution_ledger.py::test_ledger_skip_emits_warning
|
||||
|
||||
#### Delivery Trace Delta
|
||||
|
||||
- Batches: BAT-015
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
|
||||
- Reverification Needed: yes (BAT-015 에서 완료)
|
||||
- Existing Implementation Invalidated: no (관측만 추가, 전이 동작 불변)
|
||||
- Status Recommendation: Implemented (change-req → BAT-015 재검증)
|
||||
- Follow-up Action: confirm-req-implemented(BAT-015).
|
||||
|
||||
#### Validation Plan
|
||||
|
||||
- BAT-015: ledger skip WARN 로그 단위(caplog) + 회귀.
|
||||
|
||||
@@ -142,3 +142,43 @@
|
||||
- AC-3: tests/application/test_messaging_intent_consumer.py + test_messaging_event_publisher.py 조합.
|
||||
- AC-4: tests/application/test_messaging_event_publisher.py::test_event_for_strategy_a_does_not_reach_strategy_b_queue + tests/adapters/messaging/test_rabbitmq_transport.py::test_event_publish_and_per_strategy_consume.
|
||||
- AC-5: tests/adapters/messaging/test_topology.py.
|
||||
|
||||
### CHG-20260608-01
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- (change-req, dcy-011) buy intent **메시지 계약**에서 `symbol` 필드 제거, `portfolio_id` 필수화. buy 핸들러는 payload 에서 symbol 을 읽지 않고 portfolio_id 만 매핑(서버 resolve 는 REQ-007). BAT-015 재구현·재검증 완료 → Implemented 유지.
|
||||
|
||||
#### Intent
|
||||
|
||||
- 요청 매핑 원칙(payload 식별자)을 정식 식별자(portfolio_id) 기준으로 정정(issue #6). buy 핸들러 payload 파싱 변경.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
|
||||
- Updated:
|
||||
- buy payload 계약: `symbol` 제거, `portfolio_id` 필수.
|
||||
|
||||
#### Impacted Area Delta
|
||||
|
||||
- Modules: `trex_core/application/messaging_handlers.py`(buy 핸들러)
|
||||
- Docs: `docs/interface-contract.md`
|
||||
- Tests: tests/application/test_messaging_intent_consumer.py + tests/adapters/messaging/test_rabbitmq_intent_e2e.py
|
||||
|
||||
#### Delivery Trace Delta
|
||||
|
||||
- Batches: BAT-015
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
|
||||
- Reverification Needed: yes (BAT-015 에서 완료)
|
||||
- Existing Implementation Invalidated: yes (symbol 기반 buy payload)
|
||||
- Status Recommendation: Implemented (change-req → BAT-015 재검증)
|
||||
- Follow-up Action: confirm-req-implemented(BAT-015).
|
||||
|
||||
#### Validation Plan
|
||||
|
||||
- BAT-015: buy payload portfolio_id 기반 핸들러 단위 + RabbitMQ e2e.
|
||||
|
||||
@@ -153,3 +153,45 @@
|
||||
|
||||
#### Validation Plan
|
||||
- BAT-002 verification evidence 재참조로 충분.
|
||||
|
||||
### CHG-20260608-01
|
||||
|
||||
- Date: 2026-06-08
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
|
||||
- (change-req, dcy-011) buy intent admission 계약 변경: `portfolio_id` 필수화 + admission 시 universe(`SnapshotStore`) 에서 `symbol` resolve + universe 부재 시 `unknown_portfolio` 거부. 기존 symbol-필수/portfolio_id-optional 폐기(hard cutover, 하위호환 없음). BAT-015 에서 재구현·재검증 완료 → Implemented 유지.
|
||||
|
||||
#### Intent
|
||||
|
||||
- 정식 식별자(asset_id=portfolio_id) 기반 원장 귀속·safety 보호 범위 정합(issue #6). `_admit_buy` 에 portfolio_id_required/unknown_portfolio reject + symbol resolve(`resolve_symbol` 주입) 추가.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
|
||||
- Added:
|
||||
- buy 는 portfolio_id 필수(누락 시 `portfolio_id_required`), symbol 은 서버 resolve(`SnapshotStore`), universe 부재 시 `unknown_portfolio` 거부.
|
||||
- Updated:
|
||||
- 기존 admission AC 의 symbol 입력 전제 → portfolio_id 기반으로 정정.
|
||||
|
||||
#### Impacted Area Delta
|
||||
|
||||
- Modules: `trex_core/application/intents.py`(BuyIntent portfolio_id 필수+symbol resolve, IntentService.resolve_symbol), `messaging_handlers.py`(buy payload), `runtime/daemon.py`(resolver 배선)
|
||||
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
|
||||
- Tests: intent/messaging buy 테스트 portfolio_id 기반 전환
|
||||
|
||||
#### Delivery Trace Delta
|
||||
|
||||
- Batches: BAT-015
|
||||
- Releases: none
|
||||
|
||||
#### Revalidation Impact
|
||||
|
||||
- Reverification Needed: yes (BAT-015 에서 완료)
|
||||
- Existing Implementation Invalidated: yes (symbol-필수 admission 경로)
|
||||
- Status Recommendation: Implemented (change-req → BAT-015 재구현·재검증)
|
||||
- Follow-up Action: confirm-req-implemented(BAT-015) 로 Implemented 동기화.
|
||||
|
||||
#### Validation Plan
|
||||
|
||||
- BAT-015 verification: portfolio_id_required/unknown_portfolio/symbol resolve 단위 + 전체 회귀(314 passed).
|
||||
|
||||
+3
-2
@@ -74,7 +74,7 @@
|
||||
|
||||
## Next Requirement ID
|
||||
|
||||
- Current: `REQ-055`
|
||||
- Current: `REQ-056`
|
||||
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
|
||||
|
||||
## Requirement Register
|
||||
@@ -135,11 +135,12 @@
|
||||
| REQ-052 | safety-sell per-slot 재시도 쿨다운 + 영속 거부 경고 | Integration | Implemented | High | project maintainers | [req-052](./Integration/req-052_safety-sell-per-slot-cooldown.md) |
|
||||
| REQ-053 | safety-sell 재시도 쿨다운 env 설정 2종 | Configuration | Implemented | Medium | project maintainers | [req-053](./Configuration/req-053_safety-sell-retry-cooldown-env.md) |
|
||||
| REQ-054 | safety-sell 쿨다운 runtime-flows 정합 | Documentation | Implemented | Low | project maintainers | [req-054](./Documentation/req-054_safety-sell-cooldown-baseline-alignment.md) |
|
||||
| REQ-055 | closed 슬롯 ↔ ledger_outbox 누락 운영 점검 쿼리 | Exception | Implemented | Medium | project maintainers | [req-055](./Exception/req-055_ledger-gap-ops-check.md) |
|
||||
|
||||
## Recent Change Log Summary
|
||||
|
||||
- 2026-06-08 :: REQ-007/018/021 change-req + REQ-055 생성·Implemented (dcy-011, BAT-015): buy intent 계약 hard cutover — portfolio_id 필수화 + symbol 서버 resolve(SnapshotStore) + unknown_portfolio/portfolio_id_required 거부(REQ-007), buy payload symbol 제거(REQ-021), ledger skip 가시화(WARN+ledger_skipped 카운터, REQ-018), closed↔outbox anti-join 운영 점검 `find_ledger_gap_slots` 신규(REQ-055). 전체 인프라 게이트 314 passed, ruff clean. (change-req/draft-req/confirm-req-implemented)
|
||||
- 2026-06-08 :: REQ-052~054 Approved → Implemented (confirm-req-implemented): BAT-014(batch-lite) verify 완료(신규 8 단위, 전체 278 passed, ruff clean). SafetySellService per-slot 쿨다운(skip/만료재시도/경고/prune, market_close 제외), SafetySellConfig env 2종(min_retry_interval_sec 600/max_retry_warn_count 3), runtime-flows 정합. (confirm-req-implemented)
|
||||
- 2026-06-08 :: REQ-052~054 Proposed → Approved (confirm-req): dcy-010 safety-sell 쿨다운 3개 전원 승인 게이트 통과. dcy-010(confirmed) FR/OQ 와 모순 없음, 필수 필드·구체 AC 완비. 피드백 채널·DB 영속은 Out of Scope 비핵심. (confirm-req)
|
||||
- 2026-06-08 :: REQ-052~054 생성 (draft-req): dcy-010(safety-sell 영속 거부 재시도 백오프, confirmed) → 3개 REQ 초안. per-slot 쿨다운+경고(052), 쿨다운 env 2종(053), runtime-flows 정합(054). OQ-1(600s)/OQ-2(3회 경고)/OQ-3(단일 per-slot) Answered. (draft-req)
|
||||
- 2026-06-07 :: REQ-048~051 Approved → Implemented (confirm-req-implemented): BAT-013 verify 완료(신규 9 단위 + RabbitMQ 라우팅 2, 단위 271 passed, 인프라 게이트 301 passed(directed 격리 S-2 + broadcast dual S-3 + default 무회귀 S-4), ruff clean). per-instance TOML 로더+`--config`, instance_key 동적 큐명(default 리터럴 하위호환), trex.direct/trex.broadcast exchange+바인딩, baseline 3문서 정합. (confirm-req-implemented)
|
||||
- 2026-06-07 :: REQ-048~051 Proposed → Approved (confirm-req): dcy-009 multi-instance 4개 전원 승인 게이트 통과. dcy-009(confirmed) FR/OQ 와 모순 없음, 필수 필드·구체 AC 완비. strategy publish 변경·TOML 추가필드는 비핵심 후속. (confirm-req)
|
||||
|
||||
Reference in New Issue
Block a user