<!-- task=m-backtest-scenario-automation/05+04_runtime_startup plan=0 tag=TEST -->

# Runtime Startup Plan

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. active 파일을 유지한 채 리뷰 준비를 보고하고, 종결/로그화/`complete.log`/archive 이동은 code-review에 맡긴다. 사용자 결정, 사용자 소유 외부 환경, secret 준비, 범위 충돌이 필요하면 review stub의 `사용자 리뷰 요청`에 근거를 남기고 멈춘다. 직접 사용자 prompt, `request_user_input`, `USER_REVIEW.md` 작성, `complete.log` 작성은 금지다.

## 배경

원격 smoke는 migration 이후 worker가 store-backed surface를 열고, API가 그 worker와 연결된 상태에서 CLI scenario를 실행해야 의미가 있다. 이 계획은 `migration -> worker -> API -> CLI scenario` 순서를 고정하고, `ALT_WORKER_SOCKET_URL`, bind host/port, SOPS 기반 KIS env가 worker runtime까지 전달되는지 evidence로 남긴다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 prompt는 금지이며, code-review가 사용자 리뷰 요청 검증과 `USER_REVIEW.md` 작성을 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/backtest-loop/milestones/backtest-scenario-automation.md`
- Task ids:
  - `runtime-startup`: 원격 worker/API 실행 순서를 `migration -> worker -> API -> CLI scenario`로 정리하고 worker availability 및 import typed success를 검증한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/backtest-loop/PHASE.md`
- `agent-roadmap/phase/backtest-loop/milestones/backtest-scenario-automation.md`
- `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-ops/rules/project/domain/api/rules.md`
- `agent-ops/rules/project/domain/worker/rules.md`
- `bin/kis-sops-env`
- `services/worker/cmd/alt-worker/main.go`
- `services/worker/internal/config/config.go`
- `services/api/cmd/alt-api/main.go`
- `services/api/internal/config/config.go`
- `services/api/internal/socket/handlers.go`
- `services/api/internal/socket/server_test.go`
- `apps/cli/testdata/operator/api_connection_smoke.yaml`
- `apps/cli/testdata/operator/backtest_result_summary.yaml`
- `apps/cli/testdata/operator/headless_validation.md`

### 테스트 환경 규칙

`test_env=local`이다. `agent-test/local/rules.md`, `operations-smoke`, `api-smoke`, `worker-smoke`를 읽었다. local baseline은 `go test -count=1 ./apps/cli/internal/operator ./services/api/internal/socket ./services/worker/...`이며, 실제 완료 검증은 원격 runner에서 process startup과 CLI smoke를 실행해야 한다. secret/env 값은 private rule에서 세션 변수로만 읽고 task/review log에는 raw 값을 쓰지 않는다.

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

- worker/API long-running process startup: unit tests는 config와 capability logic을 검증하지만 실제 원격 process 순서와 bind port 충돌은 보장하지 않는다.
- SOPS 기반 KIS env 전달: `bin/kis-sops-env`는 wrapper 구조만 있고 실제 secret presence는 원격에서만 검증된다.
- `worker-available`: API handler unit test는 fake worker로 검증하지만 실제 API-to-worker 연결은 원격 smoke가 필요하다.

### 심볼 참조

none. rename/remove 없음.

### 분할 판단

multi-plan 중 두 번째 작업이다. `05+04_runtime_startup`은 `04_remote_env_sync`의 active 또는 archived `complete.log`가 필요하다. 현 시점에는 새 plan을 함께 작성하는 단계이므로 predecessor는 아직 active complete 상태가 아니다. 구현 시작 전 `agent-task/m-backtest-scenario-automation/04_remote_env_sync/complete.log` 또는 archive matching `04_*` complete.log를 확인해야 한다.

### 범위 결정 근거

DB/Redis/migration 정합성은 predecessor가 소유한다. matrix seed fixture/code 변경과 result summary remote completion은 후속 `06+05_matrix_seed`, `07+05_result_poll_remote`가 소유한다. 이 작업은 runtime startup과 최소 scenario evidence만 다룬다.

### 빌드 등급

`cloud-G08`. 원격 process orchestration, SOPS env, API-worker socket 연결, CLI smoke evidence가 한 번에 얽혀 있어 terminal/runtime 실패 해석이 중요하다.

## 의존 관계 및 구현 순서

`05+04_runtime_startup`은 디렉터리명 기준으로 `04_remote_env_sync`에 의존한다. 구현 시작 전에 04 작업의 `complete.log`가 active 또는 archive에 있는지 확인한다. 없으면 구현하지 말고 review stub의 `사용자 리뷰 요청`이 아니라 predecessor missing으로 보고한다.

## 구현 체크리스트

