<!-- task=02_pipeline_yaml_validation plan=0 tag=REVIEW_VALIDATE -->

# Pipeline YAML Validation Hardening

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

**구현의 마지막 단계는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이다. 이 파일이 채워지기 전에는 작업이 완료된 것이 아니다.** 구현 체크리스트를 기준으로 작업하고, 중간/최종 검증을 실행한 뒤 실제 구현 내용과 stdout/stderr를 review stub에 기록한다. review 파일의 archive/complete.log 지시는 코드리뷰 스킬 전용이며 구현 에이전트가 실행하거나 `코드리뷰 전용 체크리스트`를 수정하면 안 된다.

## 배경

YAML 최상위 검증은 보강됐지만 nested pipeline node는 여전히 `as String`, generated `fromJson` cast, late field 접근이 먼저 터질 수 있다. AI-first 개발에서는 잘못된 YAML도 Dart cast 예외 대신 위치와 필드명을 포함한 validation message로 떨어져야 한다.

## 분석 결과

### 읽은 파일

- `lib/oto/pipeline/pipeline.dart`
- `lib/oto/pipeline/pipeline_exe.dart`
- `lib/oto/pipeline/pipeline_exe_handle.dart`
- `lib/oto/pipeline/pipeline_if.dart`
- `lib/oto/pipeline/pipeline_while.dart`
- `lib/oto/pipeline/pipeline_contain.dart`
- `lib/oto/pipeline/pipeline_foreach.dart`
- `lib/oto/pipeline/pipeline_switch.dart`
- `lib/oto/pipeline/pipeline_wait_until.dart`
- `lib/oto/data/pipeline_data.dart`
- `lib/oto/data/pipeline_data.g.dart`
- `test/oto_application_test.dart`
- `test/oto_core_test.dart`

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

- `exe: 123`, `wait-until-string: 123`, malformed `if`, `foreach`, `switch.cases` 같은 nested type 오류의 사용자 친화적 메시지 테스트가 없다.
- generated `fromJson` 예외를 validation result로 바꾸는 경로가 없다.

### 심볼 참조

- renamed/removed symbols: none.

### 분할 판단

분할 정책을 먼저 평가했다. 이 task는 pipeline/data validation boundary만 다룬다. `01_command_runtime_contract`, `03_command_catalog_samples`와 독립적으로 구현/검증 가능하므로 `02_` 독립 디렉터리로 둔다.

### 범위 결정 근거

