oto/agent-task/m-runner-proto-socket-transport-hardening/02+01_dispatch_state/PLAN-cloud-G07.md
toki 88c8ff3b07 feat: runner proto socket transport hardening and related updates
- 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
2026-06-20 18:23:30 +09:00

10 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 대상으로 기록합니다.

배경

현 Milestone은 runner 기본 transport를 proto-socket push/session 기준으로 고정한다. DispatchQueuedJobs는 queued execution을 claim한 뒤 socket runner에게 RunRequest를 보내고, runner는 terminal report를 socket으로 돌려준다. 이 작업은 queued job dispatch와 execution state transition을 socket-first 경로에서 검증해 HTTP claim/polling 잔존 동작과 섞이지 않도록 한다.

사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 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:
    • dispatch-state: queued job dispatch, active execution gate, invalid RunRequest failure, terminal state transition을 socket transport 기준으로 검증한다.
  • Completion mode: check-on-pass
  • Split dependency:
    • 01_socket_lifecycle PASS complete evidence가 있어야 구현을 시작한다. 미충족이면 코드 변경 없이 dependency pending으로 보고한다.

Spec Targets

  • SDD: agent-roadmap/sdd/control-plane-product-surface/runner-proto-socket-transport-hardening/SDD.md
  • Acceptance scenarios:
    • S03: task=dispatch-state; evidence=Socket RunRequest dispatch와 terminal report가 queued/running/completed/failed/cancelled 상태 전이를 검증한다.
  • Completion mode: spec-check-on-pass

분석 결과

읽은 파일

  • agent-test/local/rules.md
  • agent-test/local/agent-smoke.md
  • agent-test/local/framework-smoke.md
  • agent-ops/rules/project/domain/agent/rules.md
  • agent-ops/rules/project/domain/framework/rules.md
  • agent-roadmap/phase/control-plane-product-surface/milestones/runner-proto-socket-transport-hardening.md
  • agent-roadmap/sdd/control-plane-product-surface/runner-proto-socket-transport-hardening/SDD.md
  • services/core/internal/runnersocket/server.go
  • services/core/internal/httpserver/server_test.go
  • services/core/internal/cicdstate/store.go
  • services/core/internal/cicdstate/store_test.go
  • apps/runner/lib/oto/agent/registration_client.dart
  • apps/runner/lib/oto/agent/agent_runner.dart
  • apps/runner/test/oto_server_connection_smoke_test.dart
  • proto/oto/runner.proto
  • Makefile

테스트 환경 규칙

test_env=local을 적용했다. agent-test/local/rules.md는 agent 변경 시 cd apps/runner && dart analyze, 관련 dart test, cd services/core && go test ./...를 요구한다. 이 plan은 proto schema 변경 없이 socket dispatch/state test와 필요한 server/runner 보강만 다룬다.

테스트 커버리지 공백

  • socket queued dispatch가 claimNextQueuedJob을 통해 하나의 queued execution만 running으로 전환하는지 직접 검증이 부족하다.
  • invalid RunRequest 전송 실패가 execution을 failed로 마감하는지 socket server 단위 테스트가 없다.
  • socket terminal report가 running 상태에서 completed/failed/cancelled 계열로만 전이하는지 HTTP report tests와 분리된 증거가 부족하다.

심볼 참조

runnersocket.Server.DispatchQueuedJobs, claimNextQueuedJob, ReportExecutionResult, proto.RunRequest, ReportRunResultRequest, OtoServerPushJobSession을 중심으로 확인했다. removed/renamed symbol 없음.

분할 판단

이 작업은 01_socket_lifecycle의 session 안정화 결과에 의존한다. 후속 03+01,02_runner_actions05+02,03,04_socket_smoke가 이 작업의 PASS evidence에 의존한다.

범위 결정 근거

이 plan은 queued execution dispatch와 state transition만 다룬다. cancel/status/self-update operator action 방향은 03+01,02_runner_actions, HTTP compatibility 경계는 04+01_compat_boundary, smoke 문서/명령 정리는 05+02,03,04_socket_smoke에서 다룬다.

빌드 등급

cloud-G07: state transition은 Go server store와 socket transport, Dart runner session이 함께 얽히며 회귀 영향이 커서 full local Go test와 targeted Dart smoke가 필요하다.

