iop/agent-spec/runtime/edge-node-execution.md
toki 51de0e259e docs(spec,contract,roadmap,scripts): 계약·스펙·로드맵 문서 갱신 및 e2e 테스트 보완
- edge-node-runtime-wire 계약 스키마 동기화
- edge-node-execution, provider-pool-config-refresh 스펙 갱신
- provider-resource-admission-ownership-alignment 마일스톤 상태 동기화
- control-plane-portal-ops phase 신규 추가 (multi-edge-operations)
- e2e-smoke: 재연결 테스트 플로우, bind timeout, reconnect 설정 반영
2026-07-22 18:11:24 +09:00

12 KiB

spec_doc_type spec_id status source_evidence
spec runtime/edge-node-execution 부분
type path notes
contract agent-contract/inner/edge-node-runtime-wire.md Edge-Node register, run stream, cancel, node command, config refresh wire 계약
type path notes
code proto/iop/runtime.proto RunRequest, RunEvent, CancelRequest, NodeCommandRequest, RegisterRequest, NodeConfigPayload 원문
type path notes
code apps/edge/internal/transport/server.go Edge TCP proto-socket server, node register handshake, event relay
type path notes
code apps/edge/internal/service/run_submit.go surface-neutral SubmitRun과 direct/queued dispatch
type path notes
code apps/edge/internal/service/provider_tunnel.go provider tunnel dispatch와 request-bound frame relay
type path notes
code apps/node/internal/node/run_handler.go Node RunRequest 처리와 adapter 실행
type path notes
code apps/node/internal/node/tunnel_handler.go Node provider tunnel request 처리와 frame relay
type path notes
code apps/node/internal/adapters/openai_compat/execute.go OpenAI-compatible provider 실행 stream과 RuntimeEvent usage 변환
type path notes
code apps/node/internal/adapters/openai_compat/provider_tunnel.go OpenAI-compatible provider raw HTTP/SSE tunnel 처리
type path notes
code apps/node/internal/adapters/vllm/vllm.go vLLM usage payload의 reasoning/cached token 변환
type path notes
test apps/edge/internal/transport/server_test.go Edge transport server 단위 검증
type path notes
test apps/node/internal/node/run_cancel_test.go Node run 실행과 cancel 처리 검증
type path notes
test apps/node/internal/node/provider_tunnel_test.go Node provider tunnel lifecycle 검증
type path notes
test apps/node/internal/adapters/openai_compat/execute_test.go OpenAI-compatible provider stream과 usage breakdown 검증
type path notes
test apps/node/internal/adapters/openai_compat/provider_tunnel_test.go OpenAI-compatible provider raw tunnel 검증
type path notes
test apps/node/internal/adapters/vllm/vllm_test.go vLLM usage breakdown 검증
type path notes
test apps/edge/internal/bootstrap/reconnect_readiness_integration_test.go 실제 iop-node reconnect 뒤 queued waiter의 ready-gated dispatch와 terminal/counter 수렴 검증

스펙: Edge-Node 실행 경로

목적

Edge와 Node 사이에 현재 구현된 실행 기능을 기능 단위로 정리한다. 코드 배치 규칙이나 도메인별 작업 지침은 domain rule을 따른다.

기능 목록

