<!-- task=jenkins_compatibility_boundary/03+01,02_docs_samples plan=0 tag=REFACTOR -->

# Jenkins Boundary Docs And Samples - REFACTOR

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

구현 후 `CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션을 반드시 채운다. 검증 명령을 실제로 실행하고 출력 원문을 붙이며, active 파일은 그대로 둔 채 review 준비 상태를 보고한다. `complete.log` 작성, `.log` 아카이브, task 디렉터리 이동은 code-review-skill 전용이다.

## 배경

Milestone은 Jenkins 전용 경로와 일반 실행 경로가 문서에서 혼동되지 않아야 한다고 요구한다. README는 이미 CLI 호환 기준선을 말하지만 Jenkins env adapter, file/scheduler 일반 실행, Jenkins command sample의 차이를 더 명시해야 한다. scheduler interval 단위도 README와 샘플 사이에 차이가 있다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/domain/sample/rules.md`
- `agent-ops/rules/project/domain/cli/rules.md`
- `agent-ops/rules/project/domain/scheduler/rules.md`
- `agent-ops/roadmap/milestones/jenkins-compatibility-boundary.md`
- `README.md`
- `assets/yaml/sample/01_basic.yaml`
- `assets/yaml/sample/12_scheduler.yaml`
- `assets/yaml/sample/20_jenkins.yaml`
- `lib/cli/commands/scheduler/scheduler_interval.dart`
- `test/oto_command_catalog_test.dart`

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

- sample parse: `test/oto_command_catalog_test.dart:346` verifies samplePath YAML parses as map with commands list.
- README examples: no test guards stale `workspacePath` in README. README currently uses `workspacePath` at `README.md:82`, while iOS samples/tests expect `xcworkspaceFilePath`.
- scheduler interval docs: `assets/yaml/sample/12_scheduler.yaml:10` says milliseconds; `README.md:267` says seconds. No test covers docs text.

### 심볼 참조

- 이름을 제거하거나 rename하지 않는다.
- `workspacePath` non-commented references found in `README.md:82` and `assets/yaml/sample/04_pipeline_exe_handle.yaml:25`. This plan changes README only; sample 04 is outside Jenkins boundary and should be handled separately if stale sample cleanup is requested.

### 분할 판단

분할 정책을 평가했다. docs/sample 작업은 code foundation과 verification이 완료된 뒤 반영하는 편이 안전하므로 `03+01,02_docs_samples`로 분리했다. directory name의 `+01,02`가 dependency source of truth다.

### 범위 결정 근거

- 이 plan은 README와 Jenkins/scheduler samples만 다룬다.
- `assets/yaml/sample/04_pipeline_exe_handle.yaml`의 stale `workspacePath`는 Jenkins boundary와 직접 관련이 없어 제외한다.
- 로드맵 파일과 Milestone 상태는 사용자가 명시하지 않았으므로 수정하지 않는다.

### 빌드 등급

- build=`local-G04`, review=`local-G04`: 문서/샘플 중심이며 sample parse 테스트로 검증 가능한 낮은 blast radius 작업이다.

## 구현 체크리스트

- [ ] REFACTOR-1 README에서 Jenkins mode, file mode, scheduler mode의 책임 경계를 명확히 한다.
- [ ] REFACTOR-2 scheduler/Jenkins 샘플 주석을 Jenkins-free 실행 경계와 실제 interval 단위에 맞게 정리한다.
- [ ] REFACTOR-3 README 예제 stale field를 고치고 최소 문서 회귀 테스트를 추가한다.
- [ ] 모든 중간 검증과 최종 검증을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-local-G04.md`에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## REFACTOR Items

### REFACTOR-1 README 실행 경계 명시

#### 문제

`README.md:53-54`는 Jenkins 의존과 file/scheduler 전제를 짧게만 설명한다. Milestone 완료 기준인 “Jenkins 없이도 OTO 파이프라인 실행 경로를 설명”하기에는 adapter/일반 실행 경계가 부족하다.

Before (`README.md:53`):

```markdown
Jenkins 의존은 `jenkins` 실행 모드의 호환 경로로 남긴다.
새 자동화 표면은 `file`과 `scheduler` 모드가 Jenkins 환경 변수 없이 동작할 수 있다는 전제를 깨지 않아야 한다.
```

#### 해결 방법

CLI 호환 기준선 아래에 짧은 `Jenkins 호환 경계` 소절을 추가한다.

After:

```markdown
### Jenkins 호환 경계

