<!-- task=jenkins_compatibility_boundary/02+01_file_scheduler_modes plan=0 tag=REFACTOR -->

# File And Scheduler Jenkins-free Verification - REFACTOR

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

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

## 배경

Milestone의 필수 기능은 file 모드와 scheduler 모드가 Jenkins 없이 실행 가능한 경로로 검증되어 있는 것이다. core foundation은 `01_core_adapter`에서 정리하므로, 이 하위 작업은 production 동작을 넓히기보다 회귀 테스트와 bin-level smoke 계약을 추가한다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/domain/cli/rules.md`
- `agent-ops/rules/project/domain/scheduler/rules.md`
- `agent-ops/rules/project/domain/core/rules.md`
- `agent-ops/roadmap/milestones/jenkins-compatibility-boundary.md`
- `lib/cli/commands/command_exe.dart`
- `lib/cli/commands/command_scheduler.dart`
- `lib/cli/commands/scheduler/scheduler_isolate.dart`
- `lib/cli/commands/scheduler/scheduler_interval.dart`
- `lib/cli/commands/scheduler/scheduler_manager.dart`
- `lib/oto/application.dart`
- `lib/oto/data/command_data.dart`
- `test/oto_application_test.dart`
- `test/oto_scheduler_runtime_test.dart`
- `test/oto_system_runtime_test.dart`
- `assets/yaml/sample/12_scheduler.yaml`

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

- file mode: `test/oto_application_test.dart:41` covers a print-only file build with explicit `property.workspace`; it does not assert Jenkins-free default workspace when `property` is absent.
- CLI file smoke: `test/oto_application_test.dart:656` covers actual `dart run bin/main.dart exe -f <file> --json`; it can remain the bin-level file smoke.
- scheduler mode: `test/oto_scheduler_runtime_test.dart:151` covers process launch/routing; it does not exercise `Application.build(BuildType.scheduler, buildData: ..., logPath: ...)`.
- scheduler YAML parse: `test/oto_application_test.dart:435` covers malformed scheduler section; no positive scheduler buildData execution regression exists.

### 심볼 참조

- 이름을 제거하거나 rename하지 않는다.
- `BuildType.scheduler` 참조: `lib/cli/commands/command_exe.dart:201`, `lib/oto/application.dart:92`.
- `CommandExe.executeScheduler` 참조: `lib/cli/commands/scheduler/scheduler_isolate.dart:132`.
- `scheduler.interval` 참조: `lib/cli/commands/scheduler/scheduler_isolate.dart:85`, `lib/cli/commands/scheduler/scheduler_interval.dart:18`.

### 분할 판단

분할 정책을 평가했다. 이 subtask는 `01_core_adapter`의 foundation이 있어야 의미 있는 regression test를 작성할 수 있으므로 `02+01_file_scheduler_modes`로 분리했다. production API 변경 없이 verification 중심 작업이며, docs/sample 정리는 `03+01,02_docs_samples`에 둔다.

### 범위 결정 근거

- scheduler daemon start/terminate 구현은 이미 `test/oto_scheduler_runtime_test.dart`에서 주입 runtime으로 검증되므로 변경하지 않는다.
- OS startup 등록, launchd/Task Scheduler 통합은 실제 외부 시스템 의존이라 이 계획에서 새 integration test를 만들지 않는다.
- command/pipeline 내부 실행 규칙은 scope 밖이다.

### 빌드 등급

- build=`cloud-G07`, review=`cloud-G07`: scheduler와 CLI 실행 경계, bin-level smoke 출력, exit-status 계약을 검증하는 terminal-agent 성격의 작업이다.

## 구현 체크리스트

- [ ] REFACTOR-1 file mode가 Jenkins env 없이 기본 workspace를 채우고 실행되는 regression test를 추가한다.
- [ ] REFACTOR-2 scheduler mode가 Jenkins env 없이 `DataBuild`와 log path만으로 실행되는 regression test를 추가한다.
- [ ] 모든 중간 검증과 최종 검증을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-cloud-G07.md`에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## REFACTOR Items

### REFACTOR-1 File Mode Jenkins-free Regression

#### 문제

`lib/cli/commands/command_exe.dart:99-104`는 file mode에서 YAML 파일을 읽어 `Application.build(BuildType.file)`로 넘긴다. 하지만 기존 positive tests는 YAML에 `property.workspace`가 있는 경우만 다루며, Jenkins env 없는 기본 workspace 경계를 직접 고정하지 않는다.

