<!-- task=m-paper-trading-readiness/02+01_worker_paper_runtime plan=1 tag=REVIEW_PAPER_WORKER -->

# Plan - REVIEW_PAPER_WORKER

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

이 계획은 `code_review_local_G07_0.log`의 FAIL Required 이슈만 좁게 해결한다. 구현 완료의 마지막 단계는 반드시 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:
  - `strategy-run`: 전략을 paper execution loop에서 실행할 수 있다.
- Completion mode: check-on-pass

## 배경

첫 리뷰는 테스트 재실행 자체는 통과했지만, paper execution loop의 pending order 처리에서 multi-instrument daily bar 계약과 fill 실패 기록이 깨지는 Required 이슈를 발견했다. 이 후속 작업은 새 worker package 범위 안에서 paper runtime correctness와 테스트를 보강한다.

## 범위 결정 근거

- Include: `services/worker/internal/papertrading/engine.go`, `services/worker/internal/papertrading/engine_test.go`.
- Include: 필요한 경우 gofmt로 위 파일 formatting을 정리한다.
- Exclude: protobuf/API/CLI monitoring, database persistence, live broker adapter, domain model shape 변경.

## 빌드 등급

- build: `local-G08`, review: `local-G08`.
- 근거: Required 이슈가 명확하고 deterministic unit test로 재현 가능하지만, 기존 local-G07 구현에서 correctness/test coverage 결함이 발생했으므로 local grade를 한 단계 올린다.

## 구현 체크리스트

- [x] Pending orders를 instrument별 다음 daily bar에서만 체결하도록 수정하고 multi-instrument 회귀 테스트를 추가한다.
- [x] `ApplyFill` 실패를 `RejectedOrder` 또는 명시적 abort 정책으로 처리하고 부족 현금 회귀 테스트를 추가한다.
- [x] `RunRequest.Account.ID`를 보존하도록 수정하고 account identity 회귀 테스트를 추가한다.
- [x] `gofmt`를 적용하고 `go test ./services/worker/internal/papertrading ./services/worker/internal/backtest -count=1`, `go test ./services/worker/... -count=1`, `go test ./packages/domain/... -count=1`, `git diff --check`, `gofmt -l services/worker/internal/papertrading/engine.go services/worker/internal/papertrading/engine_test.go`를 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_PAPER_WORKER-1] Instrument-scoped Pending Orders

### 문제

`services/worker/internal/papertrading/engine.go:111`는 모든 pending order를 현재 loop의 다음 `bar`에 대입한다. `StorageBarSource`는 한 market의 여러 instrument bar를 timestamp/instrument 순으로 반환하므로, instrument A 주문이 같은 날짜의 instrument B bar 가격으로 체결될 수 있다.

### 해결 방법

- Pending order를 `market.InstrumentID` 기준으로 분리한다.
- `FillOrderOnDailyBar`는 `bar.InstrumentID == order.InstrumentID`인 다음 bar에서만 호출한다.
- 같은 timestamp의 다른 instrument bar는 해당 주문의 next bar로 취급하지 않는다.
- Strategy decision은 현재 bar instrument에 대해 생성하되, 다음 동일 instrument daily bar까지 pending으로 유지한다.

### 테스트 작성

- `services/worker/internal/papertrading/engine_test.go`에 multi-instrument bar fixture를 추가한다.
- instrument A day1 주문이 instrument B day1/day2 가격으로 체결되지 않고 instrument A day2 open으로 체결되는지 검증한다.

## [REVIEW_PAPER_WORKER-2] Fill Apply Failure Handling

### 문제

`services/worker/internal/papertrading/engine.go:134`는 `ApplyFill` 실패를 `RejectedOrder`로 기록하지 않고 같은 order를 `nextPending`에 다시 넣는다. 부족 현금 buy처럼 `CheckRisk`를 통과했지만 portfolio apply가 실패한 주문은 snapshot에서 보이지 않고 계속 재시도된다.

### 해결 방법

- `ApplyFill` 실패 정책을 하나로 고정한다.
- 권장: apply 실패를 `RejectedOrder{Reason: err.Error(), BarTime: bar.Timestamp, Instrument: order.InstrumentID}`로 기록하고 pending에서 제거한다.
- abort 정책을 선택한다면 `Run`이 error를 반환하도록 하고 테스트/설계 결정에 이유를 남긴다.

### 테스트 작성

- 부족 현금 market buy가 포트폴리오를 변경하지 않고 `Snapshot.Rejected`에 남는지 검증한다.
- 같은 주문이 이후 bar에서 재시도되어 fill로 바뀌지 않는지 검증한다.

## [REVIEW_PAPER_WORKER-3] Account Identity Preservation

### 문제

`services/worker/internal/papertrading/engine.go:182`는 입력 `req.Account.ID`를 첫 bar에서 `req.Run.ID`로 덮어쓴다. Snapshot은 요청 account state를 반환해야 하므로 paper account identity를 run identity로 바꾸면 후속 API/CLI monitoring 단계에서 상태 추적이 흔들린다.

### 해결 방법

- 기본 동작은 `req.Account.ID`를 그대로 보존한다.
- 빈 ID fallback이 필요하면 명시적으로만 적용하고, `Run.ID`를 계정 ID로 쓰는 정책을 코드/테스트로 정당화한다.

### 테스트 작성

- `RunRequest.Account.ID`가 `Run.ID`와 다를 때 `Snapshot.Account.ID`가 입력 account ID를 유지하는지 검증한다.

## 중간 검증

```bash
go test ./services/worker/internal/papertrading ./services/worker/internal/backtest -count=1
gofmt -l services/worker/internal/papertrading/engine.go services/worker/internal/papertrading/engine_test.go
```

Expected: `go test` exit 0, `gofmt -l` no output.

## 최종 검증

```bash
go test ./services/worker/... -count=1
go test ./packages/domain/... -count=1
git diff --check
gofmt -l services/worker/internal/papertrading/engine.go services/worker/internal/papertrading/engine_test.go
```

Expected: all commands exit 0; `git diff --check` and `gofmt -l` produce no output.

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