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

# Plan - KIS Provider Foundation

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

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

## 배경

Korea Daily Data Foundation은 KIS credential 없이 mock/fixture 기반으로 먼저 검증한다. 현재 domain model은 instrument와 bar만 있고 provider selector, KIS daily response normalization, KRX date/currency 기본선이 없다. 이 작업은 후속 import/storage pipeline이 소비할 안정적인 provider boundary를 만든다.

## 사용자 리뷰 요청 흐름

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

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/data-foundation/PHASE.md`
- `agent-roadmap/phase/data-foundation/milestones/korea-daily-data-foundation.md`
- `agent-ops/rules/project/domain/domain-model/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `packages/domain/market/types.go`
- `services/worker/internal/storage/ports.go`
- `services/worker/internal/storage/postgres/mapping.go`
- `services/worker/internal/storage/postgres/mapping_test.go`
- `services/worker/testdata/providers/kis/README.md`
- `services/worker/testdata/providers/kis/daily_itemchartprice_request.sample.json`
- `services/worker/testdata/providers/kis/daily_itemchartprice_response.sample.json`
- `services/worker/testdata/providers/kis/daily_bars_normalized.expected.json`
- `.agent-cache/koreainvestment/open-trading-api/examples_llm/domestic_stock/inquire_daily_itemchartprice/inquire_daily_itemchartprice.py`
- `.agent-cache/koreainvestment/open-trading-api/examples_llm/domestic_stock/inquire_daily_itemchartprice/chk_inquire_daily_itemchartprice.py`

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

- Provider-neutral universe selector: 기존 테스트 없음. 새 domain unit test 필요.
- KIS daily chart response normalization: 기존 테스트 없음. 새 worker provider fixture test 필요.
- KRX daily timestamp/currency default: 기존 테스트 없음. 새 worker provider fixture test 필요.

### 심볼 참조

none. 이 계획은 신규 타입/패키지 추가를 우선하며 기존 심볼 rename/remove는 하지 않는다.

### 분할 판단

Split decision policy를 먼저 평가했다. 공유 foundation 없이 import/storage/job을 바로 만들면 후속 작업이 provider API를 추정하게 되므로 분할한다.

- 공통 task group: `m-korea-daily-data-foundation`
- 현재 subtask: `01_provider_foundation`, 의존 없음
- 후속 subtask: `02+01_import_storage_pipeline`, `01_provider_foundation` 완료 필요
- 후속 subtask: `03+01,02_data_check_smoke`, `01_provider_foundation`과 `02+01_import_storage_pipeline` 완료 필요

### 범위 결정 근거

실제 KIS HTTP 호출, credential/1Password wiring, PostgreSQL migration, CLI smoke는 제외한다. 이 작업은 provider-neutral selector와 KIS mock fixture normalization까지만 닫는다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. domain과 worker 경계를 새로 만들고 후속 storage 작업의 API가 되므로 cloud review가 필요하다.

## 구현 체크리스트

- [ ] `packages/domain/market`에 provider-neutral universe selector와 provider symbol vocabulary를 추가하고 unit test를 작성한다.
- [ ] `services/worker/internal/providers/kis` 또는 동등한 worker-owned provider package에 KIS daily chart fixture decoder와 normalization 함수를 추가한다.
- [ ] KIS `output2` rows를 `market.Bar`로 변환할 때 `Asia/Seoul`, `KRX`, `KRW`, `TimeframeDaily` 기본선을 테스트한다.
- [ ] fixture JSON 전체가 secret-free이고 parser test에 사용되는지 검증한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [KIS_FOUNDATION-1] Domain Selector Vocabulary

문제: [types.go](/config/workspace/alt/packages/domain/market/types.go:37)는 `Instrument.ProviderSymbols`만 있고 watchlist, exchange-wide, sector-like selector를 표현할 타입이 없다.

