<!-- task=m-backtest-multi-timeframe-coverage/01_fill_policy plan=0 tag=FILL_POLICY -->

# Plan - FILL_POLICY

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

이 task는 구현 후 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채워야 완료된다. 검증을 실행하고 active 파일은 그대로 둔 채 리뷰 준비 상태를 보고한다. 종결, archive, `complete.log` 작성은 code-review 전용이다. 선택된 SDD 결정 또는 Milestone `구현 잠금 > 결정 필요` 항목이 막을 때만 review stub의 `사용자 리뷰 요청`을 채우고, 사용자에게 직접 질문하지 않는다.

## 배경

`fill-policy` Task는 daily 전용 용어와 체결 규칙을 monthly/daily/minute에 맞게 정리해야 한다. 현재 도메인 helper는 `daily_next_bar_ohlc`와 `FillOrderOnDailyBar` 이름을 쓰지만, worker backtest engine은 같은 bar의 close로 즉시 체결한다. SDD S07은 timeframe별 deterministic result evidence를 요구하므로 정책 명칭, engine 동작, fixture 결과를 함께 맞춘다.

## 사용자 리뷰 요청 흐름

구현 중 직접 사용자 프롬프트를 띄우지 않는다. 선택된 SDD 결정 또는 Milestone lock 결정만 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 active review stub의 `사용자 리뷰 요청`에 기록하고, code-review가 `USER_REVIEW.md` 작성 여부를 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/backtest-loop/milestones/backtest-multi-timeframe-coverage.md`
- Task ids:
  - `fill-policy`: daily 전용 fill policy를 multi-timeframe 용어로 재정리하고, timeframe별 체결/next-bar 규칙을 명시한다.
- Completion mode: check-on-pass

## Spec Targets

- SDD: `agent-roadmap/sdd/backtest-loop/backtest-multi-timeframe-coverage/SDD.md`
- Acceptance scenarios:
  - `S07`: task=`fill-policy`; evidence=`deterministic backtest fixture results for monthly/daily/minute`
- Completion mode: spec-check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/domain-model-smoke.md`
- `agent-test/local/worker-smoke.md`
- `packages/domain/backtest/types.go`
- `packages/domain/backtest/types_test.go`
- `services/worker/internal/backtest/engine.go`
- `services/worker/internal/backtest/engine_test.go`
- `services/worker/internal/backtest/fixture_test.go`
- `services/worker/internal/backtest/bar_source.go`
- `services/worker/internal/backtest/bar_source_test.go`
- `services/worker/internal/backtest/strategies.go`
- `services/worker/internal/backtest/strategies_test.go`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`를 읽었고, `packages/domain/**` 변경은 `domain-model-smoke`, `services/worker/**` 변경은 `worker-smoke`를 적용한다.
- 필수 명령: domain만이면 `go test ./packages/domain/...`, worker만이면 `go test ./services/worker/...`; 이번 계획은 둘 다 바꾸므로 focused final은 `go test -count=1 ./packages/domain/backtest ./services/worker/internal/backtest`로 두고, 필요 시 `go test -count=1 ./services/worker/...`를 추가 실행한다.

### 테스트 커버리지 공백

- 현재 `packages/domain/backtest/types_test.go`는 daily 이름 helper만 검증한다.
- 현재 `services/worker/internal/backtest/fixture_test.go`는 daily fixture만 deterministic result를 검증한다.
- 현재 `services/worker/internal/backtest/engine.go`는 next-bar 정책이 아니라 같은 bar close 즉시 체결을 사용한다.

### 심볼 참조

- 변경 후보: `FillPolicyDailyNextBarOHLC`, `FillOrderOnDailyBar`.
- 현재 직접 참조는 `packages/domain/backtest/types_test.go`와 paper trading 코드에 있다. 이 계획은 compatibility alias/wrapper를 유지해 paper trading call site를 변경하지 않는다.

### 분할 판단

- split policy를 먼저 평가했다.
- 공유 task group: `m-backtest-multi-timeframe-coverage`.
- sibling plans:
  - `01_fill_policy`: domain/worker backtest 체결 정책과 S07 fixture.
  - `02_freshness_readiness`: operator freshness/readiness schema와 S08 fixture.
- 두 subtask는 서로 다른 ownership/test 축이므로 독립이다. 이 directory는 `01_...` 형식이라 predecessor `complete.log`가 없다.

### 범위 결정 근거

- paper trading engine/service call site는 legacy wrapper로 보존하고 직접 수정하지 않는다. 해당 runtime은 기존 paper-trading milestone의 별도 정책을 가진다.
- storage schema, proto contract, provider import는 변경하지 않는다. S07은 engine fixture result evidence로 닫는다.

### 빌드 등급

- `local-G07`: domain helper와 worker engine behavior를 함께 바꾸지만 bounded Go unit/fixture test로 검증 가능하다.

## 구현 체크리스트

- [ ] `packages/domain/backtest/types.go`에 timeframe-neutral canonical fill policy/helper를 추가하고 daily 이름은 compatibility alias/wrapper로 유지한다.
- [ ] `packages/domain/backtest/types_test.go`에 canonical helper와 legacy wrapper가 같은 OHLC/next-bar semantics를 갖는 regression test를 추가한다.
- [ ] `services/worker/internal/backtest/engine.go`가 strategy decision을 다음 같은-instrument bar에서 `FillOrderOnBar`로 체결하게 바꾸고, 마지막 미체결 주문은 실행하지 않는 정책을 명시한다.
- [ ] `services/worker/internal/backtest/engine_test.go`와 `fixture_test.go`에 monthly/daily/minute deterministic result fixture를 추가한다. 검증: monthly/daily/minute 각각 stable ending equity, trade count, equity curve를 낸다.
- [ ] 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [FILL_POLICY-1] Canonical Fill Policy

#### 문제

`packages/domain/backtest/types.go:330-351`에서 정책과 helper 이름이 daily에 묶여 있다.

```go
330 type FillPolicy string
332 const FillPolicyDailyNextBarOHLC FillPolicy = "daily_next_bar_ohlc"
351 func FillOrderOnDailyBar(order OrderIntent, bar market.Bar) (Fill, bool, error) {
```

#### 해결 방법

canonical 이름을 추가하고 old 이름은 alias/wrapper로 둔다.

```go
const FillPolicyNextBarOHLC FillPolicy = "next_bar_ohlc"
const FillPolicyDailyNextBarOHLC FillPolicy = FillPolicyNextBarOHLC

func FillOrderOnBar(order OrderIntent, bar market.Bar) (Fill, bool, error) { ... }
func FillOrderOnDailyBar(order OrderIntent, bar market.Bar) (Fill, bool, error) {
    return FillOrderOnBar(order, bar)
}
```

#### 수정 파일 및 체크리스트

- `packages/domain/backtest/types.go`: canonical const/function 추가, daily wrapper 주석 정리.
- `packages/domain/backtest/types_test.go`: canonical helper market/limit/open/timestamp 테스트와 legacy wrapper equivalence 테스트.

#### 테스트 작성

- 작성: `TestFillOrderOnBarMarketUsesOpen`, `TestFillOrderOnBarLimitCrossing`, `TestFillOrderOnDailyBarMatchesCanonicalHelper`.

#### 중간 검증

```bash
go test -count=1 ./packages/domain/backtest -run 'TestFillOrderOn(Bar|DailyBar)'
```

기대: exit 0.

### [FILL_POLICY-2] Worker Engine Next-Bar Fill

#### 문제

`services/worker/internal/backtest/engine.go:78-111`은 strategy가 낸 주문을 현재 bar close로 즉시 체결한다. S07의 next-bar/timeframe semantics와 맞지 않는다.

```go
91 for _, order := range orders {
92     fill := backtest.Fill{
96         Price:        bar.Close,
97     }
```

#### 해결 방법

engine loop를 같은 instrument별 pending order 방식으로 바꾼다. 각 bar 시작 시 해당 instrument pending orders를 `backtest.FillOrderOnBar(order, bar)`로 체결하고, 이후 현재 bar로 strategy decision을 생성해 다음 bar로 넘긴다. monthly/daily/minute 모두 같은 "run timeframe의 다음 available bar OHLC" 규칙을 따른다.

#### 수정 파일 및 체크리스트

- `services/worker/internal/backtest/engine.go`: pending map 추가, fill-before-decide 순서 적용, comments를 daily-free 용어로 정리.
- `services/worker/internal/backtest/engine_test.go`: same timestamp/instrument sort와 next-bar fill 회귀 보강.

#### 테스트 작성

- 작성: `TestEngineFillsOrdersOnNextMatchingInstrumentBar`, `TestEngineDoesNotFillPendingOrderWithoutNextBar`.

#### 중간 검증

```bash
go test -count=1 ./services/worker/internal/backtest -run 'TestEngine(FillsOrdersOnNextMatchingInstrumentBar|DoesNotFillPendingOrderWithoutNextBar)'
```

기대: exit 0.

### [FILL_POLICY-3] Multi-Timeframe Fixture Evidence

#### 문제

`services/worker/internal/backtest/fixture_test.go:91-159`과 후속 fixture는 daily bars만 deterministic result를 증명한다.

```go
121 Timeframe:  market.TimeframeDaily,
156 if !reflect.DeepEqual(res1, res2) {
```

#### 해결 방법

monthly/daily/minute fixture table을 추가한다. 같은 strategy와 같은 price path를 timeframe별 bar timestamp로 구성하고, expected result는 ending equity, trade count, final position, equity curve length를 고정한다.

#### 수정 파일 및 체크리스트

- `services/worker/internal/backtest/fixture_test.go`: table-driven monthly/daily/minute fixtures 추가.
- `services/worker/internal/backtest/strategies_test.go`: 필요 시 strategy comments만 최신 용어로 보정.

#### 테스트 작성

- 작성: `TestEngineProducesDeterministicResultAcrossTimeframes`.

#### 중간 검증

```bash
go test -count=1 ./services/worker/internal/backtest -run 'TestEngineProducesDeterministicResultAcrossTimeframes'
```

기대: exit 0.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/domain/backtest/types.go` | FILL_POLICY-1 |
| `packages/domain/backtest/types_test.go` | FILL_POLICY-1 |
| `services/worker/internal/backtest/engine.go` | FILL_POLICY-2 |
| `services/worker/internal/backtest/engine_test.go` | FILL_POLICY-2 |
| `services/worker/internal/backtest/fixture_test.go` | FILL_POLICY-3 |

## 최종 검증

```bash
go test -count=1 ./packages/domain/backtest ./services/worker/internal/backtest
```

기대: exit 0, S07 monthly/daily/minute deterministic fixture tests pass.

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