diff --git a/agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md b/agent-roadmap/archive/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md similarity index 78% rename from agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md rename to agent-roadmap/archive/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md index 707cfd48..438e0866 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md +++ b/agent-roadmap/archive/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md @@ -2,8 +2,8 @@ ## 위치 -- Roadmap: [ROADMAP.md](../../../ROADMAP.md) -- Phase: [PHASE.md](../PHASE.md) +- Roadmap: [ROADMAP.md](../../../../ROADMAP.md) +- Phase: [PHASE.md](../../../../phase/operational-observability-provider-management/PHASE.md) ## 목표 @@ -11,7 +11,7 @@ Control Plane을 IOP principal token과 외부 provider credential의 원장으 ## 상태 -[진행중] +[완료] ## 승격 조건 @@ -69,30 +69,33 @@ IOP bearer token의 발급, 인증 projection과 폐기를 Control Plane 원장 Control Plane 원장의 provider secret을 일반 config/header projection에 노출하지 않고 선택된 실행 경계에서만 사용한다. -- [ ] [secret-at-rest] provider raw token을 deployment secret manager가 공급한 key로 envelope-encrypt하여 Control Plane DB에 저장하고 key/원문을 tracked config와 DB row에 평문으로 두지 않는다. 검증: encrypt/decrypt/key-version/restart fixture와 저장소 inspection에서 ciphertext와 metadata만 관찰된다. -- [ ] [secure-transport] credential을 수신하거나 운반하는 Client-Control Plane, Control Plane-Edge와 Edge-Node 연결에 peer 인증과 전송 기밀성을 강제한다. 검증: 평문/미인증/잘못된 peer 연결에서는 credential management와 cloud dispatch가 차단되고 TLS test identity로만 성공한다. -- [ ] [credential-lease] Edge는 slot metadata만 캐시하고 선택된 slot/revision에 대한 bounded credential lease를 Control Plane에서 받아 dedicated sensitive payload로 실행 경계에 전달한다. 검증: 다른 principal/slot/route/target, 만료·폐기·변조 lease는 adapter 호출 전에 거부되고 raw secret이 generic header/metadata projection에 없다. -- [ ] [adapter-injection] Node/Edge provider adapter는 유효 lease의 request-local secret을 실행 직전에 profile의 auth header로 주입하고 request 종료 뒤 credential reference만 관측한다. 검증: upstream fixture에는 올바른 header가 도달하지만 proto debug, status, error, log, metric과 response에는 raw secret이 나타나지 않는다. -- [ ] [revocation] slot disable/revoke 또는 secret rotation은 revision을 증가시키고 이전 projection/lease를 bounded expiry 안에 무효화한다. 검증: in-flight 정책, 새 요청 차단과 out-of-order refresh가 deterministic clock test에서 정의된 순서로 수렴한다. +- [x] [secret-at-rest] provider raw token을 deployment secret manager가 공급한 key로 envelope-encrypt하여 Control Plane DB에 저장하고 key/원문을 tracked config와 DB row에 평문으로 두지 않는다. 검증: encrypt/decrypt/key-version/restart fixture와 저장소 inspection에서 ciphertext와 metadata만 관찰된다. +- [x] [secure-transport] credential을 수신하거나 운반하는 Client-Control Plane, Control Plane-Edge와 Edge-Node 연결에 peer 인증과 전송 기밀성을 강제한다. 검증: 평문/미인증/잘못된 peer 연결에서는 credential management와 cloud dispatch가 차단되고 TLS test identity로만 성공한다. +- [x] [credential-lease] Edge는 slot metadata만 캐시하고 선택된 slot/revision에 대한 bounded credential lease를 Control Plane에서 받아 dedicated sensitive payload로 실행 경계에 전달한다. 검증: 다른 principal/slot/route/target, 만료·폐기·변조 lease는 adapter 호출 전에 거부되고 raw secret이 generic header/metadata projection에 없다. +- [x] [adapter-injection] Node/Edge provider adapter는 유효 lease의 request-local secret을 실행 직전에 profile의 auth header로 주입하고 request 종료 뒤 credential reference만 관측한다. 검증: upstream fixture에는 올바른 header가 도달하지만 proto debug, status, error, log, metric과 response에는 raw secret이 나타나지 않는다. +- [x] [revocation] slot disable/revoke 또는 secret rotation은 revision을 증가시키고 이전 projection/lease를 bounded expiry 안에 무효화한다. 검증: in-flight 정책, 새 요청 차단과 out-of-order refresh가 deterministic clock test에서 정의된 순서로 수렴한다. ### Epic: [migration-ops] 호환 Migration과 Qualification 기존 Edge-local token/header 전달에서 Control Plane 원장으로 안전하게 전환하고 상시 provider 구독 없이 검증한다. -- [ ] [compat-migration] credential-plane 비활성 배포에서는 기존 `principal_tokens[]`/`provider_auth`가 동작하고, 활성 배포에서는 Control Plane projection이 유일한 원장이 되어 caller-supplied raw provider token을 명시적으로 거부한다. 검증: mode별 migration/rollback fixture에서 두 원장을 혼합하거나 IOP token을 provider token으로 재사용하지 않는다. -- [ ] [slot-attribution] 선택된 credential `slot_ref`와 secret revision을 immutable dispatch binding과 usage/실행 관측에 별도 safe field로 전달하고 기존 inbound IOP `token_ref`와 혼동하지 않는다. 검증: 같은 model의 두 slot 호출이 provider usage에 분리 귀속되고 alias/raw secret은 metric label에 포함되지 않는다. -- [ ] [slot-smoke] Seulgi를 포함한 vendor/model/slot fixture를 상시 실행하고 구현 시 제공된 대표 credential slot 1개로 Chat 또는 Messages E2E를 일회성 smoke한다. 검증: 일반 CI는 외부 credential/구독 없이 통과하고 live 결과에는 provider, model, slot reference, date, revision과 성공/실패만 남는다. -- [ ] [contract-ops] Control Plane-Edge/Edge-Node credential projection, public auth/model routing 계약, 운영 redaction/revocation 절차와 현재 구현 spec을 동기화한다. 검증: contract/spec index가 canonical 문서를 가리키며 raw secret이 문서 예시와 test artifact에 없다. +- [x] [compat-migration] credential-plane 비활성 배포에서는 기존 `principal_tokens[]`/`provider_auth`가 동작하고, 활성 배포에서는 Control Plane projection이 유일한 원장이 되어 caller-supplied raw provider token을 명시적으로 거부한다. 검증: mode별 migration/rollback fixture에서 두 원장을 혼합하거나 IOP token을 provider token으로 재사용하지 않는다. +- [x] [slot-attribution] 선택된 credential `slot_ref`와 secret revision을 immutable dispatch binding과 usage/실행 관측에 별도 safe field로 전달하고 기존 inbound IOP `token_ref`와 혼동하지 않는다. 검증: 같은 model의 두 slot 호출이 provider usage에 분리 귀속되고 alias/raw secret은 metric label에 포함되지 않는다. +- [x] [slot-smoke] Seulgi를 포함한 vendor/model/slot fixture를 상시 실행하고 구현 시 제공된 대표 credential slot 1개로 Chat 또는 Messages E2E를 일회성 smoke한다. 검증: 일반 CI는 외부 credential/구독 없이 통과하고 live 결과에는 provider, model, slot reference, date, revision과 성공/실패만 남는다. +- [x] [contract-ops] Control Plane-Edge/Edge-Node credential projection, public auth/model routing 계약, 운영 redaction/revocation 절차와 현재 구현 spec을 동기화한다. 검증: contract/spec index가 canonical 문서를 가리키며 raw secret이 문서 예시와 test artifact에 없다. ## 완료 리뷰 -- 상태: 없음 -- 요청일: 없음 -- 완료 근거: 01~06 archive와 현재 race 검증을 기준으로 첫째 Epic `principal-auth`와 둘째 Epic `credential-slots`의 8개 Task가 완료됐다. -- 동기화 근거: 03의 secret-free projection/cache·managed surface auth, 04의 principal-scoped discovery·explicit route/no-fallback, 05의 principal-scoped secret-blind management operation, 06의 host-local 최초 principal bootstrap evidence를 누락된 Roadmap Completion으로 복구했다. -- 후속 범위: authenticated confidential transport activation, concrete at-rest sealer와 credential lease는 셋째 Epic `secret-delivery`에서 이어간다. -- 검토 항목: CP persistence/management, token/slot isolation, explicit alias selection, confidential transport와 credential lease, slot usage attribution, revocation, migration 및 대표 slot 일회성 smoke evidence를 확인한다. -- 리뷰 코멘트: 없음 +- 상태: 통과 +- 요청일: 2026-08-02 +- 완료 근거: 같은 Milestone task group의 archive `complete.log` 10개를 집계해 17개 기능 Task의 capability·검증과 SDD S01~S17 Evidence Map 충족을 확인했다. +- 코드 감사: Control Plane credential lease가 외부 호환용 가변 built-in profile map을 다시 읽던 작은 일관성 문제를 수정했다. 서비스 생성 시 독립 profile catalog snapshot을 보관하고 전역 map 변경 뒤에도 기존 유효 route의 lease 발급이 유지되는 회귀 테스트를 추가했다. +- 동기화 근거: canonical 로그 4개의 generation header와 최종 PASS를 확인했고, 관련 Go package race test, Client 42 tests와 Flutter analyze, `go vet`, protobuf Go/Dart 재생성 무변경, 실제 3-process secure-delivery와 deterministic credential-slot smoke를 모두 통과했다. 비용 guard에 따라 이미 승인·기록된 대표 provider one-shot은 재호출하지 않았다. +- Spec sync: 완료 — [agent-spec index](../../../../../agent-spec/index.md)의 Control Plane operations, provider-pool config refresh, OpenAI-compatible surface, Edge-Node execution 문서가 현재 구현 경계를 이미 반영하며 이번 snapshot 안정화는 공개 동작·계약을 바꾸지 않아 추가 spec 본문 변경이 필요하지 않았다. +- 비차단 저장소 관찰: 전체 `go test ./...`는 현재 실행 환경의 Unix socket 경로/xattr confinement 제약과 이 Milestone 변경 전부터 존재한 Agent Task parity checksum drift에서 실패했다. 해당 경로는 현재 Milestone 커밋에서 변경되지 않았고 credential 관련 Control Plane·Edge·Node 패키지는 전체 실행에서도 통과했으며, `streamgate`는 독립 재실행에서 통과했다. +- 남은 차단: 기능·구현 잠금·SDD gate와 workspace milestone dependency 차단은 없다. +- 검토 항목: SDD S01~S17, secret-at-rest/transport/lease/revocation 경계, principal별 route 격리, migration·attribution, contract/spec 정합성 +- 리뷰 코멘트: 코드레벨 종료 검토를 통과해 Milestone과 SDD를 archive했다. ## 범위 제외 @@ -108,6 +111,6 @@ Control Plane 원장의 provider secret을 일반 config/header projection에 - 표준선(선택): Control Plane은 principal, IOP token과 provider credential의 canonical owner다. Edge는 유효 generation의 secret-free projection과 bounded credential lease만 소비하고 Edge-local provider runtime 상태의 원장은 계속 Edge다. - 표준선(선택): credential slot은 자동 선택 풀이 아니라 명시적 route 대상이다. 하나의 slot은 여러 upstream model binding을 가질 수 있고, 같은 upstream model도 서로 다른 slot/route로 동시에 노출할 수 있다. provider resource load balancing은 같은 선택 slot을 유지하는 실행 위치 선택이며 token slot rotation이 아니다. - 표준선(선택): raw IOP token은 발급 시 한 번만 반환하고 verifier만 저장한다. provider token은 복호화 가능한 ciphertext로 저장하며, authenticated confidential transport 안의 bounded request-local lease 외에는 Control Plane 밖으로 평문 전달하지 않는다. -- 선행 작업: [다중 Provider Protocol Profile과 Native Anthropic Messages](../../../archive/phase/operational-observability-provider-management/milestones/multi-provider-protocol-profile-native-messages.md) +- 선행 작업: [다중 Provider Protocol Profile과 Native Anthropic Messages](multi-provider-protocol-profile-native-messages.md) - 후속 작업: 없음 - 확인 필요: 없음 diff --git a/agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md b/agent-roadmap/archive/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md similarity index 93% rename from agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md rename to agent-roadmap/archive/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md index 54e4db17..4411efab 100644 --- a/agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md +++ b/agent-roadmap/archive/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md @@ -3,7 +3,7 @@ ## 위치 - Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md) -- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md) +- Phase: [PHASE.md](../../../../phase/operational-observability-provider-management/PHASE.md) ## 상태 @@ -30,11 +30,11 @@ |------|------|------| | Roadmap | [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md) | 목표, credential slot과 migration 완료 Task | | Control Plane Store | `apps/control-plane`, `database.url` repository | principal, IOP token hash, slot/binding/ciphertext/revision의 canonical store | -| Client-Control Plane | `apps/control-plane/internal/wire`, `apps/client`, [Client-Control Plane Wire 계약](../../../../agent-contract/inner/client-control-plane-wire.md) | principal/token/slot/binding/alias management와 authorization | -| Control Plane-Edge | `apps/control-plane/internal/wire`, `apps/edge/internal/controlplane`, [Control Plane-Edge Wire 계약](../../../../agent-contract/inner/control-plane-edge-wire.md) | auth/routing projection과 bounded credential lease | +| Client-Control Plane | `apps/control-plane/internal/wire`, `apps/client`, [Client-Control Plane Wire 계약](../../../../../agent-contract/inner/client-control-plane-wire.md) | principal/token/slot/binding/alias management와 authorization | +| Control Plane-Edge | `apps/control-plane/internal/wire`, `apps/edge/internal/controlplane`, [Control Plane-Edge Wire 계약](../../../../../agent-contract/inner/control-plane-edge-wire.md) | auth/routing projection과 bounded credential lease | | Edge Ingress | `apps/edge/internal/openai` | principal authentication, route resolution와 model discovery | -| Edge-Node | `apps/edge/internal/service`, `apps/node/internal/node`, `proto/iop/runtime.proto`, [Edge-Node Runtime Wire 계약](../../../../agent-contract/inner/edge-node-runtime-wire.md) | confidential sensitive payload 전달과 adapter injection | -| Current Compatibility | `packages/go/config`, `configs/edge.yaml`, [Edge Config/Refresh 계약](../../../../agent-contract/inner/edge-config-runtime-refresh.md) | 현재 Edge-local principal hash와 caller provider-auth migration 입력 | +| Edge-Node | `apps/edge/internal/service`, `apps/node/internal/node`, `proto/iop/runtime.proto`, [Edge-Node Runtime Wire 계약](../../../../../agent-contract/inner/edge-node-runtime-wire.md) | confidential sensitive payload 전달과 adapter injection | +| Current Compatibility | `packages/go/config`, `configs/edge.yaml`, [Edge Config/Refresh 계약](../../../../../agent-contract/inner/edge-config-runtime-refresh.md) | 현재 Edge-local principal hash와 caller provider-auth migration 입력 | | User Decision | 2026-07-31 사용자 대화 | Control Plane ownership, 사용자/vendor별 multi-token slot, optional alias, IOP token 기반 호출, Seulgi 포함, implicit rotation 없음 | ## State Machine @@ -58,7 +58,7 @@ ## Interface Contract -- 계약 원문: principal/slot management는 [Client-Control Plane Wire 계약](../../../../agent-contract/inner/client-control-plane-wire.md), Control Plane projection/lease는 [Control Plane-Edge Wire 계약](../../../../agent-contract/inner/control-plane-edge-wire.md), sensitive runtime payload는 [Edge-Node Runtime Wire 계약](../../../../agent-contract/inner/edge-node-runtime-wire.md), 현재 principal/provider auth migration은 [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md)과 [Edge Config/Refresh 계약](../../../../agent-contract/inner/edge-config-runtime-refresh.md)을 갱신한다. 구현 시 Anthropic public auth/model route는 protocol Milestone이 만드는 `agent-contract/outer/anthropic-compatible-api.md`에 연결한다. +- 계약 원문: principal/slot management는 [Client-Control Plane Wire 계약](../../../../../agent-contract/inner/client-control-plane-wire.md), Control Plane projection/lease는 [Control Plane-Edge Wire 계약](../../../../../agent-contract/inner/control-plane-edge-wire.md), sensitive runtime payload는 [Edge-Node Runtime Wire 계약](../../../../../agent-contract/inner/edge-node-runtime-wire.md), 현재 principal/provider auth migration은 [OpenAI-compatible API 계약](../../../../../agent-contract/outer/openai-compatible-api.md)과 [Edge Config/Refresh 계약](../../../../../agent-contract/inner/edge-config-runtime-refresh.md)을 갱신한다. 구현 시 Anthropic public auth/model route는 protocol Milestone이 만드는 `agent-contract/outer/anthropic-compatible-api.md`에 연결한다. - Control Plane persistence: - `principal`: stable principal ref, display alias와 status를 가진다. - `iop_token`: stable token ref, cryptographically random한 high-entropy raw token의 SHA-256 digest, principal ref, status, revision과 timestamps를 가진다. raw token은 발급 시 한 번만 반환하고 저장하지 않으며 Edge는 같은 digest를 계산해 projection과 매칭한다. diff --git a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md index efe98399..20cff53b 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md +++ b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md @@ -55,6 +55,10 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실 - 경로: [multi-provider-protocol-profile-native-messages](../../archive/phase/operational-observability-provider-management/milestones/multi-provider-protocol-profile-native-messages.md) - 요약: OpenAI Chat Completions를 cloud provider 공통 driver로 두고 provider별 endpoint/path/auth/capability를 profile로 흡수하며, Edge가 Anthropic Messages 입력과 Chat bridge를 직접 소유해 Claude Code의 agent-client dependency를 제거했다. +- [완료] 사용자별 Provider Credential Slot과 Alias Routing + - 경로: [principal-provider-credential-slot-routing](../../archive/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md) + - 요약: Control Plane을 IOP principal token과 provider credential의 원장으로 두고, 사용자/vendor별 여러 token slot과 optional alias를 명시적 model route에 결합해 선택된 credential만 안전하게 실행 경계에 주입한다. + - [계획] Provider 부하 메트릭과 Live Queue Dashboard - 경로: [provider-load-metrics-queue-dashboard](milestones/provider-load-metrics-queue-dashboard.md) - 요약: provider별 capacity 사용률, in-flight, queue 적체, queue wait를 Prometheus time series와 Grafana dashboard로 노출해 시간대별 live 부하 분석을 가능하게 한다. @@ -63,10 +67,6 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실 - 경로: [node-provider-execution-liveness-recovery](milestones/node-provider-execution-liveness-recovery.md) - 요약: Node가 provider-originated 진행 신호의 5분 무응답을 request stall로 판정하고 provider health와 local attempt fence를 별도 확정하며, ingress recovery owner가 미커밋 요청만 기존 공통 budget 안에서 재실행한다. -- [진행중] 사용자별 Provider Credential Slot과 Alias Routing - - 경로: [principal-provider-credential-slot-routing](milestones/principal-provider-credential-slot-routing.md) - - 요약: Control Plane을 IOP principal token과 provider credential의 원장으로 두고, 사용자/vendor별 여러 token slot과 optional alias를 명시적 model route에 결합해 선택된 credential만 안전하게 실행 경계에 주입한다. - - [스케치] 요청 실행 로그와 Usage Ledger 기반 - 경로: [request-execution-log-usage-ledger-foundation](milestones/request-execution-log-usage-ledger-foundation.md) - 요약: 사용자 요청 하나의 device/provider/model 선택, queue/dispatch/start/first-token/end 시간, token breakdown, status/error를 구조화된 실행 로그와 usage ledger로 남기는 로그 시스템 개편 후보를 스케치한다. diff --git a/agent-roadmap/priority-queue.md b/agent-roadmap/priority-queue.md index 7778067d..c1492367 100644 --- a/agent-roadmap/priority-queue.md +++ b/agent-roadmap/priority-queue.md @@ -7,68 +7,65 @@ 1. [IOP Agent Runtime의 Chronos 선별 이전과 IOP 의존성 제거](phase/automation-runtime-bridge/milestones/iop-agent-chronos-extraction-decoupling.md) 완료된 `iop-agent`에서 Chronos-owned 자산을 선별 전달하고 IOP standalone 의존성을 제거한 뒤 잔류 Node/provider 회귀와 Chronos 시작 잠금 해제 evidence를 남긴다. -2. [사용자별 Provider Credential Slot과 Alias Routing](phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md) - Control Plane이 principal token과 provider credential을 소유하고 사용자별 multi-token slot과 명시적 model route/alias를 안전하게 실행 credential로 연결한다. - -3. [IOP Hot Path One-shot 실행 경로](phase/knowledge-tool-optimization-extension/milestones/iop-hot-path-one-shot-execution.md) +2. [IOP Hot Path One-shot 실행 경로](phase/knowledge-tool-optimization-extension/milestones/iop-hot-path-one-shot-execution.md) 외부 `model=iop` 요청을 Gemini 3.6 Flash와 RTX 5090 `ornith-fast`의 bounded one-shot 경로로 처리해 최대 속도와 실사용 품질의 균형을 맞춘다. -4. [OpenAI-compatible 출력 검증 필터](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md) +3. [OpenAI-compatible 출력 검증 필터](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md) 실제 의미 필터 전에 deterministic diagnostic mock으로 실제 Stream Evidence Gate의 pass·observe-only·blocking recovery를 관측하는 smoke를 통과시키고, OpenAI-compatible single-stream 반복과 incoming request history에 누적된 assistant 반복, JSON contract 검증/repair 경로를 안정화한다. -5. [OpenAI-compatible Incomplete Tool Call Syntax Gate](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md) +4. [OpenAI-compatible Incomplete Tool Call Syntax Gate](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md) terminal provider 응답의 incomplete tool-call syntax를 deterministic하게 판정한다. -6. [OpenAI-compatible Runtime Output Integrity Filter](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md) +5. [OpenAI-compatible Runtime Output Integrity Filter](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md) terminal output invariant와 공통 filter/retry pipeline을 정의한다. -7. [LLM 판별 기반 Missing Tool Call 재시도 Gate](phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md) +6. [LLM 판별 기반 Missing Tool Call 재시도 Gate](phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md) tool 사용 의도 누락 케이스를 LLM judge와 buffered retry 후보로 검토한다. -8. [Tool Call 판정 모델 Gate 리뷰](phase/knowledge-tool-optimization-extension/milestones/tool-call-validator-model-gate-review.md) +7. [Tool Call 판정 모델 Gate 리뷰](phase/knowledge-tool-optimization-extension/milestones/tool-call-validator-model-gate-review.md) schema만으로 어려운 tool-call 후보에 validator 모델을 쓸지 검토한다. -9. [Provider 부하 메트릭과 Live Queue Dashboard](phase/operational-observability-provider-management/milestones/provider-load-metrics-queue-dashboard.md) +8. [Provider 부하 메트릭과 Live Queue Dashboard](phase/operational-observability-provider-management/milestones/provider-load-metrics-queue-dashboard.md) Edge provider-pool의 capacity, in-flight, queued와 queue wait를 Prometheus/Grafana로 관측해 provider별 live 부하와 적체·회복을 분석한다. -10. [Pi CLI Provider Integration](phase/automation-runtime-bridge/milestones/pi-cli-provider-integration.md) +9. [Pi CLI Provider Integration](phase/automation-runtime-bridge/milestones/pi-cli-provider-integration.md) Pi를 Node CLI provider 실행 후보에 추가하고 OpenAI-compatible route smoke로 안정화한다. -11. [단계 호출과 검증 최적화 MVP](phase/knowledge-tool-optimization-extension/milestones/knowledge-tool-validation-optimization.md) +10. [단계 호출과 검증 최적화 MVP](phase/knowledge-tool-optimization-extension/milestones/knowledge-tool-validation-optimization.md) planner/generator/verifier 단계 호출과 runtime schema 검증 실행 모드를 스케치한다. -12. [Personal Local Edge 패키징과 배포 모드 프로파일](phase/personal-edge-packaging-deployment/milestones/personal-local-edge-deployment-profiles.md) +11. [Personal Local Edge 패키징과 배포 모드 프로파일](phase/personal-edge-packaging-deployment/milestones/personal-local-edge-deployment-profiles.md) personal/server/fleet 배포 모드와 capability gate 경계를 스케치한다. -13. [요청 실행 로그와 Usage Ledger 기반](phase/operational-observability-provider-management/milestones/request-execution-log-usage-ledger-foundation.md) +12. [요청 실행 로그와 Usage Ledger 기반](phase/operational-observability-provider-management/milestones/request-execution-log-usage-ledger-foundation.md) 요청별 provider/model 선택, timing, token, status/error를 구조화된 ledger로 남기는 기반을 스케치한다. -14. [Update Plane 안정 프로토콜](phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md) +13. [Update Plane 안정 프로토콜](phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md) hello/status, manifest, command, event, recovery 최소 계약을 스케치한다. -15. [Host-local Manager 기반 자체 업데이트](phase/update-plane-self-update-foundation/milestones/host-local-manager-self-update.md) +14. [Host-local Manager 기반 자체 업데이트](phase/update-plane-self-update-foundation/milestones/host-local-manager-self-update.md) manager/updater의 release staging, 검증, restart, rollback 실행 모델을 정리한다. -16. [Edge/Node 롤아웃과 복구 정책](phase/update-plane-self-update-foundation/milestones/edge-node-rollout-recovery-policy.md) +15. [Edge/Node 롤아웃과 복구 정책](phase/update-plane-self-update-foundation/milestones/edge-node-rollout-recovery-policy.md) Edge/Node rolling update, 실패/재연결/rollback 보고 정책을 스케치한다. -17. [Provider Runtime 설정과 모델 획득 오케스트레이션](phase/operational-observability-provider-management/milestones/provider-runtime-model-acquisition-orchestration.md) +16. [Provider Runtime 설정과 모델 획득 오케스트레이션](phase/operational-observability-provider-management/milestones/provider-runtime-model-acquisition-orchestration.md) provider runtime launch/profile, model download/cache/verification 경계를 스케치한다. -18. [Provider-Device-Model Qualification 리포트와 Lifecycle 관리](phase/operational-observability-provider-management/milestones/provider-device-model-qualification-report.md) +17. [Provider-Device-Model Qualification 리포트와 Lifecycle 관리](phase/operational-observability-provider-management/milestones/provider-device-model-qualification-report.md) provider/device/model별 compatibility, performance, quality, lifecycle 리포트 경계를 정리한다. -19. [Provider 입력 컨텍스트 선택과 축소](phase/knowledge-tool-optimization-extension/milestones/request-context-assembly-optimization.md) +18. [Provider 입력 컨텍스트 선택과 축소](phase/knowledge-tool-optimization-extension/milestones/request-context-assembly-optimization.md) provider dispatch 전에 무관한 과거 요청-답변 단위를 제거하고, 유지한 답변·tool/search 결과 안에서도 필요한 문단·코드 블록·구간만 남기는 입력 context 최적화를 스케치한다. -20. [장기 기억과 RAG 업데이트 사이클 (2차)](phase/knowledge-tool-optimization-extension/milestones/long-term-memory-rag-second-wave.md) +19. [장기 기억과 RAG 업데이트 사이클 (2차)](phase/knowledge-tool-optimization-extension/milestones/long-term-memory-rag-second-wave.md) repo 장기 기억, RAG 저장소, update cycle, MCP 기반 context 절약 후보를 스케치한다. -21. [Advisor와 Context Hook 확장 (2차)](phase/knowledge-tool-optimization-extension/milestones/advisor-context-hook-second-wave.md) +20. [Advisor와 Context Hook 확장 (2차)](phase/knowledge-tool-optimization-extension/milestones/advisor-context-hook-second-wave.md) advisor 역할과 여러 기능을 실행 흐름에 연결하는 Context Hook 경계를 스케치한다. -22. [oto 자동화 스케줄러와 CI-CD 연동 (2차)](phase/automation-runtime-bridge/milestones/oto-automation-scheduler-second-wave.md) +21. [oto 자동화 스케줄러와 CI-CD 연동 (2차)](phase/automation-runtime-bridge/milestones/oto-automation-scheduler-second-wave.md) oto 기반 자동화, scheduler, CI-CD 연동 후보를 스케치한다. -23. [Node Provider 실행 Liveness 관측과 안전 복구](phase/operational-observability-provider-management/milestones/node-provider-execution-liveness-recovery.md) +22. [Node Provider 실행 Liveness 관측과 안전 복구](phase/operational-observability-provider-management/milestones/node-provider-execution-liveness-recovery.md) Node가 5분간 provider 진행이 없는 request를 health와 분리 판정하고 local attempt를 fence한 뒤 기존 recovery owner가 안전한 요청만 공통 budget 안에서 재실행한다. diff --git a/apps/control-plane/internal/credentiallease/service.go b/apps/control-plane/internal/credentiallease/service.go index f737d673..c615c2da 100644 --- a/apps/control-plane/internal/credentiallease/service.go +++ b/apps/control-plane/internal/credentiallease/service.go @@ -29,14 +29,15 @@ type opener interface { } type Service struct { - store *credentialstore.Store - opener opener - issuerKeyID string - issuerKey ed25519.PrivateKey - ttl time.Duration - clock func() time.Time - random io.Reader - live chan struct{} + store *credentialstore.Store + opener opener + protocolProfiles map[string]config.ProtocolProfileConf + issuerKeyID string + issuerKey ed25519.PrivateKey + ttl time.Duration + clock func() time.Time + random io.Reader + live chan struct{} } func New(store *credentialstore.Store, opener opener, issuerKeyID string, issuerKey ed25519.PrivateKey, ttl time.Duration, maxLive int, clock func() time.Time, randomSource io.Reader) (*Service, error) { @@ -49,7 +50,17 @@ func New(store *credentialstore.Store, opener opener, issuerKeyID string, issuer if randomSource == nil { randomSource = rand.Reader } - return &Service{store: store, opener: opener, issuerKeyID: issuerKeyID, issuerKey: append(ed25519.PrivateKey(nil), issuerKey...), ttl: ttl, clock: clock, random: randomSource, live: make(chan struct{}, maxLive)}, nil + return &Service{ + store: store, + opener: opener, + protocolProfiles: config.BuiltInProtocolProfileCatalog(), + issuerKeyID: issuerKeyID, + issuerKey: append(ed25519.PrivateKey(nil), issuerKey...), + ttl: ttl, + clock: clock, + random: randomSource, + live: make(chan struct{}, maxLive), + }, nil } // Acquire re-reads generation, route, and slot before opening secret-at-rest. @@ -80,7 +91,7 @@ func (s *Service) Acquire(ctx context.Context, request *iop.AcquireLeaseRequest) if err != nil || slot.Status != credentialstore.StatusActive || uint64(slot.Revision) != b.GetCredentialRevision() { return rejected(), nil } - profile, err := config.ResolveProtocolProfile(route.ProfileID, slot.Vendor, config.BuiltInProtocolProfiles) + profile, err := config.ResolveProtocolProfile(route.ProfileID, slot.Vendor, s.protocolProfiles) if err != nil || strings.TrimSpace(profile.Auth.Header) == "" { return rejected(), nil } diff --git a/apps/control-plane/internal/credentiallease/service_test.go b/apps/control-plane/internal/credentiallease/service_test.go index 75a02ee1..b748b0e9 100644 --- a/apps/control-plane/internal/credentiallease/service_test.go +++ b/apps/control-plane/internal/credentiallease/service_test.go @@ -12,6 +12,7 @@ import ( "iop/apps/control-plane/internal/credentialseal" "iop/apps/control-plane/internal/credentialstore" + "iop/packages/go/config" lease "iop/packages/go/credentiallease" iop "iop/proto/gen/iop" ) @@ -76,6 +77,12 @@ func TestAcquireChecksDurableBindingBeforeOpeningAndIssuesConsumableLease(t *tes if err != nil { t.Fatal(err) } + originalProfile, ok := config.BuiltInProtocolProfiles["openai"] + if !ok { + t.Fatal("missing built-in openai profile") + } + delete(config.BuiltInProtocolProfiles, "openai") + t.Cleanup(func() { config.BuiltInProtocolProfiles["openai"] = originalProfile }) binding := &iop.CredentialLeaseBinding{ PrincipalRef: principal.Principal.ID, CredentialSlotRef: slot.ID, RouteId: route.ID, ProfileId: route.ProfileID, UpstreamTarget: route.UpstreamModel, NodeId: "node-1", RecipientKeyId: "recipient-1",