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

# Plan - REVIEW_API

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

`CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 코드를 바꾸고 검증을 실행한 뒤 실제 구현 내용과 stdout/stderr를 리뷰 stub에 남기고, active 파일은 그대로 둔 채 리뷰 준비를 보고한다. 선택된 SDD 결정 또는 Milestone `구현 잠금 > 결정 필요` 항목이 막으면 리뷰 stub의 `사용자 리뷰 요청` 섹션에 정확한 연결 대상, 근거, 명령 출력, 재개 조건을 기록하고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`, `USER_REVIEW.md` 작성, log archive, `complete.log` 작성을 하지 않는다. 환경/secret/service 차단과 검증 증거 공백은 사용자 리뷰가 아니라 `검증 결과` 또는 후속 plan 대상으로 남긴다.

## 배경

첫 리뷰에서 `CheckBars`가 새 matrix `Rules`만으로 동작하지 않고 deprecated `Venues` map까지 요구하는 결함이 확인됐다. 이 작업은 matrix API foundation을 self-contained하게 만들고, 같은 결함이 다시 통과하지 않도록 rules-only 회귀 테스트를 추가한다. worker/KIS rollout은 sibling `02+01_kis_job_capability` 범위로 남긴다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 SDD 결정 또는 선택된 Milestone lock 결정이 실구현을 차단할 때만 active `CODE_REVIEW-local-G05.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 chat 질문은 금지이며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 판단한다.

## Archive Evidence Snapshot

- Archived plan: `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/plan_local_G05_0.log`
- Archived review: `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/code_review_local_G05_0.log`
- Verdict: FAIL
- Required summary:
  - `packages/domain/market/types.go:156`에서 `CheckBars`가 `Rules`를 평가하기 전에 deprecated `c.Venues`를 필수 precondition으로 사용해, `Rules`만 채운 capability를 항상 unsupported venue로 거절한다.
  - `packages/domain/market/types_test.go:168`의 matrix test는 `Venues`/`Timeframes`도 함께 채워 이 결함을 가린다.
- Affected files:
  - `packages/domain/market/types.go`
  - `packages/domain/market/types_test.go`
- Verification evidence:
  - 리뷰 중 `go test ./packages/domain/... ./services/worker/...`는 exit code 0으로 통과했으나, 현 테스트는 rules-only capability path를 검증하지 않는다.
- Narrow reread allowed if needed:
  - `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/code_review_local_G05_0.log`
  - `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/plan_local_G05_0.log`

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-roadmap/current.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/code-review/SKILL.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-ops/rules/project/domain/domain-model/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/domain-model-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/plan_local_G05_0.log`
- `agent-task/m-backtest-multi-timeframe-coverage/01_domain_capability_matrix/code_review_local_G05_0.log`
- `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`
- `services/worker/internal/providers/kis/daily_itemchartprice.go`
- `services/worker/cmd/alt-worker/main.go`

### 테스트 환경 규칙

- test_env: `local`
- env rules: `agent-test/local/rules.md` 존재 및 정독 완료
- matched profiles: `agent-test/local/domain-model-smoke.md`, `agent-test/local/worker-smoke.md`
- 적용 명령:
  - bug fix 회귀 확인: `go test -count=1 ./packages/domain/market`
  - domain/worker compatibility 확인: `go test ./packages/domain/... ./services/worker/...`
- Go test cache 정책: 첫 번째 회귀 명령은 fresh 실행을 위해 `-count=1`을 사용한다. 두 번째 compatibility 명령은 cache output 허용.
- fallback: 없음

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

- 기존 `TestProviderCapabilityMatrix`는 `ProviderCapability.Rules`와 함께 legacy `Venues`/`Timeframes`도 채워서, 새 matrix API가 rules-only capability에서도 작동하는지 검증하지 않는다.
- 후속 작업은 rules-only capability daily accepted 및 monthly/minute rejected reason을 반드시 검증한다.

### 심볼 참조

- 변경 대상 심볼: `market.ProviderCapability.CheckBars`
- renamed/removed symbols: 없음
- 관련 call sites:
  - `packages/domain/market/types_test.go`
  - `services/worker/internal/jobs/marketdata_jobs.go`는 아직 `RequireDailyBars` 호환 wrapper를 사용한다.
  - `services/worker/internal/providers/kis/daily_itemchartprice.go`는 현재 legacy `Venues`/`Timeframes` struct literal을 반환하며 worker rollout은 이 작업 범위 밖이다.

### 분할 판단

- split decision policy를 후속 plan 작성 전에 적용했다.
- 기존 split task group `agent-task/m-backtest-multi-timeframe-coverage/`와 subtask `01_domain_capability_matrix`를 유지한다.
- 이 후속은 선행 subtask 내부의 Required 리뷰 이슈만 고치는 작업이며, API foundation과 worker rollout을 다시 섞지 않는다.
- 수정 범위가 `types.go`와 `types_test.go`로 제한되어 추가 split은 필요하지 않다.

### 범위 결정 근거