- [ ] `04_remote_env_sync` complete.log가 있는지 확인하고 경로를 기록한다.
- [ ] 원격 runner에서 migration 이후 worker를 SOPS env wrapper와 DB/Redis env로 기동하고 `worker ready` 로그의 store-backed surface flags를 sanitized로 기록한다.
- [ ] 원격 runner에서 API를 `ALT_WORKER_SOCKET_URL`과 bind host/port를 명시해 기동하고 worker 연결 상태를 기록한다.
- [ ] `api_connection_smoke.yaml`이 `worker-available` capability를 요구하는 상태에서 원격 API socket을 대상으로 exit code 0을 기록한다.
- [ ] `backtest_result_summary.yaml` 또는 동등한 import/backtest scenario의 import step이 typed success로 반환되는지 원격 JSONL evidence를 기록한다.
- [ ] 필요하면 `apps/cli/testdata/operator/headless_validation.md`에 raw 값 없는 runtime startup handoff 절차를 보강한다.
- [ ] `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] Worker/API startup and worker availability smoke

#### 문제

[agent-roadmap/phase/backtest-loop/milestones/backtest-scenario-automation.md](/config/workspace/alt/agent-roadmap/phase/backtest-loop/milestones/backtest-scenario-automation.md:49)는 `migration -> worker -> API -> CLI scenario` 순서를 요구한다. [services/worker/cmd/alt-worker/main.go](/config/workspace/alt/services/worker/cmd/alt-worker/main.go:38)는 DB pool 생성 성공 시에만 store-backed deps를 주입하고, [services/api/internal/socket/handlers.go](/config/workspace/alt/services/api/internal/socket/handlers.go:81)는 worker client 연결 여부에 따라 `worker-available`/`worker-unavailable` capability를 나눈다. [apps/cli/testdata/operator/api_connection_smoke.yaml](/config/workspace/alt/apps/cli/testdata/operator/api_connection_smoke.yaml:11)는 이제 `worker-available`을 요구하므로 실제 worker 연결 없는 API는 실패해야 한다.

#### 해결 방법

원격 runner에서 predecessor migration evidence를 확인한 뒤 worker를 먼저 실행한다. worker는 `bin/kis-sops-env`와 DB/Redis env를 사용하고 [bin/kis-sops-env](/config/workspace/alt/bin/kis-sops-env:29)의 decrypted values는 command lifetime에만 둔다. API는 `ALT_WORKER_SOCKET_URL`을 worker socket으로 설정해 시작한다. CLI는 `api_connection_smoke.yaml`과 최소 import/backtest scenario를 원격 API socket 대상으로 실행한다.

#### 수정 파일 및 체크리스트

- [ ] `apps/cli/testdata/operator/headless_validation.md` - runtime startup 절차 또는 evidence 설명이 필요할 때 raw 값 없이 보강한다.
- [ ] 소스 변경이 필요해지면 `services/api/**` 또는 `services/worker/**` 변경 사유와 검증을 `계획 대비 변경 사항`에 기록한다.

#### 테스트 작성

새 unit test는 기본적으로 작성하지 않는다. 이 작업의 성공 기준은 실제 원격 process 연결과 KIS env 주입이며 unit test로 대체할 수 없다. 단, 구현 중 소스 변경이 생기면 해당 도메인의 regression test를 추가한다.

#### 중간 검증

```bash
go test -count=1 ./apps/cli/internal/operator ./services/api/internal/socket ./services/worker/...
```

기대 결과: exit code 0.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/cli/testdata/operator/headless_validation.md` | TEST-1, 필요 시 절차 보강 |
| active review stub | TEST-1 evidence 기록 |

## 최종 검증

```bash
git diff --check
go test -count=1 ./apps/cli/internal/operator ./services/api/internal/socket ./services/worker/...
test -f agent-task/m-backtest-scenario-automation/04_remote_env_sync/complete.log || find agent-task/archive -path '*/m-backtest-scenario-automation/04_remote_env_sync/complete.log' -print -quit
ssh "$ALT_REMOTE_SSH" "set -euo pipefail; cd \"$ALT_REMOTE_ALT_ROOT/services/worker\"; go run ./cmd/alt-worker-migrate"
ssh "$ALT_REMOTE_SSH" "set -euo pipefail; cd \"$ALT_REMOTE_ALT_ROOT\"; bin/kis-sops-env sh -lc 'go run ./services/worker/cmd/alt-worker' > /tmp/alt-worker.log 2>&1 & echo \$! > /tmp/alt-worker.pid"
ssh "$ALT_REMOTE_SSH" "set -euo pipefail; cd \"$ALT_REMOTE_ALT_ROOT\"; ALT_WORKER_SOCKET_URL=\"ws://127.0.0.1:18031/socket\" go run ./services/api/cmd/alt-api > /tmp/alt-api.log 2>&1 & echo \$! > /tmp/alt-api.pid"
ssh "$ALT_REMOTE_SSH" "set -euo pipefail; cd \"$ALT_REMOTE_ALT_ROOT/apps/cli\"; go run ./cmd/alt operator scenario run --file testdata/operator/api_connection_smoke.yaml --api-url \"ws://127.0.0.1:18030/socket\" --output jsonl"
ssh "$ALT_REMOTE_SSH" "set -euo pipefail; cd \"$ALT_REMOTE_ALT_ROOT/apps/cli\"; go run ./cmd/alt operator scenario run --file testdata/operator/backtest_result_summary.yaml --api-url \"ws://127.0.0.1:18030/socket\" --output jsonl"
```

기대 결과: local 명령 exit code 0. predecessor complete.log 확인. 원격 API smoke는 `worker-available` 기대를 만족하고 exit code 0. result summary 또는 동등 scenario는 import step typed success를 포함한다. runtime 종료/cleanup 명령과 log tail은 review stub에 실제로 기록한다.

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