이 작업은 pipeline YAML 구조 validation과 관련 테스트만 수정한다. command param model validation, sample 내용 보정, CLI 인자 파싱은 제외한다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`: YAML schema validation은 cross-node schema 계약이고 여러 pipeline executor에 영향을 준다.

## 구현 체크리스트

- [ ] [REVIEW_VALIDATE-1] pipeline node initialize에서 type/cast 예외가 validation message로 변환되도록 공통 guard를 둔다.
- [ ] [REVIEW_VALIDATE-2] DataPipeline/Data* validator가 필수 필드와 list/map 타입을 명시적으로 검증하도록 보강한다.
- [ ] [REVIEW_VALIDATE-3] malformed YAML 회귀 테스트를 추가한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 결과를 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_VALIDATE-1] initialize cast guard

문제: [pipeline_exe.dart](/config/workspace/oto/lib/oto/pipeline/pipeline_exe.dart:63)는 `set.values.first as String`을 직접 수행하고, [pipeline_wait_until.dart](/config/workspace/oto/lib/oto/pipeline/pipeline_wait_until.dart:24)도 동일하게 cast한다.

해결 방법: pipeline executor 입력값 검증 helper를 추가하거나 각 initialize에서 타입을 먼저 확인해 `PipelineValidateResult(enable=false, message=...)`로 반환한다.

Before:

```dart
// lib/oto/pipeline/pipeline_exe.dart:63
commandID = set.values.first as String;
```

After:

```dart
final value = set.values.first;
if (value is! String || value.trim().isEmpty) {
  result.enable = false;
  result.message = 'workflow exe requires a non-empty command id string.';
  return result;
}
commandID = value;
```

수정 파일 및 체크리스트:

- [ ] `lib/oto/pipeline/pipeline_exe.dart`: `exe`/`async` command id type 검증.
- [ ] `lib/oto/pipeline/pipeline_wait_until.dart`: wait condition type 검증.
- [ ] `lib/oto/pipeline/pipeline.dart`: child error message에 workflow index context 포함 여부 확인.

테스트 작성: 작성. `test/oto_application_test.dart`에 `exe: 123`, `wait-until-string: 123` 케이스 추가.

중간 검증:

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

기대 결과: All tests passed.

### [REVIEW_VALIDATE-2] Data validator 필수 필드 보강

문제: [pipeline_data.dart](/config/workspace/oto/lib/oto/data/pipeline_data.dart:83)의 `DataExeHandle.id`, [pipeline_data.dart](/config/workspace/oto/lib/oto/data/pipeline_data.dart:210)의 `DataForeach.iterator`, [pipeline_data.dart](/config/workspace/oto/lib/oto/data/pipeline_data.dart:243)의 `DataSwitch.cases`는 generated cast/late 접근 전에 안전하게 검증되지 않는다.

해결 방법: generated `fromJson` 호출 전 raw map shape를 확인하거나 validator에서 nullable field로 받아 검증할 수 있게 모델을 최소 조정한다. 모델 변경 시 `dart run build_runner build`를 실행한다.

Before:

```dart
// lib/oto/data/pipeline_data.dart:84
late String id;
```

After:

```dart
late String? id;
```

수정 파일 및 체크리스트:

- [ ] `lib/oto/data/pipeline_data.dart`: 필수 field null/type 검증 강화.
- [ ] `lib/oto/data/pipeline_data.g.dart`: build_runner로 생성 갱신.
- [ ] `lib/oto/pipeline/pipeline_exe_handle.dart`, `pipeline_if.dart`, `pipeline_while.dart`, `pipeline_foreach.dart`, `pipeline_switch.dart`: validator 실패를 그대로 반환.

테스트 작성: 작성. `if`, `foreach`, `switch` malformed YAML을 최소 1개씩 추가한다.

중간 검증:

```bash
dart run build_runner build --delete-conflicting-outputs
dart test test/oto_application_test.dart test/oto_core_test.dart
```

기대 결과: 생성 파일 갱신 후 tests pass.

### [REVIEW_VALIDATE-3] validation message regression

문제: [test/oto_application_test.dart](/config/workspace/oto/test/oto_application_test.dart:155)는 workflow key 오류 1개만 확인하고, nested 오류가 `type 'int' is not a subtype` 같은 내부 예외로 새지 않는지 확인하지 않는다.

해결 방법: invalid YAML별로 `BuildResult.failure`와 구체적 message substring을 검증한다. 내부 Dart cast 문구가 포함되지 않음을 함께 확인한다.

수정 파일 및 체크리스트:

- [ ] `test/oto_application_test.dart`: malformed nested pipeline cases 추가.
- [ ] 에러 메시지는 `workflow[...]`, node name, field name을 포함하도록 assertion.

테스트 작성: 작성.

중간 검증:

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

기대 결과: All tests passed.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/oto/pipeline/pipeline.dart` | REVIEW_VALIDATE-1 |
| `lib/oto/pipeline/pipeline_exe.dart` | REVIEW_VALIDATE-1 |
| `lib/oto/pipeline/pipeline_wait_until.dart` | REVIEW_VALIDATE-1 |
| `lib/oto/data/pipeline_data.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/data/pipeline_data.g.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/pipeline/pipeline_exe_handle.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/pipeline/pipeline_if.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/pipeline/pipeline_while.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/pipeline/pipeline_foreach.dart` | REVIEW_VALIDATE-2 |
| `lib/oto/pipeline/pipeline_switch.dart` | REVIEW_VALIDATE-2 |
| `test/oto_application_test.dart` | REVIEW_VALIDATE-1, REVIEW_VALIDATE-3 |
| `test/oto_core_test.dart` | REVIEW_VALIDATE-2 |

## 최종 검증

```bash
dart run build_runner build --delete-conflicting-outputs
dart analyze
dart test
```

기대 결과: generated files up to date, `No issues found!`, `All tests passed!`

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