Before (`test/oto_application_test.dart:41`):

```dart
test('file build returns success for print-only pipeline', () async {
  const yaml = '''
property:
  workspace: .
commands:
```

#### 해결 방법

`test/oto_application_test.dart`에 `property` 섹션이 없는 file build 테스트를 추가한다. 실행 후 `Application.instance.property['workspace']`가 local current path로 채워졌는지 확인한다.

After:

```dart
test('file build without property workspace uses local workspace without Jenkins env', () async {
  const yaml = '''
commands:
  - command: Print
    id: hello
    param:
      message: hi
pipeline:
  id: main
  workflow:
    - exe: hello
''';

  final result = await Application.instance.build(
    BuildType.file,
    yamlContent: yaml,
    logEnable: false,
  );

  expect(result.success, isTrue);
  expect(Application.instance.property['workspace'], Directory.current.path);
});
```

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

- [ ] `test/oto_application_test.dart`: file mode no-property workspace regression 추가.
- [ ] production source는 `01_core_adapter` 이후 실패가 드러날 때만 계획 대비 변경 사항에 기록하고 최소 수정한다.

#### 테스트 작성

작성한다.

- `test/oto_application_test.dart`: 위 regression test.
- fixture는 inline YAML만 사용한다.

#### 중간 검증

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

예상 결과: `All tests passed!`

### REFACTOR-2 Scheduler Mode Jenkins-free Regression

#### 문제

`lib/cli/commands/scheduler/scheduler_isolate.dart:124-132`는 scheduler tick에서 `CommandExe.executeScheduler(data, logEnable, logFile.path)`를 호출하고, `lib/cli/commands/command_exe.dart:199-203`은 `BuildType.scheduler` isolate를 만든다. 그러나 현재 테스트는 scheduler process control에 집중되어 있어 `Application.build(BuildType.scheduler, buildData: ..., logPath: ...)`가 Jenkins env 없이 실제 pipeline을 실행하는지 검증하지 않는다.

Before (`lib/oto/application.dart:92`):

```dart
if (_buildType == BuildType.scheduler) {
  commonData = DataCommon.fromJson(FileData.jenkinsMap!);
  build = buildData!;
  _logFile = File(logPath!);
  CLI.logFunc = log;
}
```

#### 해결 방법

`test/oto_application_test.dart`에 scheduler `DataBuild` positive regression을 추가한다. `Application.getMapFromYamlA()`와 `DataBuild.fromJson()`으로 scheduler YAML을 만들고, temp log path를 넘겨 `BuildType.scheduler`를 실행한다.

After:

```dart
test('scheduler build data runs without Jenkins env', () async {
  final logFile = File('${Directory.systemTemp.path}/oto_scheduler_${DateTime.now().microsecondsSinceEpoch}.log');
  const yaml = '''
scheduler:
  alias: local-test
  interval: 1000
  enableLog: true
commands:
  - command: Print
    id: hello
    param:
      message: hi
pipeline:
  id: main
  workflow:
    - exe: hello
''';
  final build = DataBuild.fromJson(Application.getMapFromYamlA(yaml)!);

  final result = await Application.instance.build(
    BuildType.scheduler,
    buildData: build,
    logEnable: false,
    logPath: logFile.path,
  );

  expect(result.success, isTrue);
});
```

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

- [ ] `test/oto_application_test.dart`: scheduler mode no-Jenkins regression 추가.
- [ ] test cleanup에서 temp log file을 삭제한다.
- [ ] `test/oto_scheduler_runtime_test.dart`는 process control 변경이 필요할 때만 수정한다.

#### 테스트 작성

작성한다.

- `test/oto_application_test.dart`: `scheduler build data runs without Jenkins env`
- assertion: `result.success == true`, `exitCode == 0`, temp log handling이 예외를 내지 않음.

#### 중간 검증

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

예상 결과: `All tests passed!`

## 의존 관계 및 구현 순서

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

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `test/oto_application_test.dart` | REFACTOR-1, REFACTOR-2 |
| `test/oto_scheduler_runtime_test.dart` | REFACTOR-2, 필요 시 |

## 최종 검증

```bash
dart analyze
```

예상 결과: `No issues found!`

```bash
dart test
```

예상 결과: `All tests passed!`

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

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