iop/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md
toki 2f560e3f3b feat: provider pool admission, policy config, snapshot source task archive + runtime updates
- Archive completed subtask plans/code reviews (04, 05+03,04, 07+03)
- Add provider_pool_admission_test.go
- Update edge config types, load, catalog validation
- Update runtime, config refresh, service layers for admission
- Update test docs and inventory
- Update provider scheduling, resolution, tunnel, status modules
2026-07-19 22:41:05 +09:00

15 KiB

Milestone: Provider Resource Admission Ownership 정합화

위치

목표

nodes[].providers[]가 선언한 실행 resource의 capacity와 long-context slot을 여러 models[].id가 같은 provider를 참조하더라도 하나의 provider 상태로 일관되게 적용하도록 admission 소유권을 바로잡는다. Edge는 provider 전역 lease를 실행 한도의 authoritative source로 사용하고, Node는 normalized/tunnel 경로에 같은 adapter-local 안전장치를 적용해 model alias 추가나 우회 실행이 실제 backend 동시 실행 한도를 넘지 못하게 한다. Node transport 연결 종료는 같은 provider resource의 connectivity availability로 즉시 반영해 새 admission 대상에서 제외하고, 대기 요청과 운영 snapshot이 동일한 offline 상태로 수렴하도록 한다.

상태

[진행중]

승격 조건

  • 없음

구현 잠금

  • 상태: 해제
  • SDD: 필요
  • SDD 문서: SDD.md
  • SDD 사유: provider 전역 admission 상태와 lease lifecycle, 여러 model queue의 공정한 재평가, queue config 소유권, Edge-Node 실행 경계와 live refresh 의미를 함께 변경한다.
  • 잠금 해제 조건: 아래 체크리스트
    • 에이전트 작업성 중심 저장소 구조 리팩터링이 완료되어 후속 구현 기준 파일 구조가 확정되어 있다.
    • SDD 잠금이 해제되어 있다.
    • SDD 사용자 리뷰가 없거나 승인/해결되었다.
    • Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
    • Evidence Map이 완료 시 Roadmap Completion과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
  • 결정 필요: 없음

범위

  • Edge admission의 provider resource state를 node_id + provider_id 기준 전역 상태로 두고 여러 model group이 capacity와 long-context 점유를 공유한다.
  • provider lease 획득·handoff·반환을 원자적이고 idempotent하게 처리하고, send 실패, terminal event/frame, cancel, 연결 종료와 node disconnect가 같은 lease를 중복 반환하거나 누락하지 않게 한다.
  • lease 반환과 disconnect fencing 같은 correctness 전이는 drop 가능한 관측 event fanout에 의존하지 않고 authoritative resource lifecycle에서 직접 처리한 뒤 event를 발행한다.
  • lease 반환·provider 비활성화·node 연결 해제·capacity refresh 때 model group 경계를 넘어 가장 먼저 들어온 현재 dispatch 가능한 요청부터 재평가해 starvation과 head-of-line blocking을 함께 방지한다.
  • provider별 실행 속성은 provider가 소유하고 여러 후보와 model group에 공통인 max_queuequeue_timeout_ms는 Edge의 provider-pool admission policy가 소유하도록 정렬한다. provider 전역 capacity와 아직 provider가 정해지지 않은 Edge queue를 같은 상태로 혼동하지 않는다.
  • long_context_capacity는 provider 전역 runtime slot으로 공유한다. total_context_tokens는 이번 범위에서 context_window_tokens * long_context_capacity 정적 설정 검증 기준으로 유지하며 요청별 KV token ledger로 확장하지 않는다.
  • provider snapshot이 admission과 같은 resource state에서 capacity, in_flight, long-context 점유를 읽고, queued는 SDD에서 정한 queue owner와 candidate-pressure 의미로 일관되게 계산하도록 한다.
  • Edge의 provider 전역 lease를 authoritative admission으로 두되, Node의 normalized RunRequestProviderTunnelRequest에는 같은 adapter instance를 보호하는 local capacity gate를 별도로 둔다.
  • config refresh 중 capacity·long-context capacity·priority·queue·enabled 변경이 기존 lease를 잃지 않고 이후 admission과 대기 후보 재평가에 일관되게 적용되도록 한다.
  • Node 프로세스 또는 Windows의 정상 종료 절차가 transport close를 보낸 경우 heartbeat timeout을 기다리지 않고 해당 Node의 모든 provider resource를 admission 후보에서 제외한다. 전원 단절·네트워크 blackhole처럼 close를 받을 수 없는 경우에만 heartbeat timeout을 fallback으로 사용한다.
  • Node disconnect로 대기 요청의 live candidate가 사라지면 남은 provider로 즉시 재평가하고, 후보가 하나도 없으면 원래 queue_timeout_ms까지 대기하지 않고 명시적인 unavailable 결과로 종료한다.
  • 구성에는 남아 있지만 연결이 끊긴 Node/provider는 운영 snapshot에서 사라지게 하지 않고 offline/excluded 상태로 유지해 관측 상태와 admission eligibility가 같은 connectivity source of truth를 사용하도록 한다.

