<!-- task=m-runner-output-boundary/03+01,02_core_cli_adapter plan=1 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> Do not ask the user directly; record blockers in `사용자 리뷰 요청`.
> Finalization is review-agent-only.

## 개요

date=2026-06-07
task=m-runner-output-boundary/03+01,02_core_cli_adapter, plan=1, tag=REFACTOR

## Roadmap Targets

- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md`
- Task ids:
  - `core`: data composition 경로의 printer/color 의존을 output port 또는 domain-neutral 계약으로 정리한다.
  - `cli-adapter`: 기존 CLI 출력 의미를 유지하는 adapter를 연결한다. 검증: CLI smoke 출력이 회귀하지 않는다.
- Completion mode: check-on-pass

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다.

1. predecessor complete.log 2개 확인 여부를 검증한다.
2. 판정을 append한다.
3. PASS이면 plan/review log화, complete.log 작성, archive 이동을 수행한다.
4. roadmap 수정은 런타임 책임이다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REFACTOR-1] DataComposer Neutral Output | [x] |
| [REFACTOR-2] CLI Adapter Wiring | [x] |

## 구현 체크리스트

- [x] `01_output_port_contract`와 `02+01_pipeline_output_port` complete.log를 확인한다.
- [x] DataComposer/Jenkins collector signature를 CLI `Color` 없는 output port 또는 domain-neutral style 계약으로 바꾼다.
- [x] Application이 build 시작 시 context output을 CLI adapter로 설정하고 `logEnable=false` 및 scheduler log 경계를 유지한다.
- [x] CLI adapter가 기존 `CLI.printString`, `CLI.println`, build step banner 의미를 보존하도록 연결한다.
- [x] `apps/runner/lib/oto/core/data_composer.dart`와 `apps/runner/lib/oto/pipeline/**`에 `package:oto/cli` import 또는 `CLI.` direct call이 남지 않게 한다.
- [x] core/CLI 관련 테스트와 CLI smoke를 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] active review/plan 파일을 `.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 task `.md`/`.log` artifact를 unignore하는지 확인한다.
- [x] FAIL이고 user-review gate가 트리거되지 않아 다음 active `PLAN-local-G06.md`와 `CODE_REVIEW-local-G06.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다.
- [ ] PASS split 작업이면 parent 유지/정리 상태를 확인한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다.

## 계획 대비 변경 사항

- `apps/runner/lib/cli/runner_output_adapter.dart`를 새로 추가했다. adapter는 CLI 소유 경계에 두는 것이 맞고, 기존 `cli.dart`에 섞는 것보다 output port 매핑 책임을 좁게 유지할 수 있다.
- `Application.build`에 선택적 `RunnerOutputPort? output` 인자를 추가했다. CLI 기본 출력은 adapter로 유지하면서 테스트와 후속 server/agent 경로에서 명시 output port를 주입할 수 있게 하기 위함이다.
- `logEnable=false` 보존을 위해 `_LogGateOutputPort`를 Application 내부에 두고 default/custom output 모두 같은 gate를 통과하게 했다.

## 주요 설계 결정

- `DataComposer.compose`와 `JenkinsEnvironmentCollector.collect`는 `RunnerOutputPort`만 받도록 변경해 `data_composer.dart`에서 CLI import와 `Color` type을 제거했다.
- `CliRunnerOutputPort`는 `RunnerOutputStyle`을 CLI `Color`로 매핑하고, `line`은 `CLI.println`, `block`/`buildStep`은 `CLI.printString`을 사용한다. build step banner 문자열은 기존 `Application.printBuildStep` 형태를 유지한다.
- `Application.build`는 시작 시 `context.output`을 준비하고 Build Data, 실패 error/stacktrace, 성공/실패 build step을 모두 output port로 emit한다.
- scheduler의 파일 로그 연결은 `setCliOutputLogHandler(log)` helper로 유지해 기존 `CLI.logFunc` 경계를 adapter 파일 안으로 이동했다.
- 테스트는 Application output port 주입, `logEnable=false` output 억제, Jenkins composer/collector output style을 추가로 검증한다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

## 리뷰어를 위한 체크포인트

- `data_composer.dart`에서 CLI import와 CLI `Color` type이 제거됐는지 확인한다.
- `Application`이 기존 scheduler logFunc, `logEnable=false`, validate JSON no-log 경계를 깨지 않았는지 확인한다.
- 최종 `rg` 검증이 no-match 성공 조건으로 기록됐는지 확인한다.

## 검증 결과

### REFACTOR-1 중간 검증

```bash
$ cd apps/runner && dart analyze
Analyzing runner...
No issues found!

$ cd apps/runner && dart test test/oto_core_test.dart test/oto_application_test.dart
All tests passed! (+68)
```

### REFACTOR-2 중간 검증

```bash
$ cd apps/runner && dart analyze
Analyzing runner...
No issues found!

$ cd apps/runner && dart test test/oto_application_test.dart test/oto_cli_runtime_test.dart test/oto_validate_cli_test.dart
All tests passed! (+47)
```

### 최종 검증

```bash
$ cd apps/runner && dart analyze
Analyzing runner...
No issues found!

$ cd apps/runner && dart test test/oto_application_test.dart test/oto_context_test.dart test/oto_core_test.dart test/oto_system_runtime_test.dart
All tests passed! (+76)

$ cd apps/runner && dart test test/oto_cli_runtime_test.dart test/oto_catalog_cli_test.dart test/oto_validate_cli_test.dart
All tests passed! (+18)

$ cd apps/runner && dart run bin/main.dart --help
exit=0; 현재 CLI 동작대로 `--help`는 command-not-found error 문구와 함께 Usage/Available Command 도움말을 출력한다.

$ ! rg --sort path -n "package:oto/cli|CLI\\.|Color\\." apps/runner/lib/oto/pipeline apps/runner/lib/oto/core/data_composer.dart
no output; no-match 조건 충족
```

## 코드리뷰 결과

### 2026-06-07 - 코드리뷰 판정

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Fail
  - verification trust: Pass
- 발견된 문제:
  - Required: [apps/runner/lib/oto/application.dart](/config/workspace/oto/apps/runner/lib/oto/application.dart:187)에서 최종 성공 배너가 기존 `Color.cyan` 대신 기본 `RunnerOutputStyle.success`로 출력된다. 기존 구현은 `printBuildStep('Build Successfully Complete', Color.cyan)`였고, 새 adapter의 `success`는 `Color.green`으로 매핑되므로 “기존 CLI 출력 의미 보존” 계획 항목이 미충족이다. 최종 성공 배너의 cyan 의미를 보존하도록 explicit style/adapter mapping을 복원하고, 해당 style을 검증하는 테스트를 추가한다.
- 다음 단계: FAIL이므로 user-review gate 없이 후속 `PLAN-*-G??.md`와 `CODE_REVIEW-*-G??.md`를 작성한다.
