Plan command-first operator workflow

This commit is contained in:
toki 2026-06-03 19:02:19 +09:00
parent ee01990117
commit 1314fe290b
13 changed files with 2267 additions and 4 deletions

View file

@ -7,7 +7,7 @@
## 활성 Milestone
- [계획] Command-First Operator Workflow
- [진행중] Command-First Operator Workflow
- Phase: `agent-roadmap/phase/operator-surface/PHASE.md`
- 경로: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`

View file

@ -31,7 +31,7 @@ Flutter 실화면 전에 API 서버 중심 proto-socket rail과 CLI/YAML/log/tes
- [완료] KIS Live Data Collection Pipeline
- 경로: `agent-roadmap/archive/phase/operator-surface/milestones/kis-live-data-collection-pipeline.md`
- 요약: Flutter 실화면 전에 KIS 실 API 기반 한국장 일봉 수집, worker import/storage, `StorageBarSource` 입력 조회 경계까지 검증한다.
- [계획] Command-First Operator Workflow
- [진행중] Command-First Operator Workflow
- 경로: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- 요약: Flutter 실화면을 보류하고 KIS live data, worker storage, market status, backtest 실행/결과 확인을 CLI/YAML/log 중심의 반복 가능한 operator workflow로 묶는다.

View file

@ -11,7 +11,7 @@ Flutter 실화면을 보류한 상태에서 KIS live data, worker storage, marke
## 상태
[계획]
[진행중]
## 구현 잠금
@ -33,7 +33,7 @@ Flutter 실화면을 보류한 상태에서 KIS live data, worker storage, marke
화면 없이도 운영자가 KIS 데이터 수집, 상태 조회, 백테스트 실행/결과 확인을 반복할 수 있는 command path를 만든다.
- [ ] [kis-smoke-runbook] KIS paper/real daily smoke와 Go live-provider smoke 실행 경로가 command runbook으로 정리되어 있다. 검증: secret 원문 없이 readiness/smoke/evidence key가 문서화되고 smoke command가 dry failure와 live-gated success 경로를 구분한다.
- [x] [kis-smoke-runbook] KIS paper/real daily smoke와 Go live-provider smoke 실행 경로가 command runbook으로 정리되어 있다. 검증: secret 원문 없이 readiness/smoke/evidence key가 문서화되고 smoke command가 dry failure와 live-gated success 경로를 구분한다.
- [ ] [live-import-command] KIS live daily bars를 worker storage에 import하는 command 또는 YAML scenario가 있다. 검증: fake/provider test와 필요한 integration smoke가 import result와 storage upsert를 확인한다.
- [ ] [market-status-scenario] imported market data를 CLI/YAML로 조회할 수 있다. 검증: `alt operator scenario validate/run` 또는 동등한 command가 instrument/bar count와 typed unavailable/error key를 출력한다.
- [ ] [backtest-command-flow] imported daily bars를 입력으로 backtest start/poll/result를 command workflow에서 확인할 수 있다. 검증: start/poll/result scenario가 run id, terminal status, result summary key를 출력한다.
@ -65,6 +65,10 @@ Flutter 실화면을 보류한 상태에서 KIS live data, worker storage, marke
- 표준선(선택): 현재 운영은 화면보다 CLI/YAML/log/test fixture를 우선한다. Flutter MVP는 command workflow에서 반복 운영 항목, 상태 key, 우선순위가 충분히 표면화되어 정리 가능한 뒤에 다시 연다.
- 표준선(선택): command output은 사람이 읽을 수 있으면서도 `jsonl`/status key처럼 script가 grep 가능한 형태를 유지한다.
- 표준선(선택): KIS secret은 SOPS + age command-lifetime env 주입 경계만 사용하고 tracked 문서에는 sanitized evidence만 남긴다.
- 최근 evidence: `docs/kis-live-secret-handoff.md``docs/kis-live-secret-guide.md`에 paper/real readiness, 일봉 smoke, Go live-provider smoke 명령과 sanitized evidence key가 정리되어 있다.
- 최근 evidence: `bin/kis-paper-daily-smoke``KIS_ACTIVE_ENV=paper|real`을 명시하지 않거나 필수 env가 없으면 외부 호출 전에 실패하고, SOPS 주입 live 경로에서는 `env`, `provider`, `endpoint`, `symbol`, `bar_count`, `msg_cd` 요약만 출력한다.
- 현재 작업 지점: 작은 작업인 `kis-smoke-runbook`은 완료 처리했고, 남은 큰 작업은 `agent-task/m-command-first-operator-workflow/` 아래 split plan으로 대기한다.
- 현재 작업 지점: `01_import_contract_worker_api` -> `02+01_import_cli_scenario` -> `03+02_market_status_scenario`, `04+02_backtest_runtime_flow` -> `05+03,04_operator_handoff` 순서로 진행한다.
- 선행 작업: Operator Headless Workflow Validation, Operator Client API/Core Integration Validation, KIS Live Data Collection Pipeline
- 후속 작업: Paper Trading Readiness, Paper Trading Command Workflow, US Market Expansion, Live Trading Boundary, Flutter Operator Console MVP
- 확인 필요: 없음

View file

@ -0,0 +1,155 @@
<!-- task=m-command-first-operator-workflow/01_import_contract_worker_api plan=0 tag=API -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-03
task=m-command-first-operator-workflow/01_import_contract_worker_api, plan=0, tag=API
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G08.md``code_review_cloud_G08_N.log`, `PLAN-cloud-G08.md``plan_cloud_G08_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-command-first-operator-workflow/01_import_contract_worker_api/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [API-1] Contract And Parser Surface | [ ] |
| [API-2] API Forwarding | [ ] |
| [API-3] Worker Import Handler | [ ] |
| [API-4] Worker Entrypoint Wiring | [ ] |
| [API-5] Focused Verification | [ ] |
## 구현 체크리스트
- [ ] [API-1] Add `ImportDailyBarsRequest/Response` protobuf messages, regenerate contracts, and register parsers in API/worker/CLI maps.
- [ ] [API-2] Add API workerclient and API socket forwarding for import daily bars with typed unavailable/timeout/internal errors.
- [ ] [API-3] Add worker socket import handler that validates request shape, calls the importer dependency, and returns instrument/bar counts.
- [ ] [API-4] Wire `alt-worker` store-backed deps with the KIS importer command surface without exposing secrets.
- [ ] [API-5] Run focused contract/API/worker verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_cloud_G08_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_cloud_G08_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/01_import_contract_worker_api/``agent-task/archive/YYYY/MM/m-command-first-operator-workflow/01_import_contract_worker_api/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G08.md``CODE_REVIEW-cloud-G08.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- Protobuf change is additive and generated files were regenerated rather than hand-edited.
- API remains a thin validator/forwarder and does not import worker internals.
- Worker owns import execution and returns typed `ErrorInfo` instead of handler errors.
- Capability strings match registered handlers and available deps.
- No secret/account/token/raw KIS payload is logged or written.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### API-1 중간 검증
```bash
$ bin/contracts-check
$ go test ./packages/contracts/gen/go/... -count=1
$ go test ./services/api/internal/contracts ./services/worker/internal/contracts ./apps/cli/internal/operator -run ParserMap -count=1
(output)
```
### API-2 중간 검증
```bash
$ go test ./services/api/... -count=1
(output)
```
### API-3 중간 검증
```bash
$ go test ./services/worker/internal/socket -count=1
(output)
```
### API-4 중간 검증
```bash
$ go test ./services/worker/... -count=1
(output)
```
### API-5 중간 검증
```bash
$ git diff --check
(output)
```
### 최종 검증
```bash
$ bin/contracts-check
$ go test ./packages/contracts/gen/go/... -count=1
$ go test ./services/api/... -count=1
$ go test ./services/worker/... -count=1
$ git diff --check
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

View file

