<!-- task=m-korea-daily-data-foundation/02+01_import_storage_pipeline plan=1 tag=REVIEW_KIS_IMPORT -->

# Plan - Daily Bar Import Payload Contract Follow-up

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

이 plan은 직전 code-review FAIL의 Required 항목만 보완한다. 구현 완료 전 active `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 채운다. 구현 중 사용자 결정, 외부 환경 준비, 또는 범위 충돌로 멈춰야 하면 review stub의 `사용자 리뷰 요청`에 근거와 재개 조건을 기록하고 active 파일을 그대로 둔다. `USER_REVIEW.md`, log archive, `complete.log` 작성은 code-review가 소유한다.

## 배경

`KindImportDailyBars` payload는 `provider`, `from`, `to`를 받지만 현재 handler는 selector만 importer로 넘긴다. 이로 인해 job payload의 provider/date range 계약이 실제 import 동작에 반영되지 않는다. 직전 리뷰에서는 구현 체크리스트 문구도 plan 원문과 달라져 loop protocol 보완이 필요하다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 검증과 종료 처리를 소유한다.

## 분석 결과

### 읽은 파일

- `agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline/plan_cloud_G07_0.log`
- `agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline/code_review_cloud_G07_0.log`
- `agent-roadmap/phase/data-foundation/PHASE.md`
- `agent-roadmap/phase/data-foundation/milestones/korea-daily-data-foundation.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-ops/rules/project/domain/domain-model/rules.md`
- `services/worker/internal/marketdata/importer/importer.go`
- `services/worker/internal/marketdata/importer/importer_test.go`
- `services/worker/internal/jobs/marketdata_jobs.go`
- `services/worker/internal/jobs/marketdata_jobs_test.go`
- `services/worker/internal/jobs/job.go`
- `services/worker/internal/jobs/builtin.go`
- `services/worker/internal/jobs/runner.go`
- `services/worker/internal/jobs/runner_test.go`
- `services/worker/internal/storage/ports.go`
- `services/worker/internal/storage/postgres/store.go`
- `services/worker/internal/storage/postgres/mapping.go`
- `services/worker/internal/storage/postgres/queries/queries.sql`
- `services/worker/internal/storage/postgres/migrations/000001_worker_backbone.up.sql`
- `services/worker/internal/providers/kis/daily_itemchartprice.go`
- `services/worker/internal/providers/kis/daily_itemchartprice_test.go`
- `services/worker/testdata/providers/kis/provider_symbols.sample.json`
- `services/worker/testdata/providers/kis/daily_bars_normalized.expected.json`
- `packages/domain/market/types.go`
- `packages/domain/market/types_test.go`

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

- Job payload provider/date range: 기존 `TestRegisterDailyBarImportHandlerDispatchesImporter`는 payload에 `provider/from/to`를 넣지만 importer로 전달되는지 검증하지 않는다.
- Provider mismatch/missing provider: 현재 decode path에서 provider required 여부와 expected provider mismatch가 검증되지 않는다.
- Review checklist protocol: 현재 루프 파일에서 checklist text drift가 발생했으므로 후속 review stub은 plan과 item text/order를 그대로 유지해야 한다.

### 심볼 참조

- `ImportDailyBars(ctx, selector)` call sites: `services/worker/internal/jobs/marketdata_jobs.go`, `services/worker/internal/marketdata/importer/importer_test.go`.
- `FetchDailyBars(ctx, selector)` implementations/call sites: `services/worker/internal/marketdata/importer/importer.go`, `services/worker/internal/marketdata/importer/importer_test.go`.
- `RegisterDailyBarImportHandler(runner, imp)` call sites: `services/worker/internal/jobs/marketdata_jobs_test.go`.

### 분할 판단

Single follow-up plan으로 둔다. payload contract pass-through와 review checklist protocol 보완은 같은 failed review에서 나온 좁은 보완이며, 변경 파일이 `services/worker/internal/jobs`, `services/worker/internal/marketdata/importer`, active review stub으로 한정된다. 별도 subtask로 나누면 같은 handler/importer interface를 두 번 흔들어 조정 비용이 더 크다.

### 범위 결정 근거

실제 KIS HTTP client, credential wiring, PostgreSQL schema, roadmap 상태 갱신은 제외한다. `agent-task/archive/**`는 사용자가 명시하지 않았으므로 읽지 않는다. Provider/date range는 현재 job/importer 내부 계약과 tests까지만 통과시키고, live provider behavior는 이후 smoke 단계에서 다룬다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. worker job boundary와 importer interface를 함께 조정하고 직전 리뷰에서 verification/protocol 보완이 필요했으므로 같은 route를 유지한다.

## 구현 체크리스트

- [ ] `KindImportDailyBars` payload의 `provider`, `from`, `to`가 검증되고 importer/provider 요청까지 전달되도록 job/importer 내부 계약을 보완한다.
- [ ] payload provider/date range 전달과 provider mismatch를 검증하는 regression tests를 작성한다.
- [ ] CODE_REVIEW-*-G??.md의 `구현 체크리스트` item text/order를 이 plan과 동일하게 유지하고 근거는 전용 섹션에만 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_KIS_IMPORT-1] Payload Contract Pass-through

문제: [marketdata_jobs.go](/config/workspace/alt/services/worker/internal/jobs/marketdata_jobs.go:19)는 payload가 provider와 optional date range를 담는다고 설명하지만 [selector()](/config/workspace/alt/services/worker/internal/jobs/marketdata_jobs.go:34)는 `Provider`, `From`, `To`를 버리고 [RegisterDailyBarImportHandler](/config/workspace/alt/services/worker/internal/jobs/marketdata_jobs.go:70)는 selector만 importer에 전달한다.

해결 방법: importer boundary에 selector 이상의 request 타입을 둔다. `provider`는 required로 decode하고, handler registration은 expected provider를 받아 payload provider mismatch를 error로 반환한다. `from`/`to`는 `YYYYMMDD`로 검증해 request에 포함한다.

Before:

```go
type DailyBarImporter interface {
	ImportDailyBars(ctx context.Context, selector market.UniverseSelector) (importer.Result, error)
}

type DailyBarProvider interface {
	FetchDailyBars(ctx context.Context, selector market.UniverseSelector) ([]InstrumentBars, error)
}
```

After:

```go
type DailyBarRequest struct {
	Provider market.Provider
	Selector market.UniverseSelector
	From     time.Time
	To       time.Time
}

type DailyBarProvider interface {
	FetchDailyBars(ctx context.Context, request DailyBarRequest) ([]InstrumentBars, error)
}

type DailyBarImporter interface {
	ImportDailyBars(ctx context.Context, request importer.DailyBarRequest) (importer.Result, error)
}

func RegisterDailyBarImportHandler(runner *Runner, expectedProvider market.Provider, imp DailyBarImporter)
```

수정 파일 및 체크리스트:

- [ ] `services/worker/internal/marketdata/importer/importer.go`에 `DailyBarRequest`를 추가하고 provider interface/import method가 request를 받도록 변경한다.
- [ ] 새 request 타입을 위해 필요한 `time` import를 추가하고 기존 nil provider/stores guard는 유지한다.
- [ ] `services/worker/internal/marketdata/importer/importer_test.go`의 fake provider가 request를 기록하게 바꾸고 selector/provider/date range pass-through를 검증한다.
- [ ] `services/worker/internal/jobs/marketdata_jobs.go`에서 `provider` required, expected provider mismatch, `from`/`to` date format을 검증하고 request를 importer에 전달한다.
- [ ] `services/worker/internal/jobs/marketdata_jobs_test.go`에서 `RegisterDailyBarImportHandler` call site를 갱신하고 provider/date range 전달, provider mismatch error를 검증한다.

테스트 작성: `TestRegisterDailyBarImportHandlerDispatchesImporter`는 `provider/from/to`가 importer request에 보존되는지 assert한다. `TestDecodeDailyBarImportPayloadRejectsMissingFields` 또는 새 `TestRegisterDailyBarImportHandlerRejectsProviderMismatch`에서 missing provider, mismatch provider, invalid date format을 검증한다. `TestImporterStoresInstrumentAndBars`는 fake provider가 받은 request의 selector/provider/date range를 검증한다.

중간 검증:

```bash
cd services/worker && go test -count=1 ./internal/jobs ./internal/marketdata/importer
```

### [REVIEW_KIS_IMPORT-2] Review Stub Checklist Contract

문제: [code_review_cloud_G07_0.log](/config/workspace/alt/agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline/code_review_cloud_G07_0.log:30)의 `구현 체크리스트`는 직전 plan 원문에 구현 근거를 덧붙여 plan/review item text 일치 규칙을 깨뜨렸다.

해결 방법: 이번 active `CODE_REVIEW-cloud-G07.md`에서는 `구현 체크리스트`의 checkbox만 변경한다. 구현 근거, 설계 결정, 검증 출력은 `계획 대비 변경 사항`, `주요 설계 결정`, `검증 결과`에 기록한다.

수정 파일 및 체크리스트:

- [ ] `agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline/CODE_REVIEW-cloud-G07.md`의 `구현 체크리스트` item text/order를 변경하지 않는다.

테스트 작성: 코드 테스트는 쓰지 않는다. code-review protocol artifact 보완이며, 최종 리뷰에서 plan/review checklist text/order를 대조한다.

중간 검증:

```bash
cd agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline
diff -u \
  <(awk '/^## 구현 체크리스트$/{flag=1;next}/^### \\[/{flag=0}flag && /^- \\[[ x]\\] /{sub(/^- \\[[ x]\\] /,""); print}' PLAN-cloud-G07.md) \
  <(awk '/^## 구현 체크리스트$/{flag=1;next}/^## 코드리뷰 전용 체크리스트$/{flag=0}flag && /^- \\[[ x]\\] /{sub(/^- \\[[ x]\\] /,""); print}' CODE_REVIEW-cloud-G07.md)
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/worker/internal/marketdata/importer/importer.go` | REVIEW_KIS_IMPORT-1 |
| `services/worker/internal/marketdata/importer/importer_test.go` | REVIEW_KIS_IMPORT-1 |
| `services/worker/internal/jobs/marketdata_jobs.go` | REVIEW_KIS_IMPORT-1 |
| `services/worker/internal/jobs/marketdata_jobs_test.go` | REVIEW_KIS_IMPORT-1 |
| `agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline/CODE_REVIEW-cloud-G07.md` | REVIEW_KIS_IMPORT-2 |

## 최종 검증

```bash
cd services/worker && go test -count=1 ./internal/jobs ./internal/marketdata/importer ./internal/storage/...
cd services/worker && go build ./... && go vet ./internal/jobs ./internal/marketdata/importer
cd agent-task/m-korea-daily-data-foundation/02+01_import_storage_pipeline
diff -u \
  <(awk '/^## 구현 체크리스트$/{flag=1;next}/^### \\[/{flag=0}flag && /^- \\[[ x]\\] /{sub(/^- \\[[ x]\\] /,""); print}' PLAN-cloud-G07.md) \
  <(awk '/^## 구현 체크리스트$/{flag=1;next}/^## 코드리뷰 전용 체크리스트$/{flag=0}flag && /^- \\[[ x]\\] /{sub(/^- \\[[ x]\\] /,""); print}' CODE_REVIEW-cloud-G07.md)
```

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