기능 설명
Node token 등록과 dispatch-ready Node가 RegisterRequest.token으로 ownership/config를 받고, config 적용·adapter start·handler 설치 뒤 NodeReadyRequest/ack로 dispatch-ready가 된다.
Node config payload 전달 Edge가 token에 매칭되는 node record를 찾아 NodeConfigPayloadRegisterResponse에 담아 내려준다.
등록 실패 처리 unknown token, duplicate connection, config payload build failure를 register response와 node lifecycle event로 표현한다.
실행 요청 전달 Edge service가 SubmitRun 요청을 RunRequest로 만들어 선택된 Node에 보낸다. 명시 node가 없고 연결 node가 1개면 single-node fallback을 사용한다.
adapter 실행 Node가 RunRequest.adapter로 adapter instance를 찾고 adapter Execute를 호출한다. admission은 adapter Capabilities().MaxConcurrency 기준이다.
실행 이벤트 스트림 Node adapter가 낸 start, delta, reasoning_delta, complete, error, cancelled 이벤트를 RunEvent로 Edge에 relay한다.
provider raw tunnel Edge가 ProviderTunnelRequest를 보내면 Node가 provider HTTP/SSE response를 열고 ordered ProviderTunnelFrame으로 status/header/body/end/error/usage 후보를 relay한다.
mixed provider dispatch wire provider-pool model group은 Edge service에서 provider를 먼저 선택한 뒤 OpenAI-compatible provider에는 ProviderTunnelRequest, Ollama/CLI/native provider에는 normalized RunRequest를 보낸다.
usage breakdown relay RunEvent.usageProviderTunnelFrame.usage는 provider가 보고한 input/output/reasoning/cached input token count를 Edge 관측 계층으로 전달한다.
terminal event 합성 adapter가 terminal event 없이 종료하면 Node가 terminal event를 합성한다.
run cancel Edge가 CancelRequest를 보내면 Node run manager가 active run context를 cancel한다.
logical session 종료 adapter가 SessionTerminator를 구현한 경우 TERMINATE_SESSION으로 session을 종료한다. 모든 adapter 공통 기능은 아니다.
Node command capabilities, transport status, usage status, session list, ollama API 계열 조회/제어성 command를 실행 요청과 분리해 처리한다.
Node local run store Node가 run id, adapter, target, session id, background, status, timestamps, error를 SQLite에 기록한다.
Edge event fanout Edge event bus가 run event와 node lifecycle event를 in-process subscriber에게 fanout한다.

범위

  • 포함: Edge-Node TCP/protobuf transport, register handshake, run/cancel/command, provider raw tunnel, Node adapter execution, Edge event bus fanout, Node local run store.
  • 제외: OpenAI-compatible/A2A HTTP request shape, Control Plane 운영 wire, provider-pool config refresh 상세, durable global history/audit.

주요 흐름

Node 등록

sequenceDiagram
  participant Node
  participant EdgeTransport as Edge transport
  participant NodeStore as Edge NodeStore

  Node->>EdgeTransport: TCP connect
  Node->>EdgeTransport: RegisterRequest(token)
  EdgeTransport->>NodeStore: token으로 NodeRecord 조회
  alt token valid
    EdgeTransport->>EdgeTransport: NodeConfigPayload 생성, pending ownership claim
    EdgeTransport-->>Node: RegisterResponse(accepted=true, config)
    Node->>Node: config 적용, adapter start, session handler 설치
    Node->>EdgeTransport: NodeReadyRequest(node_id)
    EdgeTransport->>EdgeTransport: current owner를 dispatch-ready로 전환
    EdgeTransport->>EdgeTransport: provider availability 활성화, queued waiter pump, connected event
    EdgeTransport-->>Node: NodeReadyResponse(ready=true)
  else token invalid or duplicate
    EdgeTransport-->>Node: RegisterResponse(accepted=false, reason)
  end

실행 요청과 이벤트

sequenceDiagram
  participant Caller
  participant EdgeService as Edge service
  participant EdgeTransport as Edge transport
  participant Node
  participant Adapter

  Caller->>EdgeService: SubmitRun(adapter, target, input)
  EdgeService->>EdgeService: Node 선택
  EdgeService->>EdgeTransport: RunRequest
  EdgeTransport->>Node: RunRequest
  Node->>Node: adapter instance resolve
  Node->>Adapter: Execute(spec)
  Adapter-->>Node: RuntimeEvent(delta/start/complete)
  Node-->>EdgeTransport: RunEvent
  EdgeTransport-->>Caller: run stream

Provider raw tunnel

sequenceDiagram
  participant OpenAI as Edge OpenAI surface
  participant EdgeService as Edge service
  participant Node
  participant Provider

  OpenAI->>EdgeService: SubmitProviderTunnel
  EdgeService->>Node: ProviderTunnelRequest
  Node->>Provider: HTTP/SSE request
  Provider-->>Node: status/header/body
  Node-->>EdgeService: ProviderTunnelFrame sequence
  EdgeService-->>OpenAI: request-bound frame stream

취소와 session 종료

sequenceDiagram
  participant EdgeService as Edge service
  participant Node
  participant Adapter

  alt cancel run
    EdgeService->>Node: CancelRequest(CANCEL_RUN, run_id)
    Node->>Node: active run context cancel
  else terminate session
    EdgeService->>Node: CancelRequest(TERMINATE_SESSION, adapter, target, session_id)
    Node->>Adapter: TerminateSession(target, session_id)
  end