기능

Epic: [resource-admission] Provider 전역 Resource Lease

model group queue와 독립된 provider resource lease를 admission의 단일 source of truth로 만든다.

  • [provider-state] Edge가 node_id + provider_id별 capacity와 in-flight를 하나의 provider resource state로 관리하고, 서로 다른 두 models[].id가 같은 provider를 참조해도 합산 점유가 capacity를 넘지 않는다. 검증: capacity 1 provider를 공유하는 두 model group의 동시 admission에서 upstream dispatch가 한 건만 발생한다.
  • [lease-lifecycle] admission이 고유 provider lease를 만들고 dispatch 전 추적과 handoff 뒤 terminal lifecycle이 이를 정확히 한 번 반환한다. correctness 경로는 drop 가능한 event fanout과 분리한다. 검증: send 실패, complete/error/cancel, tunnel terminal/close와 node disconnect 경쟁 및 event subscriber 포화에서도 일반·long counter가 음수가 되거나 남지 않는다.
  • [long-state] long-context capacity와 점유가 provider 전역으로 합산되고 total_context_tokens는 정적 설정 검증값으로 유지된다. 검증: 서로 다른 model group의 long 요청이 같은 provider long slot을 동시에 초과하지 않고 잘못된 context_window_tokens * long_context_capacity 설정은 load/refresh에서 거부된다.
  • [cross-group-wakeup] provider lease 반환, node disconnect, provider disable 또는 capacity refresh 후 전역 enqueue 순서상 가장 이른 dispatch 가능한 요청부터 model group 경계를 넘어 재평가된다. 검증: 한 model group의 종료가 다른 model group의 대기 요청을 깨우고, 막힌 long 요청 뒤의 실행 가능한 normal 요청도 진행하며, starvation·중복 예약·slot 누수가 없다.
  • [tunnel-guard] Edge의 provider 전역 lease와 별개로 Node의 normalized 실행과 provider tunnel 실행이 같은 adapter-local capacity 안전장치를 사용한다. 검증: Edge admission을 우회한 동시 tunnel 요청에서도 두 번째 upstream provider 요청이 열리지 않고 명시적인 concurrency 결과가 반환된다.

Epic: [provider-policy] Provider Policy 의미 정렬

provider config에 선언된 정책과 실제 Edge/Node 적용 위치의 불일치를 제거한다.

  • [queue-ownership] Edge의 provider_pool.max_queueprovider_pool.queue_timeout_ms가 여러 model group에 공통인 provider-pool queue policy를 소유하고 schema, compatibility, admission과 refresh 경로에서 일관되게 적용된다. provider는 capacity, long-context capacity, priority처럼 provider별 실행 속성만 소유한다. 검증: 여러 provider가 있는 model group과 하나의 provider를 공유하는 여러 model group에서 Edge 전체 pending 상한과 공통 timeout이 적용되고 first-candidate 값이 전체 정책으로 암묵 승격되지 않는다.
  • [snapshot-source] provider snapshot의 일반·long in_flight가 provider lease state와 일치하고, queued/long_queued가 Edge queue에서 해당 provider를 후보로 포함하는 candidate pressure임을 명확히 한다. 검증: cross-model 실행·대기·반환 전 과정에서 lease count가 snapshot과 일치하고 multi-candidate queued 수가 실제 Edge queue 총합과 구분되는 문서화된 규칙대로 계산된다.
  • [refresh-consistency] capacity, long-context capacity, priority, queue policy와 enabled live refresh가 기존 lease를 보존하고 새 admission과 모든 관련 대기 요청에 즉시 반영된다. 검증: capacity를 in-flight 아래로 낮추면 기존 요청은 유지하되 새 값 아래로 회복할 때까지 추가 admission을 차단하고, capacity 증가·disable·재활성화 시 대기 후보가 고립되지 않는다.

Epic: [connectivity-availability] Node 연결 기반 Provider Availability

