docs(proofline): approve KIS balance pagination spec

This commit is contained in:
Hermes Agent
2026-08-10 00:01:46 +09:00
parent bdf9761b2d
commit 701fb06362
7 changed files with 156 additions and 2 deletions
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0001"
status: active
---
# KIS 연속 잔고 전체 조회 및 종목별 집계
## Criterion
`KISBroker.get_balance()`는 KIS 국내주식 잔고조회 최초 요청에서 빈 continuation key와 공백/미지정 `tr_cont`를 사용해야 한다. 성공 응답의 response header `tr_cont`가 `F` 또는 `M`이면 body의 `ctx_area_fk100`과 `ctx_area_nk100`을 다음 요청 query에 전달하고 후속 요청 header에 `tr_cont=N`을 사용해야 하며, `D` 또는 `E`에서 종료해야 한다. 전체 성공 페이지의 유효한 양수 `hldg_qty`는 `pdno`별로 합산한 하나의 `BalanceItem`으로 반환하고 0 이하 수량 row는 제외해야 한다. `OwnershipAwareBroker`가 KIS broker를 감싸는 경우에도 완전한 raw snapshot이 기존 projection의 입력이 되어야 하며 ownership 및 `ownership_mismatch` 정책은 변경되지 않아야 한다.
## Verification
- 성공 조건: synthetic `F → M → E` 다중 페이지 응답에서 요청별 header와 continuation query가 계약대로 이어지고, 첫 페이지와 후속 페이지의 모든 양수 보유종목 및 페이지에 걸쳐 중복된 종목의 합산 수량이 최종 결과에 포함되며 `E` 이후 추가 요청이 없어야 한다. 별도 fixture로 `D` 종료도 확인한다.
- 실패·경계 조건: 정상 단일 페이지와 검증된 빈 잔고는 추가 요청 없이 기존 결과를 반환하고, 0 이하 수량 row는 결과에서 제외되어야 한다. 실전 50건·모의 20건이라는 page-size에 의존하지 않고 response header 계약만으로 순회해야 한다.
- ownership 보존 조건: 첫 페이지의 manual holding과 후속 페이지의 strategy-owned symbol을 포함한 KIS 응답을 `OwnershipAwareBroker`에 연결했을 때 후속 페이지 종목이 projection 결과에 포함되어야 한다. 전체 raw 수량이 전략 소유수량 이상이면 성공하고, 실제로 작을 때만 기존 `ownership_mismatch`가 유지되어야 한다.
- 검사 방법: `tests/adapters/broker/test_kis.py`에서 `httpx.get`을 페이지별 response header/body fixture로 대체하여 호출 횟수, 요청 header, query key, 종료 조건과 최종 `BalanceItem` 집계를 단언하고, ownership adapter 회귀 테스트에서 완전한 delegate 결과의 projection과 기존 mismatch 경계를 단언한다.
+18
View File
@@ -0,0 +1,18 @@
---
id: "ac-0002"
status: active
---
# 불완전하거나 진행하지 않는 잔고 페이지 체인의 fail-closed 처리
## Criterion
`KISBroker.get_balance()`는 최초 페이지를 포함한 어느 페이지에서든 HTTP/transport 실패, KIS `rt_cd` 실패, malformed JSON/body/row, response header `tr_cont` 누락 또는 지원하지 않는 값, `F/M`이 다음 페이지를 지시하면서 continuation key pair가 비어 있는 상태, 또는 하나의 호출에서 이미 방문한 정규화된 `(ctx_area_fk100, ctx_area_nk100)` pair가 즉시 또는 비인접하게 다시 나타나는 상태를 만나면 누적한 `BalanceItem`을 반환해서는 안 된다. non-object row, 누락되거나 정수 변환 불가능한 `hldg_qty`, 양수 수량인데 빈 `pdno`인 row는 malformed로 처리하고, `hldg_qty <= 0` row는 기존 normalization대로 제외한다. 해당 호출은 유한한 요청 횟수 안에 기존 allow-list의 정제된 `BrokerBalanceError`로 실패해야 하며, pagination 계약 위반을 이유로 새 public error taxonomy를 추가하거나 partial snapshot을 소비자에 전달해서는 안 된다.
## Verification
- 오류 matrix: HTTP status/transport, `rt_cd != 0`, JSON decode 실패, body non-object, `output1` non-list, row non-object, `hldg_qty` 누락·non-numeric, 양수 수량과 빈 `pdno`, `tr_cont` 누락·미지원, `F/M`과 빈 key pair를 각각 독립 fixture로 검증한다.
- 진행성 조건: 즉시 반복 `A → A`와 비인접 순환 `A → B → A` key-pair fixture가 모두 유한한 요청 횟수 안에 `BrokerBalanceError`를 발생시키고 결과 list를 반환하지 않아야 한다.
- 보존 조건: `hldg_qty <= 0` row는 실패가 아니라 제외로 유지하고, 검증된 정상 빈 잔고는 실패로 오인하지 않아야 한다.
- 안전 조건: 예외 code는 기존 `BrokerBalanceError` allow-list 안에 있어야 하며 pagination/shape 계약 위반은 기존의 정제된 malformed-response 계열로 귀결되어야 한다. 오류 객체나 메시지는 token, credential, raw payload 등 민감한 값을 노출하지 않아야 한다.
- 검사 방법: `tests/adapters/broker/test_kis.py`에 오류 종류별 parameterized test와 순환 fixture를 두고 예외 code, 호출 횟수, partial-return 부재, 기존 normalization과 민감정보 비노출을 단언한다.
+17
View File
@@ -0,0 +1,17 @@
---
id: "ac-0003"
status: active
---
# 후속 페이지 보유종목의 reconciliation 정합성
## Criterion
KIS 잔고조회 후속 페이지에만 존재하는 양수 보유종목도 완전한 broker snapshot에 포함되어야 한다. 해당 종목의 portfolio-hub 수량과 holding 슬롯 수량이 broker 수량과 일치하면 `reconcile_positions()`는 `case_code=C` 경고를 만들지 않아야 하고 `reconcile_core_holdings()`는 broker flat으로 판단하거나 슬롯을 `error`로 전환하지 않아야 한다. 반대로 첫 페이지 성공 후 후속 페이지가 실패하면 두 소비자는 누적된 첫 페이지 수량으로 어떤 broker-derived decision도 만들지 않고 `BrokerBalanceError`를 전파해야 하며, B/C warning 생성·해제, broker-flat `error` 전이, unmanaged/managed-non-holding 분류 또는 slot/warning write가 발생해서는 안 된다. 성공과 실패 결과는 두 소비 경로에서 각각 독립적으로 충족해야 한다.
## Verification
- 성공 조건: 첫 페이지에는 없고 후속 페이지에만 있는 종목을 가진 synthetic KIS 응답과 그 수량에 일치하는 SnapshotStore 및 holding 슬롯을 구성했을 때 `reconcile_positions()` 결과가 정상이고 durable C warning이 없으며, 별도 독립 실행한 `reconcile_core_holdings()` 결과가 `ok`이고 슬롯이 `holding`을 유지해야 한다.
- 실패 조건: 첫 페이지에 일부 보유수량이 있고 후속 페이지에서 HTTP, KIS 또는 pagination-contract 오류가 발생하는 fixture를 두 소비자에 각각 연결했을 때 `BrokerBalanceError`가 전파되고, 첫 페이지 수량을 사용한 decision map이나 warning/slot persistence side effect가 없어야 한다. 특히 `case_code=B/C`, warning set/clear, broker-flat `error`, `unmanaged_position`, `managed_non_holding_divergence`가 생성되지 않아야 한다.
- 정책 보존 조건: 성공 fixture에서 후속 페이지 종목을 의도적으로 제거한 대조 조건은 기존 소비자 정책대로 불일치 또는 broker-flat 경로를 검출해야 하며, 이 Line이 warning 분류나 상태 전이 정책 자체를 완화해서 통과해서는 안 된다.
- 검사 방법: adapter의 다중 페이지 결과와 중간 페이지 실패를 application reconciliation fixture에 연결한 repository-local 통합 테스트를 두 소비자별로 독립 실행하고 exception, decision map, warning store, slot write 기록 및 최종 슬롯 상태를 단언한다.