oto/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/PLAN-local-G06.md
toki 365995900e feat(runner): output port 경계 작업을 반영한다
runner 출력 경계 분리의 첫 계약 작업을 완료하고 후속 subtask와 로드맵 상태를 함께 기록한다. workspace 포트와 local smoke 기준도 독립 Control Plane 방향에 맞춰 정리한다.
2026-06-07 13:12:46 +09:00

7.3 KiB

Plan - REFACTOR

Roadmap Targets

  • Milestone: agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md
  • Task ids:
    • pipeline: pipeline domain이 CLI 구현체 대신 output port를 사용하도록 분리한다. 검증: runner analyze와 pipeline 관련 테스트가 통과한다.
  • Completion mode: check-on-pass

배경

이 작업은 01_output_port_contract 완료 후 진행한다. pipeline domain에서 CLI 출력 구현 import와 Application.instance.printBuildStep 직접 호출을 제거하고 explicit ExecutionContext.output을 사용한다.

Roadmap Dependency

  • predecessor: agent-task/m-runner-output-boundary/01_output_port_contract/complete.log
  • 상태: 작성 시점에는 미충족. 구현 시작 전 active 또는 archive complete.log를 확인한다.

분석 결과

읽은 파일

  • agent-roadmap/current.md
  • agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md
  • agent-ops/rules/project/domain/pipeline/rules.md
  • agent-ops/rules/project/domain/core/rules.md
  • agent-test/local/pipeline-smoke.md
  • agent-test/local/core-smoke.md
  • apps/runner/lib/oto/core/execution_context.dart
  • apps/runner/lib/oto/pipeline/pipeline.dart
  • apps/runner/lib/oto/pipeline/pipeline_exe.dart
  • apps/runner/lib/oto/pipeline/pipeline_exe_handle.dart
  • apps/runner/lib/oto/pipeline/pipeline_foreach.dart
  • apps/runner/test/oto_core_test.dart

테스트 환경 규칙

  • test_env: local
  • 읽은 env rule: agent-test/local/rules.md
  • 매칭 profile: pipeline-smoke, core-smoke
  • 적용 명령: cd apps/runner && dart analyze, cd apps/runner && dart test, 최소 test/oto_core_test.dart
  • pipeline 전용 테스트가 확인되지 않아 변경 영향이 있는 경우 runner 전체 test가 필요하다는 규칙을 적용한다.

테스트 커버리지 공백

  • pipeline 출력이 explicit context output으로 들어가는지 확인하는 테스트가 없다. apps/runner/test/oto_core_test.dart에 recording output 기반 regression test를 추가한다.
  • CLI 출력 보존은 다음 03 작업에서 검증한다.

심볼 참조

  • 제거 대상 direct dependency:
    • apps/runner/lib/oto/pipeline/pipeline_exe.dart: package:oto/cli/cli.dart, Application.instance.printBuildStep
    • apps/runner/lib/oto/pipeline/pipeline_exe_handle.dart: package:oto/cli/cli.dart, Application.instance.printBuildStep
    • apps/runner/lib/oto/pipeline/pipeline_foreach.dart: package:oto/cli/cli.dart, CLI.println
  • Application.log는 로그 파일 경계로 남길 수 있으나 output port와 중복될 경우 최소 변경으로 유지한다.

분할 판단

  • split decision policy 평가 완료.
  • 이 subtask는 02+01_pipeline_output_port이며 predecessor 01이 필요하다.
  • 03+01,02_core_cli_adapter는 이 작업 완료 후 DataComposer/Application/CLI adapter를 마무리한다.

범위 결정 근거

  • pipeline domain만 수정한다.
  • DataComposer compose signature와 Application CLI adapter 연결은 제외한다.
  • command domain의 CLI.println 직접 호출은 마일스톤 범위 밖이다.

빌드 등급

  • build lane: local-G06
  • review lane: local-G06
  • 근거: call-site 수는 적지만 pipeline 실행 이벤트와 explicit context 회귀 위험이 있어 focused regression test가 필요하다.

구현 체크리스트

  • 01_output_port_contract complete.log를 확인한다.
  • pipeline_exe.dart, pipeline_exe_handle.dart, pipeline_foreach.dart에서 CLI import와 CLI direct call을 제거한다.
  • pipeline 출력은 runtimeContext.output.line 또는 runtimeContext.output.buildStep을 사용한다.
  • explicit context output regression test를 추가한다.
  • cd apps/runner && dart analyze, cd apps/runner && dart test test/oto_core_test.dart, cd apps/runner && dart test를 실행한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

의존 관계 및 구현 순서

  • 디렉터리명 02+01_pipeline_output_port 기준 predecessor는 01_output_port_contract 하나다.
  • 구현 시작 전 agent-task/m-runner-output-boundary/01_output_port_contract/complete.log 또는 archive의 같은 subtask complete.log를 확인한다.

수정 파일 요약

파일 항목
apps/runner/lib/oto/pipeline/pipeline_exe.dart REFACTOR-1
apps/runner/lib/oto/pipeline/pipeline_exe_handle.dart REFACTOR-1
apps/runner/lib/oto/pipeline/pipeline_foreach.dart REFACTOR-1
apps/runner/test/oto_core_test.dart REFACTOR-1

[REFACTOR-1] Pipeline Output Port Rollout

문제

pipeline_exe.dart는 condition 출력에 CLI.println을 직접 호출하고, pipeline_exe.dartpipeline_exe_handle.dartApplication.instance.printBuildStep을 직접 호출한다. pipeline_foreach.dart도 CLI를 직접 호출한다.

Before:

// apps/runner/lib/oto/pipeline/pipeline_exe.dart:41
static Future printCondition(...) async {
  await CLI.println('[Pipeline-$syntax]', color: Color.magentaStrong);
  Application.log(...);
}

해결 방법

PipelineExecutor.runtimeContext.output을 사용한다. 색은 RunnerOutputStyle.progress 등 선행 계약의 neutral style로 매핑한다.

After:

await runtimeContext.output.line(
  '[Pipeline-$syntax]',
  style: RunnerOutputStyle.progress,
);

printCondition은 static이라 context를 받을 수 없으면 signature에 ExecutionContext? context를 추가하고 call site에서 runtimeContext를 넘긴다. 호출부를 모두 검색해 누락 없이 갱신한다.

수정 파일 및 체크리스트

  • pipeline_exe.dart import에서 package:oto/cli/cli.dart 제거
  • pipeline_exe_handle.dart import에서 package:oto/cli/cli.dart 제거
  • pipeline_foreach.dart import에서 package:oto/cli/cli.dart 제거
  • Application.instance.printBuildStep 직접 호출을 output port 호출로 대체
  • CLI.println 직접 호출을 output port 호출로 대체
  • apps/runner/test/oto_core_test.dart에 recording output으로 Phase Start 또는 foreach completion output 검증 추가

테스트 작성

  • 작성: apps/runner/test/oto_core_test.dart
  • 테스트 이름 후보: pipeline emits progress through explicit context output port
  • 목표: explicit ExecutionContext에 recording output을 주입한 뒤 pipeline 실행 시 output이 해당 context로 들어오고 singleton CLI 경계에 의존하지 않음을 확인한다.

중간 검증

cd apps/runner && dart analyze
cd apps/runner && dart test test/oto_core_test.dart

최종 검증

cd apps/runner && dart analyze
cd apps/runner && dart test

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