<!-- task=m-paper-trading-readiness/01_domain_paper_model plan=1 tag=REVIEW_PAPER_DOMAIN -->

# Plan - REVIEW_PAPER_DOMAIN

## 이 파일을 읽는 구현 에이전트에게

이 계획은 `code_review_local_G06_0.log`의 FAIL 판정 후속이다. 범위는 발견된 Required 이슈 3개로 제한한다. 구현 완료의 마지막 단계는 반드시 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이다. 검증 명령을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review-skill 전용이다.

구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 범위 충돌 없이는 안전하게 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션을 증거와 함께 채우고 중단한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/trading-expansion/milestones/paper-trading-readiness.md`
- Task ids:
  - `paper-account`: paper account와 portfolio state
  - `virtual-orders`: 가상 주문과 체결 모델
  - `risk-guard`: 최소 risk guard skeleton
- Completion mode: check-on-pass

## 배경

이전 구현은 paper domain vocabulary 자체는 대체로 추가했지만, daily bar fill helper의 trace/validation과 계획이 요구한 최소 테스트 일부가 빠졌다. 이 후속 작업은 worker/API/persistence로 범위를 넓히지 않고 `packages/domain/backtest` 안에서 누락된 correctness와 테스트 신뢰도를 복구한다.

## 분석 결과

### 읽은 파일

- `agent-task/m-paper-trading-readiness/01_domain_paper_model/code_review_local_G06_0.log`
- `agent-task/m-paper-trading-readiness/01_domain_paper_model/plan_local_G06_0.log`
- `agent-ops/rules/project/domain/domain-model/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/domain-model-smoke.md`
- `packages/domain/backtest/types.go`
- `packages/domain/backtest/types_test.go`
- `packages/domain/market/types.go`
- `services/worker/internal/backtest/engine.go`
- `services/worker/internal/backtest/strategies.go`

### Required 이슈 원문 요약

- `packages/domain/backtest/types_test.go`에 계획상 최소 테스트인 `TestFillOrderOnDailyBarMarketUsesOpen`, `TestFillOrderOnDailyBarLimitCrossing`, `TestFillOrderOnDailyBarRejectsMissingLimit`가 없다.
- `FillOrderOnDailyBar`가 market/limit fill에 `Timestamp: bar.Timestamp`를 설정하지 않는다.
- limit crossing 계산에서 `bar.High.Amount`와 `bar.Low.Amount` 파싱 오류를 무시해 invalid OHLC 입력에서 panic 또는 신뢰할 수 없는 비교가 발생할 수 있다.

### 테스트 환경 규칙

- test_env: `local`.
- 적용 profile: `agent-test/local/domain-model-smoke.md`.
- 필수 검증: `go test ./packages/domain/... -count=1`, `git diff --check`.
- 관련 worker 호출부 컴파일성 확인을 위해 `go test ./services/worker/... -count=1`도 실행한다.

### 빌드 등급

- build: `local-G07`, review: `local-G07`.
- 근거: 후속 범위가 deterministic domain helper/test 수정으로 좁지만, 이전 리뷰에서 테스트 증거와 실제 테스트 목록이 불일치했으므로 검증 신뢰를 한 단계 강화한다.

### 범위 결정 근거

- 포함: `packages/domain/backtest/types.go`, `packages/domain/backtest/types_test.go`.
- 제외: worker runtime fill policy 전환, protobuf/API/CLI 변경, persistence, broker adapter. 이들은 sibling subtask 범위다.
- 새 패키지나 public contract 이름을 추가하지 않는다. 기존 `FillOrderOnDailyBar`, `OrderIntent`, `Fill`, `PaperAccount`, `CheckRisk` 의미를 완성한다.

## 구현 체크리스트

- [ ] `packages/domain/backtest/types_test.go`에 계획 필수 fill 테스트(`TestFillOrderOnDailyBarMarketUsesOpen`, `TestFillOrderOnDailyBarLimitCrossing`, `TestFillOrderOnDailyBarRejectsMissingLimit`)를 추가하고 실제 테스트 목록과 리뷰 스텁 설명을 일치시킨다.
- [ ] `FillOrderOnDailyBar`가 market/limit fill 모두에 `Timestamp: bar.Timestamp`를 설정하게 하고 테스트에서 timestamp를 검증한다.
- [ ] `FillOrderOnDailyBar`가 limit crossing 전에 `bar.High`/`bar.Low`의 currency와 decimal amount를 검증해 invalid OHLC를 panic 대신 error로 반환하게 하고 테스트를 추가한다.
- [ ] `go test ./packages/domain/... -count=1`, `go test ./services/worker/... -count=1`, `git diff --check`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_PAPER_DOMAIN-1] 계획 필수 fill 테스트 복구

### 문제

`plan_local_G06_0.log`는 `TestFillOrderOnDailyBarMarketUsesOpen`, `TestFillOrderOnDailyBarLimitCrossing`, `TestFillOrderOnDailyBarRejectsMissingLimit`를 최소 테스트로 요구했다. 현재 `packages/domain/backtest/types_test.go`에는 sell-side fill 테스트만 있어 market buy/open, limit buy crossing, missing limit error가 직접 검증되지 않는다.

### 해결 방법

`packages/domain/backtest/types_test.go`에 아래 테스트를 추가한다.

- `TestFillOrderOnDailyBarMarketUsesOpen`: empty `OrderIntent.Type` default market order가 `bar.Open` 가격과 `bar.Timestamp`로 체결되는지 확인한다.
- `TestFillOrderOnDailyBarLimitCrossing`: buy limit order가 `bar.Low <= limit <= bar.High`일 때 limit price와 `bar.Timestamp`로 체결되는지 확인한다.
- `TestFillOrderOnDailyBarRejectsMissingLimit`: `OrderTypeLimit`인데 `LimitPrice`가 비어 있으면 `ok=false`와 non-nil error를 반환하는지 확인한다.

### 중간 검증

```bash
go test ./packages/domain/... -run 'TestFillOrderOnDailyBar' -count=1
```

Expected: command exits 0 and output includes the domain/backtest package.

## [REVIEW_PAPER_DOMAIN-2] fill timestamp trace 설정

### 문제

`Fill.Timestamp`를 추가했지만 `FillOrderOnDailyBar`가 반환하는 market/limit fill은 timestamp zero value를 가진다. paper trading fill trace가 필요한 후속 runtime에서 체결 시각을 잃게 된다.

### 해결 방법

`FillOrderOnDailyBar`의 market 반환과 limit 반환 모두에 `Timestamp: bar.Timestamp`를 설정한다. `REVIEW_PAPER_DOMAIN-1`의 market/limit crossing 테스트에서 timestamp equality를 함께 검증한다.

### 중간 검증

```bash
go test ./packages/domain/backtest -run 'TestFillOrderOnDailyBar(MarketUsesOpen|LimitCrossing)' -count=1
```

Expected: command exits 0.

## [REVIEW_PAPER_DOMAIN-3] limit OHLC validation

### 문제

`FillOrderOnDailyBar`는 limit price만 validation하고 `bar.High.Amount`와 `bar.Low.Amount` parse error를 무시한다. invalid OHLC decimal 또는 currency mismatch가 들어오면 panic이나 잘못된 비교가 발생할 수 있다.

### 해결 방법

limit order branch에서 아래를 명시적으로 검증한다.

- `bar.Low.Currency`와 `bar.High.Currency`가 `order.LimitPrice.Currency`와 같은지 확인하고 다르면 error를 반환한다.
- `bar.Low.Amount`, `bar.High.Amount`, `order.LimitPrice.Amount`를 각각 `decimalRat`로 파싱하고 error를 감싼 뒤 반환한다.
- `bar.Low > bar.High`인 경우도 invalid daily bar range로 error를 반환한다.
- crossing 비교는 검증된 `low`, `high`, `limit` 값만 사용한다.

테스트는 `TestFillOrderOnDailyBarRejectsInvalidBarRange`를 추가하고 high/low currency mismatch, invalid high/low decimal, low greater than high 중 최소 핵심 케이스를 subtest로 검증한다.

### 중간 검증

```bash
go test ./packages/domain/backtest -run 'TestFillOrderOnDailyBarRejectsInvalidBarRange' -count=1
```

Expected: command exits 0.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/domain/backtest/types.go` | REVIEW_PAPER_DOMAIN-2, REVIEW_PAPER_DOMAIN-3 |
| `packages/domain/backtest/types_test.go` | REVIEW_PAPER_DOMAIN-1, REVIEW_PAPER_DOMAIN-2, REVIEW_PAPER_DOMAIN-3 |

## 최종 검증

```bash
go test ./packages/domain/... -count=1
go test ./services/worker/... -count=1
git diff --check
```

Expected: all commands exit 0. Fresh execution matters, so use `-count=1`.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