@ -0,0 +1,429 @@
<!-- task=m-command-first-operator-workflow/01_import_contract_worker_api plan=0 tag=API -->
# Plan - Import Contract Worker API
## 이 파일을 읽는 구현 에이전트에게
이 plan은 구현 지시서이며, 구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 실제 내용과 검증 출력으로 채운다. 검증은 아래 명령을 실행하고 실제 stdout/stderr를 review stub에 붙인다. 최종 판정, archive 이동, `complete.log` 작성은 code-review-skill 전용이다. 사용자 결정, 사용자 소유 외부 환경/secret, 또는 범위 충돌 없이는 진행할 수 없을 때만 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
현재 KIS provider와 importer는 준비되어 있지만 operator가 API/worker socket을 통해 daily bars import를 명령할 contract가 없다. 이 작업은 CLI/YAML이 호출할 수 있는 typed request/response와 API forwarding, worker import handler를 추가한다. 이 foundation만으로는 마일스톤의 `live-import-command`를 완료하지 않으며, 후속 `02+01_import_cli_scenario`가 command surface를 완성한다.
## 사용자 리뷰 요청 흐름
구현 중 사용자-only blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 이 섹션은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 기준이며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 결정한다.
## 분석 결과
### 읽은 파일
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-test/local/rules.md`
- `agent-test/local/contracts-smoke.md`
- `agent-test/local/api-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-test/local/operations-smoke.md`
- `agent-ops/rules/project/domain/contracts/rules.md`
- `agent-ops/rules/project/domain/api/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-ops/rules/private/kis-api-local-cache.md`
- `agent-ops/rules/private/testing-env.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/operator-surface/PHASE.md`
- `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- `packages/contracts/proto/alt/v1/common.proto`
- `packages/contracts/proto/alt/v1/market.proto`
- `packages/contracts/proto/alt/v1/backtest.proto`
- `services/api/internal/contracts/parser_map.go`
- `services/api/internal/contracts/parser_map_test.go`
- `services/api/internal/socket/handlers.go`
- `services/api/internal/socket/market.go`
- `services/api/internal/socket/market_test.go`
- `services/api/internal/socket/backtest_test.go`
- `services/api/internal/socket/server_test.go`
- `services/api/internal/workerclient/client.go`
- `services/api/internal/workerclient/client_test.go`
- `services/worker/internal/contracts/parser_map.go`
- `services/worker/internal/contracts/parser_map_test.go`
- `services/worker/internal/socket/handlers.go`
- `services/worker/internal/socket/backtest.go`
- `services/worker/internal/socket/market.go`
- `services/worker/internal/socket/market_mapping.go`
- `services/worker/internal/socket/market_test.go`
- `services/worker/internal/socket/server_test.go`
- `services/worker/internal/jobs/marketdata_jobs.go`
- `services/worker/internal/jobs/runner.go`
- `services/worker/internal/marketdata/importer/importer.go`
- `services/worker/cmd/alt-worker/main.go`
- `bin/contracts-gen`
- `bin/contracts-check`
- `bin/test`
- `go.work`
- `services/api/go.mod`
- `services/worker/go.mod`
- `packages/contracts/gen/go/go.mod`
### 테스트 환경 규칙
- test_env: `local`.
- `agent-test/local/rules.md` present/read. Matched profiles: `contracts-smoke`, `api-smoke`, `worker-smoke`, `operations-smoke`.
- Applied commands: `bin/contracts-gen` for proto changes, `bin/contracts-check`, `go test ./packages/contracts/gen/go/...`, `go test ./services/api/...`, `go test ./services/worker/...`.
- Fallback: none. No `<확인 필요>` command values in matched profiles.
### 테스트 커버리지 공백
- Import protobuf parser coverage: existing parser map tests cover required messages but must be extended for `ImportDailyBarsRequest/Response`.
- API forwarding: existing market handler and workerclient tests cover list requests; import request tests are missing and must be added.
- Worker import handler: existing market read tests and importer/job tests cover adjacent behavior; direct socket import command tests are missing and must be added.
- Live KIS end-to-end command smoke remains outside this foundation; fake importer tests are sufficient here because KIS provider live smoke is already covered by the completed predecessor milestone.
### 심볼 참조
- Renamed/removed symbols: none. This is additive.
- New message registration call sites must be added in API, worker, and CLI parser maps so proto-socket decoding does not drift.
### 분할 판단
- Split policy evaluated before writing files.
- Shared task group: `agent-task/m-command-first-operator-workflow/`.
- Siblings:
- `01_import_contract_worker_api`: foundation, no predecessor.
- `02+01_import_cli_scenario`: waits for this contract/API/worker rail.
- `03+02_market_status_scenario`: waits for import CLI scenario.
- `04+02_backtest_runtime_flow`: waits for import CLI scenario.
- `05+03,04_operator_handoff`: waits for status and backtest flow.
- This plan has no predecessor. It intentionally has no `Roadmap Targets` because it does not by itself complete a Milestone 기능 Task.
### 범위 결정 근거
- Excludes CLI YAML action implementation; that belongs to `02+01_import_cli_scenario`.
- Excludes market status fixture updates; that belongs to `03+02_market_status_scenario`.
- Excludes backtest runtime wiring and strategy resolver; that belongs to `04+02_backtest_runtime_flow`.
- Excludes Flutter UI, wireframes, production scheduling, and raw KIS secret handling per milestone scope.
### 빌드 등급
- build=`cloud-G08`, review=`cloud-G08`: additive but cross-domain protobuf/API/worker protocol work with parser registration and generated-output drift risk.
## 구현 체크리스트
- [ ] [API-1] Add `ImportDailyBarsRequest/Response` protobuf messages, regenerate contracts, and register parsers in API/worker/CLI maps.
- [ ] [API-2] Add API workerclient and API socket forwarding for import daily bars with typed unavailable/timeout/internal errors.
- [ ] [API-3] Add worker socket import handler that validates request shape, calls the importer dependency, and returns instrument/bar counts.
- [ ] [API-4] Wire `alt-worker` store-backed deps with the KIS importer command surface without exposing secrets.
- [ ] [API-5] Run focused contract/API/worker verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## [API-1] Contract And Parser Surface
### 문제
[packages/contracts/proto/alt/v1/market.proto](/config/workspace/alt/packages/contracts/proto/alt/v1/market.proto:39) only has market read messages. There is no typed import command request/response for CLI/API/worker use. Parser maps currently register only list/read and backtest messages in [services/api/internal/contracts/parser_map.go](/config/workspace/alt/services/api/internal/contracts/parser_map.go:18), [services/worker/internal/contracts/parser_map.go](/config/workspace/alt/services/worker/internal/contracts/parser_map.go:14), and [apps/cli/internal/operator/parser_map.go](/config/workspace/alt/apps/cli/internal/operator/parser_map.go:20).
### 해결 방법
Add messages after `ListBarsResponse` using new field numbers only.
Before (`market.proto:49`):
```proto
message ListBarsRequest {
string instrument_id = 1;
Timeframe timeframe = 2;
int64 from_unix_ms = 3;
int64 to_unix_ms = 4;
}
```
After:
```proto
message ImportDailyBarsRequest {
string provider = 1;
string selector_kind = 2;
Market market = 3;
Venue venue = 4;
string name = 5;
repeated string symbols = 6;
string from_yyyymmdd = 7;
string to_yyyymmdd = 8;
}
message ImportDailyBarsResponse {
string provider = 1;
int32 instrument_count = 2;
int32 bar_count = 3;
ErrorInfo error = 4;
}
```
Run `bin/contracts-gen`. Do not hand-edit generated files.
### 수정 파일 및 체크리스트
- [ ] `packages/contracts/proto/alt/v1/market.proto`: add request/response.
- [ ] `packages/contracts/gen/go/alt/v1/market.pb.go`: regenerated only.
- [ ] `apps/client/lib/src/generated/alt/v1/market.pb*.dart`: regenerated only if `bin/contracts-gen` updates them.
- [ ] `services/api/internal/contracts/parser_map.go`: register both messages.
- [ ] `services/api/internal/contracts/parser_map_test.go`: require both messages.
- [ ] `services/worker/internal/contracts/parser_map.go`: register both messages.
- [ ] `services/worker/internal/contracts/parser_map_test.go`: require both messages.
- [ ] `apps/cli/internal/operator/parser_map.go`: register both messages for later CLI action.
- [ ] `apps/cli/internal/operator/parser_map_test.go`: require at least the response parser.
### 테스트 작성
Write/extend parser map tests in API, worker, and CLI to assert `protoSocket.TypeNameOf(&altv1.ImportDailyBarsRequest{})` and response are registered and parse.
### 중간 검증
```bash
bin/contracts-check
go test ./packages/contracts/gen/go/... -count=1
go test ./services/api/internal/contracts ./services/worker/internal/contracts ./apps/cli/internal/operator -run ParserMap -count=1
```
Expected: all commands exit 0.
## [API-2] API Forwarding
### 문제
[services/api/internal/workerclient/client.go](/config/workspace/alt/services/api/internal/workerclient/client.go:25) has no import method in `WorkerClient`, and [services/api/internal/socket/market.go](/config/workspace/alt/services/api/internal/socket/market.go:22) only registers list/read handlers.
### 해결 방법
Add `ImportDailyBars(ctx, *altv1.ImportDailyBarsRequest)` to `WorkerClient`, implement it as a one-line `sendTyped`, and add an API market handler that validates minimal shape then forwards. Validation should reject empty provider, empty selector kind, empty symbols, unsupported market/venue, and malformed date strings before connecting to worker.
Before (`client.go:39`):
```go
// Market query surface.
ListInstruments(ctx context.Context, req *altv1.ListInstrumentsRequest) (*altv1.ListInstrumentsResponse, error)
ListBars(ctx context.Context, req *altv1.ListBarsRequest) (*altv1.ListBarsResponse, error)
```
After:
```go
ImportDailyBars(ctx context.Context, req *altv1.ImportDailyBarsRequest) (*altv1.ImportDailyBarsResponse, error)
ListInstruments(ctx context.Context, req *altv1.ListInstrumentsRequest) (*altv1.ListInstrumentsResponse, error)
ListBars(ctx context.Context, req *altv1.ListBarsRequest) (*altv1.ListBarsResponse, error)
```
### 수정 파일 및 체크리스트
- [ ] `services/api/internal/workerclient/client.go`: interface and socket client method.
- [ ] `services/api/internal/workerclient/client_test.go`: fake worker server round-trip and unavailable guard.
- [ ] `services/api/internal/socket/market.go`: import handler registration, validation, forwarding, nil response mapping.
- [ ] `services/api/internal/socket/market_test.go`: forwarding, validation, nil worker, connect failure.
- [ ] `services/api/internal/socket/backtest_test.go`: update `fakeWorkerClient` to implement the new interface.
- [ ] `services/api/internal/socket/server_test.go`: capability/handler sync if capability is advertised.
### 테스트 작성
Add `TestWorkerClient_ImportDailyBars_Success`, `TestHandleImportDailyBarsForwards`, validation table, nil worker response, and socket typed validation tests.
### 중간 검증
```bash
go test ./services/api/... -count=1
```
Expected: API tests pass and no fake worker interface compile failure remains.
## [API-3] Worker Import Handler
### 문제
[services/worker/internal/socket/market.go](/config/workspace/alt/services/worker/internal/socket/market.go:23) only exposes reads. [services/worker/internal/marketdata/importer/importer.go](/config/workspace/alt/services/worker/internal/marketdata/importer/importer.go:73) already returns import counts, but no socket handler returns them.
### 해결 방법
Add a narrow socket dependency interface for `ImportDailyBars`, add it to `Deps`, register `ImportDailyBarsRequest`, validate and convert request fields into `importer.DailyBarRequest`, call the importer, and map errors to `ErrorInfo`. Add `venueFromProto` next to `venueToProto`.
Before (`backtest.go:38`):
```go
type Deps struct {
Starter BacktestStarter
Analysis storage.BacktestAnalysisStore
Results storage.BacktestResultStore
Instruments storage.InstrumentStore
Bars storage.BarStore
}
```
After:
```go
type DailyBarImporter interface {
ImportDailyBars(ctx context.Context, request importer.DailyBarRequest) (importer.Result, error)
}
type Deps struct {
Starter BacktestStarter
Analysis storage.BacktestAnalysisStore
Results storage.BacktestResultStore
Instruments storage.InstrumentStore
Bars storage.BarStore
DailyBarImport DailyBarImporter
}
```
Use a gofmt-friendly field name such as `DailyBarImporter` if preferred; keep the capability name stable.
### 수정 파일 및 체크리스트
- [ ] `services/worker/internal/socket/backtest.go`: add dependency interface/field.
- [ ] `services/worker/internal/socket/market.go`: handler registration, validation, conversion, error mapping.
- [ ] `services/worker/internal/socket/market_mapping.go`: add `venueFromProto`.
- [ ] `services/worker/internal/socket/market_test.go`: fake importer, success counts, validation, unavailable, socket round-trip.
- [ ] `services/worker/internal/socket/server_test.go`: capability expectations.
### 테스트 작성
Add tests for:
- success count response from fake importer,
- request conversion provider/selector/date range,
- missing provider/selector/symbol and unsupported market/venue,
- importer nil returns `unavailable`,
- socket request returns typed response without timeout.
### 중간 검증
```bash
go test ./services/worker/internal/socket -count=1
```
Expected: worker socket tests pass.
## [API-4] Worker Entrypoint Wiring
### 문제
[services/worker/cmd/alt-worker/main.go](/config/workspace/alt/services/worker/cmd/alt-worker/main.go:40) creates the KIS live provider and registers the job handler, but [services/worker/cmd/alt-worker/main.go](/config/workspace/alt/services/worker/cmd/alt-worker/main.go:42) does not expose the importer through socket deps.
### 해결 방법
Create one importer instance and pass it both to `jobs.RegisterDailyBarImportHandler` and the socket dependency field. Do not log app key, token, account, raw headers, or secret item names. Add an `import_daily_bars` or `market-import` capability only when the importer dependency exists.
Before (`main.go:40`):
```go
kisProvider := kis.NewLiveProvider(kis.NewClient(kis.ConfigFromEnv()))
jobs.RegisterDailyBarImportHandler(runner, market.ProviderKIS, importer.New(kisProvider, store))
deps = socket.Deps{
Analysis: store,
Results: store,
Instruments: store,
Bars: store,
}
```
After:
```go
kisImporter := importer.New(kisProvider, store)
jobs.RegisterDailyBarImportHandler(runner, market.ProviderKIS, kisImporter)
deps = socket.Deps{
Analysis: store,
Results: store,
Instruments: store,
Bars: store,
DailyBarImporter: kisImporter,
}
```
### 수정 파일 및 체크리스트
- [ ] `services/worker/cmd/alt-worker/main.go`: reuse importer and set deps.
- [ ] `services/worker/internal/socket/handlers.go`: add capability if implemented.
- [ ] `services/worker/internal/socket/server_test.go`: capability only present when import dependency exists.
### 테스트 작성
Entrypoint has no current direct main test. Cover behavior through `capabilitiesForDeps` and worker socket handler tests.
### 중간 검증
```bash
go test ./services/worker/... -count=1
```
Expected: worker module passes.
## [API-5] Focused Verification
### 문제
Protocol and parser changes can pass local unit tests while generated files drift. The matched contract profile requires generated drift checks.
### 해결 방법
Run the exact final commands and paste output into the review stub.
### 수정 파일 및 체크리스트
- [ ] No extra files.
### 테스트 작성
No new test beyond items above.
### 중간 검증
```bash
git diff --check
```
Expected: no whitespace or patch-format warnings.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `packages/contracts/proto/alt/v1/market.proto` | API-1 |
| `packages/contracts/gen/go/alt/v1/market.pb.go` | API-1 |
| `apps/client/lib/src/generated/alt/v1/market.pb*.dart` | API-1 |
| `services/api/internal/contracts/parser_map.go` | API-1 |
| `services/api/internal/contracts/parser_map_test.go` | API-1 |
| `services/worker/internal/contracts/parser_map.go` | API-1 |
| `services/worker/internal/contracts/parser_map_test.go` | API-1 |
| `apps/cli/internal/operator/parser_map.go` | API-1 |
| `apps/cli/internal/operator/parser_map_test.go` | API-1 |
| `services/api/internal/workerclient/client.go` | API-2 |
| `services/api/internal/workerclient/client_test.go` | API-2 |
| `services/api/internal/socket/market.go` | API-2 |
| `services/api/internal/socket/market_test.go` | API-2 |
| `services/api/internal/socket/backtest_test.go` | API-2 |
| `services/api/internal/socket/server_test.go` | API-2 |
| `services/worker/internal/socket/backtest.go` | API-3 |
| `services/worker/internal/socket/market.go` | API-3 |
| `services/worker/internal/socket/market_mapping.go` | API-3 |
| `services/worker/internal/socket/market_test.go` | API-3 |
| `services/worker/internal/socket/server_test.go` | API-3, API-4 |
| `services/worker/internal/socket/handlers.go` | API-4 |
| `services/worker/cmd/alt-worker/main.go` | API-4 |
## 최종 검증
```bash
bin/contracts-check
go test ./packages/contracts/gen/go/... -count=1
go test ./services/api/... -count=1
go test ./services/worker/... -count=1
git diff --check
```
Expected: all commands exit 0. Fresh `go test -count=1` is required; cached output is not acceptable for this protocol change.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,159 @@
<!-- task=m-command-first-operator-workflow/02+01_import_cli_scenario plan=0 tag=CLI -->
# Code Review Reference - CLI
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-03
task=m-command-first-operator-workflow/02+01_import_cli_scenario, plan=0, tag=CLI
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `live-import-command`: KIS live daily bars를 worker storage에 import하는 command 또는 YAML scenario가 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G07.md``code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md``plan_cloud_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-command-first-operator-workflow/02+01_import_cli_scenario/`로 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [CLI-1] Scenario Schema | [ ] |
| [CLI-2] API Client Method | [ ] |
| [CLI-3] Runner And Output | [ ] |
| [CLI-4] Import Fixture | [ ] |
| [CLI-5] Verification | [ ] |
## 구현 체크리스트
- [ ] [CLI-1] Add `import_daily_bars` scenario schema fields and dry-run validation.
- [ ] [CLI-2] Add CLI `APIClient.ImportDailyBars` and fake API test support.
- [ ] [CLI-3] Execute import action in runner and emit `provider`, `instrument_count`, and `bar_count` output keys.
- [ ] [CLI-4] Add import smoke YAML and expected JSONL fixture. 검증: fake/provider test and scenario validation confirm import result counts are emitted.
- [ ] [CLI-5] Run CLI-focused verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_cloud_G07_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_cloud_G07_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/02+01_import_cli_scenario/``agent-task/archive/YYYY/MM/m-command-first-operator-workflow/02+01_import_cli_scenario/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md``CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `import_daily_bars` validation fails offline before any socket call for malformed fixtures.
- CLI output contains stable `provider`, `instrument_count`, and `bar_count` keys.
- Expected typed errors still exit 0 when declared in YAML expectations.
- New fixture contains no raw KIS response, token, account, or secret values.
- Roadmap completion target is only `live-import-command`.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### CLI-1 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run 'Scenario|ImportDailyBars' -count=1
(output)
```
### CLI-2 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run APIClientImportDailyBars -count=1
(output)
```
### CLI-3 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run 'RunScenario.*Import|ExpectedTypedError' -count=1
(output)
```
### CLI-4 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run 'Handoff|ImportDailyBars' -count=1
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/kis_daily_import_smoke.yaml
(output)
```
### CLI-5 중간 검증
```bash
$ git diff --check
(output)
```
### 최종 검증
```bash
$ go test ./apps/cli/... -count=1
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/kis_daily_import_smoke.yaml
$ git diff --check
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

