<!-- task=m-backtest-multi-timeframe-coverage/02+01_kis_job_capability plan=1 tag=REVIEW_API -->

# Plan - REVIEW_API

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

이 follow-up은 직전 코드리뷰의 Required issue 하나만 해결한다. 구현 중 사용자에게 직접 질문하거나 `USER_REVIEW.md`, `complete.log`, log archive를 만들지 않는다. 선택된 SDD 결정 또는 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 active `CODE_REVIEW-local-G05.md`의 `사용자 리뷰 요청` 섹션에 기록하고 멈춘다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/backtest-loop/milestones/backtest-multi-timeframe-coverage.md`
- Task ids:
  - `capability-matrix`: provider, market, venue, asset type, timeframe별 지원/미지원 사유를 capability matrix로 표현한다.
- Completion mode: check-on-pass

## Spec Targets

- SDD: `agent-roadmap/sdd/backtest-loop/backtest-multi-timeframe-coverage/SDD.md`
- Acceptance scenarios:
  - `S02`: task=`capability-matrix`; evidence=`capability matrix accepted/rejected tests for KIS KR/US daily, minute, monthly with explicit rejection reasons`
- Completion mode: spec-check-on-pass

## Archive Evidence Snapshot

- Archived plan: `agent-task/m-backtest-multi-timeframe-coverage/02+01_kis_job_capability/plan_local_G06_0.log`
- Archived review: `agent-task/m-backtest-multi-timeframe-coverage/02+01_kis_job_capability/code_review_local_G06_0.log`
- Verdict: FAIL
- Required summary:
  - `services/worker/internal/jobs/marketdata_jobs.go:113` passes `DailyBarImportPayload.Market` directly into `ProviderCapabilityRequest`.
  - `DecodeDailyBarImportPayload` does not require `market`, and the previous `RequireDailyBars` path allowed an empty selector market.
  - `packages/domain/market/types.go:186` matches rules with `rule.Market != req.Market`, so an otherwise valid payload with `venue` but no `market` now rejects before importer dispatch.
- Affected files:
  - `packages/domain/market/types.go`
  - `packages/domain/market/types_test.go`
  - `services/worker/internal/jobs/marketdata_jobs.go`
  - `services/worker/internal/jobs/marketdata_jobs_test.go`
- Verification evidence from failed loop:
  - Review agent ran `gofmt -w services/worker/internal/jobs/marketdata_jobs_test.go services/worker/internal/providers/kis/daily_itemchartprice.go services/worker/internal/providers/kis/daily_itemchartprice_test.go` to repair formatting-only drift.
  - Review agent reran `go test ./packages/domain/... ./services/worker/...`; exit code 0, but the optional-market compatibility case was not covered.
- Roadmap/spec carryover:
  - Keep the same `Roadmap Targets` and `Spec Targets`; this follow-up still works toward `capability-matrix` and SDD `S02`.
- Narrow reread allowed:
  - The next implementer may read the two archived logs listed above and the predecessor complete evidence `agent-task/archive/2026/06/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/complete.log` if dependency context is needed.

## 범위 결정 근거

- 포함: `ProviderCapability.CheckBars` empty-market matching semantics, daily import job accepted regression tests, targeted domain/job verification.
- 제외: KIS provider matrix rows, proto/API schema, monthly aggregation, minute import endpoint, storage/backtest behavior. 이 follow-up은 새 기능 확장이 아니라 기존 daily import payload 호환성 회복이다.

## 빌드 등급

- build: `local-G05`
- review: `local-G05`
- 근거: 수정 범위가 domain matrix helper와 worker job test에 한정되고, deterministic Go tests로 닫힌다.

## 구현 체크리스트

- [ ] `ProviderCapability.CheckBars`가 `req.Market == ""`일 때 `GetVenueMetadata(req.Venue).Market`을 effective market으로 사용해 rule matching을 수행하고, non-empty market/venue mismatch는 계속 reject하게 한다.
- [ ] `packages/domain/market/types_test.go`에 empty-market KR/KRX daily accepted와 US/NASDAQ daily accepted 회귀 테스트를 추가하고, 기존 market/venue mismatch reject coverage가 유지되는지 확인한다.
- [ ] `services/worker/internal/jobs/marketdata_jobs_test.go`에 `market`을 생략한 KIS daily import payload가 importer로 dispatch되는 회귀 테스트를 추가한다.
- [ ] `gofmt -l packages/domain/market/types.go packages/domain/market/types_test.go services/worker/internal/jobs/marketdata_jobs.go services/worker/internal/jobs/marketdata_jobs_test.go`와 `go test ./packages/domain/market ./services/worker/internal/jobs`를 실행한다.
- [ ] 최종 검증으로 `go test ./packages/domain/... ./services/worker/...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_API-1] Optional market compatibility for matrix gate

문제:
`DailyBarImportPayload.Market`은 decode 단계에서 필수 필드가 아니다. 기존 `RequireDailyBars`는 selector market이 비어 있으면 venue metadata만으로 market consistency를 확인해 통과할 수 있었다. 새 job gate는 `CheckBars`에 빈 market을 그대로 넘기며, `CheckBars`는 rule matching에서 `rule.Market != req.Market`을 비교하므로 기존 valid payload를 reject한다.

해결 방법:
`CheckBars` 내부에서 venue metadata를 얻은 뒤 effective market을 계산한다.

Before:

```go
for _, rule := range c.Rules {
	if rule.Market != req.Market || rule.Venue != req.Venue {
		continue
	}
	...
}
```

After:

```go
effectiveMarket := req.Market
if effectiveMarket == "" {
	effectiveMarket = meta.Market
}
for _, rule := range c.Rules {
	if rule.Market != effectiveMarket || rule.Venue != req.Venue {
		continue
	}
	...
}
```

주의:
- `req.Market != "" && req.Market != meta.Market` rejection은 유지한다.
- rejection reason에 market을 출력할 때는 필요하면 effective market을 사용하되, 기존 exact tests를 과도하게 깨지 않게 조정한다.
- job handler가 payload를 mutation해서 importer request의 selector market을 새로 채우는 방식은 피한다. 기존 payload schema와 request conversion 의미를 유지하는 것이 목표다.

수정 파일 및 체크리스트:

- [ ] `packages/domain/market/types.go`: effective market rule matching 적용
- [ ] `packages/domain/market/types_test.go`: empty-market matrix accepted tests 추가
- [ ] `services/worker/internal/jobs/marketdata_jobs_test.go`: no-market payload dispatch test 추가

중간 검증:

```bash
gofmt -l packages/domain/market/types.go packages/domain/market/types_test.go services/worker/internal/jobs/marketdata_jobs.go services/worker/internal/jobs/marketdata_jobs_test.go
go test ./packages/domain/market ./services/worker/internal/jobs
```

기대 결과: `gofmt -l` 출력 없음, `go test` exit code 0.

## 최종 검증

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

기대 결과: exit code 0. Go test cache output은 허용한다.