Node transport lifecycle을 provider resource eligibility와 운영 관측의 같은 상태 전이로 연결한다.

  • [disconnect-exclusion] 등록된 client ownership/generation을 provider lease와 연결하고, 현재 owner의 정상 close 또는 disconnect만 해당 Node의 모든 provider resource를 즉시 offline/excluded로 fencing한다. stale callback이나 거절된 duplicate connection의 close는 live resource 상태와 disconnect event를 바꾸지 않는다. 정상적인 Node 프로세스 종료와 Windows 종료 절차는 heartbeat timeout을 기다리지 않으며, close를 받을 수 없는 전원·네트워크 장애만 설정된 heartbeat timeout 안에 제외한다. 검증: disconnect·reconnect·duplicate registration·admission 경쟁에서 offline generation의 새 lease/dispatch handoff가 없고 기존 lease는 정확히 한 번 반환된다.
  • [disconnect-queue-resolution] authoritative disconnect 전이가 모든 관련 model queue의 live candidate를 즉시 다시 해석해 남은 provider로 fallback하고, 후보가 없어진 요청은 queue_timeout_ms까지 남겨 두지 않고 명시적인 unavailable 결과로 종료한다. 이 correctness 경로는 관측 event delivery 성공 여부에 의존하지 않는다. 검증: capacity 1 provider에 실행·대기 요청이 있는 상태에서 연결을 닫거나 node event subscriber를 포화시켜도 대기 요청이 즉시 fallback 또는 terminal 상태가 되며 queue와 reservation이 남지 않는다.
  • [offline-snapshot] 구성에 존재하지만 연결이 끊긴 Node/provider를 운영 snapshot에 connected=false, status=unavailable, health=offline, effective capacity/counter 0으로 유지하고, reconnect 때 같은 resource identity의 새 generation으로 available 상태를 복구한다. 검증: disconnect/reconnect 전후 status snapshot, admission candidate와 in-flight/long counter가 같은 connectivity generation에 수렴하며 model catalog entry 자체는 삭제되지 않는다.

Epic: [ownership-verification] 계약과 회귀 검증

소유권 변경이 외부 model alias와 Edge-Node 실행 경로에서 재발하지 않도록 계약과 검증 근거를 남긴다.

  • [cross-model-tests] 같은 provider를 공유하는 ornith:35bornith-fast 형태의 두 model key를 포함해 capacity, long-context, queue fairness, cancel, send 실패, graceful disconnect, heartbeat-timeout fallback, duplicate/stale disconnect, event fanout 포화, reconnect와 refresh 회귀·race 테스트가 추가되어 있다.
  • [contract-spec-sync] 구현 결과가 Edge Config And Runtime Refresh Contract, Edge-Node Runtime Wire Contract, Control Plane-Edge Wire Contract, OpenAI-Compatible API Contract과 관련 agent-spec에 동기화되어 있다.
  • [capacity-smoke] local 또는 dev-corp의 공유 provider capacity 1 smoke에서 두 model key 동시 호출 시 backend peak concurrency가 1이고, 대기 또는 다른 provider fallback 뒤 모든 provider 상태가 0으로 회복된다.

완료 리뷰

  • 상태: 없음
  • 요청일: 없음
  • 완료 근거: SDD와 선행 리팩터링 gate는 충족되었고 기능 구현과 검증은 아직 시작되지 않았다.
  • 검토 항목: 모든 기능 Task와 Acceptance Scenario evidence, 구현 잠금 해제, provider capacity 1 cross-model smoke 결과를 확인한다.
  • agent-ui 상태 반영: 해당 없음
  • 리뷰 코멘트: 없음

범위 제외

  • ornith-fast 모델 catalog entry 추가, RTX5090 모델 다운로드·기동 또는 운영 환경 배포
  • Provider 부하 Prometheus metric과 Grafana dashboard 구현
  • provider runtime launch profile, 모델 artifact 다운로드·cache·restart lifecycle 자동화
  • Node 연결이 유지된 상태에서 Lemonade 등 provider endpoint를 능동 probe해 정적 config health를 대체하는 runtime health state machine
  • provider request_timeout_ms와 surface timeout_sec의 deadline 결합·오류 분류 재설계
  • 요청별 input/output KV 사용량을 예약·반환하는 동적 total_context_tokens ledger
  • cross-Edge 또는 cloud provider를 포함한 전역 capacity 공유
  • provider별 benchmark, 품질 평가와 qualification report

작업 컨텍스트

  • 관련 경로: apps/edge/internal/service, apps/edge/internal/transport, apps/edge/internal/controlplane, apps/edge/internal/openai, apps/node/internal/node, apps/node/internal/transport, packages/go/config, apps/edge/internal/configrefresh, proto/iop/runtime.proto, proto/iop/control.proto, agent-contract/inner, agent-contract/outer, agent-spec/runtime
  • 표준선(선택): provider/resource capacity, long-context slot, priority처럼 provider별로 달라지는 속성은 provider가 소유하고, provider-pool queue depth와 timeout처럼 공통 적용되는 정책은 Edge가 소유한다. model group은 외부 model key와 후보 집합을 소유한다.
  • 큐 배치(선택): 에이전트 작업성 중심 저장소 구조 리팩터링
  • 선행 작업: 에이전트 작업성 중심 저장소 구조 리팩터링
  • 후속 작업: Provider 부하 메트릭과 Live Queue Dashboard, Provider Runtime 설정과 모델 획득 오케스트레이션
  • 후속 정합화 후보: Node 연결이 살아 있는 동안 provider endpoint/Lemonade 프로세스 장애를 탐지하는 runtime health probe source of truth와 provider/surface request timeout 결합 규칙은 별도 Milestone/SDD에서 다룬다.
  • 확정 사항: D01은 Edge 공통 provider-pool queue policy 소유로 해결되었다. 사용자 리뷰 기록