diff --git a/README.md b/README.md index adc2dfc..5451895 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,21 @@ YAML 기반 CI/CD 파이프라인 자동화 도구 OTO의 Monorepo 프로젝트 루트 `Makefile`을 통해 모든 서브프로젝트의 의존성 설치, 분석, 테스트 작업을 통합 관리할 수 있습니다. +## Workspace 포트와 환경 기준 + +OTO는 독립 Control Plane 제품 경로를 기준으로 포트와 환경값을 기록합니다. +iop Edge 또는 wire 포트는 OTO workspace 포트 표준의 source of truth가 아닙니다. + +| 표면 | 표준 후보 | 호환 기준 | +|------|-----------|-----------| +| OTO Core HTTP | backend host publish `18020` | 로컬 실행 기본값 `OTO_CORE_ADDR` 미설정 시 `127.0.0.1:8080`은 기존 개발 호환 경로로 유지 | +| Flutter client/web preview | frontend preview `13020` | preview 포트는 UI dev server 포트이며, 서버 연결 URL은 `OTO_SERVER_HTTP_URL`로 별도 지정 | +| runner bootstrap/release | `OTO_RUNNER_RELEASE_BASE_URL` | release base URL은 `https://`만 기록하고, token/credential/private endpoint 원문은 tracked 문서에 남기지 않음 | + +Core를 workspace publish 포트로 띄울 때는 `OTO_CORE_ADDR=0.0.0.0:18020`처럼 listen 주소를 명시합니다. +Flutter web preview는 `cd apps/client && flutter run -d chrome --web-port=13020`을 기준 후보로 둡니다. +bootstrap command와 artifact URL 문서는 public validation 기준과 source of truth만 남기고, enrollment token이나 private release host는 런타임 환경에서만 주입합니다. + ### 의존성 설치 (Setup) 각 앱/서비스의 패키지 및 모듈 의존성을 설치합니다. @@ -54,4 +69,3 @@ make test - [OTO Runner README](apps/runner/README.md) - [OTO Client README](apps/client/README.md) - OTO Core Server: [services/core/](services/core/) - diff --git a/agent-roadmap/ROADMAP.md b/agent-roadmap/ROADMAP.md index ac44721..ad26a63 100644 --- a/agent-roadmap/ROADMAP.md +++ b/agent-roadmap/ROADMAP.md @@ -17,9 +17,9 @@ OTO는 YAML 기반 빌드/배포 파이프라인을 실행하는 Dart CLI에서 - [폐기] Edge 직접 연결 기반 `oto-agent` - 경로: `agent-roadmap/archive/phase/edge-direct-oto-agent/PHASE.md` - 요약: OTO가 iop Edge와 proto-socket 기반 outbound 통신을 하는 경로는 검증 근거만 보존하고, 독립 OTO Control Plane 방향으로 전환하며 기본 제품 경로에서는 폐기한다. -- [검토중] 독립 Control Plane 기반 OTO +- [진행중] 독립 Control Plane 기반 OTO - 경로: `agent-roadmap/phase/independent-control-plane/PHASE.md` - - 요약: OTO를 iop 직접 연결 구조에서 분리해 `apps/runner`, `apps/client`, `services/core`를 가진 독립 CI/CD runner/control plane 제품 구조로 전환한다. + - 요약: OTO를 iop 직접 연결 구조에서 분리해 `apps/runner`, `apps/client`, `services/core`를 가진 독립 CI/CD runner/control plane 제품 구조로 전환하며, 현재는 runner 출력 경계 분리를 진행 중이다. - [검토중] 메시지 기반 빌드 에이전트 - 경로: `agent-roadmap/phase/message-based-build-agent/PHASE.md` - 요약: `oto agent` 또는 `oto daemon` 모드에서 Edge와 양방향 메시지 통신을 사용하며, OTO를 build/deploy 전용 domain agent로 노출한다. diff --git a/agent-roadmap/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md b/agent-roadmap/archive/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md similarity index 69% rename from agent-roadmap/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md rename to agent-roadmap/archive/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md index 305f94e..cf2fa42 100644 --- a/agent-roadmap/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md +++ b/agent-roadmap/archive/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md @@ -2,7 +2,7 @@ ## 상태 -[진행중] +[완료] ## 목표 @@ -38,4 +38,17 @@ - [x] [project-map] 프로젝트 구조, 패키지 경계, 주요 entrypoint 설명을 현재 모노레포 경로로 갱신한다. - [x] [sdk-deps] Dart/Flutter/Go dependency와 SDK 설명을 실제 package 기준으로 정리한다. - [x] [domain-paths] domain rule의 파일 경로 예시와 책임 경계 설명이 현재 코드 위치와 맞는지 검토해 갱신한다. -- [ ] [test-rules] local test rule과 smoke 문서가 모노레포 target 이름과 일치하는지 확인한다. +- [x] [test-rules] local test rule과 smoke 문서가 모노레포 target 이름과 일치하는지 확인한다. + +## 완료 리뷰 + +- 상태: 승인됨 +- 요청일: 2026-06-07 +- 완료 근거: + - `Makefile`의 runner/client/core/proto target과 `agent-test/local/rules.md`의 Monorepo Targets가 일치함을 확인했다. + - `agent-test/local` smoke 문서의 runner test 파일 참조와 실제 `apps/runner/test/**` 파일 존재를 확인했다. + - common local, agent-smoke, framework-smoke 환경 설명을 Dart/Flutter/Go monorepo 기준으로 보정했다. +- 리뷰 필요: + - [x] 사용자가 완료 결과를 확인했다 + - [x] archive 이동을 승인했다 +- 리뷰 코멘트: 사용자 요청에 따라 Milestone을 완료 처리하고 archive로 이동한다. diff --git a/agent-roadmap/archive/phase/independent-control-plane/milestones/workspace-port-env-standardization.md b/agent-roadmap/archive/phase/independent-control-plane/milestones/workspace-port-env-standardization.md new file mode 100644 index 0000000..41cd966 --- /dev/null +++ b/agent-roadmap/archive/phase/independent-control-plane/milestones/workspace-port-env-standardization.md @@ -0,0 +1,67 @@ +# Milestone: 워크스페이스 포트/환경 표준화 + +## 위치 + +- Roadmap: `agent-roadmap/ROADMAP.md` +- Phase: `agent-roadmap/phase/independent-control-plane/PHASE.md` + +## 목표 + +OTO의 Core HTTP, Flutter client/dev preview, runner/local test, bootstrap/release URL 환경을 workspace 공통 포트 대역으로 정리한다. OTO는 iop Edge 직접 연결 경로가 아니라 독립 Control Plane/runner 제품이므로, IOP wire 포트와 섞이지 않는 backend/frontend 대역 기준을 먼저 문서화한다. + +## 상태 + +[완료] + +## 구현 잠금 + +- 상태: 해제 +- 결정 필요: 없음 + +## 범위 + +- OTO Core HTTP 기본 listen과 host publish 후보 정리 +- Flutter client/web preview 후보 정리 +- runner/local typed-command test 환경과 서버 선택 연결 경계 정리 +- `OTO_RUNNER_RELEASE_BASE_URL`, bootstrap command, artifact URL 같은 환경값의 public/private 기록 기준 정리 +- IOP Edge 직접 연결 폐기 경로와 독립 OTO Control Plane 포트 경계를 분리해 문서화 + +## 기능 + +### Epic: [inventory] OTO environment inventory + +OTO의 독립 Control Plane과 runner가 사용하는 환경 변수를 workspace 공통 대역으로 정렬한다. + +- [x] [core-port] OTO Core host publish 후보를 backend `18020`으로 문서화하고 기존 local default `127.0.0.1:8080`과의 compatibility note를 남긴다. +- [x] [client-preview] Flutter/web preview 후보를 frontend `13020`으로 정리한다. +- [x] [bootstrap-env] runner release/base URL, bootstrap command, artifact URL 환경값은 secret 없이 source of truth와 validation 기준만 남긴다. +- [x] [test-docs] `agent-test/local`과 smoke 문서가 독립 OTO Control Plane 포트와 iop 폐기 경로를 혼동하지 않도록 체크리스트를 만든다. + +## 완료 리뷰 + +- 상태: 승인됨 +- 요청일: 2026-06-07 +- 완료 근거: + - `README.md`에 OTO Core `18020`, Flutter preview `13020`, `OTO_RUNNER_RELEASE_BASE_URL` 검증 기준과 secret 기록 금지 기준을 추가했다. + - `apps/client/README.md`, `apps/runner/README.md`에 client preview와 agent bootstrap 환경 기준을 반영했다. + - `agent-test/local/rules.md`와 `agent-test/local/agent-smoke.md`에 독립 OTO Control Plane 포트/환경 체크리스트와 services/core bootstrap 검증 기준을 추가했다. +- 리뷰 필요: + - [x] 사용자가 완료 결과를 확인했다 + - [x] archive 이동을 승인했다 +- 리뷰 코멘트: 사용자 요청에 따라 Milestone을 완료 처리하고 archive로 이동한다. + +## 범위 제외 + +- OTO Core API 구현 변경 +- runner job/log/artifact 기능 구현 +- iop Edge 직접 domain agent 경로 복원 +- private release host, credential, token 기록 + +## 작업 컨텍스트 + +- 관련 경로: `services/core/`, `apps/client/`, `apps/runner/`, `packages/flutter/oto_console/`, `agent-test/local/` +- 표준선(선택): OTO는 독립 Control Plane 포트를 소유하고, IOP wire/Edge 포트와 같은 런타임으로 묶지 않는다. +- 현재 동기화: `18020`/`13020` 표준은 root/client/runner README와 local smoke 기준에 반영되었고, Milestone 완료 승인 후 archive로 이동한다. +- 선행 작업: workspace 공통 포트 inventory 정리 +- 후속 작업: env/test smoke 갱신과 drift 방지 +- 확인 필요: 없음 diff --git a/agent-roadmap/phase/independent-control-plane/PHASE.md b/agent-roadmap/phase/independent-control-plane/PHASE.md index de818f7..47c18f1 100644 --- a/agent-roadmap/phase/independent-control-plane/PHASE.md +++ b/agent-roadmap/phase/independent-control-plane/PHASE.md @@ -2,7 +2,7 @@ ## 상태 -[검토중] +[진행중] ## 목표 @@ -18,10 +18,13 @@ OTO를 iop Edge에 직접 붙는 domain agent가 아니라, 독립 실행 가능 - [완료] 독립 Control Plane 분리 마이그레이션 - 경로: `agent-roadmap/archive/phase/independent-control-plane/milestones/control-plane-separation-migration.md` - 요약: iop에 구현된 OTO 등록/heartbeat/bootstrap 구조를 OTO 전용 Server/Runner 계약으로 이관하고, repo를 `apps/runner`, `apps/client`, `services/core` monorepo로 전환한다. -- [진행중] agent-ops 규칙 모노레포 정합화 - - 경로: `agent-roadmap/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md` +- [완료] 워크스페이스 포트/환경 표준화 + - 경로: `agent-roadmap/archive/phase/independent-control-plane/milestones/workspace-port-env-standardization.md` + - 요약: OTO Core, Flutter client, runner/local test, bootstrap/release URL 포트를 workspace 공통 대역과 독립 Control Plane 기준으로 정리한다. +- [완료] agent-ops 규칙 모노레포 정합화 + - 경로: `agent-roadmap/archive/phase/independent-control-plane/milestones/ops-rule-monorepo-alignment.md` - 요약: 프로젝트 규칙과 domain rule을 현재 `apps/runner`, `apps/client`, `services/core`, `packages/flutter/oto_console` 구조에 맞게 최신화한다. -- [계획] runner 출력 경계 분리 +- [진행중] runner 출력 경계 분리 - 경로: `agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md` - 요약: pipeline/core 실행 로직의 CLI 출력 직접 의존을 output/progress port와 adapter 구조로 분리한다. - [계획] oto_console 계약 경계 정리 diff --git a/agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md b/agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md index eb1e520..ba8ca47 100644 --- a/agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md +++ b/agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md @@ -2,7 +2,7 @@ ## 상태 -[계획] +[진행중] ## 목표 @@ -35,7 +35,7 @@ pipeline/core 실행 로직이 CLI 출력 구현에 직접 의존하지 않도 ### Epic: [output] output port boundary -- [ ] [port] runner 실행 progress와 일반 출력에 필요한 최소 output port 계약을 정의한다. +- [x] [port] runner 실행 progress와 일반 출력에 필요한 최소 output port 계약을 정의한다. - [ ] [pipeline] pipeline domain이 CLI 구현체 대신 output port를 사용하도록 분리한다. 검증: runner analyze와 pipeline 관련 테스트가 통과한다. - [ ] [core] data composition 경로의 printer/color 의존을 output port 또는 domain-neutral 계약으로 정리한다. - [ ] [cli-adapter] 기존 CLI 출력 의미를 유지하는 adapter를 연결한다. 검증: CLI smoke 출력이 회귀하지 않는다. diff --git a/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/code_review_local_G06_0.log b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/code_review_local_G06_0.log new file mode 100644 index 0000000..c02cc7b --- /dev/null +++ b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/code_review_local_G06_0.log @@ -0,0 +1,141 @@ + + +# 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. +> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only. + +## 개요 + +date=2026-06-07 +task=m-runner-output-boundary/01_output_port_contract, plan=1, tag=REFACTOR + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md` +- Task ids: + - `port`: runner 실행 progress와 일반 출력에 필요한 최소 output port 계약을 정의한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. + +1. 판정을 append한다. +2. `CODE_REVIEW-local-G06.md` → `code_review_local_G06_N.log`, `PLAN-local-G06.md` → `plan_local_G06_M.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-runner-output-boundary/01_output_port_contract/`로 이동한다. +4. PASS이고 task group이 `m-runner-output-boundary`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [REFACTOR-1] Output Port Contract | [x] | + +## 구현 체크리스트 + +- [x] output port 계약과 no-op 구현을 core 소유 파일에 추가한다. +- [x] `ExecutionContext`가 output port를 보유하고 reset 없이 explicit context별 output을 유지하게 한다. +- [x] output port 기본 동작을 검증하는 core 테스트를 추가한다. +- [x] `cd apps/runner && dart analyze`와 지정 core 테스트를 실행한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G06_N.log`로 아카이브한다. +- [x] active `PLAN-*-G??.md`를 `plan_local_G06_M.log`로 아카이브한다. +- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [x] PASS이면 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [x] PASS이면 active task 디렉터리를 archive로 이동한다. +- [x] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [x] PASS split 작업이면 이동 후 빈 active parent를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이면 다음 active plan/review 또는 `USER_REVIEW.md`를 작성한다. + +## 계획 대비 변경 사항 + +없음. 계획에 명시된 심볼, 파일 경로, 테스트 이름을 그대로 따랐다. + +## 주요 설계 결정 + +- `RunnerOutputPort`는 CLI 패키지를 전혀 import하지 않는 독립 파일(`core/output_port.dart`)로 분리했다. +- `NoopRunnerOutputPort`는 `const` 생성자를 가지므로 `ExecutionContext`의 기본값으로 const 인스턴스를 사용한다. +- `ExecutionContext.output`은 non-final 필드로 두어 explicit context별 교체를 지원하되, reset 메서드는 추가하지 않았다 (계획 범위 외). + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- output port 계약이 `cli` 패키지를 import하지 않는지 확인한다. +- `ExecutionContext` 기본 output이 테스트/명시 context에서 안전한 no-op인지 확인한다. +- 후속 subtask가 사용할 public symbol 이름이 과도하게 CLI에 묶이지 않는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### REFACTOR-1 중간 검증 + +```bash +$ cd apps/runner && dart analyze +Analyzing runner... +No issues found! + +$ cd apps/runner && dart test test/oto_core_test.dart +00:00 +29: All tests passed! +``` + +### 최종 검증 + +```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 +00:03 +71: All tests passed! +``` + +## 코드리뷰 결과 + +### 종합 판정: PASS + +### 차원별 평가 + +- correctness: Pass +- completeness: Pass +- test coverage: Pass +- API contract: Pass +- code quality: Pass +- plan deviation: Pass +- verification trust: Pass + +### 발견된 문제 + +없음 + +### 다음 단계 + +PASS이므로 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. diff --git a/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/complete.log b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/complete.log new file mode 100644 index 0000000..36b0bd2 --- /dev/null +++ b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/complete.log @@ -0,0 +1,41 @@ +# Complete - m-runner-output-boundary/01_output_port_contract + +## 완료 일시 + +2026-06-07 + +## 요약 + +runner output port 계약, no-op 구현, ExecutionContext 보유 필드, core 테스트를 추가했고 1회 리뷰에서 PASS로 종료했다. + +## 루프 이력 + +| Plan | Review | Verdict | 메모 | +|------|--------|---------|------| +| `plan_local_G06_0.log` | `code_review_local_G06_0.log` | PASS | output port 계약과 검증이 계획 범위를 충족했다. | + +## 구현/정리 내용 + +- `RunnerOutputStyle`, `RunnerOutputPort`, `NoopRunnerOutputPort`를 core 소유 계약으로 추가했다. +- `ExecutionContext`가 기본 no-op output port를 보유하도록 했다. +- `ExecutionContext exposes no-op runner output port` 테스트로 기본 no-op 호출과 explicit context별 output 교체를 검증했다. + +## 최종 검증 + +- `cd apps/runner && dart analyze` - PASS; `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` - PASS; `All tests passed!` (`+71`) + +## Roadmap Completion + +- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md` +- Completed task ids: + - `port`: PASS; evidence=`agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/plan_local_G06_0.log`, `agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/code_review_local_G06_0.log`; verification=`cd apps/runner && dart analyze`, `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` +- Not completed task ids: 없음 + +## 잔여 Nit + +- 없음 + +## 후속 작업 + +- 없음 diff --git a/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/plan_local_G06_0.log b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/plan_local_G06_0.log new file mode 100644 index 0000000..d449944 --- /dev/null +++ b/agent-task/archive/2026/06/m-runner-output-boundary/01_output_port_contract/plan_local_G06_0.log @@ -0,0 +1,180 @@ + + +# Plan - REFACTOR + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/runner-output-boundary.md` +- Task ids: + - `port`: runner 실행 progress와 일반 출력에 필요한 최소 output port 계약을 정의한다. +- Completion mode: check-on-pass + +## 배경 + +현재 pipeline/core 실행 코드가 `package:oto/cli/cli.dart`의 `CLI`, `Color`를 직접 사용한다. 첫 단계에서는 domain-neutral output port 계약과 기본 no-op 구현만 정의하고, 실제 call-site 전환은 후속 split 작업에서 수행한다. + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/phase/independent-control-plane/PHASE.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-ops/rules/project/domain/cli/rules.md` +- `agent-test/local/rules.md` +- `agent-test/local/pipeline-smoke.md` +- `agent-test/local/core-smoke.md` +- `agent-test/local/cli-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/lib/oto/core/data_composer.dart` +- `apps/runner/lib/oto/application.dart` +- `apps/runner/lib/cli/cli.dart` +- `apps/runner/lib/cli/printer.dart` +- `apps/runner/lib/cli/cli_style.dart` +- `apps/runner/test/oto_core_test.dart` +- `apps/runner/test/oto_application_test.dart` + +### 테스트 환경 규칙 + +- test_env: `local` +- `agent-test/local/rules.md` 읽음. +- 매칭 profile: `agent-test/local/core-smoke.md`, `agent-test/local/pipeline-smoke.md`, `agent-test/local/cli-smoke.md` 읽음. +- 적용 명령: core 변경 기준 `cd apps/runner && dart analyze`, `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`. +- 이번 subtask는 core 계약 추가라 pipeline/CLI smoke는 후속 subtask에서 실행한다. +- 구조상 blank/skeleton 없음. `<확인 필요>` 값 없음. + +### 테스트 커버리지 공백 + +- 새 output port가 default no-op인지 확인하는 직접 테스트가 없다. `apps/runner/test/oto_core_test.dart`에 추가한다. +- CLI adapter 동작, pipeline call-site 제거, DataComposer printer 제거는 후속 subtask에서 다룬다. + +### 심볼 참조 + +- 변경/제거 예정 심볼: 없음. +- 추가 예정 심볼: `RunnerOutputPort`, `RunnerOutputStyle`, `NoopRunnerOutputPort`, 테스트용 recording output. + +### 분할 판단 + +- split decision policy를 평가했다. +- 공유 계약과 broad call-site rollout이 분리되어야 하므로 split한다. +- task group: `agent-task/m-runner-output-boundary` +- sibling: + - `01_output_port_contract`: output port 계약 정의, 선행 없음. + - `02+01_pipeline_output_port`: pipeline call-site 전환, `01` complete.log 필요. + - `03+01,02_core_cli_adapter`: DataComposer/Application/CLI adapter 연결, `01`, `02` complete.log 필요. + +### 범위 결정 근거 + +- 이 subtask는 계약과 기본 구현만 추가한다. +- `apps/runner/lib/oto/pipeline/**` call-site 전환은 제외한다. +- `apps/runner/lib/oto/core/data_composer.dart` compose signature 변경은 제외한다. +- CLI adapter와 기존 출력 회귀 검증은 제외한다. + +### 빌드 등급 + +- build lane: `local-G06` +- review lane: `local-G06` +- 근거: core 계약 추가와 테스트 보강은 범위가 작지만 후속 refactor의 기반이므로 명시적 테스트가 필요하다. + +## 구현 체크리스트 + +- [ ] output port 계약과 no-op 구현을 core 소유 파일에 추가한다. +- [ ] `ExecutionContext`가 output port를 보유하고 reset 없이 explicit context별 output을 유지하게 한다. +- [ ] output port 기본 동작을 검증하는 core 테스트를 추가한다. +- [ ] `cd apps/runner && dart analyze`와 지정 core 테스트를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `apps/runner/lib/oto/core/output_port.dart` | REFACTOR-1 | +| `apps/runner/lib/oto/core/execution_context.dart` | REFACTOR-1 | +| `apps/runner/test/oto_core_test.dart` | REFACTOR-1 | + +## [REFACTOR-1] Output Port Contract + +### 문제 + +[execution_context.dart](/config/workspace/oto/apps/runner/lib/oto/core/execution_context.dart:39)는 runtime state를 보유하지만 output 경계가 없다. 그래서 [pipeline_exe.dart](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_exe.dart:43), [pipeline_foreach.dart](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_foreach.dart:116), [data_composer.dart](/config/workspace/oto/apps/runner/lib/oto/core/data_composer.dart:15)가 CLI type을 직접 소비한다. + +Before: + +```dart +// apps/runner/lib/oto/core/execution_context.dart:39 +class ExecutionContext { + DataCommon? commonData; + Map property = {}; + Map commandStates = {}; + Map dataCommandMap = {}; +``` + +### 해결 방법 + +`apps/runner/lib/oto/core/output_port.dart`를 추가하고 CLI enum을 import하지 않는 최소 계약을 둔다. 이름은 runner domain 의미를 드러내되 UI/CLI 구현 세부를 갖지 않는다. + +After: + +```dart +enum RunnerOutputStyle { + normal, + success, + warning, + error, + accent, + progress, +} + +abstract class RunnerOutputPort { + Future line(String message, {RunnerOutputStyle style = RunnerOutputStyle.normal}); + Future block(String message, {RunnerOutputStyle style = RunnerOutputStyle.normal}); + Future buildStep(String name, {RunnerOutputStyle style = RunnerOutputStyle.success}); +} + +class NoopRunnerOutputPort implements RunnerOutputPort { + const NoopRunnerOutputPort(); + @override + Future line(String message, {RunnerOutputStyle style = RunnerOutputStyle.normal}) async {} + @override + Future block(String message, {RunnerOutputStyle style = RunnerOutputStyle.normal}) async {} + @override + Future buildStep(String name, {RunnerOutputStyle style = RunnerOutputStyle.success}) async {} +} +``` + +`ExecutionContext`에 기본 no-op output을 둔다. + +### 수정 파일 및 체크리스트 + +- [ ] `apps/runner/lib/oto/core/output_port.dart` 추가 +- [ ] `apps/runner/lib/oto/core/execution_context.dart`에 `RunnerOutputPort output = const NoopRunnerOutputPort();` 추가 +- [ ] core 또는 pipeline이 CLI 패키지를 import하지 않아도 output 계약을 사용할 수 있게 import 경로 정리 +- [ ] `apps/runner/test/oto_core_test.dart`에 no-op/recording output 테스트 추가 + +### 테스트 작성 + +- 작성: `apps/runner/test/oto_core_test.dart` +- 테스트 이름: `ExecutionContext exposes no-op runner output port` +- 목표: 기본 output port 호출이 예외 없이 완료되고 explicit context별로 output port를 교체할 수 있음을 검증한다. + +### 중간 검증 + +```bash +cd apps/runner && dart analyze +cd apps/runner && dart test test/oto_core_test.dart +``` + +## 최종 검증 + +```bash +cd apps/runner && dart analyze +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 +``` + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/CODE_REVIEW-local-G06.md b/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/CODE_REVIEW-local-G06.md new file mode 100644 index 0000000..e42c29b --- /dev/null +++ b/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/CODE_REVIEW-local-G06.md @@ -0,0 +1,108 @@ + + +# 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/02+01_pipeline_output_port, plan=1, tag=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 + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다. + +1. predecessor complete.log 확인 여부를 검증한다. +2. 판정을 append한다. +3. PASS이면 plan/review log화, complete.log 작성, archive 이동을 수행한다. +4. roadmap 수정은 런타임 책임이다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [REFACTOR-1] Pipeline Output Port Rollout | [ ] | + +## 구현 체크리스트 + +- [ ] `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의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] active review/plan 파일을 `.log`로 아카이브한다. +- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. +- [ ] PASS split 작업이면 parent 유지/정리 상태를 확인한다. +- [ ] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- pipeline 도메인에서 `package:oto/cli/cli.dart` import가 사라졌는지 확인한다. +- `Application.instance.printBuildStep` 직접 호출이 pipeline에 남지 않았는지 확인한다. +- explicit context output 테스트가 singleton Application output에 기대지 않는지 확인한다. + +## 검증 결과 + +### REFACTOR-1 중간 검증 + +```bash +$ cd apps/runner && dart analyze +(output) + +$ cd apps/runner && dart test test/oto_core_test.dart +(output) +``` + +### 최종 검증 + +```bash +$ cd apps/runner && dart analyze +(output) + +$ cd apps/runner && dart test +(output) +``` + +## 코드리뷰 결과 + +_리뷰 에이전트가 append한다._ diff --git a/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/PLAN-local-G06.md b/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/PLAN-local-G06.md new file mode 100644 index 0000000..53dc24f --- /dev/null +++ b/agent-task/m-runner-output-boundary/02+01_pipeline_output_port/PLAN-local-G06.md @@ -0,0 +1,160 @@ + + +# 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](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_exe.dart:43)는 condition 출력에 `CLI.println`을 직접 호출하고, [pipeline_exe.dart](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_exe.dart:93)와 [pipeline_exe_handle.dart](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_exe_handle.dart:114)는 `Application.instance.printBuildStep`을 직접 호출한다. [pipeline_foreach.dart](/config/workspace/oto/apps/runner/lib/oto/pipeline/pipeline_foreach.dart:116)도 CLI를 직접 호출한다. + +Before: + +```dart +// 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: + +```dart +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 경계에 의존하지 않음을 확인한다. + +### 중간 검증 + +```bash +cd apps/runner && dart analyze +cd apps/runner && dart test test/oto_core_test.dart +``` + +## 최종 검증 + +```bash +cd apps/runner && dart analyze +cd apps/runner && dart test +``` + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/CODE_REVIEW-cloud-G07.md b/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/CODE_REVIEW-cloud-G07.md new file mode 100644 index 0000000..7ca0b59 --- /dev/null +++ b/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/CODE_REVIEW-cloud-G07.md @@ -0,0 +1,130 @@ + + +# 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 | [ ] | +| [REFACTOR-2] CLI Adapter Wiring | [ ] | + +## 구현 체크리스트 + +- [ ] `01_output_port_contract`와 `02+01_pipeline_output_port` complete.log를 확인한다. +- [ ] DataComposer/Jenkins collector signature를 CLI `Color` 없는 output port 또는 domain-neutral style 계약으로 바꾼다. +- [ ] Application이 build 시작 시 context output을 CLI adapter로 설정하고 `logEnable=false` 및 scheduler log 경계를 유지한다. +- [ ] CLI adapter가 기존 `CLI.printString`, `CLI.println`, build step banner 의미를 보존하도록 연결한다. +- [ ] `apps/runner/lib/oto/core/data_composer.dart`와 `apps/runner/lib/oto/pipeline/**`에 `package:oto/cli` import 또는 `CLI.` direct call이 남지 않게 한다. +- [ ] core/CLI 관련 테스트와 CLI smoke를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] active review/plan 파일을 `.log`로 아카이브한다. +- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. +- [ ] PASS split 작업이면 parent 유지/정리 상태를 확인한다. +- [ ] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/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 +(output) + +$ cd apps/runner && dart test test/oto_core_test.dart test/oto_application_test.dart +(output) +``` + +### REFACTOR-2 중간 검증 + +```bash +$ cd apps/runner && dart analyze +(output) + +$ cd apps/runner && dart test test/oto_application_test.dart test/oto_cli_runtime_test.dart test/oto_validate_cli_test.dart +(output) +``` + +### 최종 검증 + +```bash +$ cd apps/runner && dart analyze +(output) + +$ 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 +(output) + +$ cd apps/runner && dart test test/oto_cli_runtime_test.dart test/oto_catalog_cli_test.dart test/oto_validate_cli_test.dart +(output) + +$ cd apps/runner && dart run bin/main.dart --help +(output) + +$ ! rg --sort path -n "package:oto/cli|CLI\\.|Color\\." apps/runner/lib/oto/pipeline apps/runner/lib/oto/core/data_composer.dart +(output) +``` + +## 코드리뷰 결과 + +_리뷰 에이전트가 append한다._ diff --git a/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/PLAN-cloud-G07.md b/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/PLAN-cloud-G07.md new file mode 100644 index 0000000..202fbc4 --- /dev/null +++ b/agent-task/m-runner-output-boundary/03+01,02_core_cli_adapter/PLAN-cloud-G07.md @@ -0,0 +1,205 @@ + + +# Plan - 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 + +## 배경 + +이 작업은 output port 계약과 pipeline rollout이 끝난 뒤 Application/DataComposer/CLI adapter를 연결하는 마무리 단계다. 완료 후 `apps/runner/lib/oto/core/data_composer.dart`와 `apps/runner/lib/oto/pipeline/**`는 CLI 구현 타입을 직접 import하지 않아야 한다. + +## Roadmap Dependency + +- predecessor: `agent-task/m-runner-output-boundary/01_output_port_contract/complete.log` +- predecessor: `agent-task/m-runner-output-boundary/02+01_pipeline_output_port/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/core/rules.md` +- `agent-ops/rules/project/domain/cli/rules.md` +- `agent-test/local/core-smoke.md` +- `agent-test/local/cli-smoke.md` +- `apps/runner/lib/oto/application.dart` +- `apps/runner/lib/oto/core/data_composer.dart` +- `apps/runner/lib/oto/core/execution_context.dart` +- `apps/runner/lib/cli/cli.dart` +- `apps/runner/lib/cli/printer.dart` +- `apps/runner/lib/cli/cli_style.dart` +- `apps/runner/test/oto_application_test.dart` +- `apps/runner/test/oto_core_test.dart` +- `apps/runner/test/oto_cli_runtime_test.dart` +- `apps/runner/test/oto_validate_cli_test.dart` + +### 테스트 환경 규칙 + +- test_env: `local` +- env rule: `agent-test/local/rules.md` +- matched profiles: `core-smoke`, `cli-smoke` +- 적용 명령: + - `cd apps/runner && dart analyze` + - `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` + - `cd apps/runner && dart test test/oto_cli_runtime_test.dart test/oto_catalog_cli_test.dart test/oto_validate_cli_test.dart` + - CLI smoke: `cd apps/runner && dart run bin/main.dart --help` + +### 테스트 커버리지 공백 + +- DataComposer가 CLI `Color` 없이 output port를 사용하는지 직접 검증하는 테스트가 없다. `oto_application_test.dart` 또는 `oto_core_test.dart`에 fake output/data compose 경로 테스트를 추가한다. +- CLI adapter의 style mapping은 unit으로 직접 검증하기 어렵다. `dart run bin/main.dart --help`와 기존 validate JSON no-log test로 회귀를 확인한다. + +### 심볼 참조 + +- 변경 대상: + - `DataComposer.compose(String?, Future Function(String, Color?) printer)` + - `JenkinsEnvironmentCollector.collect(Future Function(String, Color?) printer)` + - `Application.printBuildStep(String, Color?)` +- call sites: + - `Application.build` line 102 passes `printBuildStep` + - `DataComposerJenkins.compose` line 174 passes printer into collector + - `DataComposerJenkins.compose` line 179 calls printer + - `JenkinsEnvironmentCollector.collect` line 63 calls printer + - `Application.build` lines 123, 159, 160, 161, 169 use CLI or printBuildStep + +### 분할 판단 + +- split decision policy 평가 완료. +- 이 subtask는 `03+01,02_core_cli_adapter`이며 `01`, `02` 완료 후 진행한다. +- core DataComposer 변경과 CLI adapter 연결은 같은 runtime entrypoint에서 맞물리므로 한 subtask로 묶는다. + +### 범위 결정 근거 + +- command implementations의 direct CLI usage는 제외한다. +- agent domain output (`apps/runner/lib/oto/agent/**`)은 제외한다. +- 로그 포맷 전면 개편, remote log streaming, YAML 문법 변경은 제외한다. + +### 빌드 등급 + +- build lane: `cloud-G07` +- review lane: `cloud-G07` +- 근거: Application build path, DataComposer, CLI output adapter가 교차하고 CLI JSON/log suppression 회귀 위험이 있어 더 큰 문맥과 세밀한 검증이 필요하다. + +## 구현 체크리스트 + +- [ ] `01_output_port_contract`와 `02+01_pipeline_output_port` complete.log를 확인한다. +- [ ] DataComposer/Jenkins collector signature를 CLI `Color` 없는 output port 또는 domain-neutral style 계약으로 바꾼다. +- [ ] Application이 build 시작 시 context output을 CLI adapter로 설정하고 `logEnable=false` 및 scheduler log 경계를 유지한다. +- [ ] CLI adapter가 기존 `CLI.printString`, `CLI.println`, build step banner 의미를 보존하도록 연결한다. +- [ ] `apps/runner/lib/oto/core/data_composer.dart`와 `apps/runner/lib/oto/pipeline/**`에 `package:oto/cli` import 또는 `CLI.` direct call이 남지 않게 한다. +- [ ] core/CLI 관련 테스트와 CLI smoke를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +- 디렉터리명 `03+01,02_core_cli_adapter` 기준 predecessor는 `01_output_port_contract`, `02+01_pipeline_output_port`다. +- 구현 시작 전 두 predecessor의 active 또는 archived `complete.log`를 확인한다. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `apps/runner/lib/oto/core/data_composer.dart` | REFACTOR-1 | +| `apps/runner/lib/oto/application.dart` | REFACTOR-1, REFACTOR-2 | +| `apps/runner/lib/cli/runner_output_adapter.dart` 또는 기존 CLI 파일 | REFACTOR-2 | +| `apps/runner/test/oto_application_test.dart` | REFACTOR-1, REFACTOR-2 | +| `apps/runner/test/oto_core_test.dart` | REFACTOR-1 | + +## [REFACTOR-1] DataComposer Neutral Output + +### 문제 + +[data_composer.dart](/config/workspace/oto/apps/runner/lib/oto/core/data_composer.dart:5)는 core 도메인인데 `package:oto/cli/cli.dart`를 import한다. [data_composer.dart](/config/workspace/oto/apps/runner/lib/oto/core/data_composer.dart:15)의 compose signature가 `Color`를 노출하고, [data_composer.dart](/config/workspace/oto/apps/runner/lib/oto/core/data_composer.dart:63)는 CLI color를 core error path로 사용한다. + +Before: + +```dart +// apps/runner/lib/oto/core/data_composer.dart:15 +Future compose(String? yaml, Future Function(String, Color?) printer) async { + return simpleFuture; +} +``` + +### 해결 방법 + +선행 output port 계약을 받아 `DataComposer.compose(String? yaml, RunnerOutputPort output)` 형태 또는 equivalent domain-neutral callback으로 바꾼다. `RunnerOutputStyle.error/success`를 사용하고 CLI `Color`는 adapter에서만 매핑한다. + +### 수정 파일 및 체크리스트 + +- [ ] `data_composer.dart`에서 `package:oto/cli/cli.dart` import 제거 +- [ ] compose/collector signature를 output port 기반으로 변경 +- [ ] unsupported OS/Jenkins Variables 출력이 output port를 통해 발생하도록 변경 +- [ ] 관련 테스트에서 fake output으로 메시지를 검증 + +### 테스트 작성 + +- 작성: `apps/runner/test/oto_core_test.dart` 또는 `apps/runner/test/oto_application_test.dart` +- 목표: DataComposer/Jenkins collector가 CLI type 없이 output port로 message를 emit하는지 검증한다. + +### 중간 검증 + +```bash +cd apps/runner && dart analyze +cd apps/runner && dart test test/oto_core_test.dart test/oto_application_test.dart +``` + +## [REFACTOR-2] CLI Adapter Wiring + +### 문제 + +[application.dart](/config/workspace/oto/apps/runner/lib/oto/application.dart:8)는 core orchestration인데 CLI package를 import하고, [application.dart](/config/workspace/oto/apps/runner/lib/oto/application.dart:123), [application.dart](/config/workspace/oto/apps/runner/lib/oto/application.dart:159), [application.dart](/config/workspace/oto/apps/runner/lib/oto/application.dart:301)는 직접 CLI 출력과 `Color`를 사용한다. CLI 출력 의미는 유지하되 domain 실행 로직이 CLI 구현을 몰라야 한다. + +Before: + +```dart +// apps/runner/lib/oto/application.dart:123 +await CLI.printString( + '$enter********************************* Build Data *************************************', + color: Color.magenta, +); +``` + +### 해결 방법 + +CLI domain에 `CliRunnerOutputPort` adapter를 추가한다. `Application`은 runner entrypoint로서 adapter를 context에 주입하되, pipeline/core domain은 adapter 구현을 직접 import하지 않는다. `Application.printBuildStep`는 adapter로 이동하거나 compatibility wrapper만 남긴다. + +### 수정 파일 및 체크리스트 + +- [ ] `apps/runner/lib/cli/runner_output_adapter.dart` 추가 또는 `cli.dart` 내부 adapter 추가 +- [ ] neutral style -> `Color` mapping을 adapter 안에 둔다 +- [ ] `Application.build`가 `_logEnable`과 scheduler logFunc 흐름을 유지하며 output adapter를 설정한다 +- [ ] `Application.printBuildStep` 직접 사용을 제거하거나 deprecated wrapper로 제한한다 +- [ ] validate `--json` stdout에 execute/build logs가 섞이지 않는 기존 테스트를 유지한다 + +### 테스트 작성 + +- 작성: `apps/runner/test/oto_application_test.dart` +- 보강: build success/failure가 output port로 build step을 emit하는지 또는 log disabled일 때 emit하지 않는지 검증한다. +- 기존: `apps/runner/test/oto_validate_cli_test.dart`의 JSON no execute logs 테스트를 유지한다. + +### 중간 검증 + +```bash +cd apps/runner && dart analyze +cd apps/runner && dart test test/oto_application_test.dart test/oto_cli_runtime_test.dart test/oto_validate_cli_test.dart +``` + +## 최종 검증 + +```bash +cd apps/runner && dart analyze +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 +cd apps/runner && dart test test/oto_cli_runtime_test.dart test/oto_catalog_cli_test.dart test/oto_validate_cli_test.dart +cd apps/runner && dart run bin/main.dart --help +! rg --sort path -n "package:oto/cli|CLI\\.|Color\\." apps/runner/lib/oto/pipeline apps/runner/lib/oto/core/data_composer.dart +``` + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-test/local/agent-smoke.md b/agent-test/local/agent-smoke.md index 6974c91..c777209 100644 --- a/agent-test/local/agent-smoke.md +++ b/agent-test/local/agent-smoke.md @@ -3,18 +3,19 @@ test_env: local test_profile: agent-smoke domain: agent verification_type: smoke -last_rule_updated_at: 2026-06-05 +last_rule_updated_at: 2026-06-07 --- # agent-smoke local 테스트 ## 읽기 조건 -- `apps/runner/lib/oto/agent/**`, `apps/runner/lib/cli/commands/command_agent.dart`, 또는 `apps/runner/assets/script/shell/oto_agent_bootstrap.sh` 변경 검증이 필요한 경우 +- `apps/runner/lib/oto/agent/**`, `apps/runner/lib/cli/commands/command_agent.dart`, `apps/runner/assets/script/shell/oto_agent_bootstrap.sh`, `services/core/cmd/oto-core/main.go`, `services/core/internal/httpserver/**`, 또는 `services/core/internal/runnerregistry/**` 변경 검증이 필요한 경우 ## 적용 범위 - OTO agent 등록/설정/CLI/bootstrap smoke 경로 +- OTO Server runner registration, bootstrap command, release URL validation 경로 - legacy iop smoke는 별도 iop 쪽 OTO 제거 작업의 검증 대상이며, 이 OTO 독립 마이그레이션 agent-smoke 필수 검증에서는 제외한다. ## 분류 @@ -26,19 +27,31 @@ last_rule_updated_at: 2026-06-05 ## 환경 - host: -- port: -- runtime: Dart SDK -- package manager: dart pub +- port: backend host publish 후보 `18020`; local compatibility 기본값 `127.0.0.1:8080` +- runtime: Dart SDK, Go toolchain +- package manager: dart pub, Go modules - docker: - external service: 없음 - model endpoint: - credential: +## 포트/환경 체크리스트 + +- Core publish 검증은 `OTO_CORE_ADDR=0.0.0.0:18020` 기준 후보를 사용한다. `127.0.0.1:8080`은 기존 local default compatibility로만 남긴다. +- bootstrap command는 `--server-url`을 기준 인자로 문서화한다. `--edge-url`은 script 호환 alias로만 본다. +- `OTO_RUNNER_RELEASE_BASE_URL`은 `https://` scheme만 허용한다. token, credential, private release host 원문은 테스트 규칙과 tracked 문서에 쓰지 않는다. +- iop Edge/wire endpoint는 독립 OTO Control Plane smoke의 필수 검증 대상이 아니다. + ## 명령 -- setup: `cd apps/runner && dart pub get` (또는 `make runner-get`) -- lint: `cd apps/runner && dart analyze` (또는 `make runner-analyze`) -- unit: `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart` (또는 `make runner-test`) +- setup: + - runner: `cd apps/runner && dart pub get` (또는 `make runner-get`) + - core: `cd services/core && go mod download` +- lint: + - runner: `cd apps/runner && dart analyze` (또는 `make runner-analyze`) +- unit: + - runner: `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart` (또는 `make runner-test`) + - core: `cd services/core && go test ./...` (또는 `make core-test`) - smoke: - e2e: - model: @@ -46,17 +59,20 @@ last_rule_updated_at: 2026-06-05 ## 필수 검증 -- agent 도메인 변경 후 `cd apps/runner && dart analyze`를 실행한다. -- agent 도메인 변경 후 agent 관련 `cd apps/runner && dart test ...` 명령을 실행한다. +- runner agent 도메인 변경 후 `cd apps/runner && dart analyze`를 실행한다. +- runner agent 도메인 변경 후 agent 관련 `cd apps/runner && dart test ...` 명령을 실행한다. +- services/core registration, bootstrap command, release URL validation 변경 후 `cd services/core && go test ./...`를 실행한다. ## 보조 검증 - 전체 회귀가 필요한 경우 `cd apps/runner && dart test` 또는 `make runner-test`를 실행한다. +- OTO Server 전체 회귀가 필요한 경우 `make core-test`를 실행한다. ## 판정 기준 - `cd apps/runner && dart analyze`가 issue 없이 종료한다. - 지정한 `cd apps/runner && dart test`가 모두 통과한다. +- 지정한 `cd services/core && go test ./...`가 모두 통과한다. ## 기준 출력 예시 diff --git a/agent-test/local/framework-smoke.md b/agent-test/local/framework-smoke.md index 7a1d3fc..e5a2d76 100644 --- a/agent-test/local/framework-smoke.md +++ b/agent-test/local/framework-smoke.md @@ -3,7 +3,7 @@ test_env: local test_profile: framework-smoke domain: framework verification_type: smoke -last_rule_updated_at: 2026-06-05 +last_rule_updated_at: 2026-06-07 --- # framework-smoke local 테스트 @@ -26,8 +26,8 @@ last_rule_updated_at: 2026-06-05 - host: - port: -- runtime: Dart SDK -- package manager: dart pub +- runtime: Dart SDK, Flutter SDK, Go toolchain +- package manager: dart pub, flutter pub, Go modules - docker: - external service: 없음 - model endpoint: diff --git a/agent-test/local/rules.md b/agent-test/local/rules.md index 18a5c76..c6810ec 100644 --- a/agent-test/local/rules.md +++ b/agent-test/local/rules.md @@ -1,6 +1,6 @@ --- test_env: local -last_rule_updated_at: 2026-06-05 +last_rule_updated_at: 2026-06-07 --- # local 테스트 규칙 @@ -19,13 +19,20 @@ last_rule_updated_at: 2026-06-05 - host: - port: -- runtime: Dart SDK -- package manager: dart pub +- runtime: Dart SDK, Flutter SDK, Go toolchain +- package manager: dart pub, flutter pub, Go modules - docker: - external service: 없음 - model endpoint: - credential: +## Workspace 포트/환경 체크리스트 + +- OTO Core host publish 후보는 backend `18020`이다. 로컬 실행 기본값 `127.0.0.1:8080`은 compatibility 경로로만 해석한다. +- Flutter client/web preview 후보는 frontend `13020`이다. preview 포트와 `OTO_SERVER_HTTP_URL` 서버 연결 URL을 혼동하지 않는다. +- `OTO_RUNNER_RELEASE_BASE_URL`과 bootstrap command 검증은 source of truth와 validation 기준만 기록한다. secret, token, private release host 원문은 tracked 문서와 테스트 규칙에 남기지 않는다. +- 독립 OTO Control Plane 검증에서 iop Edge/wire 포트를 OTO workspace 포트 표준으로 간주하지 않는다. + ## 라우팅 - agent / smoke / OTO agent CLI, OTO Server registration, bootstrap script: `agent-test/local/agent-smoke.md` diff --git a/apps/client/README.md b/apps/client/README.md index 0054c91..8808a29 100644 --- a/apps/client/README.md +++ b/apps/client/README.md @@ -28,3 +28,22 @@ dependencies: Then mount any exported widget, for example `OtoConsoleShell` or `OtoAgentPanel`, inside the host application's own workbench shell. + +## Local Preview + +The workspace frontend preview port candidate is `13020`: + +```bash +flutter run -d chrome --web-port=13020 +``` + +The preview port is separate from the OTO Core server URL. When the client +needs to talk to a host-published Core server, pass the server URL with a +compile-time define: + +```bash +flutter run -d chrome --web-port=13020 --dart-define=OTO_SERVER_HTTP_URL=http://localhost:18020 +``` + +The current app-level fallback `http://localhost:8080` remains a local +compatibility default until the runtime default is intentionally migrated. diff --git a/apps/runner/README.md b/apps/runner/README.md index acf91be..b0228f0 100644 --- a/apps/runner/README.md +++ b/apps/runner/README.md @@ -8,7 +8,7 @@ Jenkins, FTP, Git, Slack/Mattermost, iOS/Flutter/Android 빌드 등 다양한 ## 현재 상태 OTO CLI는 현재 Jenkins 실행, 로컬 YAML 파일 실행, 스케줄러 실행을 지원한다. -이 실행 표면은 이후 구조화 출력, YAML validation, Edge agent 확장을 추가할 때도 깨지면 안 되는 호환 기준선이다. +이 실행 표면은 이후 구조화 출력, YAML validation, 독립 Control Plane agent 확장을 추가할 때도 깨지면 안 되는 호환 기준선이다. 상세 진행 상황과 다음 작업 후보는 [`agent-roadmap/current.md`](agent-roadmap/current.md)와 [`agent-roadmap/ROADMAP.md`](agent-roadmap/ROADMAP.md)에서 확인한다. --- @@ -287,12 +287,19 @@ scheduler: 상세 로드맵은 [`agent-roadmap/ROADMAP.md`](agent-roadmap/ROADMAP.md)에 둔다. README에는 장기 방향과 작업 진입 문서 경로만 유지한다. -OTO의 장기 방향은 Jenkins 안에서 실행되는 CLI에 머물지 않고, Edge에 직접 붙는 가벼운 build/deploy agent까지 확장하는 것이다. +OTO의 장기 방향은 Jenkins 안에서 실행되는 CLI에 머물지 않고, OTO Control Plane에 등록되는 가벼운 build/deploy agent까지 확장하는 것이다. - 현재 활성 Milestone 후보는 [`agent-roadmap/current.md`](agent-roadmap/current.md)에서 확인한다. - CLI 자동화 표면 정리: 기존 CLI 실행 모드와 YAML 파이프라인, 커맨드 확장, 단일 바이너리 배포 구조를 장기 호환 표면으로 정리한다. -- Edge bootstrap 기반 `oto-agent`: Jenkins node 연결식 UX를 Edge bootstrap 기반 `oto-agent` 설치와 등록 계약으로 재해석한다. -- 메시지 기반 빌드 에이전트: Edge가 OTO 파이프라인을 원격 제어할 수 있게 한다. +- 독립 Control Plane 기반 `oto-agent`: Jenkins node 연결식 UX를 OTO Server bootstrap 기반 `oto-agent` 설치와 등록 계약으로 재해석한다. +- 메시지 기반 빌드 에이전트: OTO Server가 OTO 파이프라인을 원격 제어할 수 있게 한다. + +### Agent bootstrap 환경 기준 + +- `OTO_RUNNER_RELEASE_BASE_URL`은 runner binary asset을 내려받는 release source of truth다. +- Core가 HTTP로 실행될 때는 release base URL을 자동 추론하지 않으며, 환경 변수로 주입한 값도 `https://` scheme이어야 한다. +- bootstrap command 예시는 public validation 기준만 문서화하고, enrollment token, private release host, credential 원문은 tracked 문서에 남기지 않는다. +- bootstrap script의 `--edge-url` 인자는 기존 호출 호환 alias로만 보며, 새 문서와 smoke 기준은 `--server-url`을 사용한다. --- diff --git a/apps/runner/lib/oto/core/execution_context.dart b/apps/runner/lib/oto/core/execution_context.dart index fbf41b5..2e3d468 100644 --- a/apps/runner/lib/oto/core/execution_context.dart +++ b/apps/runner/lib/oto/core/execution_context.dart @@ -1,4 +1,5 @@ import 'package:oto/oto/application.dart'; +import 'package:oto/oto/core/output_port.dart'; import 'package:oto/oto/data/command_data.dart'; class StepEvent { @@ -41,6 +42,7 @@ class ExecutionContext { Map property = {}; Map commandStates = {}; Map dataCommandMap = {}; + RunnerOutputPort output = const NoopRunnerOutputPort(); final List stepEvents = []; int _nextStepId = 0; diff --git a/apps/runner/lib/oto/core/output_port.dart b/apps/runner/lib/oto/core/output_port.dart new file mode 100644 index 0000000..a6619ae --- /dev/null +++ b/apps/runner/lib/oto/core/output_port.dart @@ -0,0 +1,33 @@ +enum RunnerOutputStyle { + normal, + success, + warning, + error, + accent, + progress, +} + +abstract class RunnerOutputPort { + Future line(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}); + Future block(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}); + Future buildStep(String name, + {RunnerOutputStyle style = RunnerOutputStyle.success}); +} + +class NoopRunnerOutputPort implements RunnerOutputPort { + const NoopRunnerOutputPort(); + + @override + Future line(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}) async {} + + @override + Future block(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}) async {} + + @override + Future buildStep(String name, + {RunnerOutputStyle style = RunnerOutputStyle.success}) async {} +} diff --git a/apps/runner/test/oto_core_test.dart b/apps/runner/test/oto_core_test.dart index f23739d..4ef8d31 100644 --- a/apps/runner/test/oto_core_test.dart +++ b/apps/runner/test/oto_core_test.dart @@ -2,6 +2,7 @@ import 'package:oto/oto/application.dart'; import 'package:oto/oto/commands/command.dart'; import 'package:oto/oto/commands/command_registry.dart'; import 'package:oto/oto/core/execution_context.dart'; +import 'package:oto/oto/core/output_port.dart'; import 'package:oto/oto/data/command_data.dart'; import 'package:oto/oto/pipeline/pipeline.dart'; import 'package:oto/oto/pipeline/pipeline_exe.dart'; @@ -557,6 +558,22 @@ pipeline: expect(failed.error, isNotNull); expect(failed.error!['message'], contains('Test error message')); }); + + test('ExecutionContext exposes no-op runner output port', () async { + final ctx = ExecutionContext(); + expect(ctx.output, isA()); + await expectLater(ctx.output.line('hello'), completes); + await expectLater( + ctx.output.block('block', style: RunnerOutputStyle.success), completes); + await expectLater( + ctx.output.buildStep('step', style: RunnerOutputStyle.accent), + completes); + + final recording = _RecordingOutputPort(); + ctx.output = recording; + await ctx.output.line('msg', style: RunnerOutputStyle.warning); + expect(recording.lines, contains('msg')); + }); } class ThrowingExecutor extends PipelineExecutor { @@ -567,3 +584,27 @@ class ThrowingExecutor extends PipelineExecutor { @override Future execute() => Future.error(Exception('Test error message')); } + +class _RecordingOutputPort implements RunnerOutputPort { + final List lines = []; + final List blocks = []; + final List steps = []; + + @override + Future line(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}) async { + lines.add(message); + } + + @override + Future block(String message, + {RunnerOutputStyle style = RunnerOutputStyle.normal}) async { + blocks.add(message); + } + + @override + Future buildStep(String name, + {RunnerOutputStyle style = RunnerOutputStyle.success}) async { + steps.add(name); + } +}