View file

@ -0,0 +1,301 @@
<!-- task=m-command-first-operator-workflow/02+01_import_cli_scenario plan=0 tag=CLI -->
# Plan - Import CLI Scenario
## 이 파일을 읽는 구현 에이전트에게
이 plan은 구현 지시서이며, 구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 실제 내용과 검증 출력으로 채운다. 이 task는 `01_import_contract_worker_api``complete.log`가 생긴 뒤 구현한다. 최종 판정, archive 이동, `complete.log` 작성은 code-review-skill 전용이다. 사용자-only blocker가 있으면 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다. 후속 에이전트가 재실행으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
Foundation 작업이 import request/response를 열어도 운영자는 아직 YAML scenario로 import를 실행할 수 없다. 이 작업은 `alt operator scenario validate/run``import_daily_bars` action을 추가하고, import result를 JSONL evidence key로 출력한다. PASS 시 현재 마일스톤의 `live-import-command` 기능 Task를 완료 대상으로 삼는다.
## 사용자 리뷰 요청 흐름
구현 중 사용자-only blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이를 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `live-import-command`: KIS live daily bars를 worker storage에 import하는 command 또는 YAML scenario가 있다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-test/local/rules.md`
- `agent-test/local/contracts-smoke.md`
- `agent-test/local/api-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-test/local/operations-smoke.md`
- `agent-ops/rules/project/domain/contracts/rules.md`
- `agent-ops/rules/project/domain/api/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/operator-surface/PHASE.md`
- `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- `apps/cli/internal/operator/scenario.go`
- `apps/cli/internal/operator/scenario_test.go`
- `apps/cli/internal/operator/runner.go`
- `apps/cli/internal/operator/runner_market_test.go`
- `apps/cli/internal/operator/runner_error_test.go`
- `apps/cli/internal/operator/client.go`
- `apps/cli/internal/operator/client_test.go`
- `apps/cli/internal/operator/output.go`
- `apps/cli/internal/operator/parser_map.go`
- `apps/cli/internal/operator/parser_map_test.go`
- `apps/cli/internal/cli/cli.go`
- `apps/cli/internal/cli/cli_test.go`
- `apps/cli/testdata/operator/headless_validation.md`
- `apps/cli/testdata/operator/market_data_status_query.yaml`
- `apps/cli/testdata/operator/expected/market_data_status_query.jsonl`
- `services/api/internal/socket/market.go`
- `services/api/internal/socket/market_test.go`
- `services/api/internal/workerclient/client.go`
- `services/worker/internal/socket/market.go`
- `services/worker/internal/marketdata/importer/importer.go`
- `docs/kis-live-secret-handoff.md`
- `docs/kis-live-secret-guide.md`
### 테스트 환경 규칙
- test_env: `local`.
- Matched profiles: `operations-smoke` for CLI and fixtures, plus `api-smoke`/`worker-smoke`/`contracts-smoke` inherited from predecessor surface.
- Applied commands: `go test ./apps/cli/...`, focused API/worker tests if interface signatures change, and `git diff --check`.
- External real KIS smoke is not required for this CLI action because prior milestone already proved paper/real provider access, and this plan verifies the command rail with fake socket responses.
### 테스트 커버리지 공백
- CLI scenario validation currently covers list/backtest actions, not `import_daily_bars`; add dry-run tests.
- `APIClient` has no import method until predecessor completes; add round-trip fake API test.
- Runner output has count/run/result fields but no `provider`, `instrument_count`, or `bar_count`; add output tests.
- Live import against a running API/worker remains an integration follow-up and should use sanitized SOPS evidence only when available.
### 심볼 참조
- Renamed/removed symbols: none. Additive `ActionImportDailyBars` and request fields only.
### 분할 판단
- Shared task group: `agent-task/m-command-first-operator-workflow/`.
- This subtask directory is `02+01_import_cli_scenario`; predecessor index `01` is `01_import_contract_worker_api`.
- Predecessor completion status at plan creation: missing active/archive `complete.log`; implementation must wait until `agent-task/m-command-first-operator-workflow/01_import_contract_worker_api/complete.log` or matching archive path exists.
### 범위 결정 근거
- Excludes protobuf/API/worker foundation implementation; it is in predecessor `01`.
- Excludes imported data status scenario beyond import result; it is in `03+02_market_status_scenario`.
- Excludes real secret handling and raw KIS payload capture; only sanitized command evidence is allowed.
- Excludes Flutter UI.
### 빌드 등급
- build=`cloud-G07`, review=`cloud-G07`: CLI/YAML/JSONL exit contract and stdout key behavior are central.
## 의존 관계 및 구현 순서
- Wait for predecessor `01_import_contract_worker_api` complete.log. Directory dependency is authoritative: `02+01_import_cli_scenario`.
- After predecessor completion, implement CLI schema/client/runner/output, then fixtures/tests.
## 구현 체크리스트
- [ ] [CLI-1] Add `import_daily_bars` scenario schema fields and dry-run validation.
- [ ] [CLI-2] Add CLI `APIClient.ImportDailyBars` and fake API test support.
- [ ] [CLI-3] Execute import action in runner and emit `provider`, `instrument_count`, and `bar_count` output keys.
- [ ] [CLI-4] Add import smoke YAML and expected JSONL fixture. 검증: fake/provider test and scenario validation confirm import result counts are emitted.
- [ ] [CLI-5] Run CLI-focused verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## [CLI-1] Scenario Schema
### 문제
[apps/cli/internal/operator/scenario.go](/config/workspace/alt/apps/cli/internal/operator/scenario.go:23) enumerates known actions, but `import_daily_bars` is absent. [apps/cli/internal/operator/scenario.go](/config/workspace/alt/apps/cli/internal/operator/scenario.go:145) has request fields for reads/backtests, not provider/selector/date import input.
### 해결 방법
Add `ActionImportDailyBars Action = "import_daily_bars"` to the action set. Extend `Request` with `Provider`, `SelectorKind`, `Venue`, `Name`, `Symbols`, `FromYYYYMMDD`, and `ToYYYYMMDD`. Add closed validation maps for provider (`kis`), selector kind (`watchlist` for now), and venue (`krx`, `unspecified`). Validate non-empty provider, selector kind, symbols, valid market/venue, and optional dates matching `YYYYMMDD`.
Before (`scenario.go:23`):
```go
const (
ActionHello Action = "hello"
ActionListInstruments Action = "list_instruments"
ActionListBars Action = "list_bars"
)
```
After:
```go
const (
ActionHello Action = "hello"
ActionImportDailyBars Action = "import_daily_bars"
ActionListInstruments Action = "list_instruments"
ActionListBars Action = "list_bars"
)
```
### 수정 파일 및 체크리스트
- [ ] `apps/cli/internal/operator/scenario.go`: action, request fields, validation helpers.
- [ ] `apps/cli/internal/operator/scenario_test.go`: valid import parse and invalid provider/selector/symbol/date tests.
### 테스트 작성
Add `TestValidateImportDailyBars` and table-driven invalid cases.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run 'Scenario|ImportDailyBars' -count=1
```
Expected: scenario tests pass.
## [CLI-2] API Client Method
### 문제
[apps/cli/internal/operator/client.go](/config/workspace/alt/apps/cli/internal/operator/client.go:104) starts market read methods but has no import request method. Fake API server in [apps/cli/internal/operator/client_test.go](/config/workspace/alt/apps/cli/internal/operator/client_test.go:91) has no import listener.
### 해결 방법
Add `ImportDailyBars(ctx, req)` one-line `sendTyped` method. Extend `fakeAPI` with `importDailyBarsResp`, recorded request, and a request listener.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/internal/operator/client.go`: add import method.
- [ ] `apps/cli/internal/operator/client_test.go`: fake response/recording and method round-trip test.
- [ ] `apps/cli/internal/operator/parser_map_test.go`: assert import response parser is available if not already covered by predecessor.
### 테스트 작성
Add `TestAPIClientImportDailyBars` checking provider and symbols round-trip.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run APIClientImportDailyBars -count=1
```
Expected: fake API receives request and response counts round-trip.
## [CLI-3] Runner And Output
### 문제
[apps/cli/internal/operator/runner.go](/config/workspace/alt/apps/cli/internal/operator/runner.go:191) has no case for import. [apps/cli/internal/operator/output.go](/config/workspace/alt/apps/cli/internal/operator/output.go:23) has no fields for import counts, so scripts cannot grep import evidence keys.
### 해결 방법
Map scenario strings to `altv1.ImportDailyBarsRequest`, call `client.ImportDailyBars`, and evaluate typed error the same way market actions do. Add `Provider`, `InstrumentCount`, and `BarCount` to `StepEvent`; render JSONL keys `provider`, `instrument_count`, `bar_count` and text keys `provider=`, `instrument_count=`, `bar_count=`.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/internal/operator/runner.go`: mapping, runStep case, evaluation helper.
- [ ] `apps/cli/internal/operator/output.go`: output fields and rendering.
- [ ] `apps/cli/internal/operator/runner_market_test.go`: import success and expected typed error tests.
- [ ] `apps/cli/internal/operator/runner_error_test.go`: mismatch/error exit behavior if needed.
### 테스트 작성
Add runner tests for success counts and expected typed error `unavailable`.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run 'RunScenario.*Import|ExpectedTypedError' -count=1
```
Expected: import output keys appear and expected typed errors exit 0.
## [CLI-4] Import Fixture
### 문제
[apps/cli/testdata/operator/headless_validation.md](/config/workspace/alt/apps/cli/testdata/operator/headless_validation.md:24) has no import scenario row, and there is no import YAML fixture.
### 해결 방법
Add `kis_daily_import_smoke.yaml` with one `import_daily_bars` step for provider `kis`, market `kr`, venue `krx`, selector kind `watchlist`, symbol `005930`, and date range `20240527`-`20240528`. Add expected JSONL fixture with `provider`, `instrument_count`, `bar_count`, and summary. Add it to the handoff matrix as command-first evidence, but leave UI dependency deferred.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/testdata/operator/kis_daily_import_smoke.yaml`: new fixture.
- [ ] `apps/cli/testdata/operator/expected/kis_daily_import_smoke.jsonl`: new expected fixture.
- [ ] `apps/cli/testdata/operator/headless_validation.md`: add matrix row.
- [ ] `apps/cli/internal/operator/handoff_test.go`: include required scenario.
### 테스트 작성
Extend handoff tests to include the new fixture and JSONL keys. Do not include raw KIS payload or secret values.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run 'Handoff|ImportDailyBars' -count=1
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/kis_daily_import_smoke.yaml
```
Expected: tests pass and validate prints `scenario=kis_daily_import_smoke status=valid`.
## [CLI-5] Verification
### 문제
CLI output contracts are easy to regress through fixture drift or parse-only tests.
### 해결 방법
Run full CLI tests and diff check. Record optional live run instructions only in docs/handoff if actual running API/worker and SOPS env are available; do not block this fake-socket task on user secrets.
### 수정 파일 및 체크리스트
- [ ] No extra files.
### 테스트 작성
No additional tests beyond above.
### 중간 검증
```bash
git diff --check
```
Expected: no whitespace warnings.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `apps/cli/internal/operator/scenario.go` | CLI-1 |
| `apps/cli/internal/operator/scenario_test.go` | CLI-1 |
| `apps/cli/internal/operator/client.go` | CLI-2 |
| `apps/cli/internal/operator/client_test.go` | CLI-2 |
| `apps/cli/internal/operator/parser_map_test.go` | CLI-2 |
| `apps/cli/internal/operator/runner.go` | CLI-3 |
| `apps/cli/internal/operator/output.go` | CLI-3 |
| `apps/cli/internal/operator/runner_market_test.go` | CLI-3 |
| `apps/cli/internal/operator/runner_error_test.go` | CLI-3 |
| `apps/cli/testdata/operator/kis_daily_import_smoke.yaml` | CLI-4 |
| `apps/cli/testdata/operator/expected/kis_daily_import_smoke.jsonl` | CLI-4 |
| `apps/cli/testdata/operator/headless_validation.md` | CLI-4 |
| `apps/cli/internal/operator/handoff_test.go` | CLI-4 |
## 최종 검증
```bash
go test ./apps/cli/... -count=1
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/kis_daily_import_smoke.yaml
git diff --check
```
Expected: all commands exit 0. Fresh `go test -count=1` is required for CLI behavior.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,142 @@
<!-- task=m-command-first-operator-workflow/03+02_market_status_scenario plan=0 tag=CLI -->
# Code Review Reference - CLI
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-03
task=m-command-first-operator-workflow/03+02_market_status_scenario, plan=0, tag=CLI
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `market-status-scenario`: imported market data를 CLI/YAML로 조회할 수 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [CLI-1] Import Before Status Reads | [ ] |
| [CLI-2] Status Evidence Tests | [ ] |
| [CLI-3] Handoff Discoverability | [ ] |
| [CLI-4] Verification | [ ] |
## 구현 체크리스트
- [ ] [CLI-1] Update `market_data_status_query.yaml` to run import before instrument/bar status reads.
- [ ] [CLI-2] Update expected JSONL and tests to require import counts, instrument count, bar count, and typed unavailable/error keys. 검증: `alt operator scenario validate/run` 또는 동등한 command가 instrument/bar count와 typed unavailable/error key를 출력한다.
- [ ] [CLI-3] Update handoff matrix and CLI dev hints so the command-first status scenario is discoverable.
- [ ] [CLI-4] Run CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_cloud_G07_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_cloud_G07_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/03+02_market_status_scenario/``agent-task/archive/YYYY/MM/m-command-first-operator-workflow/03+02_market_status_scenario/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md``CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `market_data_status_query` imports before reading market status.
- JSONL fixture has import counts plus instrument/bar counts.
- Typed `unavailable` or equivalent error code is asserted in tests.
- Handoff docs still defer UI and do not describe screen implementation.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### CLI-1 중간 검증
```bash
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/market_data_status_query.yaml
(output)
```
### CLI-2 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run 'MarketDataStatus|MarketStatusTypedUnavailable|Handoff' -count=1
(output)
```
### CLI-3 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run Handoff -count=1
(output)
```
### CLI-4 중간 검증
```bash
$ git diff --check
(output)
```
### 최종 검증
```bash
$ go test ./apps/cli/... -count=1
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/market_data_status_query.yaml
$ git diff --check
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

