iop/agent-spec/runtime/provider-pool-config-refresh.md
toki 0ffcb88db0 feat: provider-resource-admission-ownership alignment
- Archive provider-resource-admission-ownership milestone/SDD
- Align contract: CP-edge wire, runtime refresh, node runtime, OpenAI surface
- Update roadmap: phase state, priority queue
- Update specs: control-plane ops, OpenAI surface, edge execution, provider pool refresh
- Add node runtime supervisor bootstrapping and unit tests
- Fix control-plane edge registry handler and http_views
- Fix edge model queue admission and long context queue tests
2026-07-22 20:45:04 +09:00

14 KiB

spec_doc_type spec_id status source_evidence
spec runtime/provider-pool-config-refresh 부분
type path notes
contract agent-contract/inner/edge-config-runtime-refresh.md Edge config, provider pool, config refresh, Node payload 연결 계약
type path notes
code packages/go/config/provider_types.go provider/model catalog 설정 타입
type path notes
code packages/go/config/edge_types.go Edge root provider_pool canonical queue policy 타입과 기본값
type path notes
code packages/go/config/load.go Edge config load와 default 적용
type path notes
code packages/go/config/validate.go provider/model 참조와 numeric bound 검증
type path notes
code configs/edge.yaml provider-pool 권장 설정 예시와 live refresh 설정 예시
type path notes
code apps/edge/internal/service/provider_resolution.go provider 후보 해석과 capacity/priority policy 구성
type path notes
code apps/edge/internal/service/model_queue_admission.go provider 전역 lease, 공통 pending 상한, global enqueue 순서와 long-context admission
type path notes
code apps/edge/internal/service/model_queue_release.go lease 반환, disconnect/reconnect candidate 재구성과 global queue pump
type path notes
code apps/edge/internal/service/status_provider.go lease state와 candidate pressure 기반 online/offline provider snapshot
type path notes
code apps/edge/internal/configrefresh/classify.go dry-run/apply classification과 changed path report 생성
type path notes
code apps/edge/internal/bootstrap/runtime.go mutable config apply, runtime snapshot 교체, Node refresh push
type path notes
code apps/edge/internal/node/mapper.go provider-first NodeConfigPayload compile과 OpenAI-compatible provider label 보존
type path notes
test packages/go/config/provider_catalog_config_test.go provider/model catalog load와 queue 설정 검증
type path notes
test packages/go/config/provider_catalog_validation_config_test.go provider/model 참조와 validation 검증
type path notes
test apps/edge/internal/node/mapper_test.go provider-first adapter payload, Seulgivibe alias/provider label 검증
type path notes
test apps/edge/internal/configrefresh/node_runtime_classify_test.go node runtime과 model catalog refresh classification 검증
type path notes
test apps/edge/internal/configrefresh/provider_classify_test.go provider field refresh classification 검증
type path notes
test apps/edge/internal/service/model_queue_admission_test.go cross-model capacity, terminal unavailable, disconnect/event-drop 회귀 검증
type path notes
test apps/edge/internal/service/status_provider_test.go cross-model candidate pressure와 offline/reconnect snapshot 검증
type path notes
test apps/edge/internal/bootstrap/reconnect_readiness_integration_test.go dispatch-ready reconnect가 기존 queued waiter를 실제 Node terminal까지 수렴시키는 검증
type path notes
test scripts/e2e-provider-capacity-smoke.sh loopback OpenAI-compatible provider에서 two-alias capacity-1 queue와 final counter 회복 검증

스펙: Provider Pool과 Config Refresh

목적

Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, 어떤 설정 변경이 재시작 없이 반영되는지 설명한다.

기능 목록

