Add ProofLine criteria documentation and Strategy Catalog v1 implementation

- Add acceptance criteria documentation (AC-0013 through AC-0023)
- Add Line-0003 discovery documentation
- Implement Strategy Catalog v1 with new database migration
- Update portfolio API endpoints and schemas
- Refactor strategy and portfolio services
- Add strategy management CLI commands
- Update domain models with strategy catalog support
- Add comprehensive tests for v1 strategies
- Update design documentation (data model, interfaces, runtime flows)
This commit is contained in:
2026-08-15 11:18:31 +09:00
parent 5fc389dea8
commit 6e02d92282
48 changed files with 2114 additions and 393 deletions
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0013"
status: active
---
# active 전략 일반 조회 계약
## Criterion
일반 사용자와 admin은 `/v1/strategies`의 목록·상세 조회에서 active 전략만 받을 수 있어야 하며, inactive 전략은 목록에서 제외하고 상세에서 전략 본문 대신 `409`를 반환하고 미존재 전략은 `404`를 반환해야 한다.
## Verification
- 성공 조건: active 전략은 목록과 상세에서 안정적인 ID, 이름, config, status와 revision을 반환한다.
- 실패·경계 조건: inactive 전략은 목록에서 제외되고 일반 상세 조회는 전략 본문 대신 `409`를 반환하며, 미존재 ID는 `404`다.
- 검사 방법: 일반·admin token의 목록/상세 API 회귀 테스트로 active/inactive/missing을 각각 검사한다.
- 현재 구현 평가: working tree의 `app/api/v1_strategies.py`와 `tests/test_v1_strategies.py`가 이 계약을 실행 가능하게 검증하며 scoped 재실행에 포함되어 PASS했다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0014"
status: active
---
# 관리자 전략 카탈로그 권한과 관리 계약
## Criterion
admin은 `/v1/admin/strategies`에서 active·inactive 전체 전략을 조회하고 생성·수정·상태 변경·미참조 삭제할 수 있어야 하며, 비-admin 사용자의 모든 관리 mutation은 `403`이어야 한다.
## Verification
- 성공 조건: admin CRUD와 상태 변경이 영속화되고 관리 조회가 active·inactive를 모두 반환한다.
- 실패·경계 조건: 일반 사용자 또는 권한 부족 token의 create/update/delete는 변경 없이 `403`이다.
- 검사 방법: 역할별 token으로 admin 목록·생성·PATCH·DELETE와 비-admin 거부를 API 테스트로 검사한다.
- 현재 구현 평가: working tree의 모든 admin route가 공통 `require_admin` dependency를 사용하고 admin CRUD tests 및 비-admin 관리 GET `403` test가 scoped 재실행에서 PASS했다. 비-admin POST/PATCH/DELETE 각각의 독립 negative test는 현재 없어 mutation별 executable coverage는 `PARTIAL`이다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0015"
status: active
---
# 공유 전략 identity와 revision 계약
## Criterion
admin PATCH는 기존 전략 row의 ID를 유지하면서 요청된 `name`·`config`·`status`의 실질적 변경을 원자적으로 반영하고 revision을 증가시켜야 하며, 모든 참조 포트폴리오의 이후 portfolio-hub API 조회는 commit된 최신 설정과 revision을 반환해야 한다.
## Verification
- 성공 조건: 실질적 PATCH 뒤 ID는 동일하고 revision은 단조 증가하며 derived `nick`과 name/config가 같은 committed state에서 계산되고 참조 포트폴리오 조회에 최신 값이 나타난다.
- 실패·경계 조건: no-op PATCH는 revision을 올리지 않고, 동시 partial PATCH도 서로의 최신 필드를 잃거나 불일치한 `nick`을 만들지 않는다.
- 검사 방법: API/repository 회귀와 실제 PostgreSQL 동시 partial PATCH 시험으로 ID, revision, name/config/nick 및 포트폴리오 응답을 검사한다.
- 현재 구현 평가: `FOR UPDATE` 기반 update와 revision 응답 테스트가 존재하며, 2026-08-15 실제 PostgreSQL integration 재실행 `4 passed`에 동시 partial PATCH 검증이 포함됐다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0016"
status: active
---
# 전략 상태와 포트폴리오 선택 계약
## Criterion
신규 포트폴리오 생성·수정은 전역 카탈로그의 기존 active `strategy_id`만 선택할 수 있어야 하며, 전략을 inactive로 전환해도 기존 포트폴리오 참조는 보존되고 신규 선택만 차단되어야 한다.
## Verification
- 성공 조건: active ID 선택은 저장되고 inactive 전환 전의 기존 참조는 조회와 저장에서 유지된다.
- 실패·경계 조건: inactive ID 신규 선택은 `409`, 미존재 ID는 `404`이며 legacy `avabile_strategies`만으로 선택 권한을 얻지 못한다.
- 검사 방법: create/update 및 inactive 전환 전후 포트폴리오 회귀 테스트와 선택·상태 변경 경합 테스트로 확인한다.
- 현재 구현 평가: portfolio service/repository와 API 회귀가 scoped 재실행에서 PASS했고, 2026-08-15 실제 PostgreSQL integration `4 passed`에 선택-vs-delete 경합 검증이 포함됐다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0017"
status: active
---
# 포트폴리오 ID-only 요청과 응답 호환성 계약
## Criterion
`/v1/portfolios`와 legacy `/portfolios`의 생성에는 active `strategy_id`가 필수이고 수정도 ID-only여야 하며, 요청의 `strategy_name`·`strategy_params`는 `422`로 거부하는 동시에 응답의 `active_strategy_id`·`strategy_name`·`strategy_params`·`strategy_revision`은 유지되어야 한다.
## Verification
- 성공 조건: 명시한 active ID로만 포트폴리오가 생성·수정되고 응답에 현재 전략 identity·이름·config·revision이 나타난다.
- 실패·경계 조건: strategy ID 누락, 제거 필드 전달 또는 malformed 요청은 새 전략 row를 만들지 않고 `422`다.
- 검사 방법: v1·legacy create/update schema와 저장소 row count, 응답 호환 필드를 API/CLI 회귀로 검사한다.
- 현재 구현 평가: schemas와 양쪽 portfolio API가 ID-only 입력 및 `extra="forbid"` 계약을 구현하고 scoped portfolio/CLI 회귀는 PASS했다. 다만 제거된 `strategy_name`·`strategy_params` 각각의 `422`와 응답 호환 필드 전체를 직접 단언하는 전용 negative/response test는 현재 없어 해당 executable coverage는 `PARTIAL`이다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0018"
status: active
---
# 전략 API 오류 분류 계약
## Criterion
전략 조회·선택·관리 API는 미존재 `404`, inactive 신규 선택과 참조 중 삭제 `409`, 제거 필드·malformed 입력 `422`, 권한 부족 `403`을 서로 구분해 반환해야 한다.
## Verification
- 성공 조건: 각 오류 조건이 승인된 상태 코드와 안정적인 비민감 오류 응답으로 구분된다.
- 실패·경계 조건: 권한 부족을 `404`로, inactive를 `422`로, malformed 입력을 묵시적으로 무시하는 등 오류 클래스가 합쳐지지 않는다.
- 검사 방법: 조건별 독립 API negative test로 status code와 무변경을 검사한다.
- 현재 구현 평가: `tests/test_v1_strategies.py`와 `tests/test_v1_portfolios_crud.py`의 negative matrix가 scoped 재실행에서 PASS했다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0019"
status: active
---
# 참조 안전 전략 삭제 계약
## Criterion
전략 hard delete는 어떤 포트폴리오의 현재 `active_strategy_id` 또는 현재 선택 참조에도 없는 경우에만 허용되어야 하며, 참조 중이면 자동 이전·참조 삭제 없이 `409`를 반환해야 한다.
## Verification
- 성공 조건: 미참조 전략은 admin이 삭제할 수 있고 삭제 후 조회되지 않는다.
- 실패·경계 조건: 어떤 지원 참조 표현이라도 전략을 가리키면 `409`이며 포트폴리오 참조는 그대로다; 동시 신규 선택과 삭제에서도 orphan이 생기지 않는다.
- 검사 방법: 두 참조 형태별 삭제, retirement 대안, 선택-vs-delete 실제 PostgreSQL 경합을 검사한다.
- 현재 구현 평가: `FOR UPDATE`와 참조 검사·삭제의 단일 transaction 및 회귀 테스트가 있으며, 2026-08-15 실제 PostgreSQL integration `4 passed`에서 선택-vs-delete orphan 방지를 재검증했다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0020"
status: active
---
# v1 전략 API 전환과 운영자 CLI 무결성 계약
## Criterion
전략 HTTP API는 `/v1/strategies`와 `/v1/admin/strategies`만 제공하고 비버전 `/strategy-sets` alias를 제공하지 않아야 하며, 신뢰된 운영자 CLI도 상태·revision·참조 삭제 무결성을 우회해서는 안 된다.
## Verification
- 성공 조건: OpenAPI/router inventory에 새 v1 경로가 있고 CLI 관리 결과가 HTTP와 같은 row identity·status·revision·delete guard를 따른다.
- 실패·경계 조건: `/strategy-sets` 요청은 기존 CRUD로 동작하지 않고, CLI가 참조 중 삭제나 잘못된 상태 전이를 강행하지 않는다.
- 검사 방법: route inventory, legacy path negative test, CLI create/list/update/delete 회귀와 문서 경로 sweep을 수행한다.
- 현재 구현 평가: legacy router 제거, v1 router 등록 및 CLI tests가 존재하며 scoped 재실행에서 PASS했다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0021"
status: active
---
# 기본 전략 migration 멱등 계약
## Criterion
Alembic data migration은 active `name="target_value"`, `config={}` 전략을 중복 없이 보장하고, 동일 `(name, config)` row가 있으면 재사용해야 하며 포트폴리오 요청의 `strategy_id` 필수 조건을 완화하지 않아야 한다.
## Verification
- 성공 조건: 빈 DB upgrade 후 기본 전략 한 건이 active, revision 1과 runtime 일치 derived identity로 존재한다.
- 실패·경계 조건: migration 재실행이나 기존 동일 row가 중복 row를 만들지 않고, 기본 전략 존재가 implicit portfolio selection을 허용하지 않는다.
- 검사 방법: migration unit/idempotency test와 신규 PostgreSQL DB full upgrade/head 재실행, portfolio create negative test를 수행한다.
- 현재 구현 평가: migration unit test가 scoped 재실행에서 PASS했고, 2026-08-15 실제 PostgreSQL integration `4 passed`에서 신규 DB full upgrade와 head 재실행을 재검증했다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0022"
status: active
---
# downstream 슬롯 적용 시점 경계
## Criterion
portfolio-hub에 commit된 전략 변경은 이후 portfolio-hub API 조회에 즉시 보이되 실행 중 trex-core 슬롯·기존 주문·완료 거래에 소급 적용되지 않아야 하며, trex-core는 다음 슬롯 재생성 또는 정기 갱신에서 최신 revision을 가져와 이후 동작에 적용해야 한다.
## Verification
- 성공 조건: portfolio-hub 조회는 최신 revision을 제공하고 portfolio-hub가 daemon reload/restart 또는 config push를 발생시키지 않으며, trex-core의 다음 refresh가 최신 revision을 선택한다.
- 실패·경계 조건: PATCH가 실행 중 슬롯을 강제 변경하거나 기존 주문·완료 거래를 재해석하지 않고, 정확한 일일 scheduler 시각은 이 Line이 정하지 않는다.
- 검사 방법: portfolio-hub API/runtime-flow 문서와 outbound side-effect 부재를 검사하고, 별도 trex-core integration에서 refresh 전/후 revision 적용을 검증한다.
- 현재 구현 평가: portfolio-hub 측 최신 revision 노출과 강제 push/reload 부재는 working tree에 반영되어 있다. trex-core refresh end-to-end 검증은 이 저장소에 executable seam이 없어 현재 `UNVERIFIED`이며, `active` 상태를 satisfaction으로 해석하지 않는다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0023"
status: active
---
# 동시성 및 stale persistence 무결성 계약
## Criterion
전략 PATCH, 포트폴리오 전략 선택, 전략 상태 변경·삭제와 거래 저장이 경합해도 최신 전략 참조와 revision은 직렬화 가능하게 보존되고, stale portfolio snapshot은 현재 전략 선택을 되살리거나 덮어쓰지 않으며 portfolio mutation과 ledger 기록은 원자적이어야 한다.
## Verification
- 성공 조건: 동시 partial PATCH는 모든 변경과 단조 revision을 보존하고, A snapshot 후 B 선택·A 삭제·stale 거래 저장에서도 B 참조와 A 삭제가 유지되며 portfolio UPDATE와 ledger INSERT가 함께 commit된다.
- 실패·경계 조건: stale write가 삭제된 A를 복원하거나 B를 잃지 않고, transaction 실패 시 portfolio와 ledger가 부분 commit되지 않는다.
- 검사 방법: 실제 PostgreSQL에서 동시 PATCH, select-vs-inactivate/delete, stale BUY/SELL snapshot과 transaction rollback 시나리오를 실행한다.
- 현재 구현 평가: repository transaction/row-lock 경계와 integration tests가 존재하며, 2026-08-15 실제 PostgreSQL integration 재실행 `4 passed`에서 동시 PATCH, 선택-vs-delete, stale BUY snapshot과 migration 시나리오를 확인했다. 독립 source-time QC도 PASS를 기록한다. 다만 portfolio UPDATE 성공 후 ledger INSERT 실패를 의도적으로 주입해 rollback을 관찰하는 fault-injection test는 현재 없어 그 세부 검증은 `PARTIAL`이다.