- 포함: `packages/domain/market/types.go`, `packages/domain/market/types_test.go`
- 제외: `services/worker/**`, `services/worker/internal/providers/kis/**`, `.proto`, API socket, CLI runner, 실제 KIS capability table rollout. worker/KIS 적용은 sibling `02+01_kis_job_capability`가 담당한다.

### 빌드 등급

- build: `local-G05`
- review: `local-G05`
- 근거: 변경은 두 domain 파일로 좁지만 public domain API의 self-contained behavior와 회귀 테스트를 함께 보정해야 한다.

## 구현 체크리스트

- [ ] `CheckBars`가 `Rules`만 채운 `ProviderCapability`에서도 provider/market/venue/asset type/timeframe 판정을 수행하도록 legacy `Venues` precondition을 수정한다.
- [ ] domain tests에 rules-only capability 회귀 케이스를 추가해 KR/US daily accepted와 monthly/minute rejected reason을 검증한다.
- [ ] `go test -count=1 ./packages/domain/market`와 `go test ./packages/domain/... ./services/worker/...`를 실행해 domain behavior와 기존 worker call-site compile을 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_API-1] Make matrix capability self-contained

문제:
- `packages/domain/market/types.go:156`에서 `CheckBars`가 `Rules` 평가 전에 `c.Venues[req.Venue]`를 검사한다. 이 때문에 새 matrix API 사용자가 legacy compatibility map을 채우지 않으면 rule이 있어도 거절된다.
- `packages/domain/market/types_test.go:168`의 현재 test fixture는 legacy map까지 함께 채워 이 결함을 잡지 못한다.

해결 방법:
- `CheckBars`의 venue support 판단을 `Rules` 기반으로 옮긴다.
- legacy `Venues` map을 유지해야 하면 `len(c.Venues) > 0`일 때만 compatibility prefilter로 사용하거나, rules matching 결과가 없을 때의 legacy fallback으로만 사용한다.
- provider mismatch, unknown venue, market/venue mismatch reason은 기존 stable text를 유지한다.

Before (`packages/domain/market/types.go:149`):

```go
func (c ProviderCapability) CheckBars(req ProviderCapabilityRequest) ProviderCapabilityDecision {
	if req.Provider != c.Provider {
		return ProviderCapabilityDecision{
			Accepted: false,
			Reason:   fmt.Sprintf("provider %q does not match capability provider %q", req.Provider, c.Provider),
		}
	}
	if !c.Venues[req.Venue] {
		return ProviderCapabilityDecision{
			Accepted: false,
			Reason:   fmt.Sprintf("provider %q does not support venue %q", req.Provider, req.Venue),
		}
	}
```

After 방향:

```go
func (c ProviderCapability) CheckBars(req ProviderCapabilityRequest) ProviderCapabilityDecision {
	if req.Provider != c.Provider {
		return ProviderCapabilityDecision{
			Accepted: false,
			Reason:   fmt.Sprintf("provider %q does not match capability provider %q", req.Provider, c.Provider),
		}
	}
	meta, ok := GetVenueMetadata(req.Venue)
	if !ok {
		return ProviderCapabilityDecision{
			Accepted: false,
			Reason:   fmt.Sprintf("provider %q does not support venue %q", req.Provider, req.Venue),
		}
	}
	if len(c.Venues) > 0 && !c.Venues[req.Venue] {
		return ProviderCapabilityDecision{
			Accepted: false,
			Reason:   fmt.Sprintf("provider %q does not support venue %q", req.Provider, req.Venue),
		}
	}
	// Continue with market validation and rule matching.
}
```

수정 파일 및 체크리스트:
- [ ] `packages/domain/market/types.go`: `CheckBars`가 rules-only capability를 허용하도록 precondition 순서와 조건을 수정한다.
- [ ] `packages/domain/market/types.go`: 기존 stable rejection reason을 유지한다.
- [ ] `packages/domain/market/types_test.go`: rules-only capability fixture를 사용한 accepted/rejected regression을 추가한다.

테스트 작성:
- 작성: `packages/domain/market/types_test.go`
- test name: `TestProviderCapabilityMatrixRulesOnly` 또는 기존 `TestProviderCapabilityMatrix` 내 명확한 subcases
- assertion goal:
  - `ProviderCapability{Provider: ProviderKIS, Rules: ...}`만으로 KR/KRX equity daily accepted
  - US/NASDAQ ETF daily accepted
  - monthly, `TimeframeMin1`, `TimeframeMin5` rejected reason 유지
  - unknown venue와 no matching rule reason 유지

중간 검증:

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

기대 결과: exit code 0.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/domain/market/types.go` | REVIEW_API-1 |
| `packages/domain/market/types_test.go` | REVIEW_API-1 |

## 최종 검증

```bash
go test -count=1 ./packages/domain/market
go test ./packages/domain/... ./services/worker/...
```

기대 결과: 두 명령 모두 exit code 0. 첫 번째 명령은 fresh 실행이어야 하며, 두 번째 명령의 Go test cache output은 허용한다.

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