<!-- task=step_events/02+01_execution_result_output plan=1 tag=REVIEW_STEP_EVENT_OUTPUT -->

# REVIEW_STEP_EVENT_OUTPUT - BuildResult stepEvents 스냅샷 보존

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

이 계획은 `code_review_cloud_G07_0.log`의 Required 이슈만 해결한다. 구현 완료 전 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 반드시 채우고, active 파일은 제자리에 둔 채 리뷰 준비 상태를 보고한다. 판정과 archive 이동은 code-review-skill 전용이다.

## 배경

이전 구현은 `executionResult` JSON에 `stepEvents`를 노출했지만, `Application.build()`가 `BuildResult` 생성 시 `context.stepEvents` mutable 리스트를 그대로 전달했다. 다음 build 시작 시 `context.resetStepEvents()`가 같은 리스트를 비우므로, 이전 `BuildResult`가 완료 시점의 이벤트 히스토리를 안정적으로 보존하지 못한다.

## 구현 체크리스트

- [ ] `Application.build()` 성공/실패 return path 모두 `context.stepEvents`의 snapshot을 `BuildResult`에 전달하도록 수정한다.
- [ ] 이전 `BuildResult`의 `stepEvents`/`toJson()`이 다음 build 이후에도 유지되는 회귀 테스트를 추가한다.
- [ ] 중간 검증과 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_STEP_EVENT_OUTPUT-1] BuildResult stepEvents 스냅샷 보존

### 문제

[Application.build](/config/workspace/oto/lib/oto/application.dart:160)와 [Application.build](/config/workspace/oto/lib/oto/application.dart:166)가 `context.stepEvents`를 그대로 `BuildResult`에 넘긴다. 같은 메서드 시작부 [Application.build](/config/workspace/oto/lib/oto/application.dart:81)는 다음 build마다 `context.resetStepEvents()`를 호출하므로, 이전 build 결과 객체의 `stepEvents`도 함께 비워질 수 있다.

현재 형태:

```dart
return BuildResult.failure(e, stacktrace, stepEvents: context.stepEvents);
...
return BuildResult.success(stepEvents: context.stepEvents);
```

### 해결 방법

성공/실패 반환 시 완료 시점의 이벤트 리스트를 복사해서 전달한다. 구현은 기존 구조를 우선하되, 두 return path에서 동일한 실수를 반복하지 않도록 작은 지역 변수 또는 helper를 사용해도 된다.

예시:

```dart
final stepEvents = List<StepEvent>.of(context.stepEvents);
return BuildResult.success(stepEvents: stepEvents);
```

`BuildResult` 생성자 자체에서 defensive copy를 하도록 바꾸는 대안도 가능하지만, 기존 `const BuildResult.success()` 호출 호환성을 깨뜨리지 않는지 먼저 확인한다. 단순 call-site snapshot으로 충분하면 그쪽을 우선한다.

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

- [ ] `lib/oto/application.dart`: success/failure result 생성 시 `context.stepEvents` snapshot 전달.
- [ ] `test/oto_application_test.dart`: 첫 번째 build의 result JSON이 두 번째 build 이후에도 첫 번째 build의 `stepEvents`를 유지하는 회귀 테스트 추가.

### 테스트 작성

- 작성: `test/oto_application_test.dart`
  - 성공 file build를 두 번 실행한다.
  - 첫 번째 `BuildResult`를 보관한 뒤 두 번째 build를 실행한다.
  - 두 번째 build 이후 첫 번째 result의 `toJson()['stepEvents']`가 여전히 비어 있지 않고 첫 번째 실행의 `started/completed` 이벤트를 유지하는지 검증한다.

### 중간 검증

```bash
dart test test/oto_application_test.dart
```

예상 결과: 모든 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/oto/application.dart` | REVIEW_STEP_EVENT_OUTPUT-1 |
| `test/oto_application_test.dart` | REVIEW_STEP_EVENT_OUTPUT-1 |

## 최종 검증

```bash
dart analyze && dart test test/oto_application_test.dart test/oto_core_test.dart
```

예상 결과: analyze issue 없음, 모든 테스트 통과.

```bash
rg --sort path -n "stepEvents|resetStepEvents|BuildResult" lib/oto/application.dart lib/oto/core/build_result.dart test/oto_application_test.dart
```

예상 결과: `Application.build()`가 snapshot을 전달하고, 회귀 테스트가 다음 build 이후 기존 `BuildResult`의 `stepEvents` 보존을 검증한다.

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