View file

@ -0,0 +1,250 @@
<!-- task=m-command-first-operator-workflow/03+02_market_status_scenario plan=0 tag=CLI -->
# Plan - Market Status Scenario
## 이 파일을 읽는 구현 에이전트에게
이 plan은 구현 지시서이며, 구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채운다. 이 task는 `02+01_import_cli_scenario` 완료 뒤 구현한다. 최종 판정, archive 이동, `complete.log` 작성은 code-review-skill 전용이다. 사용자-only blocker가 있으면 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다.
## 배경
현재 `market_data_status_query`는 저장된 market data를 조회하지만, 같은 scenario 안에서 import가 먼저 되었는지는 보장하지 않는다. 이 작업은 import action 후 instruments/bars를 조회하는 command-first status scenario로 바꾼다. PASS 시 `market-status-scenario` 기능 Task를 완료 대상으로 삼는다.
## 사용자 리뷰 요청 흐름
구현 중 사용자-only blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이를 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `market-status-scenario`: imported market data를 CLI/YAML로 조회할 수 있다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-test/local/rules.md`
- `agent-test/local/operations-smoke.md`
- `agent-test/local/api-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/operator-surface/PHASE.md`
- `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- `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_error_test.go`
- `apps/cli/internal/operator/client_test.go`
- `apps/cli/internal/operator/output.go`
- `apps/cli/internal/operator/handoff_test.go`
- `apps/cli/testdata/operator/market_data_status_query.yaml`
- `apps/cli/testdata/operator/expected/market_data_status_query.jsonl`
- `apps/cli/testdata/operator/headless_validation.md`
- `bin/dev`
### 테스트 환경 규칙
- test_env: `local`.
- Matched profile: `operations-smoke` for CLI fixtures; `api-smoke`/`worker-smoke` are covered by predecessor rail and not changed here unless implementation touches API/worker.
- Applied commands: `go test ./apps/cli/...`, `go run ./apps/cli/cmd/alt operator scenario validate ...`, `git diff --check`.
### 테스트 커버리지 공백
- Existing `TestRunScenarioMarketDataStatus` covers list instruments/bars but not import-before-read.
- Handoff tests validate expected JSONL shape but do not require `instrument_count`/`bar_count` until the fixture is updated.
- Typed unavailable/error key is covered generically by runner tests; add explicit status scenario test with `ErrorInfo{Code:"unavailable"}` for import or list.
### 심볼 참조
- Renamed/removed symbols: none.
### 분할 판단
- Shared task group: `agent-task/m-command-first-operator-workflow/`.
- This subtask directory is `03+02_market_status_scenario`; predecessor index `02` is `02+01_import_cli_scenario`.
- Predecessor completion status at plan creation: missing active/archive `complete.log`; implementation waits for predecessor completion.
### 범위 결정 근거
- Excludes implementing `import_daily_bars`; predecessor owns it.
- Excludes backtest start/poll/result; `04+02_backtest_runtime_flow` owns it.
- Excludes UI layout and wireframes; handoff stays command evidence only.
### 빌드 등급
- build=`cloud-G07`, review=`cloud-G07`: command workflow and machine-readable terminal output are the success surface.
## 의존 관계 및 구현 순서
- Wait for `02+01_import_cli_scenario` complete.log.
- Update status fixture and fake API tests after import action is available.
## 구현 체크리스트
- [ ] [CLI-1] Update `market_data_status_query.yaml` to run import before instrument/bar status reads.
- [ ] [CLI-2] Update expected JSONL and tests to require import counts, instrument count, bar count, and typed unavailable/error keys. 검증: `alt operator scenario validate/run` 또는 동등한 command가 instrument/bar count와 typed unavailable/error key를 출력한다.
- [ ] [CLI-3] Update handoff matrix and CLI dev hints so the command-first status scenario is discoverable.
- [ ] [CLI-4] Run CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## [CLI-1] Import Before Status Reads
### 문제
[apps/cli/testdata/operator/market_data_status_query.yaml](/config/workspace/alt/apps/cli/testdata/operator/market_data_status_query.yaml:1) reads instruments/bars but does not import first. That makes the scenario a generic status query rather than an imported market data status workflow.
### 해결 방법
Prepend an `import_daily_bars` step after `hello`, using the same KIS symbol/date range as the import smoke. Keep the existing `list_instruments` and `list_bars` steps so status still reports counts.
Before (`market_data_status_query.yaml:9`):
```yaml
- id: hello
action: hello
```
After:
```yaml
- id: hello
action: hello
- id: import_kr_daily_bars
action: import_daily_bars
request:
provider: kis
selector_kind: watchlist
market: kr
venue: krx
symbols: ["005930"]
from_yyyymmdd: "20240527"
to_yyyymmdd: "20240528"
```
### 수정 파일 및 체크리스트
- [ ] `apps/cli/testdata/operator/market_data_status_query.yaml`: add import step.
- [ ] `apps/cli/testdata/operator/expected/market_data_status_query.jsonl`: add import output line and step count.
### 테스트 작성
Existing handoff JSONL parser test should catch malformed fixture. Add a runner test that loads this fixture and asserts fake API call order: import, list instruments, list bars.
### 중간 검증
```bash
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/market_data_status_query.yaml
```
Expected: `scenario=market_data_status_query status=valid`.
## [CLI-2] Status Evidence Tests
### 문제
[apps/cli/internal/operator/runner_market_test.go](/config/workspace/alt/apps/cli/internal/operator/runner_market_test.go:34) verifies status count output for list/read only. It does not prove `import_daily_bars` counts and typed unavailable keys survive the scenario run.
### 해결 방법
Update fake API support from predecessor if needed, then adjust `TestRunScenarioMarketDataStatus` to expect import, list, and bars output. Add a second test where import or list returns `ErrorInfo{Code:"unavailable"}` and the step expects `status: error`, proving the JSON/text output includes `error_code`.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/internal/operator/runner_market_test.go`: update happy path and add unavailable typed error case.
- [ ] `apps/cli/internal/operator/client_test.go`: expose last import request if not already available.
- [ ] `apps/cli/internal/operator/handoff_test.go`: assert expected JSONL step lines include import count keys for status scenario.
### 테스트 작성
Write focused runner tests:
- `TestRunScenarioMarketDataStatusImportsBeforeReads`
- `TestRunScenarioMarketStatusTypedUnavailable`
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run 'MarketDataStatus|MarketStatusTypedUnavailable|Handoff' -count=1
```
Expected: tests pass and output key assertions are covered.
## [CLI-3] Handoff Discoverability
### 문제
[apps/cli/testdata/operator/headless_validation.md](/config/workspace/alt/apps/cli/testdata/operator/headless_validation.md:29) describes `market_data_status_query` as list-only. [bin/dev](/config/workspace/alt/bin/dev:20) points to this scenario, so the developer hint should match the new import-before-read behavior.
### 해결 방법
Update matrix text for `market_data_status_query` to mention `ImportDailyBarsResponse.instrument_count`, `ImportDailyBarsResponse.bar_count`, `ListInstrumentsResponse.instruments`, and `ListBarsResponse.bars`. Keep UI dependency deferred.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/testdata/operator/headless_validation.md`: update checked fields and scenario description.
- [ ] `bin/dev`: no path change expected; update text only if it says read-only.
### 테스트 작성
No new test beyond handoff coverage; existing doc/fixture tests validate referenced paths.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run Handoff -count=1
```
Expected: handoff tests pass.
## [CLI-4] Verification
### 문제
Fixture drift can make the scenario validate but leave expected JSONL stale.
### 해결 방법
Run CLI tests, validate the scenario, and diff check.
### 수정 파일 및 체크리스트
- [ ] No extra files.
### 테스트 작성
No additional tests.
### 중간 검증
```bash
git diff --check
```
Expected: no warnings.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `apps/cli/testdata/operator/market_data_status_query.yaml` | CLI-1 |
| `apps/cli/testdata/operator/expected/market_data_status_query.jsonl` | CLI-1 |
| `apps/cli/internal/operator/runner_market_test.go` | CLI-2 |
| `apps/cli/internal/operator/client_test.go` | CLI-2 |
| `apps/cli/internal/operator/handoff_test.go` | CLI-2 |
| `apps/cli/testdata/operator/headless_validation.md` | CLI-3 |
| `bin/dev` | CLI-3 |
## 최종 검증
```bash
go test ./apps/cli/... -count=1
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/market_data_status_query.yaml
git diff --check
```
Expected: all commands exit 0.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,156 @@
<!-- task=m-command-first-operator-workflow/04+02_backtest_runtime_flow plan=0 tag=API -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-03
task=m-command-first-operator-workflow/04+02_backtest_runtime_flow, plan=0, tag=API
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `backtest-command-flow`: imported daily bars를 입력으로 backtest start/poll/result를 command workflow에서 확인할 수 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [API-1] GetBacktestRun Rail | [ ] |
| [API-2] Worker Runtime Wiring | [ ] |
| [API-3] Execution Evidence Tests | [ ] |
| [API-4] Backtest YAML Flow | [ ] |
| [API-5] Verification | [ ] |
## 구현 체크리스트
- [ ] [API-1] Add API and worker `GetBacktestRun` forwarding/handler support for polling.
- [ ] [API-2] Wire worker `alt-worker` with `BacktestStarter`, `RegisterRunBacktestHandler`, `StorageBarSource`, result store, and a built-in strategy resolver.
- [ ] [API-3] Add/update tests for built-in strategy resolver, worker execution wiring, and typed run polling.
- [ ] [API-4] Update backtest YAML scenarios to import daily bars before start/poll/result. 검증: start/poll/result scenario가 run id, terminal status, result summary key를 출력한다.
- [ ] [API-5] Run API/worker/CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_cloud_G08_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_cloud_G08_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/04+02_backtest_runtime_flow/``agent-task/archive/YYYY/MM/m-command-first-operator-workflow/04+02_backtest_runtime_flow/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G08.md``CODE_REVIEW-cloud-G08.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `GetBacktestRunRequest` is registered and forwarded through API to worker.
- Worker process advertises backtest start only when `Starter` is actually wired.
- Backtest execution uses `StorageBarSource` and a bounded built-in strategy resolver, not API internals.
- YAML backtest scenarios import bars before start/poll/result.
- Result output includes run id, terminal status, and summary keys.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### API-1 중간 검증
```bash
$ go test ./services/api/internal/workerclient ./services/api/internal/socket ./services/worker/internal/socket -run 'GetBacktestRun|BacktestHandlers|Capabilities' -count=1
(output)
```
### API-2 중간 검증
```bash
$ go test ./services/worker/internal/backtest ./services/worker/internal/jobs ./services/worker/internal/socket -count=1
(output)
```
### API-3 중간 검증
```bash
$ go test ./services/worker/... -run 'Backtest.*Flow|StorageBarSource|RunBacktest|BacktestStarter' -count=1
(output)
```
### API-4 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run 'Backtest|Handoff' -count=1
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_run_polling.yaml
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_result_summary.yaml
(output)
```
### API-5 중간 검증
```bash
$ git diff --check
(output)
```
### 최종 검증
```bash
$ go test ./services/api/... -count=1
$ go test ./services/worker/... -count=1
$ go test ./apps/cli/... -count=1
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_run_polling.yaml
$ go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_result_summary.yaml
$ git diff --check
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

