- Add runner-proto-socket-transport-hardening milestone and SDD docs - Add runnersocket package for Go service - Update agent config, runner, and job client (Dart) - Update Bootstrap scripts (PowerShell, shell) - Update Go service HTTP server handlers and routes - Add CICD state store updates - Update agent-ops domain rules and phase roadmap
12 KiB
Plan - API
이 파일을 읽는 구현 에이전트에게
CODE_REVIEW-cloud-G07.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것까지가 구현입니다. 검증을 실행하고 실제 stdout/stderr를 붙인 뒤 active 파일을 그대로 두고 review ready로 보고하세요. 선택된 SDD 결정 또는 Milestone 구현 잠금 > 결정 필요 항목이 막으면 review stub의 사용자 리뷰 요청 섹션을 채우고 멈추며, 직접 사용자에게 질문하거나 USER_REVIEW.md, complete.log, archive를 만들지 않습니다. 환경/secret/서비스 문제나 증거 공백은 일반 follow-up 대상으로 기록합니다.
배경
operator HTTP action 표면은 cancel/status/self-update 요청을 받지만, 현 Milestone의 기본 runner transport는 proto-socket이다. cancel은 server에서 runner socket으로 내려갈 수 있는 CancelExecution 경로가 있고, status는 state read 성격이 강하며, self-update는 runner-side 실행 경로가 아직 HTTP compatibility로 남아 있다. 이 작업은 세 action의 방향을 socket-first 기준으로 명확히 하고, cancel/report 충돌을 상태 전이에서 안전하게 막는다.
사용자 리뷰 요청 흐름
사용자 리뷰 요청은 선택된 SDD 결정 또는 선택된 Milestone lock 결정이 실구현을 차단할 때만 active CODE_REVIEW-cloud-G07.md의 사용자 리뷰 요청 섹션에 기록한다. 구현 중 직접 사용자 프롬프트, 채팅 선택지, request_user_input, USER_REVIEW.md 생성은 금지이며, code-review가 검증과 파일 생성을 소유한다.
Roadmap Targets
- Milestone:
agent-roadmap/phase/control-plane-product-surface/milestones/runner-proto-socket-transport-hardening.md - Task ids:
runner-actions: cancel/status/self-update runner action의 socket/HTTP 방향을 정하고 취소와 terminal report 충돌을 막는다.
- Completion mode: check-on-pass
- Split dependency:
01_socket_lifecyclePASS complete evidence가 있어야 구현을 시작한다.02+01_dispatch_statePASS complete evidence가 있어야 구현을 시작한다.
Spec Targets
- SDD:
agent-roadmap/sdd/control-plane-product-surface/runner-proto-socket-transport-hardening/SDD.md - Acceptance scenarios:
S04: task=runner-actions; evidence=cancel/status/self-update 요청 경로가 socket-first flow 또는 compatibility 제외 범위로 명시되고 검증된다.
- Completion mode: spec-check-on-pass
분석 결과
읽은 파일
agent-test/local/rules.mdagent-test/local/agent-smoke.mdagent-test/local/framework-smoke.mdagent-ops/rules/project/domain/agent/rules.mdagent-ops/rules/project/domain/framework/rules.mdagent-roadmap/phase/control-plane-product-surface/milestones/runner-proto-socket-transport-hardening.mdagent-roadmap/sdd/control-plane-product-surface/runner-proto-socket-transport-hardening/SDD.mdservices/core/internal/httpserver/runner_cicd_handlers.goservices/core/internal/runnersocket/server.goservices/core/internal/cicdstate/store.goservices/core/internal/httpserver/server_test.goapps/runner/lib/oto/agent/registration_client.dartapps/runner/lib/oto/agent/agent_runner.dartapps/runner/lib/oto/agent/oto_server_job_client.dartapps/runner/test/oto_server_connection_smoke_test.dartproto/oto/runner.protoMakefile
테스트 환경 규칙
test_env=local을 적용했다. agent/core 양쪽 action behavior가 걸리므로 Go 전체 테스트, runner socket smoke, Dart analyzer를 실행한다. proto schema를 변경하면 make proto와 generated code 갱신이 추가로 필요하지만, 기본 plan은 기존 CancelRunRequest, SelfUpdateRequest, status HTTP DTO 범위에서 처리한다.
테스트 커버리지 공백
- operator cancel endpoint와 socket
CancelExecutiondelivery가 하나의 흐름으로 검증되지 않는다. - runner Dart session은 pushed
RunRequest만 처리하며CancelRunRequestlistener가 없다. - self-update request는 proto message와 HTTP client method가 있으나 socket consumer가 없어서 compatibility 제외 여부가 문서/테스트에서 불명확하다.
- cancel 이후 late terminal report가 cancelled state를 뒤집지 않는지 socket action scenario로 고정되어 있지 않다.
심볼 참조
CancelExecution, CancelExecutionHandler, GetExecutionStatusHandler, RequestRunnerSelfUpdateHandler, CancelRunRequest, SelfUpdateRequest, OtoServerJobClient.cancelRun, requestSelfUpdate를 중심으로 확인했다. removed/renamed symbol 없음.
분할 판단
이 작업은 session lifecycle과 dispatch/state guard가 선행되어야 의미가 있다. 후속 05+02,03,04_socket_smoke는 이 작업에서 확정한 action direction을 smoke pass criteria에 반영한다.
범위 결정 근거
이 plan은 action direction과 cancel/report 충돌만 다룬다. queued dispatch의 일반 상태 전이는 02+01_dispatch_state, HTTP fallback 명명과 compatibility boundary는 04+01_compat_boundary에서 다룬다.
빌드 등급
cloud-G07: action behavior가 operator HTTP endpoint, core state store, socket server, Dart runner session을 가로지른다. 반쪽 구현이 smoke에서 늦게 드러날 수 있어 full local core/agent verification이 필요하다.
구현 체크리스트
- 선행
01_socket_lifecycle,02+01_dispatch_statePASS complete evidence를 확인한다. - [API-1] cancel/status action의 socket-first 방향과 상태 guard를 구현/검증한다. 검증:
cd services/core && go test -count=1 ./... - [API-2] runner-side cancel handling 또는 명시적 compatibility 제외를 구현/검증한다. 검증:
cd apps/runner && dart test test/oto_server_connection_smoke_test.dart - [API-3] self-update action을 socket-first 구현 또는 compatibility 제외 범위로 명확히 한다. 검증:
cd apps/runner && dart analyze - CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
[API-1] cancel/status action의 socket-first 방향과 상태 guard
문제: runner_cicd_handlers.go는 operator cancel endpoint를 제공하고, server.go는 runner에게 socket cancel을 보낼 수 있다. 두 경로가 한 action flow로 묶여 있는지와 late terminal report guard가 부족하다.
해결 방법:
// before: services/core/internal/runnersocket/server.go:108
func (s *Server) CancelExecution(ctx context.Context, runnerID string, executionID string) error {
client := s.clientForRunner(runnerID)
...
}
operator cancel handler가 state cancel만 수행하는지, socket runner cancel delivery까지 수행해야 하는지 현재 wiring을 확인한다. SDD S04 기준으로 socket-first가 목표이면 cancel endpoint에서 runner id를 찾아 CancelExecution을 호출할 수 있도록 dependency 주입을 보강한다. status endpoint는 state read action으로 명시하고 socket delivery 대상이 아님을 테스트/문서에 남긴다.
수정 파일 및 체크리스트:
- cancel endpoint에서 state cancel과 runner socket cancel delivery 관계를 명확히 함
- cancel 후 late terminal report가 cancelled state를 뒤집지 않는 테스트 추가
- status endpoint가 socket command가 아니라 state query임을 테스트 이름/설명으로 명확히 함
- 필요 시
services/core/internal/httpserver/server.go또는 handler dependency 보강
테스트 작성: 작성한다. 테스트 이름 후보: TestCancelExecutionSendsSocketCancelToRunner, TestCancelPreventsLateTerminalReportFromOverwritingCancelledState.
중간 검증:
cd services/core && go test -count=1 ./...
기대 결과: 모든 Go package 통과.
[API-2] runner-side cancel handling 또는 compatibility 제외
문제: registration_client.dart는 CancelRunRequest parser를 등록하지만 agent_runner.dart의 socket push loop는 RunRequest만 처리한다. socket cancel을 실제로 보낼 경우 runner가 수신 후 active execution을 중단하거나, 현재 Milestone에서 제외한다고 명시해야 한다.
해결 방법:
// before: apps/runner/lib/oto/agent/agent_runner.dart:108
await for (final runRequest in session.runRequests) {
...
}
가능한 범위에서 push session을 typed command stream으로 확장해 CancelRunRequest를 처리한다. active process cancel이 runner executor 구조상 큰 변경이면, 이번 Milestone에서는 cancel delivery evidence를 core socket send까지로 제한하고 runner process cancel은 compatibility/follow-up으로 명시한다. 단, 이 제외는 SDD S04 evidence에 남겨야 하며 smoke pass criteria와 충돌하면 사용자 리뷰 요청이 아니라 follow-up plan 대상으로 기록한다.
수정 파일 및 체크리스트:
- runner socket client가
CancelRunRequest를 수신할 수 있는지 확인/테스트 - active execution cancel handling 구현 가능성을 판단하고 구현 또는 범위 제외 기록
- core에서 cancel send 실패 시 operator action response/state 정책을 고정
- 필요 시 runner smoke에 cancel request 수신 검증 추가
테스트 작성: 작성한다. 테스트 이름 후보: runner receives socket cancel for active execution.
중간 검증:
cd apps/runner && dart test test/oto_server_connection_smoke_test.dart
기대 결과: socket smoke 통과.
[API-3] self-update action 방향 명확화
문제: proto/runner.proto는 SelfUpdateRequest를 정의하고 oto_server_job_client.dart는 HTTP self-update client를 제공한다. 그러나 server-side self-update socket dispatch와 runner consumer가 없다.
해결 방법:
이번 Milestone에서 self-update를 socket command로 구현할지, HTTP compatibility action으로 제외할지 결정하고 코드/테스트 이름/문서에 반영한다. 기본 추천은 product surface가 아직 operator action 수준이므로 self-update는 compatibility 제외로 명시하고, socket command 구현은 별도 Milestone으로 넘기는 것이다. 단, 기존 code path가 socket-first rule을 위반해 기본 path처럼 보이면 이름과 테스트를 compatibility로 정리한다.
수정 파일 및 체크리스트:
- self-update HTTP path가 compatibility/follow-up인지 명시
- socket-first smoke가 self-update를 필수 socket command로 오해하지 않게 정리
- 필요 시 roadmap SDD evidence에 excluded compatibility wording 업데이트
- Dart analyzer 통과 확인
테스트 작성: 변경 범위에 따라 작성한다. 문서/테스트 이름만 바꾸면 기존 smoke와 analyzer로 검증한다.
중간 검증:
cd apps/runner && dart analyze
기대 결과: analyzer issue 없음.
수정 파일 요약
| 파일 | 항목 |
|---|---|
services/core/internal/httpserver/runner_cicd_handlers.go |
API-1, API-3 |
services/core/internal/httpserver/server.go |
API-1 |
services/core/internal/runnersocket/server.go |
API-1 |
services/core/internal/cicdstate/store.go |
API-1 |
services/core/internal/httpserver/server_test.go |
API-1, API-3 |
apps/runner/lib/oto/agent/agent_runner.dart |
API-2 |
apps/runner/lib/oto/agent/registration_client.dart |
API-2 |
apps/runner/lib/oto/agent/oto_server_job_client.dart |
API-3 |
apps/runner/test/oto_server_connection_smoke_test.dart |
API-2, API-3 |
최종 검증
cd services/core && go test -count=1 ./...
cd apps/runner && dart test test/oto_server_connection_smoke_test.dart
cd apps/runner && dart analyze
기대 결과: Go tests 통과, runner socket smoke 통과, analyzer issue 없음. 모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.