<!-- task=m-scheduled-market-data-refresh/05+04_backtest_readiness plan=1 tag=REVIEW_cloud-G08 -->

# Plan - REVIEW_cloud-G08 Backtest Readiness Evidence Fix

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

이 follow-up plan은 직전 code review FAIL의 Required findings만 해결한다. 사용자에게 직접 질문하지 말고, selected Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 막는 경우에만 `CODE_REVIEW_cloud_G08.md`의 `사용자 리뷰 요청` 섹션을 채운다. remote endpoint, token, credential, 개인 host 원문은 tracked 파일에 기록하지 않는다.

## Roadmap Targets

- `agent-roadmap/phase/backtest-loop/milestones/scheduled-market-data-refresh.md`
  - Handoff epic: `[backtest-readiness] remote runner`

## Archive Evidence Snapshot

- Current archived plan: `agent-task/m-scheduled-market-data-refresh/05+04_backtest_readiness/plan_cloud_G08_0.log`
- Current archived review: `agent-task/m-scheduled-market-data-refresh/05+04_backtest_readiness/code_review_cloud_G08_0.log`
- Verdict: FAIL
- Required summary:
  - `CODE_REVIEW_cloud_G08.md:44`: SDD S05 remote runner evidence after scheduler tick was not collected.
  - `apps/cli/testdata/operator/scheduled_backtest_readiness.yaml:18` / `apps/cli/internal/operator/runner.go:1284`: scenario documents `imported_bar_count > 0`, but runner only enforces `scheduler_status`.
- Affected files:
  - `apps/cli/internal/operator/scenario.go`
  - `apps/cli/internal/operator/runner.go`
  - `apps/cli/internal/operator/runner_market_test.go`
  - `apps/cli/internal/operator/runner_backtest_test.go`
  - `apps/cli/testdata/operator/scheduled_backtest_readiness.yaml`
  - `apps/cli/testdata/operator/expected/scheduled_backtest_readiness.jsonl` if output changes
  - `apps/cli/testdata/operator/headless_validation.md` if PASS criteria wording changes
  - `CODE_REVIEW_cloud_G08.md`
- Verification evidence from archived review:
  - `go test -count=1 ./apps/cli/internal/operator -run 'Test(ScheduledBacktestReadiness|HeadlessValidationHandoff|ExpectedOutputFixtures)'` passed locally.
  - `go test -count=1 ./apps/cli/...` passed locally.
  - `go test -count=1 ./services/api/...` passed locally.
  - `go test -count=1 ./services/worker/...` passed locally.
  - `gofmt -l apps/cli/internal/operator/runner_backtest_test.go apps/cli/internal/operator/handoff_test.go` produced no output for changed Go files.
- Roadmap carryover:
  - SDD S05 requires remote runner smoke after scheduler tick and exit code `0` evidence.
  - Do not modify `agent-roadmap/**` in this follow-up. PASS completion metadata will carry `backtest-readiness`; runtime owns roadmap updates.
- Allowed narrow archive reread:
  - `agent-task/m-scheduled-market-data-refresh/05+04_backtest_readiness/plan_cloud_G08_0.log`
  - `agent-task/m-scheduled-market-data-refresh/05+04_backtest_readiness/code_review_cloud_G08_0.log`

## 구현 체크리스트

- [ ] [REVIEW_cloud-G08-1] `scheduler_refresh_status` expect가 scheduler-backed readiness의 imported bar count 최소값을 강제하게 한다.
- [ ] [REVIEW_cloud-G08-2] `scheduled_backtest_readiness` fixture와 tests가 `imported_bar_count >= 1` 실패 케이스와 success 케이스를 모두 고정한다.
- [ ] [REVIEW_cloud-G08-3] scheduler enabled remote runner에서 S05 readiness scenario를 실행하고 transcript/artifact evidence를 review 파일에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 구현 항목

### [REVIEW_cloud-G08-1] Imported bar count expectation enforcement

