<!-- task=m-korea-daily-data-foundation/01_provider_foundation plan=1 tag=REVIEW_KIS_FOUNDATION -->

# Plan - Review Follow-up: Fixture-backed KIS Foundation Tests

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 구현의 마지막 단계다. 구현 중 사용자 결정, 외부 환경, 범위 충돌로 막히면 active review stub의 `사용자 리뷰 요청`에 정확한 근거를 남기고 멈춘다. `USER_REVIEW.md`, `complete.log`, archive 이동은 code-review 전용이다.

## 배경

1차 구현은 KIS daily response decoder와 `NormalizeDailyBars` 자체는 추가했지만, 계획이 요구한 fixture-backed 검증이 빠졌다. 특히 `daily_bars_normalized.expected.json`은 README와 계획에서 worker test가 소비해야 하는 expected fixture로 정의됐지만, 현재 테스트는 expected bar를 인라인으로 다시 만든다. 이 후속 작업은 fixture가 실제 parser/normalization 테스트의 계약이 되도록 복구한다.

## 사용자 리뷰 요청 흐름

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

## 분석 결과

### 읽은 파일

- `agent-task/m-korea-daily-data-foundation/01_provider_foundation/plan_cloud_G07_0.log`
- `agent-task/m-korea-daily-data-foundation/01_provider_foundation/code_review_cloud_G07_0.log`
- `agent-ops/rules/project/domain/domain-model/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `services/worker/internal/providers/kis/daily_itemchartprice_test.go`
- `services/worker/testdata/providers/kis/README.md`
- `services/worker/testdata/providers/kis/daily_bars_normalized.expected.json`
- `services/worker/testdata/providers/kis/provider_symbols.sample.json`

### Required issue source

- `PLAN-cloud-G07.md:158` and `PLAN-cloud-G07.md:160` required `TestNormalizeDailyItemChartPriceBars` to compare against `daily_bars_normalized.expected.json`.
- The archived review found `daily_itemchartprice_test.go` builds expected bars inline and does not read `daily_bars_normalized.expected.json` or `provider_symbols.sample.json`.

### 범위 결정

Production decoder/normalization API 변경은 기본 범위가 아니다. 테스트 fixture 소비와 검증 신뢰도 회복에 집중한다. 필요하면 test-only helper structs를 추가한다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. 실패 원인이 verification trust와 계획 완료성에 있고, 기존 route가 충분하므로 유지한다.

## 구현 체크리스트

- [ ] `daily_bars_normalized.expected.json`을 `daily_itemchartprice_test.go`에서 직접 decode하고 `NormalizeDailyBars` 결과와 instrument/currency/provider symbol 기대값을 fixture 기준으로 비교한다.
- [ ] `provider_symbols.sample.json`을 selector/provider symbol fixture로 test에서 직접 decode해 watchlist, exchange, sector selector와 KIS provider symbol vocabulary를 검증한다.
- [ ] fixture 사용 여부와 secret-free 상태를 deterministic command 출력으로 검증한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_KIS_FOUNDATION-1] Fixture-backed Parser Tests

문제: `daily_itemchartprice_test.go`가 expected normalized bars를 인라인으로 만들고 있어 `daily_bars_normalized.expected.json`이 깨져도 테스트가 실패하지 않는다. 또한 `provider_symbols.sample.json`도 README상 selector/provider symbol fixture지만 테스트에서 소비되지 않는다.

해결 방법:

- `daily_bars_normalized.expected.json`용 test-only struct를 추가해 expected instrument와 bars를 decode한다.
- `TestNormalizeDailyItemChartPriceBars`에서 hard-coded `want := []market.Bar{...}`를 제거하고 expected fixture에서 instrument와 bars를 만든다.
- `provider_symbols.sample.json`용 test-only struct 또는 generic struct를 추가해 provider, selector kind, venue/name/symbols, instrument provider_symbols 값을 검증한다.
- production package API는 불필요하게 넓히지 않는다. test-only helper로 충분하면 test file 안에 둔다.

Before:

```go
want := []market.Bar{
	newExpectedBar(t, "2024-05-27T00:00:00+09:00", "74800", "75600", "74400", "75000", "9100000"),
	newExpectedBar(t, "2024-05-28T00:00:00+09:00", "75200", "76200", "75100", "76000", "10500000"),
}
```

After:

```go
expected := decodeExpectedDailyBarsFixture(t)
inst := expected.instrument()
bars, err := NormalizeDailyBars(resp, inst)
// compare every bar against expected.bars()
```

수정 파일 및 체크리스트:

- [ ] `services/worker/internal/providers/kis/daily_itemchartprice_test.go`에서 expected normalized fixture decode helper 추가
- [ ] `services/worker/internal/providers/kis/daily_itemchartprice_test.go`에서 provider symbols fixture decode test 추가
- [ ] `services/worker/internal/providers/kis/daily_itemchartprice_test.go`에서 인라인 expected bar 재구성을 fixture 기반 비교로 교체

테스트 작성:

- `TestNormalizeDailyItemChartPriceBars`는 `daily_bars_normalized.expected.json`의 instrument id, currency, provider symbol, 두 bar의 timestamp/OHLCV/currency를 모두 비교해야 한다.
- 새 테스트 또는 기존 테스트 확장으로 `provider_symbols.sample.json`의 `provider == market.ProviderKIS`, selector kinds, `KRX` venue, `kis` provider symbol 값을 검증해야 한다.

중간 검증:

```bash
cd services/worker && go test -count=1 ./internal/providers/kis
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/worker/internal/providers/kis/daily_itemchartprice_test.go` | REVIEW_KIS_FOUNDATION-1 |

## 최종 검증

```bash
cd services/worker && go test -count=1 ./internal/providers/kis
cd packages/domain && go test -count=1 ./...
rg -n "daily_bars_normalized.expected.json|provider_symbols.sample.json" services/worker/internal/providers/kis/daily_itemchartprice_test.go
rg -n -i "appkey|appsecret|access_token|refresh_token|approval|authorization|secret|password|op://|account" services/worker/testdata/providers/kis/*.json
```

마지막 `rg` 명령은 secret-like JSON 매칭이 없으면 exit code 1이 정상이다. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