- `oto -j`만 Jenkins 환경 변수와 Jenkins BuildData 입력을 읽는 compatibility adapter다.
- `oto -f <path>`는 YAML 파일만 입력으로 삼으며 Jenkins env 없이 local workspace 기본값으로 실행된다.
- `oto scheduler ...`는 등록된 YAML과 scheduler 설정으로 실행되며 Jenkins env를 요구하지 않는다.
- `JenkinsParameterModify`는 Jenkins job XML을 다루는 command일 뿐 `-j` 실행 모드를 요구한다는 뜻이 아니다.
```

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

- [ ] `README.md`: CLI 호환 기준선 아래 boundary 소절 추가.
- [ ] `README.md`: Jenkins mode 제거로 읽히는 표현을 쓰지 않는다.

#### 테스트 작성

직접적인 README 렌더 테스트는 생략한다. `REFACTOR-3`에서 stale field 문서 회귀 테스트를 추가한다.

#### 중간 검증

```bash
rg --sort path -n "Jenkins 호환 경계|JenkinsParameterModify|oto -f <path>|oto scheduler" README.md
```

예상 결과: 새 boundary 문구가 README에 검색된다.

### REFACTOR-2 Scheduler/Jenkins Sample 주석 정리

#### 문제

`assets/yaml/sample/12_scheduler.yaml:10`은 interval이 ms 단위라고 쓰고, 실제 `SchedulerInterval`도 `Duration(milliseconds: interval)`을 사용한다. 반면 `README.md:267`은 초 단위라고 설명한다. `assets/yaml/sample/20_jenkins.yaml:2`는 Jenkins command sample이 Jenkins execution mode sample로 오해될 수 있다.

Before (`README.md:266`):

```markdown
  cron: "0 2 * * *"     # cron 표현식 또는
  # interval: 3600      # 초 단위 interval
```

Before (`assets/yaml/sample/20_jenkins.yaml:2`):

```yaml
# [샘플] Jenkins 파라미터 수정
```

#### 해결 방법

README interval 설명을 ms 단위로 맞추고, scheduler/Jenkins 샘플 상단 주석에 Jenkins env 요구 여부를 명시한다.

After:

```markdown
  cron: "0 2 * * *"        # cron 표현식 또는
  # interval: 3600000      # 밀리초 단위 interval
```

```yaml
# [샘플] Jenkins 파라미터 수정 command
# Jenkins job XML을 다루는 command 예시이며, oto -j 실행 모드를 요구하지 않는다.
```

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

- [ ] `README.md`: scheduler interval 단위 문구를 milliseconds로 정정.
- [ ] `assets/yaml/sample/12_scheduler.yaml`: Jenkins env 없이 등록 가능한 scheduler YAML임을 주석으로 명시.
- [ ] `assets/yaml/sample/20_jenkins.yaml`: command sample과 Jenkins execution mode를 구분하는 주석 추가.

#### 테스트 작성

새 테스트는 생략한다. 샘플 YAML parse regression은 기존 `test/oto_command_catalog_test.dart:346`이 담당한다.

#### 중간 검증

```bash
dart test test/oto_command_catalog_test.dart
```

예상 결과: `All tests passed!`

### REFACTOR-3 README stale field 회귀 방지

#### 문제

`README.md:82`는 `workspacePath`를 사용한다. `test/oto_command_catalog_test.dart:105`는 iOS sample에서 `workspacePath`를 금지하지만 README 예제는 보호하지 않는다.

Before (`README.md:79`):

```yaml
  - command: BuildiOS
    id: buildApp
    param:
      workspacePath: <!property.workspace>/ios/Runner.xcworkspace
      scheme: Runner
```

#### 해결 방법

README 예제를 현재 iOS 모델에 맞춰 `xcworkspaceFilePath`로 바꾸고, README의 non-comment YAML 예제에 stale field가 돌아오지 않도록 테스트를 추가한다.

After:

```yaml
  - command: BuildiOS
    id: buildApp
    param:
      xcworkspaceFilePath: <!property.workspace>/ios/Runner.xcworkspace
      scheme: Runner
```

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

- [ ] `README.md`: `workspacePath` 예제를 `xcworkspaceFilePath`로 교체.
- [ ] `test/oto_command_catalog_test.dart`: README non-comment line에 `workspacePath:`가 없는지 검증하는 테스트 추가.

#### 테스트 작성

작성한다.

- `test/oto_command_catalog_test.dart`: `README examples must not contain stale field workspacePath`
- assertion: comment line 제외 후 `RegExp(r'^[ \t]+workspacePath\s*:')`와 매칭되는 줄이 없어야 한다.

#### 중간 검증

```bash
dart test test/oto_command_catalog_test.dart
```

예상 결과: `All tests passed!`

## 의존 관계 및 구현 순서

이 subtask는 sibling `01_core_adapter`, `02+01_file_scheduler_modes`의 `complete.log`가 있어야 시작한다. directory name `03+01,02_docs_samples`의 `+01,02`가 유일한 runtime dependency다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `README.md` | REFACTOR-1, REFACTOR-2, REFACTOR-3 |
| `assets/yaml/sample/12_scheduler.yaml` | REFACTOR-2 |
| `assets/yaml/sample/20_jenkins.yaml` | REFACTOR-2 |
| `test/oto_command_catalog_test.dart` | REFACTOR-3 |

## 최종 검증

```bash
dart analyze
```

예상 결과: `No issues found!`

```bash
dart test test/oto_command_catalog_test.dart
```

예상 결과: `All tests passed!`

```bash
dart test
```

예상 결과: `All tests passed!`

검증 명령은 이 저장소에서 실행 확인했다. 테스트 캐시 개념이 없는 Dart test라 별도 cache busting은 필요 없다.

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