기능 설명
model catalog models[].id는 외부 OpenAI-compatible model key이자 provider-pool ModelGroupKey다.
provider mapping models[].providers는 provider id를 실제 served model name으로 매핑한다.
node provider catalog nodes[].providers[]는 Node 아래 resource/provider catalog이며 provider id는 Edge config에서 전역 유일해야 한다.
config validation config load가 provider id 참조, served model membership, numeric bounds, long-context budget을 검증한다.
provider 후보 필터링 dispatch는 dispatch-ready connection을 가진 Node의 provider 후보 중 catalog match, enabled, healthy/available, capacity 조건을 만족하는 후보만 사용한다.
provider 전역 capacity/priority dispatch node_id + provider_id lease가 여러 model group의 일반·long in-flight를 합산한다. available 후보 중 낮은 in-flight를 고르고 동률이면 낮은 priority와 round-robin을 적용한다.
provider-pool 공통 queue policy Edge root provider_pool.max_queue가 모든 model group의 전체 pending 상한을, queue_timeout_ms가 각 pending request timeout을 소유한다.
global queue 재평가 lease 반환, capacity/priority/enabled refresh, disconnect/reconnect 뒤 global enqueue 순서에서 현재 dispatch 가능한 가장 이른 waiter부터 candidate를 다시 구성한다.
provider snapshot 일반·long in-flight는 provider lease state, queued 값은 Edge queue에서 해당 provider를 후보로 포함하는 고유 pending request pressure에서 계산한다. offline provider는 catalog identity를 유지하고 effective 수치를 0으로 보고한다.
mixed provider execution path 같은 model group의 OpenAI-compatible provider와 Ollama/CLI/native provider를 같은 후보군으로 두며, 선택된 provider capability로 passthrough 또는 normalized 실행 경로를 결정한다.
long-context admission estimated input token이 threshold 이상이면 context_class=long으로 분류하고, provider long slot이 있으면 일반 capacity slot과 함께 점유한다.
config refresh dry-run/apply loopback admin HTTP POST /refresh가 candidate config를 dry-run 또는 apply한다.
refresh classification listener, Edge identity, bootstrap path, adapter structural 변경 등은 restart-required로 분류한다.
mutable apply 적용 가능한 변경은 Edge Cfg, NodeStore, service/input model catalog, OpenAI long-context threshold를 copy-on-write로 교체한다.
Node config refresh push 변경이 있으면 Edge가 dispatch-ready Node에 node-specific NodeConfigRefreshRequest를 push한다. accepted지만 pending인 Node는 register response config를 적용한 뒤 ready가 될 때까지 push 대상이 아니다.
Node registry swap Node는 refresh payload로 새 adapter registry를 만들고 router registry를 swap한다. old registry stop은 active run이 있으면 drain 이후로 지연한다.
principal token mapping config openai.principal_tokens[]는 raw token 없이 token_ref, token_hash_sha256, principal_ref, optional alias를 관리하고 OpenAI usage metering의 principal/token label 후보를 제공한다. 같은 principal에 여러 token entry를 둘 수 있다.
provider auth forwarding config openai.provider_auth는 caller가 요청 header로 제공한 raw provider token을 selected OpenAI-compatible provider tunnel header로 전달하는 규칙만 저장한다.
Seulgivibe provider aliases seulgivibe_claude, seulgivibe_openai provider type은 runtime adapter type을 openai_compat로 정규화하고, 명시 provider label이 없으면 canonical Seulgivibe alias를 Node payload provider label로 보존한다.

범위

  • 포함: Edge config load/default/validation, provider-pool dispatch, queue admission, long-context admission, config refresh classification/apply, Node config refresh payload.
  • 제외: 개별 adapter의 provider API 호출 세부, OpenAI HTTP request/response shape, Control Plane 원격 config 변경 UX, private credential 관리.

주요 흐름

sequenceDiagram
  participant Caller
  participant Service as Edge service
  participant Queue as Provider queue
  participant Node

  Caller->>Service: SubmitRun(model)
  Service->>Queue: dispatch-ready provider 후보 선택(capacity + priority)
  Queue-->>Service: selected provider + served target
  alt selected provider supports OpenAI-compatible call
    Service->>Node: ProviderTunnelRequest(adapter, served target)
  else selected provider is Ollama/CLI/native
    Service->>Node: RunRequest(adapter, served target)
  end

  participant Operator
  participant Refresh as Config refresh
  Operator->>Refresh: POST /refresh(apply)
  Refresh->>Refresh: load, validate, classify
  Refresh->>Node: NodeConfigRefreshRequest

계약

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

