<!-- task=10+07_scheduler_process_runtime_rollout plan=1 tag=REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT -->

# Plan - REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT

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

이 계획은 `code_review_cloud_G08_0.log`의 FAIL 판정에서 나온 Required 항목만 다룬다.
구현의 마지막 단계는 `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션을 모두 채우는 것이다.
아래 `구현 체크리스트` 순서대로 구현하고 중간/최종 검증을 실행한 뒤, 실제 구현 내용과 stdout/stderr를 `CODE_REVIEW-cloud-G08.md`에 기록한다.
리뷰 파일의 아카이브 지시와 `코드리뷰 전용 체크리스트`는 코드리뷰 에이전트 전용이므로 실행하거나 수정하지 않는다.

## 배경

이전 구현은 scheduler runtime rollout의 핵심 변경을 소스에 반영하지 않았다.
`SchedulerManager`는 여전히 실제 process/exit API를 직접 호출하고, `CommandScheduler`는 manager 주입 경로가 없으며, 필수 테스트 파일과 리뷰 검증 출력도 없다.

## 리뷰 발견 사항

- `lib/cli/commands/scheduler/scheduler_manager.dart:205`, `:214`, `:236`, `:244`, `:255`의 직접 process/exit/search 호출을 주입 가능한 boundary로 치환해야 한다.
- `lib/cli/commands/command_scheduler.dart:20`, `:36`에 optional manager/exit handler 주입 경로를 추가해야 한다.
- `test/oto_scheduler_runtime_test.dart`를 추가해 fake runtime/process finder/exit handler와 injected manager routing을 검증해야 한다.
- 구현 완료 후 active `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채워야 한다.

## 구현 체크리스트

- [ ] `SchedulerManager`가 `SystemRuntime`/process finder/exit handler를 주입받고 직접 process/exit 호출을 제거한다.
- [ ] `CommandScheduler`가 optional manager/exit handler 주입을 지원하면서 기존 argument routing을 유지한다.
- [ ] `test/oto_scheduler_runtime_test.dart`에 scheduler fake runtime/routing 테스트를 추가한다.
- [ ] 고정 검증 명령을 실행하고 직접 호출 검색 결과가 `handler.exit()`만 남는지 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1] SchedulerManager process boundary 주입

#### 문제

`SchedulerManager`가 실제 daemon start/kill/search/exit를 직접 호출해 fake runtime으로 검증할 수 없다.
현재 `exit(0)`, `Process.killPid`, `Process.start`, `ProcessExecutor.run`, `findProcess`가 남아 있어 원래 계획의 핵심 계약을 만족하지 못한다.

#### 해결 방법

`SchedulerManager` constructor에 optional `SystemRuntime runtime`, `Future<List<ProcessInfo>> Function(String) processFinder`, `void Function(int) exitHandler`를 추가한다.
기본값은 `DefaultSystemRuntime()`, 기존 `findProcess`, `exit`를 사용해 운영 동작을 유지한다.
`enableScheduler`, `terminate`, `_startProcess`, `_checkProcess`는 이 주입된 boundary만 사용한다.
OS subclass는 `super(...)`로 optional 인자를 전달할 수 있는 constructor를 제공한다.

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

- [ ] `lib/cli/commands/scheduler/scheduler_manager.dart`: runtime/processFinder/exitHandler field와 constructor 추가.
- [ ] `lib/cli/commands/scheduler/scheduler_manager.dart`: `_startProcess`, `terminate`, `_checkProcess`, `enableScheduler` 직접 호출 제거.
- [ ] `lib/cli/commands/scheduler/scheduler_linux.dart`: optional super constructor 호환.
- [ ] `lib/cli/commands/scheduler/scheduler_osx.dart`: optional super constructor 호환.
- [ ] `lib/cli/commands/scheduler/scheduler_windows.dart`: optional super constructor 호환.

#### 테스트 작성

작성한다.
fake runtime과 fake process finder를 사용해 Windows branch의 detached `startExecutable`, non-Windows branch의 shell 실행, pid kill, enable exit handler 호출을 검증한다.
테스트가 실제 process를 시작하거나 kill하지 않아야 한다.

#### 중간 검증

```bash
dart test test/oto_scheduler_runtime_test.dart
```

기대 결과: scheduler runtime 테스트 통과.

### [REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-2] CommandScheduler 주입 호환 및 exit boundary

#### 문제

`CommandScheduler`는 `SchedulerManager.create()`를 필드 초기화에서 고정하고 `exit(0)`를 직접 호출한다.
이 구조에서는 injected fake manager routing을 테스트할 수 없고, 최종 직접 호출 검색도 통과하지 못한다.

#### 해결 방법

기존 default constructor 동작은 유지하되 optional `SchedulerManager? scheduler`, `void Function(int)? exitHandler`를 받는 constructor를 추가한다.
`-r` 성공 경로의 직접 `exit(0)`는 `_exitHandler(0)`처럼 검색 패턴에 걸리지 않는 wrapper 호출로 교체한다.
argument parsing semantics는 변경하지 않는다.

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

