<!-- task=m-backtest-engine-baseline/03+01,02_fixture_verification plan=0 tag=TEST -->

# Backtest Fixture Verification Plan

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 검증 출력, 계획 대비 변경 사항을 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 외부 환경 준비, 범위 충돌 없이는 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션을 근거와 함께 채우고 멈춘다. `USER_REVIEW.md`, archive log, `complete.log` 작성은 code-review 전용이다.

## 배경

마일스톤의 마지막 검증은 동일 fixture daily bars와 동일 strategy 입력이 항상 같은 result를 만든다는 것이다. lifecycle과 result store가 준비된 뒤에는 engine, storage, contract shape를 잇는 deterministic test가 필요하다. 이 subtask는 full-cycle fixture와 workspace-level 검증을 묶는다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이 내용을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/backtest-loop/PHASE.md`
- `agent-roadmap/phase/backtest-loop/milestones/backtest-engine-baseline.md`
- `agent-test/local/rules.md`
- `agent-test/local/domain-model-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-test/local/contracts-smoke.md`
- `packages/domain/backtest/types.go`
- `packages/domain/backtest/types_test.go`
- `packages/domain/market/types.go`
- `services/worker/internal/marketdata/importer/importer.go`
- `services/worker/internal/marketdata/importer/importer_test.go`
- `services/worker/internal/storage/ports.go`
- `services/worker/internal/storage/postgres/store.go`
- `bin/test`
- `bin/lint`

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

- Current tests cover importer idempotence and domain portfolio math, but no test currently drives bars -> strategy -> fills -> result store.
- `bin/test` also runs Flutter tests; this may expose environment blockers unrelated to Go backtest code and must be reported with actual output.
- `bin/lint` runs Go vet and Flutter analyze; final milestone verification requires it only after fixture path is implemented.

### 심볼 참조

- renamed/removed symbols: none.
- New symbols from `01_worker_lifecycle` and `02+01_result_store` must be referenced by deterministic fixture tests.

### 분할 판단

Split policy를 먼저 평가했다. 이 task directory는 `03+01,02_fixture_verification`이며 `01_worker_lifecycle`과 `02+01_result_store` 둘 다의 `complete.log`에 의존한다. Fixture verification is deliberately last because failures should point to integrated behavior, not missing lifecycle/storage foundation.

### 범위 결정 근거

이 plan은 deterministic fixture와 final verification만 다룬다. New trading strategy catalog, advanced performance metrics, live/paper trading, API/client UI are out of scope.

### 빌드 등급

build=`local-G06`, review=`cloud-G06`. Work is test-heavy and deterministic, but it depends on two prior subtasks and full workspace scripts.

## 의존 관계 및 구현 순서

이 task directory 이름은 `03+01,02_fixture_verification`이다. 같은 task group의 `01_worker_lifecycle`과 `02+01_result_store`가 모두 `complete.log`를 만든 뒤 시작한다.

## 구현 체크리스트

- [ ] fixture daily bars와 deterministic test strategy를 추가한다.
- [ ] engine execution이 동일 fixture와 strategy 입력에서 동일 result를 두 번 생성함을 검증한다.
- [ ] result store 조회가 expected starting cash, ending equity, trades/positions summary를 반환함을 검증한다.
- [ ] `bin/test`와 `bin/lint`를 실행해 fixture-test 검증 조건을 충족한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] Deterministic fixture full path

#### 문제

현재 `packages/domain/backtest/types_test.go:54`-`116`은 portfolio fill/equity 계산만 검증한다. Worker 쪽에는 fixture bars가 strategy execution과 result persistence를 거쳐 같은 결과를 내는 테스트가 없다.

```go
func TestPortfolioStateAppliesFillsAndCalculatesEquity(t *testing.T) {
	state := NewPortfolioState(price("1000"))
	// domain-only portfolio checks...
}
```

#### 해결 방법

`services/worker/internal/backtest/engine_test.go` 또는 `services/worker/internal/backtest/fixture_test.go`에 in-memory bar source, strategy, result store를 둔다. 동일 fixture를 두 번 실행해 `backtest.Result` 전체가 동일한지 비교하고, expected cash/equity/trades/positions를 명시한다.

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

- [ ] `services/worker/internal/backtest/fixture_test.go`
- [ ] 필요한 경우 `services/worker/internal/backtest/testdata/*.json`
- [ ] 필요하면 `services/worker/internal/backtest/engine.go`의 public test seam 조정

#### 테스트 작성

작성한다.

- `TestEngineProducesDeterministicResultFromFixtureBars`: 동일 input 두 번 실행 결과가 `cmp` 또는 manual equality로 동일
- `TestEngineStoresAndQueriesFixtureResult`: result store fake 또는 in-memory store에서 조회 결과가 expected summary와 동일

#### 중간 검증

```bash
go test ./services/worker/...
```

기대 결과: exit code 0. Fresh execution이 필요하므로 cache가 의심되면 `go test -count=1 ./services/worker/...`로 대체하고 reason을 review stub에 기록한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/worker/internal/backtest/fixture_test.go` | TEST-1 |
| `services/worker/internal/backtest/testdata/*.json` | TEST-1 |
| `services/worker/internal/backtest/engine.go` | TEST-1 |

## 최종 검증

```bash
go test ./services/worker/...
bin/test
bin/lint
```

기대 결과: 모든 명령 exit code 0. `bin/test` 또는 `bin/lint`가 Flutter/toolchain 환경 때문에 막히면 `command -v flutter` 결과와 실제 stderr를 review stub의 `사용자 리뷰 요청` 또는 검증 결과에 기록한다.

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