<!-- task=02+01_process_executor_commands plan=1 tag=REVIEW_REFACTOR -->

# ProcessExecutor Command Rollout Follow-up Plan

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

**구현 마지막 단계에서 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 채워야 한다. 해당 파일의 모든 구현 소유 섹션을 채우기 전까지 작업은 완료가 아니다.** 이 plan은 `code_review_cloud_G07_0.log`의 Required 이슈만 처리한다.

## 배경

이전 구현은 command 파일의 `ProcessExecutor.start/run` 직접 호출을 대부분 `runtime.start/run`으로 이전했지만, 리뷰에서 두 가지 Required 이슈가 남았다.

- `BuildiOS.execute` main build path가 `runtime.start` 결과의 `ProcessData.exitCode`를 우선 사용하지 않아 fake runtime 검증이 막힌다.
- iOS/macOS command shell 동작 변경이 plan과 구현 기록, 회귀 테스트 없이 섞였다.

## 구현 체크리스트

- [ ] `BuildiOS.execute` main build path가 fake runtime `ProcessData.exitCode`를 사용하도록 수정하고 회귀 테스트를 추가한다.
- [ ] iOS/macOS command shell 동작 변경을 후속 범위로 명시하고 shell-level 회귀 테스트로 고정하거나, 의도하지 않은 변경은 되돌린다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 `ProcessExecutor` 잔여 호출을 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REFACTOR-1] BuildiOS fake runtime exit code 호환

#### 문제

`BuildiOS.execute`는 `runtime.start`로 받은 `ProcessData`에서 exit code를 읽을 때 아직 실제 `Process`를 직접 요구한다.

Before:

```dart
var exitCode = await process.process.exitCode;
```

fake runtime의 `ProcessData`가 이미 `exitCode`를 제공해도 이 경로는 `process` getter를 호출해 테스트가 실패한다.

#### 해결 방법

`GitHubPullRequestCreate/List`에 적용된 것과 같은 방어 패턴으로 변경한다.

After:

```dart
var exitCode = process.exitCode ?? await process.process.exitCode;
```

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

- [ ] `lib/oto/commands/build/build_ios_build.dart`
- [ ] `test/oto_command_runtime_test.dart`

#### 테스트 작성

작성한다. temp workspace에 최소 `*.xcodeproj/project.pbxproj`를 만들고 `BuildiOS.execute`를 fake runtime으로 실행해 main build path가 `UnsupportedError` 없이 완료되는지 확인한다. 동시에 `runtime.start` shell에 `xcodebuild`가 기록되는지 검증한다.

#### 중간 검증

```bash
dart test test/oto_command_runtime_test.dart
```

예상: 추가 runtime 테스트 통과.

### [REVIEW_REFACTOR-2] iOS/macOS shell 동작 변경 검증

#### 문제

이전 구현에는 runtime 이전과 별개인 shell 동작 변경이 포함됐다.

- `lib/oto/commands/build/build_ios_build.dart`: `PodFile` → `Podfile`, `derivedDataPath` 값 사용, keychain/cd shell 구성 변경
- `lib/oto/commands/build/macos_signing.dart`: `entitlementPath` 조건 변경

이 변경들은 의도한 기능 수정일 수 있으나, 이전 plan/review 구현 기록과 테스트에 없어서 완료 판정을 줄 수 없다.

#### 해결 방법

후속 범위에서 해당 변경을 명시적으로 확정한다. 의도한 수정이면 shell-level 회귀 테스트를 추가하고 `CODE_REVIEW`의 `계획 대비 변경 사항` 또는 `주요 설계 결정`에 기록한다. 의도한 범위가 아니면 runtime 위임 변경만 남기도록 되돌린다.

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

- [ ] `lib/oto/commands/build/build_ios_build.dart`
- [ ] `lib/oto/commands/build/macos_signing.dart`
- [ ] `test/oto_command_runtime_test.dart`

#### 테스트 작성

작성한다.

- `BuildiOS.execute` fake runtime 테스트에서 `derivedDataPath`, `macPassword`, `cleanPod`/`Podfile` 조건이 의도한 shell 조각으로 반영되는지 검증한다.
- `CodeSign` fake runtime 테스트에서 `entitlementPath`가 있을 때만 `--entitlements`가 포함되는지 검증한다.

#### 중간 검증

```bash
dart test test/oto_command_runtime_test.dart
```

예상: 추가 shell-level 회귀 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/oto/commands/build/build_ios_build.dart` | REVIEW_REFACTOR-1, REVIEW_REFACTOR-2 |
| `lib/oto/commands/build/macos_signing.dart` | REVIEW_REFACTOR-2 |
| `test/oto_command_runtime_test.dart` | REVIEW_REFACTOR-1, REVIEW_REFACTOR-2 |

## 최종 검증

```bash
test -f agent-task/archive/2026/05/01_command_runtime_api/complete.log
dart format lib/oto/commands/build/build_ios_build.dart lib/oto/commands/build/macos_signing.dart test/oto_command_runtime_test.dart
dart analyze
dart test test/oto_command_runtime_test.dart
rg --sort path -n "ProcessExecutor\\.(start|run)" lib/oto/commands -g '!command_runtime.dart' -g '!*.g.dart'
rg --sort path -n "var exitCode = await process\\.process\\.exitCode" lib/oto/commands/build/build_ios_build.dart
```

예상: dependency check 성공, format 정상, analyze/test 통과, 첫 번째 `rg`는 출력 없음, 두 번째 `rg`도 출력 없음.

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