설정/데이터/이벤트

  • long_context_threshold_tokens 기본 예시는 100000이고 0 이하 값은 config load에서 거부된다.
  • provider_pool.max_queue는 0/생략 시 기본값 16, queue_timeout_ms는 생략 시 30000이고 명시적 0은 timeout 없음이다. canonical root key가 없을 때만 서로 같은 legacy provider queue pair를 승격하며 값이 다르면 load를 거부한다.
  • nodes[].providers[].capacitylong_context_capacity는 provider resource 속성이고 같은 provider를 공유하는 model alias가 합산 점유한다. total_context_tokens는 runtime ledger가 아니라 context_window_tokens * long_context_capacity 정적 validation 값이다.
  • provider enabled=false는 dispatch pool에서 제외하지만 adapter process lifecycle 변경을 의미하지 않는다.
  • accepted registration은 provider candidate를 바로 복구하지 않는다. Node가 config 적용과 handler 설치 뒤 ready ack를 받아야 해당 generation이 candidate, connected snapshot, refresh push 대상이 되며 이 transition이 stranded provider-pool waiter를 재평가한다.
  • provider capacity, long-context capacity, priority, enabled toggle, root queue policy와 model generation policy는 live apply 대상으로 분류된다. apply는 기존 lease를 보존하고 이후 admission 및 모든 관련 waiter의 live candidate/deadline을 새 값으로 재평가한다.
  • Edge listener, control plane, openai/a2a listener, bootstrap artifact path, node 추가/삭제, node token/alias, adapter 설정 변경은 restart-required 대상이다.
  • openai.principal_tokens[]token_reftoken_hash_sha256 중복을 거부하고, raw token 원문은 tracked config에 저장하지 않는다.
  • 여러 openai.principal_tokens[] entry가 같은 principal_ref를 공유할 수 있으며, 이때 token_ref가 앱/통합/용도별 사용량 분해 기준이다.
  • openai.principal_tokens[] 변경은 credential/hash 변경으로 보고 restart-required로 분류된다.
  • openai.provider_auth.enabled=true이면 생략된 header fields는 from_header=X-IOP-Provider-Authorization, target_header=Authorization, scheme=Bearer, required=true로 해석된다. raw provider token 값은 config/spec/docs에 저장하지 않는다.
  • Seulgivibe provider catalog는 top-level models[]의 정적 provider mapping을 source of truth로 사용한다. provider /models endpoint는 IOP catalog source가 아니다.
  • models[]는 mixed provider group과 Ollama-only group을 모두 표현할 수 있다. Ollama는 후보에서 제외하지 않고 capacity/priority로 운영자가 낮은 동시성과 낮은 선호도를 표현한다.
  • refresh result는 changed nodes/providers/models와 restart-required paths를 stable non-nil slice로 보고한다.

검증

  • go test ./packages/go/config
  • go test ./apps/edge/internal/configrefresh
  • go test ./apps/edge/internal/service
  • go test ./apps/edge/internal/node
  • go test ./apps/node/internal/adapters ./apps/node/internal/node
  • go test ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$'
  • ./scripts/e2e-provider-capacity-smoke.sh

한계와 주의사항

  • provider health는 현재 config/provider snapshot 기반이다. 모든 runtime에 대한 active health probe가 완성된 것은 아니다.
  • refresh admin API는 operator-local 표면이다. 접근 제어 없이 public interface에 노출하지 않는다.
  • adapter structural 변경은 contract상 restart-required로 분류된다. Node handler가 registry swap을 지원하더라도 Edge refresh classifier가 허용한 변경만 apply해야 한다.
  • no-change apply는 runtime snapshot을 교체하지만 Node push는 생략한다.
  • NodeRuntimeConfig.concurrency는 legacy metadata이며 provider-pool admission의 node-wide capacity로 쓰지 않는다.
  • provider가 full인 상태는 일시적인 queue block이지만, disconnect/disable로 live candidate가 모두 사라지면 waiter는 기존 queue timeout까지 남지 않고 unavailable로 종료된다.
  • credential, private endpoint, bearer token 원문은 tracked config/docs/spec에 남기지 않는다.
  • principal token mapping은 완성된 사용자/테넌트 source of truth가 아니라 외부 principal_ref 또는 내부 alias에 대한 얇은 운영 매핑이다.
  • Seulgivibe provider endpoint와 raw user token은 환경별 private config 또는 request-time header로 주입해야 하며 tracked 예시에 실제 값을 남기지 않는다.

변경 기록

  • 2026-07-07: 현재 코드, 계약, config 예시 기준으로 bootstrap spec 작성.
  • 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.
  • 2026-07-10: OpenAI usage metering용 principal token hash mapping config와 restart-required 기준을 반영.
  • 2026-07-11: Seulgivibe OpenAI-compatible provider aliases, provider auth forwarding config, static catalog 기준을 현재 코드/계약/테스트 기준으로 반영.
  • 2026-07-12: Model Group Mixed Provider Dispatch 종료 검토 기준으로 mixed provider group과 Ollama-only group, capacity/priority 가중 예시를 반영.
  • 2026-07-18: 저장소 구조 분해 뒤 config, provider resolution/admission, split test의 source_evidence를 현재 경로로 동기화.
  • 2026-07-22: pending accepted connection과 dispatch-ready connection을 구분하고, ready ack 뒤에만 provider candidate 복구·refresh push·queued waiter pump가 일어나는 현재 동작을 반영.
  • 2026-07-22: root provider-pool queue policy, cross-model provider lease, global queue 재평가, refresh lease 보존과 connectivity 기반 snapshot 의미를 현재 구현·계약·테스트 기준으로 동기화.