- [ ] `lib/cli/commands/command_scheduler.dart`: optional manager/exit handler constructor 추가.
- [ ] `lib/cli/commands/command_scheduler.dart`: 직접 `exit(0)` 제거, 기존 CLI 종료 동작은 기본 exit handler로 유지.

#### 테스트 작성

작성한다.
테스트명: `command_scheduler accepts injected manager for routing`.
검증: `-t`, `-l` 등 최소 하나의 branch가 fake manager로 위임되는지 확인한다.

#### 중간 검증

```bash
dart test test/oto_scheduler_runtime_test.dart
```

기대 결과: injected manager routing 테스트 통과.

### [REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-3] scheduler fake runtime 테스트 추가

#### 문제

필수 테스트 파일 `test/oto_scheduler_runtime_test.dart`가 없어 `dart test test/oto_scheduler_runtime_test.dart`가 파일 없음으로 실패한다.
process boundary 변경은 실제 OS process를 건드리지 않는 fake 기반 검증이 필요하다.

#### 해결 방법

`test/oto_scheduler_runtime_test.dart`를 추가한다.
테스트 파일에는 최소 fake `SystemRuntime`, fake process finder, fake exit handler, 필요 시 test subclass를 두고 public API를 통해 boundary 호출을 검증한다.
테스트가 scheduler 등록 파일을 다루는 경우 임시 디렉터리만 사용하고 repository-local artifact를 남기지 않는다.

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

- [ ] `test/oto_scheduler_runtime_test.dart`: fake runtime/process finder/exit handler 정의.
- [ ] `test/oto_scheduler_runtime_test.dart`: SchedulerManager start/kill/search/exit boundary 검증.
- [ ] `test/oto_scheduler_runtime_test.dart`: CommandScheduler injected manager routing smoke 검증.

#### 테스트 작성

작성한다.

#### 중간 검증

```bash
dart test test/oto_scheduler_runtime_test.dart
```

기대 결과: 모든 scheduler runtime 테스트 통과.

### [REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-4] 검증 출력 및 리뷰 문서 완성

#### 문제

이전 active `CODE_REVIEW-cloud-G08.md`는 구현 완료 표, 구현 체크리스트, 계획 대비 변경 사항, 주요 설계 결정, 검증 결과가 placeholder 상태였다.
리뷰 파일이 채워지지 않으면 구현 완료 여부와 verification trust를 판단할 수 없다.

#### 해결 방법

구현 후 고정 검증 명령을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-cloud-G08.md`에 붙인다.
구현 완료 표와 구현 체크리스트를 실제 완료 상태로 체크하고, 계획 대비 변경 사항과 주요 설계 결정을 구체적으로 기록한다.

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

- [ ] `agent-task/10+07_scheduler_process_runtime_rollout/CODE_REVIEW-cloud-G08.md`: 구현 완료 표와 구현 체크리스트 체크.
- [ ] `agent-task/10+07_scheduler_process_runtime_rollout/CODE_REVIEW-cloud-G08.md`: 계획 대비 변경 사항, 주요 설계 결정, 검증 결과 작성.

#### 테스트 작성

별도 테스트는 위 항목으로 충분하다.

#### 중간 검증

```bash
rg --sort path -n "ProcessExecutor\\.(start|run)|Process\\.run|Process\\.start|Process\\.killPid|exit\\(" lib/cli/commands/scheduler lib/cli/commands/command_scheduler.dart
```

기대 결과: `handler.exit()` 외 직접 process/exit 호출 없음. 출력이 있으면 의도적 예외를 계획 대비 변경 사항에 기록한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/cli/commands/scheduler/scheduler_manager.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1 |
| `lib/cli/commands/scheduler/scheduler_linux.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1 |
| `lib/cli/commands/scheduler/scheduler_osx.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1 |
| `lib/cli/commands/scheduler/scheduler_windows.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1 |
| `lib/cli/commands/command_scheduler.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-2 |
| `test/oto_scheduler_runtime_test.dart` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-1, REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-2, REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-3 |
| `agent-task/10+07_scheduler_process_runtime_rollout/CODE_REVIEW-cloud-G08.md` | REVIEW_SYSTEM_RUNTIME_SCHEDULER_ROLLOUT-4 |

## 최종 검증

```bash
test -f agent-task/archive/2026/05/07_system_runtime_foundation/complete.log || test -f agent-task/07_system_runtime_foundation/complete.log
dart format --output=none --set-exit-if-changed lib/cli/commands/scheduler/scheduler_manager.dart lib/cli/commands/scheduler/scheduler_linux.dart lib/cli/commands/scheduler/scheduler_osx.dart lib/cli/commands/scheduler/scheduler_windows.dart lib/cli/commands/command_scheduler.dart test/oto_scheduler_runtime_test.dart
dart analyze
dart test test/oto_scheduler_runtime_test.dart
rg --sort path -n "ProcessExecutor\\.(start|run)|Process\\.run|Process\\.start|Process\\.killPid|exit\\(" lib/cli/commands/scheduler lib/cli/commands/command_scheduler.dart
```

기대 결과: 선행 complete marker 존재, 포맷/analyze/test 성공, `rg`는 `handler.exit()` 외 직접 process/exit 호출을 보고하지 않음.

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