View file

@ -0,0 +1,330 @@
<!-- task=m-command-first-operator-workflow/04+02_backtest_runtime_flow plan=0 tag=API -->
# Plan - Backtest Runtime Flow
## 이 파일을 읽는 구현 에이전트에게
이 plan은 구현 지시서이며, 구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채운다. 이 task는 `02+01_import_cli_scenario` 완료 뒤 구현한다. 최종 판정, archive 이동, `complete.log` 작성은 code-review-skill 전용이다. 사용자-only blocker가 있으면 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다.
## 배경
CLI에는 start/poll/result action이 있지만 real API/worker rail에는 poll이 호출하는 `GetBacktestRun` handler가 없고, worker entrypoint는 backtest starter/executor를 store-backed deps에 연결하지 않는다. 이 작업은 imported daily bars를 `StorageBarSource`로 읽는 worker runtime을 연결하고, backtest scenario들이 import 후 start/poll/result를 확인하게 만든다. PASS 시 `backtest-command-flow` 기능 Task를 완료 대상으로 삼는다.
## 사용자 리뷰 요청 흐름
구현 중 사용자-only blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이를 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `backtest-command-flow`: imported daily bars를 입력으로 backtest start/poll/result를 command workflow에서 확인할 수 있다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-test/local/rules.md`
- `agent-test/local/api-smoke.md`
- `agent-test/local/worker-smoke.md`
- `agent-test/local/operations-smoke.md`
- `agent-ops/rules/project/domain/api/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/operator-surface/PHASE.md`
- `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- `packages/contracts/proto/alt/v1/backtest.proto`
- `services/api/internal/socket/backtest.go`
- `services/api/internal/socket/backtest_test.go`
- `services/api/internal/socket/server_test.go`
- `services/api/internal/workerclient/client.go`
- `services/api/internal/workerclient/client_test.go`
- `services/worker/internal/socket/backtest.go`
- `services/worker/internal/socket/backtest_test.go`
- `services/worker/internal/socket/backtest_mapping.go`
- `services/worker/internal/socket/backtest_mapping_test.go`
- `services/worker/internal/socket/handlers.go`
- `services/worker/internal/socket/server_test.go`
- `services/worker/internal/jobs/backtest_starter.go`
- `services/worker/internal/jobs/backtest_jobs.go`
- `services/worker/internal/backtest/engine.go`
- `services/worker/internal/backtest/engine_test.go`
- `services/worker/internal/backtest/bar_source.go`
- `services/worker/internal/backtest/bar_source_test.go`
- `services/worker/internal/backtest/fixture_test.go`
- `services/worker/internal/storage/ports.go`
- `services/worker/cmd/alt-worker/main.go`
- `packages/domain/backtest/types.go`
- `apps/cli/internal/operator/runner.go`
- `apps/cli/internal/operator/output.go`
- `apps/cli/testdata/operator/backtest_run_request.yaml`
- `apps/cli/testdata/operator/backtest_run_polling.yaml`
- `apps/cli/testdata/operator/backtest_result_summary.yaml`
- `apps/cli/testdata/operator/expected/backtest_run_request.jsonl`
- `apps/cli/testdata/operator/expected/backtest_run_polling.jsonl`
- `apps/cli/testdata/operator/expected/backtest_result_summary.jsonl`
### 테스트 환경 규칙
- test_env: `local`.
- Matched profiles: `api-smoke`, `worker-smoke`, `operations-smoke`.
- Applied commands: `go test ./services/api/...`, `go test ./services/worker/...`, `go test ./apps/cli/...`, scenario validate commands, `git diff --check`.
- `bin/worker-storage-check` is not required unless implementation changes SQL/storage generated files.
### 테스트 커버리지 공백
- `GetBacktestRunRequest` exists in protobuf but API/worker socket handlers are missing; add forwarding/handler tests.
- `jobs.BacktestStarter` and `RegisterRunBacktestHandler` have unit tests but `cmd/alt-worker` does not wire them into deps; add focused wiring coverage through helper extraction or capability tests.
- Backtest engine has fake strategy tests but no production strategy resolver. Add built-in `strategy-v1` or equivalent deterministic strategy port for command validation.
- Existing backtest YAML fixtures start runs without importing bars first. Update them to import first.
### 심볼 참조
- Renamed/removed symbols: none.
- Additive call sites: workerclient interface fake implementations, API/worker handler registries, parser maps are already aware of `GetBacktestRunRequest/Response`.
### 분할 판단
- Shared task group: `agent-task/m-command-first-operator-workflow/`.
- This subtask directory is `04+02_backtest_runtime_flow`; predecessor index `02` is `02+01_import_cli_scenario`.
- Predecessor completion status at plan creation: missing active/archive `complete.log`; implementation waits for predecessor completion.
### 범위 결정 근거
- Excludes import CLI implementation; predecessor owns it.
- Excludes market status handoff finalization; `03` and `05` own it.
- Excludes trading order/paper trading/live trading APIs and production scheduling.
- Excludes Flutter UI.
### 빌드 등급
- build=`cloud-G08`, review=`cloud-G08`: worker runtime wiring, async execution, API forwarding, storage-backed backtest input, and CLI command flow are cross-domain.
## 의존 관계 및 구현 순서
- Wait for `02+01_import_cli_scenario` complete.log.
- Implement `GetBacktestRun` rail first, then worker runtime wiring, then backtest fixtures.
## 구현 체크리스트
- [ ] [API-1] Add API and worker `GetBacktestRun` forwarding/handler support for polling.
- [ ] [API-2] Wire worker `alt-worker` with `BacktestStarter`, `RegisterRunBacktestHandler`, `StorageBarSource`, result store, and a built-in strategy resolver.
- [ ] [API-3] Add/update tests for built-in strategy resolver, worker execution wiring, and typed run polling.
- [ ] [API-4] Update backtest YAML scenarios to import daily bars before start/poll/result. 검증: start/poll/result scenario가 run id, terminal status, result summary key를 출력한다.
- [ ] [API-5] Run API/worker/CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## [API-1] GetBacktestRun Rail
### 문제
[packages/contracts/proto/alt/v1/backtest.proto](/config/workspace/alt/packages/contracts/proto/alt/v1/backtest.proto:44) defines `GetBacktestRunRequest`, and [apps/cli/internal/operator/runner.go](/config/workspace/alt/apps/cli/internal/operator/runner.go:317) polls it. But API and worker session handlers only register start/list/detail/result/compare: [services/worker/internal/socket/backtest.go](/config/workspace/alt/services/worker/internal/socket/backtest.go:52) and API tests do not include `GetBacktestRunRequest`.
### 해결 방법
Add `GetBacktestRun` to `workerclient.WorkerClient`, implement a one-line socket client method, add API forwarding handler, and add worker handler that validates `run_id` and reads the run through store-backed analysis/run store. Prefer using `Analysis.GetRunDetail` to avoid growing `Deps` unless direct `BacktestRunStore` access is clearer.
Before (`workerclient/client.go:31`):
```go
StartBacktest(ctx context.Context, req *altv1.StartBacktestRequest) (*altv1.StartBacktestResponse, error)
ListBacktestRuns(ctx context.Context, req *altv1.ListBacktestRunsRequest) (*altv1.ListBacktestRunsResponse, error)
```
After:
```go
StartBacktest(ctx context.Context, req *altv1.StartBacktestRequest) (*altv1.StartBacktestResponse, error)
GetBacktestRun(ctx context.Context, req *altv1.GetBacktestRunRequest) (*altv1.GetBacktestRunResponse, error)
ListBacktestRuns(ctx context.Context, req *altv1.ListBacktestRunsRequest) (*altv1.ListBacktestRunsResponse, error)
```
### 수정 파일 및 체크리스트
- [ ] `services/api/internal/workerclient/client.go`: interface and method.
- [ ] `services/api/internal/workerclient/client_test.go`: fake worker `GetBacktestRun` round-trip.
- [ ] `services/api/internal/socket/backtest.go`: forwarding handler.
- [ ] `services/api/internal/socket/backtest_test.go`: fake client method, validation, forwarding, socket test, handler registration.
- [ ] `services/api/internal/socket/server_test.go`: capability sync if needed.
- [ ] `services/worker/internal/socket/backtest.go`: handler registration and implementation.
- [ ] `services/worker/internal/socket/backtest_test.go`: success, validation, not found, unavailable, socket test, handler coverage.
### 테스트 작성
Add `TestHandleGetBacktestRunForwards`, `TestHandleGetBacktestRunRequiresRunID`, worker success/not_found, and socket typed validation tests.
### 중간 검증
```bash
go test ./services/api/internal/workerclient ./services/api/internal/socket ./services/worker/internal/socket -run 'GetBacktestRun|BacktestHandlers|Capabilities' -count=1
```
Expected: API and worker poll rail tests pass.
## [API-2] Worker Runtime Wiring
### 문제
[services/worker/cmd/alt-worker/main.go](/config/workspace/alt/services/worker/cmd/alt-worker/main.go:42) sets Analysis/Results/Instruments/Bars but leaves [services/worker/cmd/alt-worker/main.go](/config/workspace/alt/services/worker/cmd/alt-worker/main.go:61) `backtest_start_surface` false. `RegisterRunBacktestHandler` and `NewBacktestStarter` exist but are not wired in production.
### 해결 방법
Add a worker-internal built-in strategy resolver, e.g. `NewBuiltInStrategyPort()` with `strategy-v1` buy-and-hold or deterministic minimal strategy. In `main.go`, build:
```go
barSource := workerbacktest.NewStorageBarSource(store, store)
strategyPort := workerbacktest.NewBuiltInStrategyPort()
engine := workerbacktest.NewEngine(barSource, strategyPort, store)
jobs.RegisterRunBacktestHandler(runner, store, engine, time.Now)
starter := jobs.NewBacktestStarter(runner, store)
deps.Starter = starter
```
Keep import aliases clear (`workerbacktest`) to avoid package name collisions.
### 수정 파일 및 체크리스트
- [ ] `services/worker/internal/backtest/strategies.go`: built-in strategy resolver and strategy implementation.
- [ ] `services/worker/internal/backtest/strategies_test.go`: known strategy success and unknown strategy error.
- [ ] `services/worker/cmd/alt-worker/main.go`: wire bar source, strategy port, engine, job handler, starter.
- [ ] `services/worker/internal/socket/server_test.go`: capability now reflects Starter when deps include it.
### 테스트 작성
Add strategy tests and, if feasible, extract a small helper for store-backed deps wiring so a unit test can assert `Starter != nil` without launching the process. If extraction adds too much scope, document in `계획 대비 변경 사항` and rely on strategy/job/socket tests.
### 중간 검증
```bash
go test ./services/worker/internal/backtest ./services/worker/internal/jobs ./services/worker/internal/socket -count=1
```
Expected: worker backtest engine/job/socket tests pass.
## [API-3] Execution Evidence Tests
### 문제
Existing job and engine tests are separate. They do not prove command start, poll, and result can use storage-backed bars together.
### 해결 방법
Add or update a worker test using in-memory/fake stores to import/upsert bars, start a run synchronously via `BacktestStarter` with `WithStarterLaunch(func(fn func()) { fn() })`, poll/get run, and get result. Keep it unit-level; no Docker is required.
### 수정 파일 및 체크리스트
- [ ] `services/worker/internal/jobs/backtest_starter_test.go` or new worker backtest flow test: synchronous launch flow.
- [ ] `services/worker/internal/backtest/fixture_test.go`: reuse or extend imported bars fixture if lower risk.
- [ ] `services/worker/internal/socket/backtest_test.go`: typed run status/result queries as needed.
### 테스트 작성
Write a test whose assertions cover pending/running/succeeded transition enough for the command flow. At minimum assert terminal status `succeeded` and `GetResult` summary fields exist.
### 중간 검증
```bash
go test ./services/worker/... -run 'Backtest.*Flow|StorageBarSource|RunBacktest|BacktestStarter' -count=1
```
Expected: focused worker flow tests pass.
## [API-4] Backtest YAML Flow
### 문제
[apps/cli/testdata/operator/backtest_run_request.yaml](/config/workspace/alt/apps/cli/testdata/operator/backtest_run_request.yaml:1), [apps/cli/testdata/operator/backtest_run_polling.yaml](/config/workspace/alt/apps/cli/testdata/operator/backtest_run_polling.yaml:1), and [apps/cli/testdata/operator/backtest_result_summary.yaml](/config/workspace/alt/apps/cli/testdata/operator/backtest_result_summary.yaml:1) start runs without importing bars first.
### 해결 방법
Add an `import_daily_bars` step to each backtest scenario before `start_backtest`, using the same symbol/date range as the import/status scenario. Keep `strategy_id: strategy-v1` if the built-in resolver uses that ID. Update expected JSONL fixtures to include import line and adjusted step counts.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/testdata/operator/backtest_run_request.yaml`
- [ ] `apps/cli/testdata/operator/backtest_run_polling.yaml`
- [ ] `apps/cli/testdata/operator/backtest_result_summary.yaml`
- [ ] matching expected JSONL fixtures.
- [ ] `apps/cli/internal/operator/runner_error_test.go` or runner tests if expectations change.
### 테스트 작성
Update fake API tests so backtest scenarios include import line and still assert `run_id`, terminal `run_status`, and summary keys.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run 'Backtest|Handoff' -count=1
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_run_polling.yaml
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_result_summary.yaml
```
Expected: tests and scenario validation pass.
## [API-5] Verification
### 문제
This plan spans API, worker, and CLI; a package-only test can miss an interface compile failure in another module.
### 해결 방법
Run the final commands exactly.
### 수정 파일 및 체크리스트
- [ ] No extra files.
### 테스트 작성
No additional tests.
### 중간 검증
```bash
git diff --check
```
Expected: no warnings.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `services/api/internal/workerclient/client.go` | API-1 |
| `services/api/internal/workerclient/client_test.go` | API-1 |
| `services/api/internal/socket/backtest.go` | API-1 |
| `services/api/internal/socket/backtest_test.go` | API-1 |
| `services/api/internal/socket/server_test.go` | API-1 |
| `services/worker/internal/socket/backtest.go` | API-1 |
| `services/worker/internal/socket/backtest_test.go` | API-1 |
| `services/worker/internal/backtest/strategies.go` | API-2 |
| `services/worker/internal/backtest/strategies_test.go` | API-2 |
| `services/worker/cmd/alt-worker/main.go` | API-2 |
| `services/worker/internal/socket/server_test.go` | API-2 |
| `services/worker/internal/jobs/backtest_starter_test.go` | API-3 |
| `services/worker/internal/backtest/fixture_test.go` | API-3 |
| `apps/cli/testdata/operator/backtest_run_request.yaml` | API-4 |
| `apps/cli/testdata/operator/backtest_run_polling.yaml` | API-4 |
| `apps/cli/testdata/operator/backtest_result_summary.yaml` | API-4 |
| `apps/cli/testdata/operator/expected/backtest_run_request.jsonl` | API-4 |
| `apps/cli/testdata/operator/expected/backtest_run_polling.jsonl` | API-4 |
| `apps/cli/testdata/operator/expected/backtest_result_summary.jsonl` | API-4 |
| `apps/cli/internal/operator/runner_error_test.go` | API-4 |
## 최종 검증
```bash
go test ./services/api/... -count=1
go test ./services/worker/... -count=1
go test ./apps/cli/... -count=1
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_run_polling.yaml
go run ./apps/cli/cmd/alt operator scenario validate --file apps/cli/testdata/operator/backtest_result_summary.yaml
git diff --check
```
Expected: all commands exit 0. Fresh `go test -count=1` is required.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,134 @@
<!-- task=m-command-first-operator-workflow/05+03,04_operator_handoff plan=0 tag=DOCS -->
# Code Review Reference - DOCS
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-03
task=m-command-first-operator-workflow/05+03,04_operator_handoff, plan=0, tag=DOCS
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `operator-handoff`: command-first workflow가 UI MVP로 넘길 화면 후보와 아직 화면으로 올리지 않을 항목을 분리한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [DOCS-1] Handoff Matrix | [ ] |
| [DOCS-2] Handoff Guard Tests | [ ] |
| [DOCS-3] Verification | [ ] |
## 구현 체크리스트
- [ ] [DOCS-1] Update handoff matrix with command, expected output key, repeatability, UI candidate, and UI defer reason for import/status/backtest workflows.
- [ ] [DOCS-2] Add tests that guard required scenarios and handoff columns/keys. 검증: handoff 문서가 command, expected output key, 반복 운영 여부, UI defer 사유를 함께 기록하고, 충분히 표면화되지 않은 기능은 화면 후보에서 제외한다.
- [ ] [DOCS-3] Run docs/CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_local_G05_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_local_G05_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/05+03,04_operator_handoff/``agent-task/archive/YYYY/MM/m-command-first-operator-workflow/05+03,04_operator_handoff/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-local-G05.md``CODE_REVIEW-local-G05.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- Handoff doc separates UI candidates from deferred items.
- Commands, expected output keys, repeatability, and defer reasons are all documented.
- No UI implementation, wireframe commitment, or screen layout sneaks into this task.
- Tests guard required rows/fixtures/keys.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### DOCS-1 중간 검증
```bash
$ rg --sort path -n 'UI defer reason|repeatable|expected output' apps/cli/testdata/operator/headless_validation.md
(output)
```
### DOCS-2 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run Handoff -count=1
(output)
```
### DOCS-3 중간 검증
```bash
$ git diff --check
(output)
```
### 최종 검증
```bash
$ go test ./apps/cli/... -count=1
$ rg --sort path -n 'UI defer reason|repeatable|expected output' apps/cli/testdata/operator/headless_validation.md
$ git diff --check
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