- 문제: `scheduled_backtest_readiness.yaml`은 주석과 handoff 문서에서 `imported_bar_count > 0`을 PASS 기준으로 선언하지만, runner는 `scheduler_status`만 비교한다.
- 해결:
  - `apps/cli/internal/operator/scenario.go`의 `Expect`에 scheduler refresh status 전용 최소 imported bar count 필드를 추가한다. 권장 이름은 `min_imported_bar_count`이며, 음수 값은 validation error로 거부한다.
  - `evaluateSchedulerRefreshStatus`에서 response entry의 `ImportedBarCount`가 최소값보다 작으면 `statusMismatch`와 non-zero exit code를 반환한다.
  - 필드는 `scheduler_refresh_status` action에서만 의미 있게 사용하고, 다른 action에 잘못 쓰면 validation error로 막는다.
- 중간 검증:
  - `go test -count=1 ./apps/cli/internal/operator -run 'TestRunScenarioRefreshStatus'`

### [REVIEW_cloud-G08-2] Fixture/test coverage

- 문제: 현재 local golden은 imported bar count가 출력되는지만 확인하므로, count가 0일 때 readiness scenario가 실패하는지 보장하지 않는다.
- 해결:
  - `apps/cli/testdata/operator/scheduled_backtest_readiness.yaml`의 first step expect에 `min_imported_bar_count: 1`을 추가한다.
  - `runner_backtest_test.go` 또는 `runner_market_test.go`에 imported count가 0이면 mismatch/non-zero exit code가 되는 test를 추가한다.
  - 기존 `TestScheduledBacktestReadinessFixture` success path와 exact-match golden을 유지한다.
  - output key가 바뀌면 expected JSONL과 handoff matrix를 함께 갱신하고, 바뀌지 않으면 golden drift를 만들지 않는다.
- 중간 검증:
  - `go test -count=1 ./apps/cli/internal/operator -run 'Test(ScheduledBacktestReadiness|RunScenarioRefreshStatus|HeadlessValidationHandoff|ExpectedOutputFixtures)'`

### [REVIEW_cloud-G08-3] Remote runner S05 evidence

- 문제: SDD Evidence Map의 S05 필수 증거가 아직 없다.
- 해결:
  - scheduler enabled remote worker/API runtime에서 scheduler tick 완료를 확인한다.
  - 아래 두 명령을 remote checkout root 기준으로 실행하고, raw secret/endpoint 값을 제외한 stdout/stderr 또는 artifact path를 `CODE_REVIEW_cloud_G08.md`에 기록한다.
  - remote 환경에 접근할 수 없으면 PASS로 표시하지 말고 실행 명령, 실제 실패/차단 출력, 미실행 사유를 기록한다. 외부 환경 접근 불가는 그 자체로 USER_REVIEW gate가 아니다.
- remote 검증:
  - `go run ./apps/cli/cmd/alt operator scenario run --file apps/cli/testdata/operator/scheduler_refresh_status.yaml --api-url "$ALT_OPERATOR_API_URL" --output jsonl`
  - `go run ./apps/cli/cmd/alt operator scenario run --file apps/cli/testdata/operator/scheduled_backtest_readiness.yaml --api-url "$ALT_OPERATOR_API_URL" --output jsonl`

## 최종 검증

- `gofmt -l apps/cli/internal/operator/scenario.go apps/cli/internal/operator/runner.go apps/cli/internal/operator/runner_market_test.go apps/cli/internal/operator/runner_backtest_test.go`
- `go test -count=1 ./apps/cli/internal/operator -run 'Test(ScheduledBacktestReadiness|RunScenarioRefreshStatus|HeadlessValidationHandoff|ExpectedOutputFixtures)'`
- `go test -count=1 ./apps/cli/...`
- `go test -count=1 ./services/api/...`
- `go test -count=1 ./services/worker/...`
- Remote runner S05 commands from `[REVIEW_cloud-G08-3]`

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