docs: formalize issue 60 proofline specification

This commit is contained in:
Hermes Agent
2026-08-19 13:05:02 +09:00
parent 359ea098ff
commit 4975d7166f
11 changed files with 317 additions and 2 deletions
+16
View File
@@ -0,0 +1,16 @@
---
id: "ac-0015"
status: active
---
# 명시적 sell 미수락·미체결 상태 수렴
## Criterion
KIS submission 또는 authoritative order lookup이 sell 주문의 미수락·미체결을 명시적으로 확인하면 core는 실패 evidence를 기록하고 해당 dispatch를 정리하며 새 broker attempt를 생성하지 않고 slot을 broker-authoritative 보유수량의 `holding`으로 수렴시켜야 한다. 이 경로는 로컬 추정수량으로 보유량을 변경하거나 strategy에 broker retry 판단을 요구해서는 안 된다.
## Verification
- 성공 조건: `pending_sell`에서 명시적 rejection 또는 lookup-confirmed absence가 발생하면 기존 보유수량을 유지한 `holding`으로 전이하고 dispatch metadata가 정리되며 broker submit 호출은 한 번뿐이다.
- 실패·경계 조건: 체결 가능성이 남은 unknown outcome을 rejection으로 취급하거나, 수량을 0으로 만들거나, 자동 새 주문을 제출하거나, broker-authoritative 수량과 다른 값으로 수렴하면 FAIL이다.
- 검사 방법: `tests/application/test_execution_policy.py`, `tests/application/test_order_timeout_reconciliation.py`와 관련 repository transition tests에서 상태·수량·dispatch·broker call count를 단언하고 전체 회귀를 실행한다.
+16
View File
@@ -0,0 +1,16 @@
---
id: "ac-0016"
status: active
---
# 결과 불명확 submission의 중복 제출 방지와 reconciliation
## Criterion
주문 submission timeout, 연결 단절, 응답 누락 또는 응답 해석 실패로 broker acceptance 여부가 불명확하면 core는 original dispatch identity와 결과 불명확 sentinel을 durable하게 보존하고 새 broker order를 제출하지 않아야 한다. daemon 재시작과 반복 tick에서도 original order date·client identity를 사용한 broker lookup과 reconciliation을 먼저 수행하고 authoritative terminal evidence가 생기기 전에는 slot을 재사용 가능한 상태로 전환하지 않아야 한다.
## Verification
- 성공 조건: submit 결과 불명확 후 동일 slot의 반복 tick과 restart 모사에서 broker submit call count가 증가하지 않고 lookup/reconciliation이 실행되며 durable dispatch metadata가 유지된다.
- 실패·경계 조건: timeout 자체로 terminal reject·holding·inactive를 추론하거나, sentinel을 지우거나, 새 broker attempt를 만들거나, 현재 날짜·wall-clock 값으로 original order identity를 대체하면 FAIL이다.
- 검사 방법: `tests/application/test_order_timeout_reconciliation.py`의 timeout, restart, order visibility와 lookup fixture에서 call ordering·dispatch persistence·상태를 검증한다.
+16
View File
@@ -0,0 +1,16 @@
---
id: "ac-0017"
status: active
---
# strategy·TVR과 broker failure ownership 분리
## Criterion
KIS failure, raw broker error, broker attempt identity, retryability, retry schedule과 retry budget은 `trex-core` 내부 execution/reconciliation 경계를 벗어나 strategy 또는 TVR wire에 노출되어서는 안 된다. core도 broker failure를 retryable/non-retryable로 분류하여 자동 새 주문 attempt를 생성해서는 안 되며 strategy/TVR은 core가 수렴한 slot snapshot만 소비해야 한다. 이후 strategy가 독립적으로 생성한 별도 intent는 core의 자동 retry와 구분한다.
## Verification
- 성공 조건: sell response와 strategy-facing schema에 retryability·KIS error·attempt field가 없고 explicit reject 및 unknown outcome에서 자동 resubmit이 발생하지 않는다.
- 실패·경계 조건: raw KIS payload나 retryable boolean이 strategy/TVR wire에 나타나거나, core가 retry schedule·budget을 산출하거나, 동일 intent에서 새 broker attempt를 자동 생성하면 FAIL이다.
- 검사 방법: `tests/application/test_sell_retryable_flag.py`, messaging handler tests, execution rejection·unknown tests와 schema/document contract 검색을 실행한다.
+16
View File
@@ -0,0 +1,16 @@
---
id: "ac-0018"
status: active
---
# 주문 venue 기본값·명시값 보존과 AUTO 제거
## Criterion
intent venue가 누락되거나 null이면 core는 original order venue를 `SOR`로 정규화해야 하고 explicit `KRX`, `NXT`, `SOR`는 submit·ack·slot·restart·cancel 전 과정에서 변경 없이 보존해야 한다. `AUTO`는 admission, broker request와 persistence에서 거부해야 하며 기존 persisted AUTO는 migration으로 SOR로 전환해야 한다. core는 wall-clock time이나 session 추정으로 order venue를 KRX/NXT로 재라우팅해서는 안 된다.
## Verification
- 성공 조건: 누락/null→SOR, explicit KRX/NXT/SOR identity 보존, SOR 부분체결 후 잔량 cancel과 restart가 original SOR를 사용하는 흐름이 통과한다.
- 실패·경계 조건: AUTO acceptance·저장, 시간 기반 venue 변환, ack actual venue로 slot order venue 덮어쓰기 또는 restart/cancel에서 original venue 손실은 FAIL이다.
- 검사 방법: `tests/adapters/broker/test_venue.py`, `tests/application/test_venue_intent_flow.py`, migration/drift tests와 KIS request capture를 실행하여 wire·slot·SQL constraint를 단언한다.
+16
View File
@@ -0,0 +1,16 @@
---
id: "ac-0019"
status: active
---
# 원주문 venue와 실제 체결 venue의 durable 분리
## Criterion
core는 original `order_venue`와 broker-authoritative actual `execution_venue`를 서로 다른 의미로 보존해야 한다. `order_venue`는 KRX/NXT/SOR이며 submit, ack, slot, restart와 cancel에 사용한다. actual venue는 KRX/NXT 또는 미확정 NULL이며 KIS의 검증된 `ORD_EXG_GB`와 명시 exchange-id allowlist에서만 결정하여 fill, ledger와 outbox에 기록한다. `SOR`, 누락, 미지원 코드 또는 wall-clock time으로 actual venue를 추론해서는 안 된다. historical outbox SOR는 `order_venue=SOR`, actual NULL로 변환하고 migration replay는 신규 정상 조합을 오염시키지 않아야 한다.
## Verification
- 성공 조건: SOR order의 actual KRX/NXT fill이 `(order_venue=SOR, venue=KRX|NXT)`로 기록되고 cancel/restart는 SOR를 유지한다. historical SOR는 `(SOR,NULL)`이며 정상 `(order=KRX, actual=NXT)`는 migration 반복 후 보존된다.
- 실패·경계 조건: actual SOR 저장, unknown code를 KRX/NXT로 추론, actual venue로 slot order venue 덮어쓰기, NULL actual SOR fill의 거짓 ledger 기록, AUTO·NULL order 저장 또는 migration replay 오염은 FAIL이다.
- 검사 방법: KIS parser tests, execution ledger tests, `tests/adapters/persistence/test_postgresql_ledger_outbox.py`, `tests/adapters/persistence/test_migration_and_drift.py`를 실행한다. 실제 PostgreSQL에서 historical conversion, replay, round-trip과 check violation을 검증하고 전체 회귀·Ruff 및 독립 read-only QC를 수행한다.
+2 -2
View File
@@ -1,5 +1,5 @@
{
"schema_version": 1,
"next_line_number": 5,
"next_ac_number": 15
"next_line_number": 6,
"next_ac_number": 20
}
+67
View File
@@ -0,0 +1,67 @@
---
id: "dcy-0005"
status: confirmed
---
# broker 실행 실패의 기록·상태 수렴 경계
## Problem
`trex-core`의 broker execution 경계는 명시적인 주문 거부, timeout·연결 단절·응답 누락처럼 결과가 불명확한 submission, 취소·부분체결·재시작을 서로 다른 authority로 처리해야 한다. 기존 계약이 이 경계를 충분히 명시하지 않으면 core가 broker failure를 retryability로 분류하거나 새 주문 attempt를 자동 생성하여 중복 주문을 만들 수 있고, strategy/TVR이 KIS 실패와 broker retry 판단을 소유하는 잘못된 결합이 생길 수 있다.
주문 venue도 같은 execution lifecycle에서 의미가 혼재될 위험이 있었다. 누락 venue의 기본값, 명시 `KRX`/`NXT`/`SOR`, 폐기된 `AUTO`, 원주문 routing venue와 실제 KRX/NXT 체결 venue를 구분하지 않으면 wall-clock routing, 취소 시 원주문 venue 손실, ledger/outbox에 실제 거래소 대신 `SOR` 기록, 기존 persisted `AUTO` 및 historical `SOR` row의 잘못된 해석이 발생할 수 있다.
기대 상태는 core가 broker-authoritative evidence로 상태를 수렴하되 자동 새 주문을 만들지 않고, strategy/TVR에는 core slot snapshot만 노출하며, 원주문 venue와 실제 체결 venue를 각각 durable하게 보존하는 것이다.
## Evidence
- 원본 승인 문서: GitHub issue #60 `https://github.com/fourblocks2020/trex-core/issues/60`의 승인된 본문은 명시적 sell rejection, unknown outcome reconciliation, TVR wire 경계, SOR 기본값, AUTO 제거와 자동 retry 금지를 정의한다.
- 연계 승인 계약: GitHub issue #61은 venue admission부터 broker request/ack/cancel과 ledger/outbox까지 explicit venue 보존 경계를 정의한다.
- 구현 진행 원본: issue #60 comment `https://github.com/fourblocks2020/trex-core/issues/60#issuecomment-5336722059`은 기준 revision, 계획, 구현·검증 진행, 두 차례의 독립 QC blocker와 교정 기록을 포함한다.
- 구현 완료 원본: issue #60 comment `https://github.com/fourblocks2020/trex-core/issues/60#issuecomment-5337338182`은 구현 내용, 검증 결과, 로컬 commit 및 push·PR·배포·릴리스·실주문 경계를 기록한다.
- 구현 revision은 `15aeae6930f8c3e6ef9cf659f41278b099a78459`, `7366cadf03fc6002bfd01ecf0cba7c24486bb618`, `359ea098ff717e7f04cf4206dcbc64ad17b47755`이며 현재 local `main` HEAD는 `359ea098ff717e7f04cf4206dcbc64ad17b47755`다.
- `trex_core/application/execution.py`는 명시적 sell 미수락·미체결의 `pending_sell → holding`, 결과 불명확 submission의 durable dispatch sentinel·lookup/reconciliation, fill의 actual venue 확인과 ledger enqueue 경계를 구현한다.
- `trex_core/application/broker_port.py`는 original submission/routing venue를 가진 `OrderAck`와 nullable broker-authoritative `FillStatus.execution_venue`를 분리한다.
- `trex_core/adapters/broker/kis.py`는 주문 요청의 `KRX`/`NXT`/`SOR`를 보존하고 `ORD_EXG_GB` 및 명시 exchange-id allowlist로 실제 KRX/NXT만 파싱하며 `SOR` 단독·unknown을 추론하지 않는다.
- `trex_core/adapters/persistence/sql/023_remove_auto_order_venue.sql`은 persisted `AUTO → SOR` 변환과 이후 AUTO 저장 차단을 수행한다.
- `trex_core/adapters/persistence/sql/024_add_ledger_order_venue.sql`은 original `order_venue`와 nullable actual `venue`를 분리하고 historical SOR actual을 NULL로 보존하며 replay-safe NULL-only backfill과 DB constraint를 적용한다.
- `trex_core/adapters/persistence/postgresql.py`와 `trex_core/application/ledger_port.py`는 outbox에서 `order_venue`와 actual `venue`를 독립적으로 저장·복원한다.
- 구현자 검증은 focused unit `77 passed`, 전체 `1074 passed, 52 skipped`, disposable PostgreSQL 16 `24 passed`, Ruff `All checks passed!`였다.
- 최종 독립 read-only QC는 `359ea098ff717e7f04cf4206dcbc64ad17b47755`에서 blocker/critical/major/minor finding 없이 PASS했다. 실제 PostgreSQL 16에서 historical SOR→`order_venue=SOR`+actual NULL, 정상 actual NXT/order KRX의 replay 보존, actual SOR·AUTO·NULL order 거부를 확인했고 worktree는 clean이었다.
- 현재 `proofline validate`는 exit 0이다.
## Scope
- AC admission은 기존 active AC-0011의 timeout/cancel reconciliation 및 AC-0013의 terminal cancel·partial fill 상태 수렴과 인접하지만, 명시적 submission rejection, strategy wire ownership, venue admission/migration 및 order/execution venue 분리를 독립적으로 검증 가능한 장기 계약으로 추가하는 `create`다. 기존 AC의 의미나 status는 변경하지 않는다.
- KIS 조회로 sell 주문의 미수락·미체결이 명시적으로 확인되면 새 broker attempt 없이 실패 evidence를 기록하고 dispatch를 정리하며 broker-authoritative 보유수량으로 `pending_sell → holding` 전이한다.
- timeout, 연결 단절, 응답 누락 등 submission 결과가 불명확하면 durable sentinel을 유지하고 새 주문을 생성하지 않으며 broker lookup과 reconciliation을 먼저 수행한다.
- core는 broker failure의 retryability, retry schedule, retry budget을 판정하거나 자동 새 broker attempt를 생성하지 않는다. 이후 strategy가 독립적으로 생성한 새 intent는 이 자동 retry 금지와 구분한다.
- strategy/TVR에는 KIS failure, raw broker error, broker attempt, retryability를 노출하지 않는다. strategy/TVR은 core가 수렴한 slot snapshot만 소비한다.
- intent venue 누락은 `SOR`로 정규화하고 명시 `KRX`/`NXT`/`SOR`는 보존한다. `AUTO`는 admission과 persistence에서 거부하고 기존 persisted AUTO는 SOR로 전환하며 wall-clock venue routing을 수행하지 않는다.
- original `order_venue` KRX/NXT/SOR는 submit/ack/slot/restart/cancel에 보존한다. broker-authoritative actual `execution_venue`는 KRX/NXT 또는 미확정 NULL로 별도 취급하고 fill·ledger/outbox에 기록한다.
- KIS actual venue는 검증된 `ORD_EXG_GB`와 명시 exchange-id allowlist에서만 KRX/NXT로 변환한다. `SOR` 단독, 누락 또는 미지원 값은 KRX/NXT로 추론하지 않는다.
- historical outbox의 SOR는 original order venue로 보존하고 actual venue는 NULL로 전환한다. migration 재실행은 신규 정상 order/execution venue 조합을 오염시키지 않아야 하며 DB는 actual SOR와 invalid order venue를 거부한다.
- 관련 focused·전체 회귀, PostgreSQL migration·round-trip, lint와 독립 QC evidence를 구현 상태 평가에 포함한다.
## Out of Scope
- strategy/TVR의 KIS failure 수신, retryability 판단, broker attempt 관리 또는 자동 retry 기능
- TVR 세션·portfolio `markets` 판단 구현과 KRX/NXT session policy 자체
- 실제 KIS 주문·취소, production credential, live RabbitMQ·database·portfolio-hub 연결
- push, PR, 원격 main 반영, image publication, 운영 migration, deployment, GitHub Release 또는 실주문
- ProofLine delivery/release lifecycle이 과거 구현 당시 완료되었다는 소급 주장
## Risks and Unknowns
### Risks
- KIS 응답의 실제 venue 필드가 누락되거나 미지원 코드이면 SOR 주문의 actual venue가 NULL로 남아 ledger enqueue가 fail-closed 될 수 있다. 임의 시간 추론보다 안전하며 운영 관측과 authoritative reconciliation이 필요하다.
- migration runner는 history table 없이 SQL을 재실행하므로 migration 024의 NULL-only backfill과 replay-safe 불변식을 이후 변경에서도 유지해야 한다.
- 환경 의존 KIS·RabbitMQ 검증은 skip되었으므로 실제 운영 외부 시스템 상호작용은 별도 승인 환경에서 확인해야 한다.
### Approval State
- Discovery status: `confirmed`
- 승인 근거: 요청자 genichin이 승인 상태인 issue #60 본문을 최대한 보존하여 템플릿 기반 Discovery를 승인된 상태로 정리하라고 명시했다.
- 추가로 필요한 제품 결정: 없음
- 이 확인은 사후 specification 정리이며 구현·테스트·독립 QC의 실제 evidence는 별도 보존한다. push, PR, 배포, release 또는 실주문 승인을 뜻하지 않는다.
@@ -0,0 +1,49 @@
# GitHub issue #60 comment evidence
- Source: https://github.com/fourblocks2020/trex-core/issues/60#issuecomment-5337338182
- Author: `genichin`
- Created At: `2026-08-19T03:57:52Z`
- Evidence Role: repository-local snapshot of a non-canonical implementation comment
- Canonical Authority: GitHub source comment; this snapshot does not create ProofLine lifecycle status
---
## 구현 완료
### 구현 내용
- 명시적 주문 미수락·미체결 sell 실패를 자동 재주문 없이 `pending_sell → holding`으로 수렴시켰다.
- submission outcome unknown은 durable sentinel과 broker lookup/reconciliation을 우선하고 중복 제출하지 않는다.
- strategy RPC에서 KIS failure·broker attempt·retryability 전달을 제거했다.
- venue 누락은 SOR, 명시 KRX/NXT/SOR는 보존하고 AUTO 및 wall-clock routing을 제거했다.
- 기존 persisted AUTO를 SOR로 전환하는 migration을 추가했다.
- SOR 원주문 venue와 실제 체결 venue를 분리했다.
- slot·재시작·취소: `order_venue` KRX/NXT/SOR
- fill·ledger/outbox actual venue: KRX/NXT, 복원 불가능한 historical SOR는 NULL
- KIS `ORD_EXG_GB` 및 명시 exchange-id allowlist로 실제 KRX/NXT를 파싱하며 SOR/unknown은 추론하지 않는다.
- migration replay가 정상 `(actual=NXT, order=KRX)` 행을 오염시키지 않도록 NULL-only backfill과 DB constraint를 적용했다.
### 실제 검증 결과
- 구현자 전체 회귀: `1074 passed, 52 skipped`
- 구현자 focused unit: `77 passed`
- 구현자 disposable PostgreSQL 16: `24 passed`
- Ruff: `All checks passed!`
- 독립 QC 전체 pytest + PostgreSQL 16 검증: PASS
- 독립 QC finding: blocker/critical/major/minor 모두 없음
- 독립 QC worktree: clean
### 로컬 커밋
- `15aeae6930f8c3e6ef9cf659f41278b099a78459` — broker 실패 수렴·AUTO 제거
- `7366cadf03fc6002bfd01ecf0cba7c24486bb618` — SOR 원주문/실제 체결 venue 분리
- `359ea098ff717e7f04cf4206dcbc64ad17b47755` — actual venue DB constraint 및 replay-safe migration 보강
### 비차단 후속 권고
- migration runner는 history table 없이 SQL 전체를 재실행하므로 현재 migration의 replay-safe 불변식을 계속 유지한다.
- 실제 운영 KIS 응답·RabbitMQ·자격증명 게이트 검증은 별도 승인된 환경에서 수행한다.
### 범위 경계
현재 완료된 것은 **로컬 `main`의 구현·테스트·PostgreSQL 검증·커밋과 독립 QC PASS**다. push, PR, 원격 main 반영, 이미지 게시, 운영 배포, migration 운영 실행, GitHub Release, 실주문은 수행하지 않았으며 완료를 의미하지 않는다.
@@ -0,0 +1,55 @@
# GitHub issue #60 comment evidence
- Source: https://github.com/fourblocks2020/trex-core/issues/60#issuecomment-5336722059
- Author: `genichin`
- Created At: `2026-08-19T02:20:28Z`
- Evidence Role: repository-local snapshot of a non-canonical implementation comment
- Canonical Authority: GitHub source comment; this snapshot does not create ProofLine lifecycle status
---
## 구현 진행 상황
- **대상:** [Discovery] broker 실행 실패의 기록·상태 수렴 경계
- **브랜치:** `main`
- **기준:** `main` (`be98965f2c5d1bad933802282bd7284642203cb8`)
- **상태:** 로컬 main 구현·검증·커밋 및 독립 QC PASS — 미푸시, 미배포
- **최종 업데이트:** 2026-08-19 12:57:49 KST
### 구현 계획 및 작업 목록
- [x] 명시적으로 주문이 거부되고 미체결임이 확인된 매도 주문을 새 주문 없이 보유 상태로 복구한다.
- 주문 배정 정보를 정리하고 기존 보유수량을 유지하는 집중 검증을 통과했다.
- [x] 주문 결과가 불명확한 경우 중복 주문을 만들지 않고 조회·대조 절차를 우선한다.
- 기존 결과불명 sentinel·조회 경로와 재시작 중복 제출 방지 회귀를 확인했다.
- [x] 전략 서비스에 KIS 실패·재시도 판단 정보를 전달하지 않고, core가 자동 주문 재시도를 추가하지 않았음을 검증한다.
- sell 응답의 `retryable` 필드를 제거하고 strategy RPC 응답에 retryability가 없음을 검증했다.
- [x] venue 누락 시 SOR 기본값, 명시 venue 보존, AUTO 제거·기존 데이터 전환 계약과의 교차 회귀를 검증한다.
- 원주문 `order_venue`와 실제 `execution_venue`를 분리하고, KIS allowlist 파싱·outbox 이중 보존·실제 PostgreSQL migration 검증을 완료했다.
- [x] 관련 집중 테스트와 전체 회귀 테스트를 실행하고 결과를 기록한다.
- [x] 변경사항을 검토하고 로컬 main에 커밋한다.
- commits: `15aeae6930f8c3e6ef9cf659f41278b099a78459`, blocker fixes `7366cadf03fc6002bfd01ecf0cba7c24486bb618`, `359ea098ff717e7f04cf4206dcbc64ad17b47755`; push·PR·배포·릴리스·실주문은 수행하지 않았다.
### 진행 기록
- 2026-08-19 11:29:51 KST — 승인된 이슈 본문과 `main` 기준 SHA를 확인하고 별도 worktree·기능 브랜치 없이 구현을 시작했다.
- 2026-08-19 11:29:51 KST — sell 명시적 거부 후 `pending_sell → holding`, dispatch 정리, 후속 자동 재주문 부재를 검증했다.
- 2026-08-19 11:29:51 KST — 결과불명 주문은 durable sentinel과 broker lookup/reconciliation 경로를 유지하며 재제출하지 않는 회귀를 확인했다.
- 2026-08-19 11:29:51 KST — venue 누락→SOR, explicit KRX/NXT/SOR 보존, AUTO admission 거부, wall-clock routing 제거, persisted AUTO→SOR migration을 구현했다.
- 2026-08-19 11:29:51 KST — 집중 테스트 `127 passed`; 전체 회귀 `1062 passed, 51 skipped`; ruff `All checks passed!`.
- 2026-08-19 11:29:51 KST — disposable PostgreSQL 16 실제 엔진 검증 `23 passed`; 검증 컨테이너를 제거했다.
- 2026-08-19 11:29:51 KST — 로컬 main commit `15aeae6930f8c3e6ef9cf659f41278b099a78459` 생성 후 집중 테스트 `127 passed`, ruff 통과, 작업트리 clean을 재확인했다.
- 2026-08-19 11:59:05 KST — 독립 QC 결과 FAIL. KIS adapter가 SOR 요청값을 ack/slot/ledger에 그대로 보존하고 일별 체결조회 row의 실제 KRX/NXT venue를 파싱하지 않아 AC 6을 충족하지 못한다. 수정·독립 재검증 전에는 delivery 검증 완료로 판정하지 않는다.
- 2026-08-19 12:47:57 KST — 승인된 해결책을 적용했다. Slot/취소에는 원주문 KRX/NXT/SOR를 유지하고, KIS fill의 `ORD_EXG_GB` 및 명시 exchange-id allowlist에서 실제 KRX/NXT를 `FillStatus.execution_venue`로 전달한다. outbox는 `order_venue`와 실제 `venue`를 분리 저장하며 SOR 단독·미지원 코드는 실제 거래소로 추론하지 않는다.
- 2026-08-19 12:47:57 KST — 전체 회귀 `1074 passed, 51 skipped`, disposable PostgreSQL 16 검증 `23 passed`, ruff 통과, migration 024 및 outbox round-trip을 확인했다.
- 2026-08-19 12:48:36 KST — blocker 수정 commit `7366cadf03fc6002bfd01ecf0cba7c24486bb618`을 로컬 main에 생성하고 worktree clean을 확인했다. 독립 재QC를 시작했다.
- 2026-08-19 12:54:15 KST — 독립 재QC에서 migration 024의 historical SOR actual 값과 replay-safe backfill 결함을 blocker로 확인했다. `order_venue IS NULL` one-time backfill, historical SOR actual→NULL, actual venue KRX/NXT/NULL DB constraint를 적용했다. 신규 actual NXT + order KRX 행이 replay 후 보존됨을 검증했다.
- 2026-08-19 12:54:15 KST — 수정 commit `359ea098ff717e7f04cf4206dcbc64ad17b47755`; 전체 `1074 passed, 52 skipped`, PostgreSQL 16 `24 passed`, ruff 통과, worktree clean. 독립 재QC를 다시 요청한다.
- 2026-08-19 12:57:49 KST — 독립 재QC PASS. blocker/critical/major/minor finding 없음. 독립 PG16에서 historical SOR→order SOR+actual NULL, 정상 NXT/KRX replay 보존, actual SOR·AUTO·NULL order 거부를 확인했다. HEAD `359ea098ff717e7f04cf4206dcbc64ad17b47755`, worktree clean.
> 각 작업이 실제로 완료되고 검증될 때마다 이 댓글의 체크박스와 진행 기록을 갱신한다. 체크 표시는 구현 완료 또는 해당 검증의 실제 통과를 의미하며, 배포·릴리스 완료를 의미하지 않는다.
+3
View File
@@ -0,0 +1,3 @@
---
id: "line-0005"
---
+61
View File
@@ -0,0 +1,61 @@
---
id: "req-0005"
status: approved
discovery: "dcy-0005"
criteria:
create:
- "ac-0015"
- "ac-0016"
- "ac-0017"
- "ac-0018"
- "ac-0019"
update: []
retire: []
satisfy: []
---
# broker 실행 실패의 기록·상태 수렴 경계
## Objective
`trex-core`가 broker-authoritative evidence를 기준으로 주문 실패·불명확 결과·부분체결·취소 상태를 중복 주문 없이 수렴하게 한다. core가 자동 broker retry를 생성하거나 strategy/TVR에 KIS 실패 판단을 넘기지 않도록 ownership을 제한하고, original order venue와 actual execution venue를 durable하게 분리하여 submit부터 restart·cancel·ledger/outbox까지 의미를 보존한다.
## Scope
- 명시적으로 미수락·미체결이 확인된 sell 주문은 실패 evidence를 기록하고 dispatch를 정리하며 새 broker attempt 없이 broker-authoritative 보유수량으로 `pending_sell → holding` 전이한다.
- submission timeout·연결 단절·응답 누락 등 결과 불명확 상태는 durable sentinel로 보존하고 신규 주문 없이 original order lookup과 reconciliation을 우선한다.
- core는 broker failure의 retryability, retry schedule, retry budget 또는 자동 새 broker attempt를 산출하지 않는다. 이후 별도 strategy intent는 자동 retry와 구분한다.
- strategy/TVR 응답·이벤트에는 KIS failure, raw broker error, broker attempt와 retryability를 노출하지 않는다. strategy/TVR은 core slot snapshot만 소비한다.
- intent venue 누락은 `SOR`로 정규화하고 explicit `KRX`/`NXT`/`SOR`를 그대로 보존한다. `AUTO`는 admission·broker routing·persistence에서 허용하지 않고 persisted AUTO는 SOR로 전환하며 wall-clock routing을 제거한다.
- original `order_venue`는 submit, ack, slot, restart와 cancel에 KRX/NXT/SOR로 보존한다. actual `execution_venue`는 broker-authoritative KRX/NXT 또는 미확정 NULL이며 fill, ledger와 outbox에 별도로 기록한다.
- KIS actual venue는 `ORD_EXG_GB`의 승인된 mapping과 명시 exchange-id allowlist만 사용한다. `SOR`, 누락, 미지원 값과 wall-clock time으로 actual KRX/NXT를 추론하지 않는다.
- historical outbox SOR는 `order_venue=SOR`, actual `venue=NULL`로 보존한다. migration은 NULL-only backfill로 반복 적용이 안전해야 하고 정상 `(actual=NXT, order=KRX)` 같은 조합을 오염시키지 않아야 한다.
- PostgreSQL은 order venue를 KRX/NXT/SOR non-null로 제한하고 actual venue를 KRX/NXT/NULL로 제한한다.
- focused·전체 회귀, actual PostgreSQL migration·round-trip, lint와 독립 read-only QC를 verification evidence로 유지한다.
## Constraints
- broker evidence가 없는 actual venue, 체결, 미수락 또는 terminal state를 추론하지 않는다.
- explicit order venue와 original order date·broker order identity를 restart/cancel 중 변경하지 않는다.
- strategy/TVR에 KIS failure나 retry ownership을 추가하지 않는다.
- live credential·token·connection string·raw sensitive payload를 문서나 외부 wire에 기록하지 않는다.
- existing active AC-0011의 timeout/cancel reconciliation 및 AC-0013의 terminal cancellation·partial fill 계약을 완화하거나 대체하지 않는다.
- Normative Design Documents: 없음. 이 REQ와 active AC가 normative specification을 소유한다.
### Current Implementation Assessment
- 이 specification은 승인된 GitHub issue #60과 연결된 #61을 이미 local `main`에서 구현·검증한 결과를 사후 정리한다. 과거 구현이 ProofLine delivery chronology를 따랐다는 뜻은 아니다.
- 구현 revision은 `15aeae6930f8c3e6ef9cf659f41278b099a78459`, `7366cadf03fc6002bfd01ecf0cba7c24486bb618`, `359ea098ff717e7f04cf4206dcbc64ad17b47755`다.
- 현재 구현은 명시적 sell rejection 수렴, unknown submission sentinel·lookup, strategy wire retryability 제거, SOR default·explicit venue 보존·AUTO 제거, KIS actual venue parser와 order/execution venue 분리, replay-safe migration·DB constraint를 포함한다.
- 구현자 검증은 focused `77 passed`, 전체 `1074 passed, 52 skipped`, disposable PostgreSQL 16 `24 passed`, Ruff PASS다.
- 최종 독립 read-only QC는 actual PostgreSQL 16 probe를 포함하여 blocker/critical/major/minor finding 없이 PASS했으며 HEAD `359ea098ff717e7f04cf4206dcbc64ad17b47755`와 clean worktree를 확인했다.
- 환경 의존 KIS·RabbitMQ 검증은 skip되었고 실제 외부 system interaction은 수행하지 않았다.
- `approved` REQ와 `active` AC는 current specification authority 및 현재 implementation assessment를 나타낸다. push, PR, 원격 main 반영, deployment, release 또는 운영 주문 완료를 뜻하지 않는다.
## Non-Goals
- strategy/TVR의 KIS failure 수신, retryability 계산, broker retry schedule·budget 또는 자동 재주문
- TVR session·portfolio `markets` gate와 거래 세션 정책 구현
- live KIS 주문·취소, 운영 broker/account/database/RabbitMQ/portfolio-hub 연결
- push, PR, remote main merge, image publication, production migration, deployment, GitHub Release 또는 실주문
- ProofLine delivery·release lifecycle closure의 소급 주장