계약

  • iop.edge-node-runtime-wire: agent-contract/inner/edge-node-runtime-wire.md
  • proto 원문: proto/iop/runtime.proto

설정/데이터/이벤트

  • Edge의 node source of truth는 configs/edge.yamlpackages/go/confignodes[] 구조다.
  • accepted registration은 duplicate ownership claim과 config 전달만 담당한다. ready ack 전 Node는 direct/provider-pool dispatch, provider tunnel/command, config refresh push, connected snapshot/event에서 제외된다.
  • Edge registry의 connection generation은 internal fence이며 wire/config로 노출하지 않는다. current client의 첫 ready만 provider resource activation과 queue pump를 수행하고, duplicate ready는 idempotent ack, stale/rejected ready는 reject로 처리한다.
  • RunEvent는 adapter execution stream이고, EdgeNodeEvent는 node lifecycle/control event다.
  • ProviderTunnelFrame.body는 OpenAI-compatible provider passthrough의 source of truth이며 RunEvent.delta나 Edge event bus payload로 보내지 않는다.
  • ProviderTunnelFrame.usagemetadata는 관측 후보이며 pure passthrough body에 합쳐지지 않는다.
  • provider-pool mixed dispatch에서 ProviderTunnelRequestRunRequest 중 어느 wire를 사용할지는 selected provider capability에서 파생되며, client request metadata selector로 결정하지 않는다.
  • Usage.reasoning_tokensUsage.cached_input_tokens는 provider가 별도 보고한 경우에만 채워지는 optional breakdown이다.
  • Node local DB는 기본 file:iop.db?cache=shared&mode=rwc로 열린다.
  • heartbeat는 Edge와 Node transport 양쪽에서 2초 interval, 5초 wait 기준을 사용한다. 정상적인 프로세스·OS 종료는 transport close로 즉시 감지하고, heartbeat timeout은 종료 신호가 오지 않는 전원 차단·네트워크 단절의 fallback으로 사용한다.

검증

  • go test ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/node
  • go test ./apps/node/internal/transport ./apps/node/internal/node ./apps/node/internal/router ./apps/node/internal/adapters ./apps/node/internal/store
  • go test ./apps/node/internal/adapters/openai_compat ./apps/node/internal/adapters/vllm
  • go test ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$' - 실제 iop-node 재연결 뒤 기존 provider-pool waiter의 dispatch 1회, terminal 1회, counter 0 수렴을 확인한다.
  • make test-e2e - Edge-Node와 OpenAI 보조 smoke를 함께 실행한다. runtime path 변경 시 사용자 흐름 검증을 대체하지 않는다.

한계와 주의사항

  • mTLS helper는 존재하지만 현재 Edge-Node transport 설정에는 연결되어 있지 않다.
  • TERMINATE_SESSION은 모든 adapter에 공통으로 보장되는 기능이 아니다.
  • Node store는 전역 query/audit API가 아니다. 상위 운영 이력은 별도 설계가 필요하다.
  • provider raw tunnel은 기존 socket 위 request-bound stream이다. 별도 Node stream server나 Edge의 provider direct access 경로가 아니다.
  • usage breakdown은 provider-reported 값만 전달한다. provider가 보고하지 않은 reasoning token을 Node나 Edge가 추정하지 않는다.

변경 기록

  • 2026-07-07: 현재 코드, 계약, README 기준으로 bootstrap spec 작성.
  • 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.
  • 2026-07-08: Provider raw tunnel 실행 흐름과 passthrough event/data 경계를 현재 계약 기준으로 반영.
  • 2026-07-10: RunEvent.usage/ProviderTunnelFrame.usage의 input/output/reasoning/cached input breakdown 전달 기준을 반영.
  • 2026-07-12: Model Group Mixed Provider Dispatch 종료 검토 기준으로 selected provider capability에서 파생되는 ProviderTunnelRequest/RunRequest 분기 경계를 반영.
  • 2026-07-18: 저장소 구조 분해 뒤 Edge run/tunnel, Node handler, adapter split test의 source_evidence를 현재 경로로 동기화.
  • 2026-07-22: accepted registration을 pending ownership/config 단계로 제한하고, handler 설치 뒤 NodeReadyRequest/ack로 dispatch eligibility와 reconnect waiter pump를 여는 순서를 반영.