해결 방법: `packages/domain/market/types.go`에 `Provider`, `UniverseSelectorKind`, `UniverseSelector`를 추가한다. 기존 `Instrument.ProviderSymbols map[string]string`은 유지하고, 새 타입은 provider-neutral request vocabulary로만 둔다.

Before:

```go
type Instrument struct {
	ID              InstrumentID
	Market          Market
	Venue           Venue
	Symbol          string
	Name            string
	Currency        Currency
	ProviderSymbols map[string]string
}
```

After:

```go
type Provider string

const ProviderKIS Provider = "kis"

type UniverseSelectorKind string

const (
	UniverseSelectorWatchlist UniverseSelectorKind = "watchlist"
	UniverseSelectorExchange  UniverseSelectorKind = "exchange"
	UniverseSelectorSector    UniverseSelectorKind = "sector"
)

type UniverseSelector struct {
	Kind    UniverseSelectorKind
	Market  Market
	Venue   Venue
	Symbols []string
	Name    string
}
```

수정 파일 및 체크리스트:

- [ ] `packages/domain/market/types.go`에 타입/상수 추가
- [ ] `packages/domain/market/types_test.go` 추가

테스트 작성: `TestUniverseSelectorVocabulary`를 추가해 watchlist/exchange/sector 값이 안정적인 string 값을 갖는지 확인한다.

중간 검증:

```bash
cd packages/domain && go test -count=1 ./market
```

### [KIS_FOUNDATION-2] KIS Fixture Decoder

문제: [daily_itemchartprice_response.sample.json](/config/workspace/alt/services/worker/testdata/providers/kis/daily_itemchartprice_response.sample.json:1)은 fixture로 존재하지만 이를 KIS response shape로 decode하는 worker package가 없다.

해결 방법: worker 내부에 `internal/providers/kis` package를 만들고 KIS daily item chart request/response structs, fixture loader test, response validation을 둔다.

수정 파일 및 체크리스트:

- [ ] `services/worker/internal/providers/kis/daily_itemchartprice.go` 추가
- [ ] `services/worker/internal/providers/kis/daily_itemchartprice_test.go` 추가
- [ ] fixture path는 `services/worker/testdata/providers/kis/*.json`을 사용

테스트 작성: `TestLoadDailyItemChartPriceFixture`에서 request endpoint/TR ID와 response `output1`, `output2` row count를 검증한다.

중간 검증:

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

### [KIS_FOUNDATION-3] KIS Row Normalization

문제: KIS row의 `stck_bsop_date`, `stck_oprc`, `stck_hgpr`, `stck_lwpr`, `stck_clpr`, `acml_vol`을 ALT `market.Bar`로 바꾸는 규칙이 없다.

해결 방법: `NormalizeDailyBars`를 추가해 KIS rows를 `market.Bar`로 변환한다. 날짜는 `Asia/Seoul` 자정, currency는 `KRW`, timeframe은 `1d`, instrument id는 provider symbol metadata에서 받은 `KRX:<symbol>`을 사용한다.

수정 파일 및 체크리스트:

- [ ] `services/worker/internal/providers/kis/daily_itemchartprice.go`에 normalization 함수 추가
- [ ] `services/worker/internal/providers/kis/daily_itemchartprice_test.go`에 expected normalized fixture 대조 추가

테스트 작성: `TestNormalizeDailyItemChartPriceBars`에서 [daily_bars_normalized.expected.json](/config/workspace/alt/services/worker/testdata/providers/kis/daily_bars_normalized.expected.json:1)의 두 bar와 완전 대조한다.

중간 검증:

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

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/domain/market/types.go` | KIS_FOUNDATION-1 |
| `packages/domain/market/types_test.go` | KIS_FOUNDATION-1 |
| `services/worker/internal/providers/kis/daily_itemchartprice.go` | KIS_FOUNDATION-2, KIS_FOUNDATION-3 |
| `services/worker/internal/providers/kis/daily_itemchartprice_test.go` | KIS_FOUNDATION-2, KIS_FOUNDATION-3 |

## 최종 검증

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

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