구현 체크리스트

  • 선행 01_socket_lifecycle PASS complete evidence를 확인한다.
  • [API-1] socket queued dispatch와 invalid RunRequest failure 테스트/보강을 구현한다. 검증: cd services/core && go test -count=1 ./...
  • [API-2] socket terminal report와 active execution gate 테스트/보강을 구현한다. 검증: cd services/core && go test -count=1 ./...
  • runner socket smoke 관련 회귀를 확인한다. 검증: cd apps/runner && dart test test/oto_server_connection_smoke_test.dart
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

[API-1] socket queued dispatch와 invalid RunRequest failure

문제: server.goDispatchQueuedJobs는 connected runner 목록을 순회하고 server.goclaimNextQueuedJob으로 queued execution을 running으로 바꾼다. 다만 socket dispatch 단위에서 "한 queued job만 claim", "runner 전송 실패 시 failed"가 고정되어 있지 않다.

해결 방법:

// before: services/core/internal/runnersocket/server.go:75
func (s *Server) DispatchQueuedJobs(ctx context.Context) {
    for _, runnerID := range s.connectedRunnerIDs() {
        ...
        execution, job, ok, err := s.claimNextQueuedJob(ctx, runnerID)
        ...
    }
}

services/core/internal/runnersocket/server_test.go에 dispatch 전용 tests를 추가한다. fake or loopback proto-socket client로 RunRequest 수신을 확인하고, 전송 오류/invalid request fixture에서는 FailExecution 또는 동일 정책의 failed transition을 검증한다. HTTP claim handler tests와 assertion 이름을 분리해 socket dispatch evidence로 읽히게 한다.

수정 파일 및 체크리스트:

  • services/core/internal/runnersocket/server_test.go에 queued dispatch test 추가
  • dispatch가 runner id와 queued execution filter를 지키는지 검증
  • send failure 또는 invalid request가 execution을 failed로 마감하는지 검증
  • 필요 시 services/core/internal/runnersocket/server.go 보강

테스트 작성: 작성한다. 테스트 이름 후보: TestServerDispatchQueuedJobOverSocket, TestServerFailsExecutionWhenRunRequestCannotBeSent.

중간 검증:

cd services/core && go test -count=1 ./...

기대 결과: 모든 Go package 통과.

[API-2] socket terminal report와 active execution gate

문제: server.go의 report handler는 runner terminal report를 받아 ReportExecutionResult로 넘긴다. store.go의 state transition guard가 있으나 socket report path에서 active execution과 runner ownership이 어긋난 경우의 test evidence가 부족하다.

해결 방법:

// before: services/core/internal/runnersocket/server.go:197
s.handlers.Register(func(ctx context.Context, req *pb.ReportRunResultRequest) (*pb.ReportRunResultResponse, error) {
    err := s.state.ReportExecutionResult(ctx, req.ExecutionId, cicdstate.ExecutionResult{...})
    ...
})

socket report handler tests를 추가해 running execution만 terminal report를 받을 수 있는지, completed/failed report가 terminal state와 timestamps/log fields를 보존하는지 확인한다. cancelled 상태와 terminal report가 충돌하는 경우에는 현재 store 정책을 테스트로 고정하거나, SDD의 cancelled evidence가 필요하면 store guard를 보강한다.

수정 파일 및 체크리스트:

  • socket report success/completed test 추가
  • socket report failure test 추가
  • wrong runner 또는 non-running execution report guard test 추가
  • cancelled state와 terminal report 충돌 정책을 테스트로 고정
  • 필요 시 services/core/internal/cicdstate/store.go 보강

테스트 작성: 작성한다. 테스트 이름 후보: TestServerReportsRunResultOverSocket, TestServerRejectsTerminalReportForInactiveExecution.

중간 검증:

cd services/core && go test -count=1 ./...

기대 결과: 모든 Go package 통과.

수정 파일 요약

파일 항목
services/core/internal/runnersocket/server.go API-1, API-2
services/core/internal/runnersocket/server_test.go API-1, API-2
services/core/internal/cicdstate/store.go API-2
services/core/internal/cicdstate/store_test.go API-2
apps/runner/test/oto_server_connection_smoke_test.dart API-1, API-2

최종 검증

cd services/core && go test -count=1 ./...
cd apps/runner && dart test test/oto_server_connection_smoke_test.dart

기대 결과: Go tests 통과, socket connection smoke 통과. 모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.