Merge branch 'feature/provider-usage-attribution-hot-path' into dev
This commit is contained in:
commit
26feeff17c
8 changed files with 780 additions and 6 deletions
265
HANDOFF.md
Normal file
265
HANDOFF.md
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
# Handoff: Chronos Standalone Agent Runtime과 Node Domain-Agent Gateway
|
||||
|
||||
- 작성일: 2026-07-31
|
||||
- 현재 타겟: 새 `Chronos` 프로젝트의 최종 아키텍처 확정안 검토와 이후 Milestone 설계 준비
|
||||
- 다음 세션 첫 진입점: 이 문서
|
||||
- 상태: 프로젝트명·저장소 경계·gateway 방향 확정, 새 저장소·구현·이전·로드맵 생성 미착수
|
||||
- 기록 위치: Chronos 저장소가 아직 없으므로 이 파일만 `iop` 루트에 임시 handoff로 둔다. Chronos 초기화 후 canonical handoff와 Roadmap은 Chronos로 옮긴다.
|
||||
|
||||
## 사용자 확정 사항
|
||||
|
||||
1. 현재 `/config/workspace/iop-s0`의 `IOP Agent CLI Runtime` Milestone은 기존 범위대로 끝까지 완료한다. 지금 구조를 중간에 재편하거나 새 원격 gateway 범위를 끌어오지 않는다.
|
||||
2. `agentic-framework`는 문서·셸 중심의 가벼운 공통 agent-ops 프레임워크로 그대로 유지한다. 어디든 설치 가능한 현재 성격을 보존하고 application runtime을 추가하지 않는다.
|
||||
3. 새 독립 프로젝트의 이름은 `Chronos`로 확정한다. 저장소·CLI·daemon의 기본 이름은 각각 `chronos`, `chronos`, `chronosd`로 사용한다.
|
||||
4. 아래의 단계 2 이후 작업은 새 `Chronos` 프로젝트를 장기 기준 저장소이자 Roadmap/Milestone source of truth로 삼는다.
|
||||
5. 다음 세션은 우선 Chronos의 최종 아키텍처와 책임 경계만 확정한다. 이 handoff에서는 새 저장소, Milestone, 구현 plan, 코드 이전을 생성하지 않는다.
|
||||
6. 확정안이 정리된 뒤 Chronos 저장소에 Roadmap/Milestone을 만들고, IOP·OTO 코드 변경은 해당 Milestone이 가리키는 cross-repo 구현 작업으로 관리한다.
|
||||
|
||||
## 프로젝트 이름과 상징
|
||||
|
||||
프로젝트명은 **Chronos**로 확정한다.
|
||||
|
||||
사용자가 기존 skill/runtime에 일을 맡겨 실제로 얻은 가장 큰 가치는 자신의 시간이 크게 늘어난 것이다. Chronos는 단순 scheduler 명칭이 아니라 다음 경험을 상징한다.
|
||||
|
||||
> 일의 시간을 Chronos에게 맡기고, 내 시간을 되찾는다.
|
||||
|
||||
Chronos가 작업을 `Plan → Work → Review → Recovery` 순서로 계속 진행하는 동안 사용자는 작업을 상시 감시하지 않는다. 이름은 체계적으로 흐르는 작업 시간과 사용자에게 반환되는 시간을 함께 뜻한다.
|
||||
|
||||
- 영문 문구: `Chronos — Take your time back.`
|
||||
- 한국어 문구: `일은 맡기고, 시간은 되찾다.`
|
||||
- 저장소 기본명: `chronos`
|
||||
- CLI 기본명: `chronos`
|
||||
- daemon 기본명: `chronosd`
|
||||
- runtime package/product family: `chronos-runtime`
|
||||
- Node bridge kind 후보: `chronos-agent`
|
||||
|
||||
동명의 scheduler·workflow·AI 제품이 존재한다는 점은 인지하고 선택했다. 내부/초기 프로젝트명은 `Chronos`로 유지하고, 공개 배포 시점에만 조직 prefix, package namespace, domain·상표 충돌을 별도 검토한다. 다음 세션이 충돌만을 이유로 이름을 다시 열지 않는다.
|
||||
|
||||
## 최종 방향
|
||||
|
||||
현재 `/config/workspace/iop-s0`에서 완성할 `iop-agent` 구현을 선행 source로 삼아, 완료 후 standalone daemon/runtime의 제품 소유권을 새 Chronos 프로젝트로 이전한다. Chronos는 Node에 내장하지 않는다. 로컬 사용에서 Node는 필수가 아니다. IOP 관리 환경에서만 Node가 선택적 `domain-agent gateway`가 되어 기존 outbound Edge 연결과 로컬 Chronos 연결을 중계한다.
|
||||
|
||||
```text
|
||||
Local standalone
|
||||
|
||||
CLI / Skill / Flutter / Unity
|
||||
↕ versioned local control
|
||||
Chronos daemon (`chronosd`)
|
||||
↕
|
||||
workflow runtime과 durable state
|
||||
|
||||
IOP managed
|
||||
|
||||
Control Plane → Edge → 기존 Node outbound session
|
||||
↕
|
||||
Node agent_bridge gateway
|
||||
↕ local typed connection
|
||||
동일한 Chronos daemon
|
||||
```
|
||||
|
||||
책임은 다음과 같이 고정한다.
|
||||
|
||||
| 소유자 | 책임 |
|
||||
|---|---|
|
||||
| `agentic-framework` | 어디든 설치 가능한 agent-ops 공통 규칙·skill·sync framework. Chronos runtime을 포함하지 않음 |
|
||||
| `Chronos` | standalone runtime core, CLI/daemon, local control, workflow adapter, durable state/replay, scoped execution, Roadmap lifecycle 조합 |
|
||||
| IOP Node | 로컬 agent discovery/registration, capability·health, admission, request correlation, bounded relay, timeout/backpressure, Edge 연결 중계 |
|
||||
| IOP Edge/Control Plane | 원격 principal authorization, Node/agent routing, command/event summary, audit와 운영 표면 |
|
||||
| OTO | pipeline/job/artifact/log 의미와 실행 상태의 원본 |
|
||||
| Flutter/Unity | runtime client. CLI를 감싸지 않고 versioned local proto-socket 계열 계약을 직접 사용 |
|
||||
|
||||
Node는 workflow artifact, Plan/Review 해석, project state, OTO job state의 원본을 소유하지 않는다. Node 또는 Edge 연결이 끊겨도 이미 수락된 standalone 작업은 계속되어야 한다.
|
||||
|
||||
## Provider 경계
|
||||
|
||||
외부에서는 하나의 provider/resource 계열로 발견할 수 있지만, 기존 model/CLI provider와 같은 실행 의미로 합치지 않는다.
|
||||
|
||||
```text
|
||||
agent_bridge provider framework
|
||||
├─ kind: chronos-agent
|
||||
└─ kind: oto-runner
|
||||
```
|
||||
|
||||
공유 가능한 것은 다음 lifecycle뿐이다.
|
||||
|
||||
- versioned registration과 stable instance identity
|
||||
- capability catalog와 availability/health
|
||||
- command correlation과 idempotency
|
||||
- ordered event, result, cancel/stop
|
||||
- disconnect/reconnect와 snapshot/replay
|
||||
- capacity, timeout, bounded queue와 audit metadata
|
||||
|
||||
Chronos의 Plan/Review/Milestone 상태와 OTO의 pipeline/job/artifact payload는 kind별 typed driver가 소유한다. 자유형 terminal output, model prompt/delta, HTTP `ProviderTunnel` body로 변환하지 않는다.
|
||||
|
||||
Node의 기존 terminal/CLI 기능은 설치·bootstrap·업데이트·비상 진단 후보일 뿐 정상 제어면이 아니다. `chronosd`를 terminal에서 실행하고 stdout을 파싱하는 구조는 singleton ownership, command correlation, cancel/resume, event ordering과 crash recovery를 중복 구현하게 하므로 폐기한다.
|
||||
|
||||
## 제품 사용 표면
|
||||
|
||||
같은 runtime을 다음 범위로 독립 사용 가능해야 한다.
|
||||
|
||||
- Plan/Review cycle만 실행
|
||||
- 하나의 Milestone 범위만 실행
|
||||
- 여러 Milestone을 포함한 전체 Roadmap lifecycle 실행
|
||||
- 로컬 CLI에서 수동 시작·상태·중단·재개
|
||||
- agent용 Skill이 CLI 또는 안정된 client interface를 통해 같은 기능 사용
|
||||
- Flutter/Unity가 local control 계약으로 상태·event·control 사용
|
||||
- IOP 관리 환경에서 Node gateway를 통한 선택적 원격 상태·제어
|
||||
|
||||
Plan/Review cycle의 상태 의미와 artifact 규칙은 공통 core가 소유한다. 실행 위치에 따라 adapter를 분리한다.
|
||||
|
||||
- 로컬 workflow: plan, work, review를 동일 사용자 장비의 standalone runtime이 수행한다.
|
||||
- remote user-agent workflow: plan, work, review 요청과 결과가 모두 원격 사용자 agent를 통과한다. 공통 cycle을 사용하지만 transport, executor, retry, attention/승인 경로는 별도 adapter다.
|
||||
|
||||
따라서 실행 지점이 같다는 이유로 두 workflow를 하나의 pipeline 구현으로 강제하지 않는다. 공통 core는 cycle state와 transition을 제공하고, local/remote adapter가 각 수행 방식을 제공한다.
|
||||
|
||||
## OTO에서 흡수할 것과 버릴 것
|
||||
|
||||
OTO에서 제품화할 핵심은 `agent가 outbound 장기 session으로 등록 → capability 보고 → server push 수신 → heartbeat/report`하는 연결 패턴이다.
|
||||
|
||||
흡수한다.
|
||||
|
||||
- session abstraction
|
||||
- protocol/capability version registration
|
||||
- heartbeat와 disconnect 처리
|
||||
- duplicate connection 교체
|
||||
- server-push command와 typed report
|
||||
- execution ownership 검사
|
||||
|
||||
그대로 가져오지 않는다.
|
||||
|
||||
- legacy OTO→IOP Edge direct registration code
|
||||
- OTO domain proto를 Chronos에도 공통 적용
|
||||
- 빈 값 여부만 확인하는 enrollment token
|
||||
- TLS, reconnect/backoff, 실제 cancel 집행이 빠진 현재 한계
|
||||
- Node가 OTO scheduler나 artifact/log store가 되는 구조
|
||||
|
||||
OTO와 Chronos는 같은 `agent_bridge` framework 아래 서로 다른 driver/instance로 둔다.
|
||||
|
||||
## 로컬 연결과 보안 경계
|
||||
|
||||
현재 iop-agent local control에서 검증 중인 Unix socket `0600`, owner-only state root `0700`, 동일 effective UID peer 경계를 Chronos 이전 후에도 보존한다. 이 경계를 원격 통합을 위해 느슨하게 만들지 않는다.
|
||||
|
||||
초기 후보는 두 단계다.
|
||||
|
||||
1. 같은 사용자 MVP: Node companion/connector가 Chronos의 owner-only local socket을 사용한다.
|
||||
2. system Node 또는 다중 사용자 제품형: 사용자 agent가 Node가 소유한 local gateway로 outbound 등록하고 session을 유지한다. Unix domain socket/Windows named pipe가 목표이며, 공통 transport가 준비되지 않은 초기 구현은 `127.0.0.1` only + ephemeral port + short-lived credential을 사용할 수 있다.
|
||||
|
||||
어느 경우든 사용자 장비에 외부 inbound port를 추가하지 않는다. 원격 traffic은 기존 Node→Edge outbound session 하나로 multiplex한다.
|
||||
|
||||
production remote mutation 전 필수 gate:
|
||||
|
||||
- Edge–Node transport authentication/confidentiality
|
||||
- remote principal → local owner/project/workspace scope authorization
|
||||
- operation allowlist와 audit
|
||||
- stable `command_id`를 이용한 duplicate convergence
|
||||
- ordered event relay와 cursor replay
|
||||
- replay 범위를 벗어나면 fresh snapshot으로 복구
|
||||
- `node online`, `bridge connected`, `agent available`, `project running` 상태 구분
|
||||
- 원격 UI start/focus와 임의 shell/path/protobuf forwarding 기본 금지
|
||||
|
||||
현재 Edge–Node transport에는 mTLS helper가 실제 transport에 연결되지 않았으므로, 이 gate 전에는 production `project.start/stop/resume`을 열지 않는다.
|
||||
|
||||
## 보류·분리 항목
|
||||
|
||||
- local LLM 감시/advisor는 현시점 over-spec으로 보류한다. 결정적 runtime monitoring에는 LLM을 넣지 않는다.
|
||||
- remote terminal은 별도 기능이다. Node agent gateway와 합치지 않는다.
|
||||
- Flutter/Unity는 CLI 제어가 아니라 proto-socket 계열 계약을 사용한다.
|
||||
- remote coding 유지보수는 별도 Desktop Agent를 만들지 않고 향후 Chronos의 remote user-agent workflow adapter로 흡수한다.
|
||||
- Node가 Chronos process, workflow, durable state를 기본 소유하거나 Edge reconnect 시 종료시키지 않는다.
|
||||
- direct specialized agent→Edge protocol은 현재 기본 경로로 부활시키지 않는다.
|
||||
- Node와 Chronos의 겹쳐 보이는 코드를 성급히 공통 package로 추출하지 않는다. shared contract/SDK만 먼저 고정하고 실제로 host-neutral한 구현 경계가 증명된 뒤 추출한다.
|
||||
|
||||
## 단계 기준
|
||||
|
||||
이전 대화에서 사용한 번호는 다음을 뜻한다.
|
||||
|
||||
1. `/config/workspace/iop-s0`의 현재 `IOP Agent CLI Runtime` 완료
|
||||
2. `Agent Runtime Ownership Extraction`
|
||||
- 완료된 standalone runtime 소유권을 새 Chronos 프로젝트로 이전
|
||||
- 제품·CLI·daemon 명칭을 `chronos`, `chronos`, `chronosd`로 정리
|
||||
- local CLI/socket/offline 사용성 보존
|
||||
- versioned control contract/SDK 경계 고정
|
||||
3. `Scoped Agent Task Execution Surface`
|
||||
- Plan/Review, Milestone, Roadmap 범위별 독립 실행과 종료 경계
|
||||
4. `Node External Agent Provider Foundation`
|
||||
- `agent_bridge` registration, discovery, health, typed command/event/replay
|
||||
5. `Edge Managed Agent Routing & Security`
|
||||
- Edge–Node remote control wire, authorization, audit, reconnect
|
||||
6. `Roadmap Lifecycle Orchestration`
|
||||
- 3번 scope를 조합하되 작은 범위 사용성을 보존
|
||||
7. `OTO Provider Adapter`
|
||||
8. `Remote User-Agent Workflow Bridge`
|
||||
|
||||
2번 이후 Roadmap/Milestone은 새 Chronos 저장소에서 관리한다. 4, 5, 7번은 구현 파일이 IOP/OTO에 있더라도 Chronos Milestone에서 cross-repo 대상과 검증을 명시한다.
|
||||
|
||||
3번과 6번의 local lifecycle 설계는 Node gateway와 독립적으로 진행할 수 있다. 원격 mutation만 5번 보안 gate를 선행한다.
|
||||
|
||||
## 다음 세션 실행 순서
|
||||
|
||||
1. 이 문서와 아래 `필수 탐색 경로`만 먼저 읽는다.
|
||||
2. `agentic-framework`는 변경하지 않고 경량 공통 프레임워크로 유지한다. Chronos runtime, Roadmap, project rule을 이 저장소에 추가하지 않는다.
|
||||
3. 새 Chronos 저장소의 위치·module namespace·초기 scaffold는 최종 아키텍처 확정 뒤 결정한다. 아직 `/config/workspace/chronos`가 존재한다고 가정하지 않는다.
|
||||
4. 최종 아키텍처 문서에서 다음을 결정 가능한 형태로 고정한다.
|
||||
- component/process topology
|
||||
- repository와 package ownership
|
||||
- versioned contract source와 generated SDK 배포
|
||||
- local/managed deployment mode
|
||||
- identity/authorization
|
||||
- command/event/replay/cancel failure semantics
|
||||
- Node/Edge/agent disconnect 시 lifecycle
|
||||
5. 사용자에게 최종안을 확인받은 뒤 Chronos 저장소를 초기화하고 `create-roadmap`을 사용해 2번 이후 Milestone을 생성한다.
|
||||
6. Chronos 저장소가 생기면 이 문서의 확정 사항을 그 저장소의 canonical handoff/architecture 입력으로 이전한다. `agentic-framework`에는 Chronos runtime·Roadmap을 남기지 않는다.
|
||||
7. 현재 `/config/workspace/iop-s0` checkout은 Milestone 완료 정합화 전까지 수정, 이동, 정리하지 않는다. 1번 완료 evidence가 생긴 뒤 extraction 범위를 산정한다.
|
||||
|
||||
## 필수 탐색 경로
|
||||
|
||||
### 유지할 `agentic-framework` 경계
|
||||
|
||||
- [`README.md`](README.md): 현재 저장소가 app runtime이 아닌 agent-ops 공통 원본이라고 명시한다. 저장소 역할 확장은 의식적인 결정이어야 한다.
|
||||
- [`agent-ops/rules/common/philosophy.md`](agent-ops/rules/common/philosophy.md): runtime과 LLM 책임, Roadmap과 실행 상태 경계.
|
||||
- [`agent-ops/bin/sync.sh`](agent-ops/bin/sync.sh): push 대상은 `agent-ops` 공통 영역으로 제한된다. Chronos는 이 sync payload가 아니라 별도 소비 프로젝트다.
|
||||
|
||||
### 현재 `iop-agent` 구현과 계약
|
||||
|
||||
- [`../iop-s0/agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`](../iop-s0/agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md): 현재 Milestone 범위, 제외 항목, 완료 전 남은 작업.
|
||||
- [`../iop-s0/agent-contract/inner/iop-agent-cli-runtime.md`](../iop-s0/agent-contract/inner/iop-agent-cli-runtime.md): standalone/local control 계약.
|
||||
- [`../iop-s0/proto/iop/agent.proto`](../iop-s0/proto/iop/agent.proto): typed envelope, `command_id`, snapshot, event sequence와 replay.
|
||||
- [`../iop-s0/apps/agent/internal/localcontrol/server.go`](../iop-s0/apps/agent/internal/localcontrol/server.go): Unix socket, permission, same-UID peer credential 경계.
|
||||
- [`../iop-s0/apps/agent/internal/localcontrol/service.go`](../iop-s0/apps/agent/internal/localcontrol/service.go): status와 project start/stop/resume port.
|
||||
- [`../iop-s0/apps/agent/internal/taskloop/workflow.go`](../iop-s0/apps/agent/internal/taskloop/workflow.go): agent-ops Plan/Review/Milestone artifact 의존성이 집중된 workflow adapter.
|
||||
- [`../iop-s0/packages/go/agentruntime/types.go`](../iop-s0/packages/go/agentruntime/types.go): 기존 유한 실행 Provider와 agent durable control의 의미 차이.
|
||||
|
||||
### IOP Node/Edge gateway 후보
|
||||
|
||||
- [`../iop-s0/apps/node/README.md`](../iop-s0/apps/node/README.md): 기존 Edge–Node transport, logical session, mTLS 미연결 상태.
|
||||
- [`../iop-s0/proto/iop/runtime.proto`](../iop-s0/proto/iop/runtime.proto): `RunRequest`, `RunEvent`, `NodeCommand`, `ProviderTunnel`; 새 durable agent control을 억지로 넣지 않아야 하는 기존 wire.
|
||||
- [`../iop-s0/apps/node/internal/transport/session.go`](../iop-s0/apps/node/internal/transport/session.go): 기존 단일 Edge–Node session의 message family multiplex.
|
||||
- [`../iop-s0/proto/iop/control.proto`](../iop-s0/proto/iop/control.proto): `EdgeDomainAgentSummary`, `EdgeCommandRequest/Response/Event` scaffold.
|
||||
- [`../iop-s0/apps/edge/internal/service/status_provider.go`](../iop-s0/apps/edge/internal/service/status_provider.go): `GetDomainAgents()`가 현재 비어 있는 integration point.
|
||||
- [`../iop-s0/apps/edge/internal/service/control_command.go`](../iop-s0/apps/edge/internal/service/control_command.go): 현재 `agent.command`가 제한적 scaffold인 상태.
|
||||
- [`../iop-s0/agent-roadmap/phase/control-plane-portal-ops/milestones/multi-edge-operations.md`](../iop-s0/agent-roadmap/phase/control-plane-portal-ops/milestones/multi-edge-operations.md): OTO/build-deploy를 Edge-owned domain-agent summary로 노출한다는 기존 결정.
|
||||
- [`../iop-s0/agent-roadmap/phase/automation-runtime-bridge/milestones/remote-terminal-bridge-poc.md`](../iop-s0/agent-roadmap/phase/automation-runtime-bridge/milestones/remote-terminal-bridge-poc.md): remote terminal을 별도 기능으로 유지하는 경계.
|
||||
|
||||
### OTO 연결 패턴
|
||||
|
||||
- [`../oto/proto/oto/runner.proto`](../oto/proto/oto/runner.proto): registration, capability, heartbeat, push run/cancel, report 계약.
|
||||
- [`../oto/apps/runner/lib/oto/agent/registration_client.dart`](../oto/apps/runner/lib/oto/agent/registration_client.dart): 현재 outbound session abstraction.
|
||||
- [`../oto/apps/runner/lib/oto/agent/agent_runner.dart`](../oto/apps/runner/lib/oto/agent/agent_runner.dart): push job loop와 현재 cancel 한계.
|
||||
- [`../oto/apps/runner/lib/oto/agent/edge_registration_client.dart`](../oto/apps/runner/lib/oto/agent/edge_registration_client.dart): legacy direct IOP Edge client임을 파일 자체가 명시한다.
|
||||
- [`../oto/services/core/internal/runnersocket/server.go`](../oto/services/core/internal/runnersocket/server.go): runner registry, push, duplicate connection과 report ownership 패턴.
|
||||
- [`../oto/services/core/internal/runnerregistry/registry.go`](../oto/services/core/internal/runnerregistry/registry.go): capability/version 검사와 현재 enrollment 검증 한계.
|
||||
|
||||
### 보조 컨텍스트
|
||||
|
||||
- 이전 Codex context ID: `019fb30f-08e6-7643-bc73-ef72a3199dcb`
|
||||
- 위 context를 조회할 수 있으면 보조 근거로만 사용한다. 이 handoff의 사용자 확정 사항과 책임 경계를 우선한다.
|
||||
|
||||
## 작업 상태와 검증
|
||||
|
||||
- 이번 세션에서 구현, migration, Milestone/SDD/contract 생성은 하지 않았다.
|
||||
- `/config/workspace/agentic-framework`는 `main`, 기준 commit `afd34c3`이며 handoff 이동 후 clean 상태다.
|
||||
- `/config/workspace/iop`는 `feature/provider-usage-attribution-hot-path`이며 이동 전 clean 상태였다. 현재 변경은 untracked `HANDOFF.md` 한 건뿐이다.
|
||||
- 새 Chronos 저장소는 아직 생성하지 않았다.
|
||||
- `/config/workspace/iop-s0`는 `feature/iop-agent-cli-runtime`, HEAD `4e420910`이며 원격 브랜치와 동일한 clean 상태다. Milestone 완료 정합화 전에는 해당 checkout을 임의로 수정하거나 이동하지 않는다.
|
||||
- `/config/workspace/oto`는 `master`, 기준 commit `ae2b14f`였고 확인 당시 clean 상태였다.
|
||||
- 문서 작업이므로 코드 테스트는 실행하지 않는다. `git diff --check`만 검증한다.
|
||||
|
|
@ -19,14 +19,15 @@ IOP(Inference Operations Platform)는 Control Plane - Edge - Node 계층 구조
|
|||
내부 실행 모델은 `adapter + target`을 기준으로 하며, Edge가 로컬 실행 그룹의 상태와 라우팅을 소유하고 Control Plane은 Edge를 통해 시스템을 관찰하고 제어한다.
|
||||
|
||||
IOP는 NomadCode에 종속된 Agent Shell이 아니라, NomadCode와 외부 agent, 운영 CLI, client, 자동화 도구가 함께 소비할 수 있는 범용 추론/자동화 운영 엔진이다.
|
||||
로드맵 전반에서 OpenAI-compatible API는 외부 클라이언트의 모델 기반 호출 표면으로, A2A API는 외부 agent의 agent-to-agent 작업 위임 표면으로, IOP native protocol은 운영 제어, logical session, background run, command, lifecycle event, remote terminal session 같은 IOP 고유 기능의 기준으로 둔다.
|
||||
로드맵 전반에서 OpenAI-compatible API와 Anthropic-compatible Messages API는 외부 클라이언트의 모델 기반 호출 표면으로, A2A API는 외부 agent의 agent-to-agent 작업 위임 표면으로, IOP native protocol은 운영 제어, logical session, background run, command, lifecycle event, remote terminal session 같은 IOP 고유 기능의 기준으로 둔다.
|
||||
OpenAI-compatible API는 현재 chat completions baseline을 넘어 Responses API 호환 표면까지 지원해야 한다.
|
||||
Anthropic-compatible Messages API는 Edge가 직접 제공해 Claude Code를 포함한 client가 별도 agent-client gateway 없이 IOP를 호출하게 하며, Chat-only upstream은 IOP의 protocol bridge로 연결한다.
|
||||
IOP의 외부 실행 호출 계약은 OpenAI-compatible API 방식을 기본 표면으로 채택하고, IOP 고유의 workspace, session, agent, approval, artifact, notification 의미는 별도 `iop` wrapper field가 아니라 `metadata` 또는 IOP native endpoint의 명시 필드로 전달한다.
|
||||
IOP native protocol은 proto-socket을 기본으로 하며, HTTP는 OpenAI-compatible/A2A/health/bootstrap처럼 필요한 경계에서만 사용한다.
|
||||
A2A는 표면으로 유지하되, NomadCode가 A2A를 도입하는 시점은 현재 확정하지 않는다.
|
||||
현재 제1 active delivery는 NomadCode가 IOP를 실행 백엔드로 사용할 수 있도록 OpenAI-compatible Responses 요청의 `metadata.workspace`, task/source metadata, 내부 workspace-bound agent 실행 경로를 먼저 안정화하는 것이다.
|
||||
|
||||
모델 선택, 로컬/클라우드 라우팅, 모델별 profile, token/속도/품질 최적화, 모델 호출 로그와 품질 평가는 IOP 책임으로 둔다.
|
||||
모델 선택, 로컬/클라우드 라우팅, 모델별 profile, token/속도/품질 최적화, 모델 호출 로그와 품질 평가는 IOP 책임으로 둔다. Control Plane은 principal과 IOP token, 사용자별 provider credential slot의 원장을 소유하고 Edge는 principal별 route와 제한된 credential lease를 실행에 사용한다.
|
||||
또한 원격지와 로컬의 Ollama, vLLM, SGLang, Lemonade 같은 추론 엔진은 단순 endpoint가 아니라 provider/device/model 조합으로 관리하고, provider별 lifecycle capability, device 상태, 모델 qualification, 테스트 결과 리포트를 운영 데이터로 축적하는 방향을 목표로 한다.
|
||||
특히 로컬 모델을 우선 활용하되, cloud fallback과 품질 평가를 결합해 엔터프라이즈 모델 서비스에 가까운 운영 품질을 목표로 한다.
|
||||
RAG, context 구성/압축, web search, MCP 정책, tool policy, output validation, retry/fallback은 기본 모델 서빙과 부하 라우팅이 가능해진 뒤 확장한다.
|
||||
|
|
@ -67,7 +68,7 @@ Phase는 실행 순서가 아니라 도메인/책임 영역의 구조적 지도
|
|||
|
||||
- [진행중] 운영 관측과 Provider 관리
|
||||
- 경로: [PHASE.md](phase/operational-observability-provider-management/PHASE.md)
|
||||
- 요약: 사용자/토큰/사용량/로그 추적과 API/CLI/local inference provider catalog, 로컬 디바이스 provider 상태 관리, provider/device/model qualification report와 모델 lifecycle 관리 방향을 MVP 운영 축과 후속 심화 축으로 스케치한다.
|
||||
- 요약: 사용자/IOP token/provider credential/사용량/로그 추적과 cloud API protocol profile, native Messages, API/CLI/local inference provider catalog, 로컬 디바이스 provider 상태 관리, provider/device/model qualification report와 모델 lifecycle 관리 방향을 MVP 운영 축과 후속 심화 축으로 스케치한다.
|
||||
|
||||
- [진행중] Update Plane과 자체 업데이트 기반
|
||||
- 경로: [PHASE.md](phase/update-plane-self-update-foundation/PHASE.md)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
|
||||
## 목표
|
||||
|
||||
IOP가 여러 Edge, Node, CLI Agent, local inference provider를 운영할 때 필요한 사용자/토큰/사용량/로그/provider 상태 관찰 기준을 정리한다.
|
||||
IOP가 여러 Edge, Node, CLI Agent, local inference provider와 cloud API provider를 운영할 때 필요한 사용자/토큰/credential/사용량/로그/provider 상태 및 protocol profile 기준을 정리한다.
|
||||
이 Phase는 완성된 billing, enterprise IAM, provider marketplace를 바로 구현하지 않고, 1차 MVP에서 어떤 운영 데이터를 모으고 어떤 화면/명령으로 검토할지 스케치한다.
|
||||
provider 확장 Phase에서 검증한 Ollama, vLLM, SGLang, Lemonade 같은 추론 엔진은 provider/device/model 조합으로 관찰하고, 후반부에서는 모델 lifecycle capability와 qualification report를 운영 데이터로 축적하는 방향을 정리한다.
|
||||
cloud API provider는 Chat Completions 공통 profile과 Edge native Anthropic Messages 표면으로 수렴시키며, Control Plane이 principal token과 사용자별 provider credential slot의 원장을 소유한다.
|
||||
|
||||
## Milestone 흐름
|
||||
|
||||
|
|
@ -58,6 +59,14 @@ 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 Protocol Profile과 Native Anthropic Messages
|
||||
- 경로: [multi-provider-protocol-profile-native-messages](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](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로 남기는 로그 시스템 개편 후보를 스케치한다.
|
||||
|
|
@ -72,8 +81,8 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실
|
|||
|
||||
## Phase 경계
|
||||
|
||||
- Control Plane은 Edge/Node 상태를 보기 쉽게 연결하지만 Edge 내부 상태의 canonical store가 되지 않는다.
|
||||
- provider adapter 구현과 endpoint별 serving 검증은 `추론 서버 provider 확장` Phase 책임으로 둔다.
|
||||
- Control Plane은 principal, IOP token과 외부 provider credential의 canonical store를 소유한다. Edge/Node provider health, capacity, queue와 실행 중 상태의 canonical store는 계속 Edge이며 Control Plane이 복제 소유하지 않는다.
|
||||
- Ollama/vLLM/SGLang/Lemonade 같은 local inference adapter 구현과 serving 검증은 `추론 서버 provider 확장` Phase의 완료 기준을 유지한다. cloud API protocol/profile, public Chat/Messages compatibility와 credential routing은 이 Phase 책임으로 둔다.
|
||||
- provider/device/model qualification report는 provider serving path와 capacity/concurrency 기준선이 잡힌 뒤 이 Phase의 후반부에서 다룬다.
|
||||
- 이 Phase는 운영 데이터와 제어 표면의 MVP 경계를 다루며, billing/chargeback, 조직 IAM, 상세 audit schema, 장기 retention 정책은 후속 구체화에서 결정한다.
|
||||
- 누적 요청 컨텍스트 최적화, RAG, advisor, Context Hook, output validation 실행 모드는 `지식과 도구 최적화 확장` Phase 책임으로 둔다.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
# Milestone: 다중 Provider Protocol Profile과 Native Anthropic Messages
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: [ROADMAP.md](../../../ROADMAP.md)
|
||||
- Phase: [PHASE.md](../PHASE.md)
|
||||
|
||||
## 목표
|
||||
|
||||
OpenAI Chat Completions를 공통 cloud provider 실행 기준으로 두고 provider별 차이는 선언형 protocol profile overlay와 제한된 확장 driver로 흡수한다. Edge가 Anthropic Messages 입력과 응답 변환을 직접 소유하여 Claude Code가 `agent-client` gateway 없이 IOP를 호출하게 하고, 기존 Responses driver와 표면은 선택적 capability로 유지하되 공통 provider 완료 기준에는 포함하지 않는다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 승격 조건
|
||||
|
||||
- 없음
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- SDD: 필요
|
||||
- SDD 문서: [SDD.md](../../../sdd/operational-observability-provider-management/multi-provider-protocol-profile-native-messages/SDD.md)
|
||||
- SDD 사유: 외부 HTTP/SSE 계약, provider별 endpoint/path/auth/capability profile, Anthropic↔OpenAI 변환과 Edge-Node tunnel wire를 함께 변경한다.
|
||||
- 잠금 해제 조건:
|
||||
- [x] SDD 잠금이 해제되어 있다.
|
||||
- [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
|
||||
- [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
|
||||
- [x] Evidence Map이 완료 시 `Roadmap Completion`과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- `openai_chat`, `anthropic_messages`와 기존 선택적 `openai_responses` driver가 공유하는 endpoint/path, auth header, request option, capability provider profile schema
|
||||
- 공통 base profile을 상속해 endpoint/capability/extension만 덮어쓰고 runtime에서는 완전한 immutable profile로 해소되는 선언형 profile overlay
|
||||
- OpenAI, Gemini, Anthropic, GLM, Kimi, MiniMax, MiMo, Grok, Seulgi GPT의 Chat Completions profile
|
||||
- Anthropic, MiniMax, MiMo, Seulgi Claude처럼 native Messages를 제공하는 upstream의 `anthropic_messages` profile
|
||||
- Edge의 canonical `POST /v1/messages`, `POST /v1/messages/count_tokens`, Anthropic 방식 model discovery와 기존 `/anthropic/v1/*` client 설정을 위한 migration alias
|
||||
- Anthropic Messages와 OpenAI Chat Completions 사이의 system/content/tool/thinking/usage/error/stream 변환
|
||||
- 기존 `openai_compat`, `seulgivibe_claude`, `seulgivibe_openai` type/config의 호환 migration
|
||||
- 반복 가능한 fixture/contract test와 provider profile 구현 시 대표 모델 1개로 수행하는 일회성 live smoke
|
||||
|
||||
## 기능
|
||||
|
||||
### Epic: [protocol-core] 공통 Protocol Driver와 Profile
|
||||
|
||||
provider별 차이를 경로 분기 코드가 아니라 검증 가능한 profile과 protocol driver 경계로 수렴시킨다.
|
||||
|
||||
- [ ] [profile-contract] `openai_chat`, `anthropic_messages`와 기존 선택적 `openai_responses` driver가 공통 provider profile의 endpoint, operation path, auth declaration, model mapping, capability와 extension을 소비하고 base profile overlay를 immutable runtime profile로 해소하도록 config/runtime 계약을 만든다. 검증: overlay cycle과 잘못된 protocol/path/auth/capability 조합은 config load에서 거부되고 legacy type alias는 동일 runtime profile로 정규화된다.
|
||||
- [ ] [path-resolution] base URL에 `/v1`, `/v1beta/openai`, `/api/paas/v4` 같은 provider prefix가 있어도 operation path를 중복 결합하지 않는 profile 기반 URL resolver를 적용한다. 검증: OpenAI, Gemini, GLM, Kimi, MiniMax, MiMo, Grok, Seulgi fixture의 최종 URL이 기대값과 일치한다.
|
||||
- [ ] [profile-catalog] OpenAI, Gemini, Anthropic, GLM, Kimi, MiniMax, MiMo, Grok와 Seulgi의 Chat/Messages 지원 범위를 base profile+overlay catalog와 custom profile 예시로 제공한다. 검증: 각 built-in/custom profile이 공통 schema validation과 request fixture를 통과하고 미지원 operation은 dispatch 전에 명시적으로 거부된다.
|
||||
- [ ] [contract-sync] provider profile config, Edge-Node tunnel operation과 public Chat/Messages 표면의 inner/outer 계약 및 현재 구현 spec을 동기화한다. 검증: contract/spec index와 구현 경로가 새 source of truth를 가리키고 중복 계약 원문이 남지 않는다.
|
||||
|
||||
### Epic: [messages-ingress] Edge Native Anthropic Messages
|
||||
|
||||
Claude Code가 IOP Edge를 Anthropic-compatible endpoint로 직접 사용하고 대상 profile에 따라 native passthrough 또는 Chat 변환을 수행하게 한다.
|
||||
|
||||
- [ ] [messages-surface] Edge에 canonical `POST /v1/messages`, `POST /v1/messages/count_tokens`, `GET /v1/models` Anthropic variant와 `/anthropic/v1/*` migration alias를 추가하고 IOP principal auth를 모든 표면에 공통 적용한다. 검증: `ANTHROPIC_BASE_URL`과 auth token/helper를 사용한 Claude Code 형태의 non-stream/stream/count-tokens/model-list fixture가 `agent-client` 프로세스 없이 Edge에 도달하고 `anthropic-version`이 `/v1/models` 응답 schema를 명확히 선택한다.
|
||||
- [ ] [messages-native] `anthropic_messages` upstream은 request/response/error/SSE body 의미를 보존하는 raw tunnel로 전달한다. 검증: Anthropic, MiniMax, MiMo, Seulgi Claude fixture에서 header allowlist, model rewrite, content block ordering, terminal event가 보존된다.
|
||||
- [ ] [messages-chat-bridge] `openai_chat` upstream에는 Anthropic system/content/tool/tool-result/tool-choice/thinking/usage/error와 streaming event를 양방향 변환한다. 검증: text-only, mixed content, tool round-trip, reasoning, stop reason, usage와 provider error golden fixture가 Anthropic 응답 계약으로 수렴한다.
|
||||
- [ ] [responses-regression] 기존 `/v1/responses` passthrough/normalized driver, body/stream 계약과 `agent-client/pi` 소비 동작을 선택적 capability로 유지한다. 검증: 기존 Responses route/stream/provider-auth 회귀 테스트가 통과하며 새 provider 공통 인증 기준에는 Responses live smoke가 요구되지 않는다.
|
||||
|
||||
### Epic: [qualification] Provider Qualification
|
||||
|
||||
지속 구독 없이 profile 구현 품질을 재현 가능한 fixture와 제한된 실호출 근거로 남긴다.
|
||||
|
||||
- [ ] [fixture-suite] 각 provider profile의 URL, header, model rewrite, non-stream/stream parsing과 오류 mapping을 credential-free deterministic fixture로 검증한다. 검증: 전체 fixture/contract suite가 네트워크와 provider 구독 없이 반복 실행된다.
|
||||
- [ ] [live-smoke] 새 profile을 구현하거나 protocol profile이 실질적으로 바뀔 때에만 제공된 credential로 대표 모델 1개를 일회성 smoke하고 model/revision/date/result를 qualification evidence로 남긴다. 검증: live smoke는 opt-in이며 일반 local test와 CI에서 자동 실행되거나 모든 provider 구독을 요구하지 않는다.
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 계획 Milestone이며 기능 Task가 아직 충족되지 않았다.
|
||||
- 검토 항목: Chat/Messages deterministic fixture, Claude Code direct Edge smoke, 기존 Responses 회귀와 provider별 일회성 qualification evidence를 확인한다.
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- `/v1/responses` 공통 provider 표준화 또는 모든 provider에 대한 Responses 지원 강제
|
||||
- provider credential의 저장, 사용자별 slot/alias 선택과 secret delivery
|
||||
- provider 간 자동 fallback, token slot 자동 rotation/round-robin
|
||||
- provider별 비공개 기능을 공통 schema에 강제로 승격하는 작업
|
||||
- 상시 live provider CI와 모든 provider 계정/구독 유지
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/adapters`, `packages/go/config`, `proto/iop/runtime.proto`, `agent-client/claude`, `agent-client/pi`, `agent-contract`
|
||||
- 표준선(선택): 공통 cloud API 기준은 Chat Completions이고 provider별 차이는 base profile+overlay로 흡수한다. runtime dispatch는 상속 관계가 아니라 검증 완료된 concrete profile만 소비하며, 공통 schema로 표현할 수 없는 차이만 protocol driver extension으로 제한한다.
|
||||
- 표준선(선택): Anthropic Messages는 Edge가 직접 노출하며 native Messages upstream은 passthrough, Chat-only upstream은 Edge-owned bridge를 사용한다. `agent-client/claude`는 migration 참고 구현이지 최종 runtime dependency가 아니다.
|
||||
- 표준선(선택): 기존 Responses 구현은 유지하지만 이 Milestone의 provider 공통 qualification baseline과 정기 live smoke 대상은 아니다.
|
||||
- 선행 작업: 없음
|
||||
- 후속 작업: [사용자별 Provider Credential Slot과 Alias Routing](principal-provider-credential-slot-routing.md)
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
# Milestone: 사용자별 Provider Credential Slot과 Alias Routing
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: [ROADMAP.md](../../../ROADMAP.md)
|
||||
- Phase: [PHASE.md](../PHASE.md)
|
||||
|
||||
## 목표
|
||||
|
||||
Control Plane을 IOP principal token과 외부 provider credential의 원장으로 두고, 한 사용자가 같은 vendor에 여러 credential slot을 소유할 수 있게 한다. 호출자는 IOP token과 principal별 model route/alias만 사용하며 Edge는 선택된 slot의 credential을 안전하게 실행 경계에 주입하고, 자동 slot rotation이나 caller-supplied provider token 없이 OpenAI Chat, Anthropic Messages와 기존 Responses를 호출한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 승격 조건
|
||||
|
||||
- 없음
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- SDD: 필요
|
||||
- SDD 문서: [SDD.md](../../../sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md)
|
||||
- SDD 사유: Control Plane 영속 원장, IOP token 발급/폐기, provider secret 암호화와 Edge/Node 전달, principal별 model discovery/routing 및 인증 실패 정책을 함께 변경한다.
|
||||
- 잠금 해제 조건:
|
||||
- [x] SDD 잠금이 해제되어 있다.
|
||||
- [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
|
||||
- [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
|
||||
- [x] Evidence Map이 완료 시 `Roadmap Completion`과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- Control Plane 영속 저장소의 principal, IOP bearer token hash/revision/revocation 원장
|
||||
- 사용자별 provider credential slot의 stable ID, optional alias, vendor/credential kind, encrypted secret revision, enabled/revoked 상태
|
||||
- credential slot, provider protocol profile과 upstream model을 묶어 principal별 client-facing model route를 만드는 binding
|
||||
- 같은 vendor/model에 여러 slot을 연결한 별도 route와 alias collision/ambiguity의 fail-closed 처리
|
||||
- Control Plane에서 Edge로 전달되는 secret-free auth/routing projection과 generation/expiry/revocation
|
||||
- principal/operator가 자신의 IOP token과 provider slot/model binding/alias를 생성·조회·변경·폐기하는 Control Plane 관리 operation
|
||||
- credential-bearing Client-Control Plane, Control Plane-Edge와 Edge-Node 경로의 인증·기밀 transport
|
||||
- 선택된 slot credential의 bounded runtime lease와 provider adapter 직전 auth header 주입
|
||||
- OpenAI Chat, Anthropic Messages, 기존 Responses의 공통 principal auth와 principal-filtered model discovery
|
||||
- 선택된 provider credential slot ref/revision의 dispatch·usage attribution
|
||||
- 기존 Edge `openai.principal_tokens[]`와 request header 기반 `openai.provider_auth`의 명시적 compatibility/migration mode
|
||||
- Seulgi Claude/GPT를 포함한 provider slot fixture와 구현 시 대표 slot 1개의 일회성 E2E smoke
|
||||
|
||||
## 기능
|
||||
|
||||
### Epic: [principal-auth] Control Plane Principal Token 원장
|
||||
|
||||
IOP bearer token의 발급, 인증 projection과 폐기를 Control Plane 원장으로 수렴시킨다.
|
||||
|
||||
- [ ] [principal-store] Control Plane DB에 principal과 IOP token hash, token reference, status/revision을 저장하고 raw IOP token은 발급 시 한 번만 반환한다. 검증: 발급/조회/폐기/restart persistence test에서 raw token이 DB, API 조회, log와 metric에 남지 않는다.
|
||||
- [ ] [auth-projection] Control Plane이 Edge에 principal token hash와 route 권한의 generation/expiry projection을 동기화하고 Edge가 bounded cache로 인증한다. 검증: fresh/stale/revoked/out-of-order generation fixture에서 fresh projection만 사용하고 expiry 뒤 CP-managed 외부 호출은 fail closed한다.
|
||||
- [ ] [surface-auth] OpenAI-compatible 표면은 `Authorization: Bearer`, Anthropic-compatible 표면은 같은 IOP token의 bearer 또는 `x-api-key` 입력을 동일 principal로 인증한다. 검증: 두 헤더가 같은 token이면 성공하고 불일치, 미등록, 폐기 token은 provider dispatch 전에 `401`로 종료된다.
|
||||
|
||||
### Epic: [credential-slots] Provider Credential Slot 원장과 Route
|
||||
|
||||
사용자가 vendor별 여러 token을 독립 slot으로 소유하고 명시적으로 선택하게 한다.
|
||||
|
||||
- [ ] [slot-store] Control Plane이 principal별 credential slot의 stable `slot_id`, optional alias, vendor/credential kind, encrypted secret revision과 lifecycle을 protocol profile과 분리해 저장한다. 검증: 같은 principal/vendor에 여러 slot과 한 slot의 여러 compatible profile binding을 허용하고 secret envelope key가 없거나 중복 alias/invalid binding이면 저장 또는 활성화를 거부한다.
|
||||
- [ ] [model-binding] 각 client-facing `route_id`가 정확히 하나의 principal, credential slot, provider protocol profile과 upstream model에 결합되고 optional slot alias를 선택 표면에 반영한다. 검증: 같은 upstream model에 `claude-1`, `claude-2` 같은 별도 slot route와 한 slot의 여러 compatible protocol/model route를 만들 수 있으며 ambiguous alias, incompatible profile과 다른 principal의 route는 fail closed한다.
|
||||
- [ ] [model-discovery] `/v1/models`의 OpenAI/Anthropic variant가 인증 principal에게 허용된 active route만 반환한다. 검증: principal별 list가 격리되고 disabled/revoked/expired slot과 충돌 alias가 노출되지 않으며 Claude Code가 반환 route를 선택할 수 있다.
|
||||
- [ ] [explicit-selection] 요청 `model`은 principal별 route를 명시 선택하고 한 route 안에서 token slot을 자동 round-robin, fallback 또는 vendor 교차 대체하지 않는다. 검증: 같은 model의 두 slot 중 요청 route에 결합된 slot만 선택되고 그 slot 실패는 다른 slot의 암묵적 사용으로 이어지지 않는다.
|
||||
- [ ] [credential-management] host-local Control Plane operator CLI로 principal/최초 IOP token을 bootstrap하고, 인증 principal은 자신의 추가 token/slot/model binding/alias만 관리하는 Control Plane operation을 제공한다. 검증: bootstrap/create/list/update/rotate/disable/revoke와 cross-principal authorization fixture에서 secret은 입력 시에만 수신되고 이후 조회에는 반환되지 않는다.
|
||||
|
||||
### Epic: [secret-delivery] Credential 보호와 실행 주입
|
||||
|
||||
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에서 정의된 순서로 수렴한다.
|
||||
|
||||
### 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에 없다.
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 계획 Milestone이며 기능 Task가 아직 충족되지 않았다.
|
||||
- 검토 항목: CP persistence/management, token/slot isolation, explicit alias selection, confidential transport와 credential lease, slot usage attribution, revocation, migration 및 대표 slot 일회성 smoke evidence를 확인한다.
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 동일 slot 또는 여러 slot의 자동 rotation, round-robin, quota 기반 선택과 failover
|
||||
- 여러 provider를 하나의 외부 model alias 뒤에 숨기는 자동 vendor fallback
|
||||
- billing/chargeback, 조직 역할 기반 IAM과 provider marketplace
|
||||
- raw provider token을 caller header, tracked YAML, Node static config에 저장하는 방식
|
||||
- 모든 provider 계정의 상시 구독과 정기 live smoke CI
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `apps/control-plane`, `apps/client`, `apps/edge/internal/controlplane`, `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/adapters`, `packages/go/config`, `proto/iop`, `configs/control-plane.yaml`, `configs/edge.yaml`, `agent-contract`
|
||||
- 표준선(선택): 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](multi-provider-protocol-profile-native-messages.md)
|
||||
- 후속 작업: 없음
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -87,3 +87,9 @@
|
|||
|
||||
28. [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 안에서 재실행한다.
|
||||
|
||||
30. [다중 Provider Protocol Profile과 Native Anthropic Messages](phase/operational-observability-provider-management/milestones/multi-provider-protocol-profile-native-messages.md)
|
||||
Chat Completions 공통 driver와 provider profile을 정리하고 Edge가 Anthropic Messages를 직접 흡수해 Claude Code가 agent-client 없이 IOP를 호출하게 한다.
|
||||
|
||||
31. [사용자별 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로 연결한다.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
# SDD: 다중 Provider Protocol Profile과 Native Anthropic Messages
|
||||
|
||||
## 위치
|
||||
|
||||
- Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/multi-provider-protocol-profile-native-messages.md)
|
||||
- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md)
|
||||
|
||||
## 상태
|
||||
|
||||
[승인됨]
|
||||
|
||||
## SDD 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 사용자 리뷰: 없음
|
||||
- 잠금 항목: 없음
|
||||
|
||||
## 문제 / 비목표
|
||||
|
||||
- 문제: 현재 `openai_compat` adapter는 Chat/Responses operation path를 코드에서 조합하고 여러 vendor type을 같은 adapter type으로만 정규화하므로 Gemini의 `/v1beta/openai` 같은 base path, provider별 operation/auth/capability 차이를 안전하게 표현하기 어렵다. Anthropic Messages는 Edge에 없고 `agent-client/claude/iop-claude-gateway.py`가 Seulgi native passthrough와 OpenAI Chat 변환을 대신 소유해 Claude Code의 IOP 직접 호출 경로가 성립하지 않는다.
|
||||
- 비목표:
|
||||
- `/v1/responses`를 모든 provider가 구현해야 하는 공통 표준으로 승격하거나 기존 Responses pipeline을 재설계하는 일
|
||||
- 사용자/provider credential 저장, slot alias, rotation과 secret delivery
|
||||
- vendor 간 자동 fallback, quota 최적화와 provider marketplace
|
||||
- provider별 beta/private 기능을 공통 request schema에 무손실로 강제 통합하는 일
|
||||
|
||||
## Source of Truth
|
||||
|
||||
| 영역 | 기준 | 메모 |
|
||||
|------|------|------|
|
||||
| Roadmap | [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/multi-provider-protocol-profile-native-messages.md) | 목표, provider 범위와 완료 Task |
|
||||
| Public API | `apps/edge/internal/openai`, [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md) | Chat/Responses 기존 표면과 새 Messages ingress host |
|
||||
| Provider Runtime | `apps/edge/internal/service`, `apps/node/internal/adapters/openai_compat` | profile 선택, raw tunnel, URL/auth/model rewrite 실행 |
|
||||
| Wire | `proto/iop/runtime.proto`, [Edge-Node Runtime Wire 계약](../../../../agent-contract/inner/edge-node-runtime-wire.md) | operation-neutral provider tunnel request/frame |
|
||||
| Config | `packages/go/config`, [Edge Config/Refresh 계약](../../../../agent-contract/inner/edge-config-runtime-refresh.md) | protocol profile schema, alias normalization과 validation |
|
||||
| Migration Evidence | `agent-client/claude/iop-claude-gateway.py`, `agent-client/pi/install.sh` | 현재 Messages bridge와 Responses 소비 동작의 참고 구현 |
|
||||
| External Provider | [Claude API overview](https://platform.claude.com/docs/en/api/overview), [Claude Code LLM gateway 설정](https://docs.anthropic.com/en/docs/claude-code/llm-gateway), 각 provider 공식 API 문서와 live qualification record | profile별 operation/path/header/capability revision 기준 |
|
||||
| User Decision | 2026-07-31 사용자 대화 | Chat Completions 공통 기준, Edge native Messages 흡수, Responses 현행 유지, 구현 시점 한정 live smoke |
|
||||
|
||||
## State Machine
|
||||
|
||||
| 상태 | 진입 조건 | 다음 상태 | 근거 |
|
||||
|------|-----------|-----------|------|
|
||||
| request/received | Chat, Messages, count-tokens, models 또는 기존 Responses 요청 수신 | request/authenticated / request/rejected | ingress method/path와 principal auth |
|
||||
| request/authenticated | IOP principal 인증 성공 | request/route-resolved / request/rejected | request `model`, principal context와 model catalog |
|
||||
| request/route-resolved | model route가 하나의 provider profile과 upstream model로 확정됨 | request/native-tunnel / request/bridge / request/rejected | profile protocol/capability snapshot |
|
||||
| request/native-tunnel | ingress와 upstream protocol이 같고 operation이 지원됨 | response/streaming / response/terminal | raw body/header allowlist와 model rewrite |
|
||||
| request/bridge | Anthropic Messages ingress가 `openai_chat` upstream을 선택함 | response/streaming / response/terminal / request/rejected | validated Messages↔Chat transform |
|
||||
| request/rejected | path, model, capability, content block 또는 auth가 유효하지 않음 | response/terminal | public protocol별 typed error |
|
||||
| response/streaming | upstream response start 뒤 body/event가 도착함 | response/streaming / response/terminal | protocol driver parser와 ordered emitter |
|
||||
| response/terminal | complete, provider error, parse error, cancel 또는 timeout 확정 | 없음 | ingress protocol의 exactly-once terminal |
|
||||
|
||||
## Interface Contract
|
||||
|
||||
- 계약 원문: 기존 Chat/Responses는 [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md), provider tunnel은 [Edge-Node Runtime Wire 계약](../../../../agent-contract/inner/edge-node-runtime-wire.md)을 따른다. 구현 시 native Messages 원문은 `agent-contract/outer/anthropic-compatible-api.md`에 새로 만들고 index에 등록한다.
|
||||
- 입력:
|
||||
- public operation: `GET /v1/models`, `POST /v1/chat/completions`, `POST /v1/messages`, `POST /v1/messages/count_tokens`, 기존 `POST /v1/responses`다. `agent-client/claude` migration을 위해 `/anthropic/v1/messages`, `/anthropic/v1/messages/count_tokens`, `/anthropic/v1/models`를 같은 handler의 compatibility alias로 둘 수 있으나 canonical 계약은 `/v1/*`다.
|
||||
- protocol profile: stable profile id, driver(`openai_chat|anthropic_messages|openai_responses`), base URL, operation별 상대/절대 path, auth header/scheme declaration, supported operation/capability, upstream model mapping과 제한된 extension options를 가진다. `openai_responses`는 기존 선택적 driver이며 공통 qualification baseline이 아니다.
|
||||
- profile overlay: top-level reusable profile catalog를 `nodes[].providers[]` resource가 profile id로 참조한다. profile은 optional base profile 하나를 확장하고 endpoint/path/auth declaration/capability/extension만 override할 수 있으며, cycle/unknown base/conflicting driver는 config error다. runtime과 Node payload에는 상속 정보가 아니라 validation이 끝난 concrete profile만 전달한다.
|
||||
- Chat profile catalog: OpenAI, Gemini, Anthropic OpenAI-compatible, GLM, Kimi, MiniMax, MiMo, Grok와 Seulgi GPT를 `openai_chat` driver로 표현한다.
|
||||
- Messages profile catalog: Anthropic, MiniMax, MiMo와 Seulgi Claude처럼 native Messages가 검증된 endpoint만 `anthropic_messages` operation을 선언한다. 한 vendor가 두 protocol을 제공하면 별도 profile 또는 명시 capability로 표현하고 vendor 이름으로 protocol을 추정하지 않는다.
|
||||
- URL resolution: operation path가 절대 URL이면 그대로 사용하고 상대 path면 normalized base URL에 한 번만 결합한다. `/v1`, `/v1beta/openai`, `/api/paas/v4`, `/anthropic/v1` prefix는 문자열 suffix heuristic으로 추정하지 않고 profile operation path가 원문이다.
|
||||
- Messages auth: milestone 구현 시 기존 principal resolver를 추상화해 bearer와 `x-api-key`를 같은 IOP credential로 판정한다. Control Plane 원장 전환과 충돌 정책의 최종 소유자는 후속 credential-slot Milestone이다.
|
||||
- model discovery: 공식 Anthropic 요청에 필수인 `anthropic-version` header가 있는 `GET /v1/models`와 `/anthropic/v1/models`에는 Anthropic-compatible list/model shape를, header가 없는 일반 `/v1/models`에는 기존 OpenAI shape를 반환한다. 양쪽 모두 같은 internal model route snapshot을 사용하며 vendor/`User-Agent` 추정으로 schema를 선택하지 않는다.
|
||||
- Claude Code direct config: `ANTHROPIC_BASE_URL`은 Edge canonical root 또는 `/anthropic` compatibility mount를 가리키고, `ANTHROPIC_AUTH_TOKEN` 또는 `apiKeyHelper`가 반환한 IOP token을 principal auth에 사용한다. `Authorization`과 `X-Api-Key`가 함께 오면 같은 token이어야 한다.
|
||||
- Messages bridge input: top-level system, text/image content block, assistant content, tool definition, `tool_use`, `tool_result`, `tool_choice`, stop/max token, temperature와 profile capability가 선언한 thinking block을 Chat request로 변환한다. 변환 불가능한 block/option은 조용히 제거하지 않고 dispatch 전 `invalid_request_error`로 거부한다.
|
||||
- Anthropic version/beta headers: ingress는 지원하는 `anthropic-version`을 검증하고 알려진 `anthropic-beta` capability만 native upstream에 전달한다. Chat bridge가 의미를 구현하지 못하는 beta는 무시하지 않고 unsupported error로 거부한다.
|
||||
- count tokens: native upstream capability가 있으면 tunnel로 전달하고 Chat-only profile은 model profile에 등록된 deterministic counter/estimator를 사용한다. counter가 없으면 임의 provider 호출로 대체하지 않고 명시적인 unsupported error를 반환한다.
|
||||
- 출력:
|
||||
- native Messages tunnel은 status, content type, Anthropic SSE event/body 순서와 provider error body를 public allowlist 안에서 보존한다.
|
||||
- Chat bridge는 Chat text/reasoning/tool call/finish reason/usage/error를 Anthropic message object 또는 `message_start` → content block events → `message_delta` → `message_stop` 순서로 변환한다.
|
||||
- usage는 input/output/cache/reasoning 중 양쪽 protocol에 대응되는 필드만 보존하고 알 수 없는 값을 만들어내지 않는다.
|
||||
- profile qualification record는 provider/profile/model, official-doc revision 또는 확인일, smoke date, result와 sanitized failure만 저장한다.
|
||||
- Responses 보존:
|
||||
- `/v1/responses` route, `openai_responses` normalized/passthrough body/stream response와 `agent-client/pi` 소비는 현행 동작을 유지한다.
|
||||
- provider 공통 완료 판단은 Chat fixture와 profile이 선언한 Messages fixture를 기준으로 하며 Responses 지원이나 live smoke를 강제하지 않는다.
|
||||
- 금지:
|
||||
- vendor 이름 분기만으로 endpoint/path/protocol을 선택하거나 모든 type을 의미 없는 단일 `openai_compat` capability로 취급하지 않는다.
|
||||
- native Messages response를 불필요하게 JSON decode/re-encode하거나 Chat bridge에서 알 수 없는 content/tool block을 silently drop하지 않는다.
|
||||
- `agent-client/claude` gateway를 Claude Code → IOP production 호출의 필수 hop으로 남기지 않는다.
|
||||
- live provider credential을 fixture, tracked config, CI secret requirement와 qualification artifact에 남기지 않는다.
|
||||
|
||||
## Acceptance Scenarios
|
||||
|
||||
| ID | Milestone Task | Given | When | Then |
|
||||
|----|----------------|-------|------|------|
|
||||
| S01 | `profile-contract` | valid/invalid driver, base overlay, operation, auth와 legacy provider type config가 있음 | config load와 runtime normalization을 수행함 | valid overlay는 immutable concrete profile이 되고 cycle/conflict/invalid 조합은 거부되며 legacy alias는 같은 profile id로 수렴한다. |
|
||||
| S02 | `path-resolution` | `/v1`, `/v1beta/openai`, `/api/paas/v4`, `/anthropic/v1` base/path fixture가 있음 | operation URL을 resolve함 | prefix 중복/손실 없이 profile에 선언된 정확한 URL이 만들어진다. |
|
||||
| S03 | `profile-catalog` | OpenAI, Gemini, Anthropic, GLM, Kimi, MiniMax, MiMo, Grok와 Seulgi Chat/Messages built-in/custom profile fixture가 있음 | 각 operation의 admission과 request build를 실행함 | 선언한 operation만 허용되고 header/model/path가 provider fixture와 일치한다. |
|
||||
| S04 | `contract-sync` | protocol/config/wire 구현이 완료됨 | contract/spec drift check를 수행함 | public/inner contract와 spec index가 구현 source of truth를 정확히 가리킨다. |
|
||||
| S05 | `messages-surface` | `ANTHROPIC_BASE_URL`, auth token/helper, `anthropic-version`, models, Messages와 count-tokens 요청이 있음 | canonical root와 `/anthropic` mount를 `agent-client` 없이 Edge에 직접 요청함 | 동일 principal 인증과 명시적 Anthropic model schema 선택 뒤 native 또는 bridge 실행으로 진입한다. |
|
||||
| S06 | `messages-native` | native Messages non-stream/stream/error fixture가 있음 | raw tunnel로 요청함 | model/auth rewrite 외 body와 SSE ordering이 보존되고 terminal이 한 번만 발생한다. |
|
||||
| S07 | `messages-chat-bridge` | text/image/tool/thinking/usage/error Chat fixtures가 있음 | Messages↔Chat bridge를 왕복함 | 지원 의미는 Anthropic 계약으로 복원되고 미지원 block은 dispatch 전에 거부된다. |
|
||||
| S08 | `responses-regression` | 기존 Responses normalized/passthrough/provider-auth fixture가 있음 | 선택적 `openai_responses` profile/runtime test와 함께 실행함 | 기존 status/body/stream 의미와 Pi 소비 경로가 바뀌지 않는다. |
|
||||
| S09 | `fixture-suite` | 외부 network와 credential이 없는 test 환경임 | 전체 provider contract suite를 실행함 | 모든 deterministic profile test가 구독 없이 반복 통과한다. |
|
||||
| S10 | `live-smoke` | 구현 중인 profile의 opt-in credential과 대표 model 1개가 제공됨 | 한정 live smoke를 수동 실행함 | sanitized qualification record가 남고 일반 CI에는 live 의존성이 생기지 않는다. |
|
||||
|
||||
## Evidence Map
|
||||
|
||||
| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|
||||
|----------|-------------------|------------------|---------------------------|
|
||||
| S01-S03 | config validation, URL resolver와 provider request golden tests | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `profile-contract`, `path-resolution`, `profile-catalog` Task id와 provider별 table result |
|
||||
| S04 | contract/spec index check와 implementation path search | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `contract-sync` Task id와 drift 없음 근거 |
|
||||
| S05-S07 | Claude Code request fixture, native tunnel bytes/SSE와 Messages↔Chat golden tests | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `messages-surface`, `messages-native`, `messages-chat-bridge` Task id별 direct Edge evidence |
|
||||
| S08 | 기존 Responses route/stream/provider-auth regression suite | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `responses-regression` Task id와 기존 test 통과 근거 |
|
||||
| S09 | credential-free full provider fixture suite | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `fixture-suite` Task id와 network-disabled test 결과 |
|
||||
| S10 | opt-in one-shot command와 sanitized qualification record | `agent-task/m-multi-provider-protocol-profile-native-messages/...` | `live-smoke` Task id, provider/profile/model/date/result; secret 없음 |
|
||||
|
||||
## Cross-repo Dependencies
|
||||
|
||||
- 없음
|
||||
|
||||
## Drift Check
|
||||
|
||||
- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
|
||||
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
|
||||
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
|
||||
- [x] 사용자 리뷰가 필요한 항목은 `USER_REVIEW.md`에만 남겼다.
|
||||
|
||||
## 사용자 리뷰 이력
|
||||
|
||||
- 2026-07-31: 사용자가 Chat Completions 공통 기준, Edge의 Anthropic Messages 직접 흡수, Responses 현행 유지와 구현 시점 한정 smoke를 확정했다.
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 표준선: protocol driver는 wire/stream semantics를, provider profile은 endpoint/path/auth/model/capability 차이를 소유한다. 공통 profile로 표현할 수 없는 검증된 차이만 extension hook으로 추가한다.
|
||||
- 후속 SDD: [SDD.md](../principal-provider-credential-slot-routing/SDD.md)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
# SDD: 사용자별 Provider Credential Slot과 Alias Routing
|
||||
|
||||
## 위치
|
||||
|
||||
- Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md)
|
||||
- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md)
|
||||
|
||||
## 상태
|
||||
|
||||
[승인됨]
|
||||
|
||||
## SDD 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 사용자 리뷰: 없음
|
||||
- 잠금 항목: 없음
|
||||
|
||||
## 문제 / 비목표
|
||||
|
||||
- 문제: 현재 IOP bearer identity는 Edge YAML의 `openai.principal_tokens[]` hash mapping이 원장이고, 외부 provider token은 caller가 `X-IOP-Provider-Authorization` header로 매번 전달한다. 이 구조는 Control Plane이 사용자와 provider credential을 소유하지 않으며, 한 사용자가 같은 vendor/model의 여러 token을 독립 slot과 alias로 관리하거나 Claude Code가 IOP token만으로 직접 호출할 수 없게 한다.
|
||||
- 비목표:
|
||||
- 여러 token slot의 자동 rotation, round-robin, failover 또는 quota 최적화
|
||||
- 여러 vendor를 한 model alias 뒤에서 자동 대체하는 routing policy
|
||||
- 조직 역할 기반 IAM, billing/chargeback, provider credential marketplace
|
||||
- 모든 provider 계정의 상시 구독과 정기 live smoke
|
||||
|
||||
## Source of Truth
|
||||
|
||||
| 영역 | 기준 | 메모 |
|
||||
|------|------|------|
|
||||
| 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 |
|
||||
| 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 입력 |
|
||||
| User Decision | 2026-07-31 사용자 대화 | Control Plane ownership, 사용자/vendor별 multi-token slot, optional alias, IOP token 기반 호출, Seulgi 포함, implicit rotation 없음 |
|
||||
|
||||
## State Machine
|
||||
|
||||
| 상태 | 진입 조건 | 다음 상태 | 근거 |
|
||||
|------|-----------|-----------|------|
|
||||
| iop-token/issued | principal에 새 IOP token을 발급하고 hash만 commit함 | iop-token/active | one-time raw token 반환과 token revision |
|
||||
| iop-token/active | active hash가 유효 projection에 포함됨 | iop-token/revoked / iop-token/expired | Control Plane token lifecycle |
|
||||
| iop-token/revoked | revoke revision이 commit됨 | 없음 | 이후 projection/인증에서 제거, 재활성화 대신 재발급 |
|
||||
| slot/draft | principal이 vendor/profile/secret/model binding을 등록함 | slot/active / slot/rejected | alias, key, profile, binding validation |
|
||||
| slot/active | encrypted secret revision과 한 개 이상의 valid binding이 있음 | slot/disabled / slot/rotated / slot/revoked | slot lifecycle command |
|
||||
| slot/rotated | 새 ciphertext revision이 commit됨 | slot/active | 이전 lease는 만료 또는 revision rejection으로 수렴 |
|
||||
| slot/disabled | 운영자가 일시 중지함 | slot/active / slot/revoked | 새 route/lease 발급 차단, 명시 re-enable 가능 |
|
||||
| slot/revoked | slot을 영구 폐기함 | 없음 | route와 새 lease 제거 |
|
||||
| projection/fresh | Edge가 더 큰 generation의 signed/authorized projection을 적용함 | projection/fresh / projection/stale | expiry와 generation order |
|
||||
| projection/stale | expiry 전 refresh에 실패하거나 expiry가 지남 | projection/fresh / request/rejected | expiry 뒤 CP-managed principal auth/route fail closed |
|
||||
| request/authenticated | inbound IOP token이 fresh projection의 principal과 매칭됨 | request/route-resolved / request/rejected | request model과 principal-scoped route catalog |
|
||||
| request/route-resolved | route id/alias가 정확히 한 slot, protocol profile과 upstream model을 가리킴 | request/lease-ready / request/rejected | active slot/binding/revision과 provider resource selector |
|
||||
| request/lease-ready | authenticated confidential channel에서 받은 bounded credential lease가 valid함 | request/dispatched / request/rejected | principal/slot/route/target/revision/expiry validation |
|
||||
| request/dispatched | adapter가 실행 직전에 secret을 주입함 | request/terminal | upstream response, cancel, timeout 또는 error |
|
||||
|
||||
## 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`에 연결한다.
|
||||
- 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과 매칭한다.
|
||||
- `provider_credential_slot`: stable slot id, principal ref, optional user alias, vendor, credential kind, encrypted typed secret material, secret/key revision, status와 timestamps를 가진다. slot은 protocol profile이나 model을 직접 소유하지 않는다.
|
||||
- `provider_model_binding`: stable route id, slot id, provider profile id, upstream model, optional route alias, provider resource selector, capability/allowlist와 status를 가진다. binding profile의 vendor/auth declaration이 slot의 vendor/credential kind와 호환되어야 하며, 한 slot은 Chat/Messages를 포함한 여러 compatible profile/model binding을 가질 수 있고 같은 upstream model은 서로 다른 slot의 route로 각각 존재할 수 있다.
|
||||
- alias uniqueness: slot alias는 principal 안에서 유일하다. client `model` 선택에 쓰는 route id/route alias도 principal 안에서 유일해야 하며 중복 또는 다의적 해석은 저장/활성화 단계에서 fail closed한다. single-model slot은 slot alias를 route alias로 직접 쓸 수 있고 multi-model slot은 각 binding의 고유 route id/alias를 사용한다.
|
||||
- Control Plane management:
|
||||
- host-local Control Plane operator CLI가 principal과 최초 IOP token을 bootstrap한다. 이 CLI는 Control Plane host의 deployment admin 권한과 DB/service boundary 안에서만 실행하며 unauthenticated remote admin endpoint를 만들지 않는다.
|
||||
- 이후 principal은 IOP token으로 인증해 자신의 추가 token ref, credential slot, model binding과 alias를 create/list/update/rotate/disable/revoke한다. provider raw secret은 create/rotate 입력에서만 받고 이후 list/get 응답에는 secret, ciphertext와 token digest를 반환하지 않는다.
|
||||
- operator의 secret-blind disable/revoke/recovery는 host-local CLI로 제한하고 raw provider secret 조회/reveal operation은 제공하지 않는다. 마지막 active IOP token 폐기처럼 principal의 자기 접근을 끊는 operation은 명시 확인을 요구하되 조직 RBAC와 세부 remote operator role model은 이 Milestone 범위가 아니다.
|
||||
- mutation은 expected revision을 받아 stale update를 conflict로 거부하고, alias/binding validation과 encrypted secret commit이 모두 성공한 뒤 새 revision을 publish한다.
|
||||
- Secret at rest:
|
||||
- provider secret은 authenticated encryption envelope의 ciphertext, nonce, key id/version과 AAD metadata만 DB에 저장한다.
|
||||
- master/envelope key material은 deployment secret manager 또는 동등한 외부 secret source가 제공하고 tracked YAML, DB와 API payload에 저장하지 않는다. key source가 없으면 slot secret 생성/rotation/활성화를 거부한다.
|
||||
- Edge projection:
|
||||
- projection은 generation, issued/expiry time, active IOP token hash→principal mapping, principal별 route/slot reference, profile/upstream model과 status revision만 포함한다. provider ciphertext/plaintext와 encryption key를 포함하지 않는다.
|
||||
- Edge는 더 큰 generation만 atomic apply하고 bounded memory cache를 사용한다. refresh 실패 중에도 expiry 전 projection은 사용할 수 있지만 expiry 뒤 CP-managed principal 인증/선택은 identity projection unavailable typed error로 fail closed한다. health와 별도 Edge-local admin auth 표면은 이 projection에 종속시키지 않는다.
|
||||
- Inbound auth:
|
||||
- OpenAI Chat/Responses는 `Authorization: Bearer <IOP token>`을 사용한다. Anthropic Messages는 같은 bearer 또는 `x-api-key: <IOP token>`을 허용해 Claude Code의 API-key helper와 직접 연결한다.
|
||||
- bearer와 `x-api-key`가 동시에 있으면 두 값이 같은 active token이어야 한다. 불일치, unknown, disabled 또는 revoked token은 route/model lookup과 provider dispatch 전에 `401`로 종료한다.
|
||||
- caller metadata/user field와 caller-supplied provider token은 principal 또는 slot 선택 source가 아니다.
|
||||
- Route and alias resolution:
|
||||
- public request의 `model`은 인증 principal의 canonical route id 또는 unique route alias만 해석한다. slot alias는 model binding의 route alias 생성/표시에 사용할 수 있지만 실행 시 항상 하나의 concrete route id, slot id, protocol profile id와 upstream model로 고정된다.
|
||||
- `/v1/models`의 OpenAI/Anthropic response variant는 그 principal의 active binding만 반환한다. 다른 principal, disabled/revoked slot과 expired projection의 route는 숨긴다.
|
||||
- binding의 provider resource selector는 기존 Edge provider pool 안에서 같은 profile/model을 실행할 Node/provider resource 후보를 제한한다. capacity/load 기반 실행 위치 선택은 동일 credential slot을 유지하며 token slot rotation으로 취급하지 않는다.
|
||||
- 같은 vendor/model의 `claude-1`, `claude-2` route가 있으면 요청된 route의 slot만 사용한다. quota/auth/provider failure가 발생해도 다른 slot 또는 vendor로 자동 전환하지 않는다.
|
||||
- Secure credential delivery:
|
||||
- provider secret을 입력·운반하는 Client-Control Plane, Control Plane-Edge와 Edge-Node 연결은 server identity verification과 전송 기밀성을 제공해야 한다. system peer는 enrollment-bound identity로 상호 인증하고 principal client는 TLS 위에서 IOP token으로 인증한다. 현재 평문 TCP/WS 연결은 credential-bearing operation에 사용할 수 없다.
|
||||
- Edge는 route resolution 뒤 Control Plane에서 principal/slot/secret revision/route/target/expiry에 묶인 짧은 credential lease를 받고, 동일 scope와 revision 안에서만 bounded memory cache를 사용할 수 있다. Control Plane availability가 없고 유효 lease도 없으면 cloud dispatch를 거부한다.
|
||||
- credential lease는 wire의 dedicated sensitive payload로 구분하고 generic `headers`, metadata, config refresh, status snapshot과 event payload에 raw secret을 싣지 않는다. transport/debug interceptor도 sensitive payload body를 기록하지 않는다.
|
||||
- adapter는 request 실행 직전에 request-local lease secret을 provider profile의 auth header로 주입하고 terminal/cancel 뒤 보존하지 않는다. 관측에는 slot ref와 secret revision만 허용한다.
|
||||
- slot disable/revoke/rotation projection을 받은 뒤 새 lease와 새 dispatch를 차단한다. 이미 upstream에 dispatch된 요청은 강제 replay/cancel하지 않지만 그 lease는 새 attempt/retry에 재사용하지 않는다.
|
||||
- Attribution:
|
||||
- route resolution 결과의 `credential_slot_ref`와 `credential_revision`은 request 동안 immutable dispatch binding으로 유지한다. 기존 `token_ref`는 inbound IOP token을 뜻하므로 provider credential slot 식별자로 재사용하지 않는다.
|
||||
- provider usage/실행 관측은 safe stable slot ref로 분리 집계할 수 있지만 user alias, raw secret, verifier/ciphertext와 lease id는 metric label에 넣지 않는다.
|
||||
- Responses compatibility:
|
||||
- credential plane 활성 뒤 기존 Responses도 같은 principal route와 credential resolver를 사용하지만 Responses request/response/stream schema는 변경하지 않는다.
|
||||
- Compatibility migration:
|
||||
- credential plane이 명시적으로 비활성인 배포만 기존 Edge `openai.principal_tokens[]`와 request-time `openai.provider_auth`를 사용할 수 있다.
|
||||
- credential plane 활성 시 Control Plane projection이 유일한 identity/slot 원장이다. legacy mapping과 충돌하면 병합하거나 우선순위를 추정하지 않고 startup/apply를 거부하며 caller provider-auth header는 무시가 아니라 명시적으로 거부한다.
|
||||
- IOP bearer token을 upstream provider credential로 재사용하지 않는다.
|
||||
- 금지:
|
||||
- provider raw token, encryption key 또는 runtime auth header를 tracked config, generic protobuf map, status/error body, log, metric, trace와 qualification record에 남기지 않는다.
|
||||
- slot alias만 보고 vendor/model을 추정하거나 같은 model의 다른 slot으로 암묵적으로 회전하지 않는다.
|
||||
- stale/out-of-order projection이나 만료/변조/다른 target용 lease로 dispatch하지 않는다.
|
||||
|
||||
## Acceptance Scenarios
|
||||
|
||||
| ID | Milestone Task | Given | When | Then |
|
||||
|----|----------------|-------|------|------|
|
||||
| S01 | `principal-store` | operator bootstrap과 신규 principal의 IOP token 발급/폐기 요청이 있음 | Control Plane restart를 포함해 lifecycle을 실행함 | raw token은 한 번만 반환되고 SHA-256 digest/revision만 영속화되며 폐기 token은 복구되지 않는다. |
|
||||
| S02 | `auth-projection` | fresh, stale, expired, revoked와 out-of-order projection이 있음 | Edge가 refresh와 인증을 수행함 | 더 큰 fresh generation만 atomic apply되고 expiry/revocation 뒤 CP-managed 외부 호출은 fail closed한다. |
|
||||
| S03 | `surface-auth` | bearer, x-api-key, 동시 일치/불일치 token이 있음 | OpenAI/Anthropic ingress를 호출함 | 같은 principal 인증만 성공하고 실패는 provider/model 조회 전에 401로 끝난다. |
|
||||
| S04 | `slot-store` | 한 principal의 같은 vendor에 두 provider token/alias와 한 token의 Chat/Messages profile 사용이 있음 | slot 생성/rotation/disable/revoke를 실행함 | credential은 protocol과 분리된 stable slot/revision으로 저장되고 compatible profile 재사용만 허용되며 secret은 ciphertext만 남고 충돌 alias는 거부된다. |
|
||||
| S05 | `model-binding` | 같은 upstream Claude model을 쓰는 `claude-1`, `claude-2` slot과 multi-profile/model slot이 있음 | route/binding을 활성화하고 lookup함 | 각 route가 정확히 한 slot/profile/model로 수렴하고 multi-profile/model binding도 독립 route id로 선택된다. |
|
||||
| S06 | `model-discovery` | 서로 다른 route 권한을 가진 두 principal이 있음 | OpenAI/Anthropic model list를 요청함 | 각 principal은 자신의 active route만 보고 Claude Code가 반환 alias/route를 선택할 수 있다. |
|
||||
| S07 | `explicit-selection` | 같은 model에 두 active slot이 있고 하나가 quota/auth 실패함 | 첫 slot route로 요청함 | 요청 slot만 한 번 사용되고 다른 slot/vendor로 암묵적 fallback하지 않는다. |
|
||||
| S08 | `credential-management` | host-local operator bootstrap과 principal create/list/update/rotate/disable/revoke 요청이 있음 | CLI와 Control Plane management operation을 실행함 | remote bootstrap은 없고 principal 범위/revision이 강제되며 secret은 입력 뒤 조회/로그에 반환되지 않는다. |
|
||||
| S09 | `secret-at-rest` | provider token 저장, key rotation과 restart가 있음 | DB/API/log를 검사하고 decrypt fixture를 수행함 | ciphertext와 safe metadata만 저장되며 올바른 key revision만 복호화된다. |
|
||||
| S10 | `secure-transport` | TLS identity가 올바르거나 없거나 다른 peer인 Client/Edge/Node 연결이 있음 | credential-bearing operation과 cloud dispatch를 시도함 | 인증·기밀 연결만 허용되고 평문/잘못된 peer에서는 secret을 보내기 전에 차단된다. |
|
||||
| S11 | `credential-lease` | valid lease와 다른 principal/route/target, expired/revoked/tampered lease가 있음 | Edge/Node 실행 경계가 검증함 | valid scope/revision만 dedicated sensitive payload로 전달되고 나머지는 upstream 호출 전에 거부된다. |
|
||||
| S12 | `adapter-injection` | valid Chat/Messages profile과 credential lease가 있음 | provider fixture endpoint를 호출함 | 기대 auth header만 upstream에 도달하고 wire debug/log/status/response에는 raw secret이 없다. |
|
||||
| S13 | `revocation` | in-flight 요청과 아직 dispatch되지 않은 요청 중 slot revoke/rotation이 도착함 | 새 projection을 적용함 | in-flight는 기존 attempt만 terminal까지 가고 새 lease/dispatch/retry는 새 revision 없이는 차단된다. |
|
||||
| S14 | `compat-migration` | legacy-only와 credential-plane-enabled config가 있음 | load/migrate/rollback을 실행함 | legacy-only는 유지되고 enabled mode는 CP만 원장으로 사용하며 dual-source 충돌은 거부되고 Responses schema는 유지된다. |
|
||||
| S15 | `slot-attribution` | 같은 principal/model을 서로 다른 credential slot으로 호출함 | dispatch와 provider usage를 관측함 | 별도 `credential_slot_ref`로 분리 귀속되고 inbound `token_ref`와 alias/raw secret이 섞이지 않는다. |
|
||||
| S16 | `slot-smoke` | deterministic Seulgi/vendor fixture와 opt-in 대표 provider credential 1개가 있음 | 일반 CI와 구현 시 one-shot E2E를 각각 수행함 | CI는 구독 없이 통과하고 live evidence에는 safe slot ref/revision/result만 남는다. |
|
||||
| S17 | `contract-ops` | persistence/management/secure wire/auth 구현이 완료됨 | contract/spec/redaction runbook drift check를 수행함 | index와 계약이 구현 경계를 가리키고 raw secret 예시가 없다. |
|
||||
|
||||
## Evidence Map
|
||||
|
||||
| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|
||||
|----------|-------------------|------------------|---------------------------|
|
||||
| S01-S03 | CP repository lifecycle, projection generation/expiry와 dual-header ingress tests | `agent-task/m-principal-provider-credential-slot-routing/...` | `principal-store`, `auth-projection`, `surface-auth` Task id별 persistence/auth 결과 |
|
||||
| S04-S08 | multi-slot, alias collision, multi-model binding, principal discovery/no-fallback와 management authorization tests | `agent-task/m-principal-provider-credential-slot-routing/...` | `slot-store`, `model-binding`, `model-discovery`, `explicit-selection`, `credential-management` Task id별 isolation 근거 |
|
||||
| S09-S13 | encrypted-store inspection, TLS peer matrix, credential lease scope, upstream header와 revocation race tests | `agent-task/m-principal-provider-credential-slot-routing/...` | `secret-at-rest`, `secure-transport`, `credential-lease`, `adapter-injection`, `revocation` Task id와 secret scan 결과 |
|
||||
| S14 | legacy/CP mode config and migration table tests | `agent-task/m-principal-provider-credential-slot-routing/...` | `compat-migration` Task id와 dual-source rejection/Responses regression 근거 |
|
||||
| S15 | two-slot dispatch/usage attribution test와 metric label allowlist check | `agent-task/m-principal-provider-credential-slot-routing/...` | `slot-attribution` Task id, slot별 usage와 inbound token ref 분리 근거 |
|
||||
| S16 | credential-free provider fixtures와 opt-in representative one-shot record | `agent-task/m-principal-provider-credential-slot-routing/...` | `slot-smoke` Task id, provider/model/safe slot ref/date/revision/result |
|
||||
| S17 | contract/spec index check와 repository-wide credential leak scan | `agent-task/m-principal-provider-credential-slot-routing/...` | `contract-ops` Task id, drift 없음과 raw secret 미검출 근거 |
|
||||
|
||||
## Cross-repo Dependencies
|
||||
|
||||
- 없음
|
||||
|
||||
## Drift Check
|
||||
|
||||
- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
|
||||
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
|
||||
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
|
||||
- [x] 사용자 리뷰가 필요한 항목은 `USER_REVIEW.md`에만 남겼다.
|
||||
|
||||
## 사용자 리뷰 이력
|
||||
|
||||
- 2026-07-31: 사용자가 Control Plane credential ownership, 사용자/vendor별 multi-token slot, optional alias, IOP token 기반 호출, Seulgi 포함과 implicit rotation 제외를 확정했다.
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 표준선: Control Plane DB가 identity/credential metadata의 원장이고 Edge는 secret-free projection을 소비한다. credential-bearing management와 runtime 경로는 authenticated confidential transport를 전제로 하며 실행 target은 scope/revision/expiry가 제한된 request-local lease만 사용한다. Edge-local provider health/capacity/runtime state의 원장은 계속 Edge다.
|
||||
- 후속 SDD: 없음
|
||||
Loading…
Reference in a new issue