View file

@ -0,0 +1,203 @@
<!-- task=m-command-first-operator-workflow/05+03,04_operator_handoff plan=0 tag=DOCS -->
# Plan - Operator Handoff
## 이 파일을 읽는 구현 에이전트에게
이 plan은 구현 지시서이며, 구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채운다. 이 task는 `03+02_market_status_scenario``04+02_backtest_runtime_flow` 완료 뒤 구현한다. 최종 판정, archive 이동, `complete.log` 작성은 code-review-skill 전용이다. 사용자-only blocker가 있으면 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다.
## 배경
사용자는 화면 작업을 뒤로 미루고 기능이 표면화될 때까지 command-first 운영을 유지하려고 한다. 따라서 UI MVP로 넘길 후보는 command, expected output key, 반복 운영 여부, defer 사유가 충분히 정리된 뒤에만 올라가야 한다. 이 작업은 기존 headless validation handoff를 현재 마일스톤의 import/status/backtest 흐름 기준으로 갱신한다.
## 사용자 리뷰 요청 흐름
구현 중 사용자-only blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이를 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
- `operator-handoff`: command-first workflow가 UI MVP로 넘길 화면 후보와 아직 화면으로 올리지 않을 항목을 분리한다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-test/local/rules.md`
- `agent-test/local/operations-smoke.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/operator-surface/PHASE.md`
- `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- `apps/cli/testdata/operator/headless_validation.md`
- `apps/cli/internal/operator/handoff_test.go`
- `apps/cli/testdata/operator/expected/market_data_status_query.jsonl`
- `apps/cli/testdata/operator/expected/backtest_run_polling.jsonl`
- `apps/cli/testdata/operator/expected/backtest_result_summary.jsonl`
- `bin/dev`
- `docs/kis-live-secret-handoff.md`
- `docs/kis-live-secret-guide.md`
### 테스트 환경 규칙
- test_env: `local`.
- Matched profile: `operations-smoke`.
- Applied commands: `go test ./apps/cli/...`, optional scenario validate commands if fixture paths are changed, and `git diff --check`.
### 테스트 커버리지 공백
- Current handoff tests require scenario names and JSONL validity, but do not verify UI candidate/defer reason fields.
- Handoff doc currently has a `Remaining Flutter wireframe dependency` column, but not explicit `repeatable operation` or `UI candidate/defer reason` separation for newly surfaced workflows.
### 심볼 참조
- Renamed/removed symbols: none.
### 분할 판단
- Shared task group: `agent-task/m-command-first-operator-workflow/`.
- This subtask directory is `05+03,04_operator_handoff`.
- Predecessor index `03`: `03+02_market_status_scenario`; completion missing at plan creation.
- Predecessor index `04`: `04+02_backtest_runtime_flow`; completion missing at plan creation.
- Implementation waits for both predecessor complete logs.
### 범위 결정 근거
- Excludes Flutter UI, wireframes, navigation, charts, and widgets.
- Excludes changing command behavior; predecessors own behavior.
- Excludes roadmap archive movement; code-review/runtime own completion handling.
### 빌드 등급
- build=`local-G05`, review=`local-G05`: bounded docs/test update with explicit fixtures and no runtime code changes expected.
## 의존 관계 및 구현 순서
- Wait for `03+02_market_status_scenario` and `04+02_backtest_runtime_flow` complete logs.
- Read their completed review/complete evidence if needed through active/archive complete.log dependency exception only.
- Update handoff doc and tests.
## 구현 체크리스트
- [ ] [DOCS-1] Update handoff matrix with command, expected output key, repeatability, UI candidate, and UI defer reason for import/status/backtest workflows.
- [ ] [DOCS-2] Add tests that guard required scenarios and handoff columns/keys. 검증: handoff 문서가 command, expected output key, 반복 운영 여부, UI defer 사유를 함께 기록하고, 충분히 표면화되지 않은 기능은 화면 후보에서 제외한다.
- [ ] [DOCS-3] Run docs/CLI verification and `git diff --check`.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## [DOCS-1] Handoff Matrix
### 문제
[apps/cli/testdata/operator/headless_validation.md](/config/workspace/alt/apps/cli/testdata/operator/headless_validation.md:24) is the existing UI handoff matrix, but it only has a broad remaining wireframe dependency column. The current milestone needs explicit separation between UI candidates and items still deferred.
### 해결 방법
Keep the existing file instead of creating a new doc. Update the matrix columns to include:
- command,
- input fixture,
- expected output fixture,
- expected output keys,
- repeatable operation (`yes/no/manual-only`),
- UI candidate,
- UI defer reason.
Do not describe actual UI layout or build a screen.
### 수정 파일 및 체크리스트
- [ ] `apps/cli/testdata/operator/headless_validation.md`: update matrix and notes.
- [ ] `bin/dev`: update short hint only if scenario names changed in predecessors.
### 테스트 작성
No direct code test for prose, but DOCS-2 must assert required columns/key text to avoid silent drift.
### 중간 검증
```bash
rg --sort path -n 'UI defer reason|repeatable|expected output' apps/cli/testdata/operator/headless_validation.md
```
Expected: updated column/section text is present.
## [DOCS-2] Handoff Guard Tests
### 문제
[apps/cli/internal/operator/handoff_test.go](/config/workspace/alt/apps/cli/internal/operator/handoff_test.go:12) guards scenario names and JSONL shape, but not the new handoff decisions.
### 해결 방법
Extend tests to assert:
- required scenarios include import/status/backtest scenarios produced by predecessors,
- each required scenario row references input and expected output fixtures,
- matrix contains the new handoff columns,
- expected JSONL fixtures contain the keys promised by each row where feasible (`provider`, `instrument_count`, `bar_count`, `count`, `run_id`, `run_status`, `starting_cash`, `ending_equity`, `total_return`, `trade_count`).
### 수정 파일 및 체크리스트
- [ ] `apps/cli/internal/operator/handoff_test.go`: add column/key coverage.
- [ ] `apps/cli/testdata/operator/expected/*.jsonl`: no content changes unless predecessor fixtures require final alignment.
### 테스트 작성
Add `TestHandoffMatrixDocumentsCommandFirstColumns` and `TestExpectedFixturesContainPromisedKeys`.
### 중간 검증
```bash
go test ./apps/cli/internal/operator -run Handoff -count=1
```
Expected: handoff guard tests pass.
## [DOCS-3] Verification
### 문제
Docs-only changes can still break CLI fixture tests if paths or scenario names drift.
### 해결 방법
Run CLI package tests and diff check.
### 수정 파일 및 체크리스트
- [ ] No extra files.
### 테스트 작성
No additional tests.
### 중간 검증
```bash
git diff --check
```
Expected: no warnings.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `apps/cli/testdata/operator/headless_validation.md` | DOCS-1 |
| `bin/dev` | DOCS-1 |
| `apps/cli/internal/operator/handoff_test.go` | DOCS-2 |
| `apps/cli/testdata/operator/expected/*.jsonl` | DOCS-2 |
## 최종 검증
```bash
go test ./apps/cli/... -count=1
rg --sort path -n 'UI defer reason|repeatable|expected output' apps/cli/testdata/operator/headless_validation.md
git diff --check
```
Expected: all commands exit 0.
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.