update agent-spec templates and skills, add agent-spec dir

This commit is contained in:
toki 2026-07-07 11:08:25 +09:00
parent f7dcf9118e
commit ae243a03c1
11 changed files with 697 additions and 46 deletions

View file

@ -4,7 +4,7 @@
## 목적
`agent-spec/`AI agent가 현재 구현된 기능의 동작, 책임 경계, 코드 진입점, 계약 링크, 검증 방법을 빠르게 파악하기 위한 living spec 저장소다.
`agent-spec/`사람과 AI agent가 현재 구현된 기능 목록, 동작 흐름, 계약 링크, 검증 방법을 함께 파악하기 위한 living spec 저장소다.
로드맵 완료 이력, SDD 설계 논의, 계약 원문, 사람용 가이드를 대체하지 않는다.
## 기본 구조
@ -28,9 +28,11 @@ agent-spec/
- `agent-spec/**`는 현재 구현 지도를 제공하지만 최종 truth는 코드, `agent-contract/`, 테스트, 설정 예시다.
- API, wire protocol, runtime call, event/config schema, 프로세스 간 요청/응답 계약 원문은 `agent-contract/`에 두고 agent-spec에는 링크와 사용 맥락만 남긴다.
- 코드 배치, 주요 구성 요소, 구현 진입점, 도메인 간 책임 경계, 유지할 패턴, 금지 사항은 domain rule에 둔다.
- agent-spec에는 기능 이해에 필요한 최소 경계만 적고, 코딩할 때 따라야 하는 경계 규칙을 반복하지 않는다.
- SDD는 구현 전 설계 게이트다. agent-spec은 구현 후 현재 상태를 설명한다.
- 로드맵과 complete.log는 완료 근거와 변경 힌트로 사용한다. 현재 동작은 코드와 계약으로 재확인한다.
- 사람용 최신 가이드는 `docs/`에 둔다. agent-spec은 agent 작업 문맥을 우선한다.
- 사람용 최신 가이드는 `docs/`에 둔다. agent-spec은 기능 파악과 작업 문맥을 우선한다.
## Frontmatter Schema
@ -51,10 +53,11 @@ agent-spec/
## 읽기 규칙
- 일반 작업마다 `agent-spec/`를 읽지 않는다.
- 기존 기능의 현재 동작, 책임 경계, 코드 진입점, 계약 링크가 필요한 작업에서만 세션 1회 `agent-spec/index.md`를 읽는다.
- 기존 기능의 기능 목록, 주요 흐름, 계약 링크, 현재 구현 상태가 필요한 작업에서만 세션 1회 `agent-spec/index.md`를 읽는다.
- `index.md`에서 매칭되는 spec 문서만 읽는다.
- 매칭 spec이 없으면 스펙이 없다고 보고하고 코드, 계약, 테스트에서 직접 확인한다. 추측으로 spec 내용을 만들지 않는다.
- spec 문서가 코드/계약과 충돌하면 코드/계약을 우선하고 `update-spec` 필요를 보고한다.
- 코드 배치, 구현 위치, 패턴, 금지 사항, 도메인 간 상세 책임 경계가 필요하면 프로젝트 규칙의 도메인 매핑에 따라 domain rule을 읽는다.
- API, wire protocol, runtime call, event/config schema, 프로세스 간 요청/응답 계약에 닿으면 `agent-contract/index.md`의 규칙에 따라 매칭 계약 문서도 읽는다.
- `agent-spec/archive/**`는 일반 작업에서 읽지 않는다.
- 예외: 사용자가 과거 스펙 확인, 복원, 비교, 특정 archive 경로 확인을 요청한 경우에만 필요한 archive 문서만 좁게 읽는다.
@ -73,26 +76,31 @@ agent-spec/
- 현재형으로 작성한다.
- 과거 작업 일지, 설계 논쟁 전문, 완료된 roadmap task 전체 복사, 함수 단위 코드 설명을 넣지 않는다.
- 스펙 본문은 기능 단위의 작동 지도여야 한다.
- 스펙 본문은 기능 단위의 작동 지도여야 한다. 먼저 기능 목록을 두고, 필요한 흐름만 뒤에 보강한다.
- 기능 목록은 `기능``설명` 중심으로 작성한다. 활성 spec은 구현된 기능만 기록하므로 기능별 `상태` 칼럼을 기본으로 두지 않는다.
- 기능별 부분 지원, 조건부 동작, 한계는 설명 또는 `한계와 주의사항`에 짧게 적는다.
- 주요 흐름은 텍스트만 길게 나열하지 말고 Mermaid `sequenceDiagram` 또는 `flowchart`를 우선 고려한다. 단순 기능은 짧은 목록으로 충분하다.
- 책임 경계는 기능 오해를 막는 최소 수준만 허용한다. 패키지 배치, 구현 진입점, 유지할 패턴, 금지 사항은 domain rule에 둔다.
- `코드 진입점` 섹션은 기본 섹션으로 두지 않는다. 필요한 코드 근거는 frontmatter `source_evidence`와 domain rule로 좁힌다.
- 계약 원문, proto field 전체 목록, config schema 원문을 복제하지 말고 `agent-contract/` 또는 코드 경로를 링크한다.
- 불확실한 내용은 단정하지 말고 `불명확` 또는 `확인 필요`로 남긴다.
- spec 갱신이 필요 없으면 `Spec update not needed: <사유>`를 결과 보고나 Milestone 완료 리뷰에 남긴다.
## 표준 섹션
## 기본 섹션
spec 문서는 아래 섹션 순서를 유지한다.
spec 문서는 아래 섹션을 기본 순서로 작성한다. 해당 spec에 의미가 없는 섹션은 만들지 않는다.
1. `목적`
2. `현재 동작`
2. `기능 목록`
3. `범위`
4. `주요 흐름`
5. `책임 경계`
6. `계약`
7. `코드 진입점`
8. `설정/데이터/이벤트`
9. `검증`
10. `한계와 주의사항`
11. `변경 기록`
5. ``
6. `설정/데이터/이벤트`
7. `검증`
8. `한계와 주의사항`
9. `변경 기록`
`책임 경계`가 기능 이해에 꼭 필요하면 별도 섹션으로 짧게 둘 수 있다. 이때 domain rule의 구성 요소, 코드 배치, 금지 사항을 반복하지 않는다.
## 템플릿

View file

@ -3,11 +3,11 @@ spec_doc_type: index
status: 활성
---
# Agent Spec Index
# 구현 스펙 색인
## 목적
이 디렉터리는 현재 구현 기능의 agent-facing living spec을 관리한다.
이 디렉터리는 사람과 agent가 함께 보는 현재 구현 기능 living spec을 관리한다.
로드맵 완료 이력, SDD, 계약 원문, 사람용 docs를 대체하지 않는다.
## 읽기 규칙
@ -15,16 +15,19 @@ status: 활성
- 필요한 작업에서만 이 index를 읽고, 매칭되는 spec 문서만 읽는다.
- `archive/**`는 과거 비교, 복원, 특정 근거 확인 요청이 있을 때만 읽는다.
- API, wire protocol, config/event schema, 프로세스 간 계약 원문은 `agent-contract/`를 따른다.
- 코드 배치, 구현 진입점, 도메인 간 상세 책임 경계는 domain rule을 따른다.
## Spec Map
| id | 상태 | 읽는 조건 | path | 주요 evidence |
|----|------|-----------|------|---------------|
| id | 상태 | 언제 읽나 | path | 주요 근거 |
|----|------|-----------|------|-----------|
| 없음 | 없음 | 없음 | 없음 | 없음 |
## 작성 규칙
- 현재 구현 기준으로 작성한다.
- 기능 목록과 주요 흐름을 먼저 파악할 수 있게 작성한다.
- 코드/계약/테스트 evidence를 우선한다.
- 계약 원문은 복제하지 않고 링크한다.
- 코드 진입점과 도메인룰 성격의 상세 경계는 반복하지 않는다.
- 불확실한 내용은 `불명확`으로 남긴다.

View file

@ -8,15 +8,17 @@ source_evidence:
notes: <현재 구현 근거>
---
# Spec: <title>
# 스펙: <title>
## 목적
< spec이 설명하는 현재 구현 기능과 agent가 문서를 읽어야 하는 이유>
< spec이 설명하는 현재 구현 기능과 문서를 읽어야 하는 이유>
## 현재 동작
## 기능 목록
- <현재 코드와 계약으로 확인된 동작>
| 기능 | 설명 |
|------|------|
| <기능명> | <현재 코드와 계약으로 확인된 동작> |
## 범위
@ -25,31 +27,28 @@ source_evidence:
## 주요 흐름
1. <주요 실행 흐름>
## 책임 경계
- <컴포넌트/프로세스/계층별 책임 경계>
```mermaid
sequenceDiagram
participant A as <주체>
participant B as <주체>
A->>B: <주요 메시지 또는 동작>
```
## 계약
- <관련 agent-contract 문서 또는 없음>
## 코드 진입점
- `<path>` - <역할>
- <관련 agent-contract 문서 또는 코드 계약 포인터>
## 설정/데이터/이벤트
- <관련 config, 저장소, event, runtime state 요약. 원문 schema는 링크만 .>
- <관련 config, 저장소, event, runtime state 요약. 원문 schema는 복제하지 않는다.>
## 검증
- `<command or profile>` - <기대 결과 또는 근거>
- `<command or profile>` - <기대 결과>
## 한계와 주의사항
- <현재 구현 한계, known limitation, 수정 주의점>
- <현재 구현 한계 또는 조건부 동작>
## 변경 기록

View file

@ -8,8 +8,8 @@ description: agent-spec 최초 생성, 현재 구현 스펙 작성, living spec
## 목적
현재 구현된 기능의 agent-facing living spec을 새로 만든다.
스펙은 로드맵 완료 이력이나 계약 원문을 복제하지 않고, agent가 작업 전에 현재 동작과 코드 진입점을 빠르게 찾는 지도로 유지한다.
현재 구현된 기능의 living spec을 새로 만든다.
스펙은 로드맵 완료 이력이나 계약 원문을 복제하지 않고, 사람과 agent가 구현된 기능, 동작 흐름, 계약/검증 포인터를 함께 확인하는 문서로 유지한다.
## 언제 호출할지
@ -55,14 +55,19 @@ description: agent-spec 최초 생성, 현재 구현 스펙 작성, living spec
- 기존 같은 `spec-id` 문서가 있으면 새로 만들지 말고 `update-spec` 대상이라고 보고한다.
4. **spec 문서 작성**
- spec template의 표준 섹션 순서를 유지한다.
- spec template의 기본 섹션 구조를 따른다.
- frontmatter의 `spec_doc_type`, `spec_id`, `status`, `source_evidence`를 채운다.
- `status`는 evidence 수준에 따라 `구현됨`, `부분`, `가정`, `불명확` 중 하나로 둔다.
- `기능 목록``목적` 다음에 바로 둔다.
- 기능 목록은 `기능``설명` 중심으로 작성한다. 기능별 `상태` 칼럼은 기본 생성하지 않는다.
- `주요 흐름`은 Mermaid `sequenceDiagram` 또는 `flowchart`를 우선 고려한다. 단순 기능은 짧은 목록으로 둔다.
- 책임 경계는 기능 이해에 필요한 최소 수준만 적고, 도메인별 코드 배치나 금지 사항은 domain rule로 넘긴다.
- 계약 원문, proto field 전체 목록, config schema 원문은 복제하지 않고 링크한다.
- 주요 코드 진입점과 검증 방법을 경로와 명령으로 남긴다.
- `코드 진입점` 섹션은 만들지 않는다. 코드 근거는 `source_evidence`에 남긴다.
- 검증 방법은 실행 가능한 명령 또는 확인 기준으로 남긴다.
5. **index 갱신**
- `Spec Map`에 새 spec id, 상태, 읽는 조건, path, 주요 evidence를 추가하거나 보정한다.
- `Spec Map`에 새 spec id, 상태, 읽는 조건, path, 주요 근거를 추가하거나 보정한다.
- 매칭 조건은 agent가 좁게 읽을 수 있도록 기능명, 코드 경로, 계약 id, 운영 표면 중심으로 쓴다.
- 기존 행을 삭제하거나 재정렬하지 않는다. 명백히 placeholder인 `없음` 행은 첫 실제 spec 추가 시 제거할 수 있다.
@ -73,7 +78,9 @@ description: agent-spec 최초 생성, 현재 구현 스펙 작성, living spec
## 실행 결과 검증
- [ ] `agent-spec/index.md`가 존재하고 Spec Map에 생성한 spec이 들어 있는가
- [ ] 생성한 spec 문서가 `rules-agent-spec.md`의 표준 섹션 순서를 유지하는가
- [ ] 생성한 spec 문서가 `rules-agent-spec.md`의 기본 섹션 기준을 따르는가
- [ ] 기능 목록이 기능/설명 중심이며 불필요한 상태 칼럼이나 과한 상세 설명을 만들지 않았는가
- [ ] 코드 진입점, 패키지 배치, 도메인별 금지 사항을 spec 본문에 반복하지 않았는가
- [ ] frontmatter의 `spec_doc_type`, `spec_id`, `status`, `source_evidence`가 채워졌는가
- [ ] source evidence path가 실제 파일이거나 `path: null`인 사용자 근거인가
- [ ] 계약 원문을 복제하지 않고 `agent-contract/` 또는 코드 링크로 연결했는가
@ -91,7 +98,7 @@ description: agent-spec 최초 생성, 현재 구현 스펙 작성, living spec
- [index.md](agent-spec/index.md)
- [<spec-id>.md](agent-spec/<area>/<spec-id>.md)
- 상태: <구현됨 | 부분 | 가정 | 불명확>
- 주요 evidence:
- 주요 근거:
- <path 또는 사용자 근거> - <요약>
## TODO 항목
@ -105,5 +112,6 @@ description: agent-spec 최초 생성, 현재 구현 스펙 작성, living spec
- 현재 코드/계약으로 확인하지 않은 내용을 구현 사실처럼 쓰지 않는다.
- archive 전체를 훑지 않는다.
- 기존 spec이 있으면 중복 spec을 만들지 않는다.
- 코드 진입점, 구현 배치, 도메인 간 상세 책임 경계, 유지할 패턴, 금지 사항을 domain rule 대신 agent-spec에 길게 쓰지 않는다.
- 사람용 공개 가이드를 agent-spec에 장황하게 작성하지 않는다.
- spec 생성과 무관한 코드 파일을 수정하지 않는다.

View file

@ -50,7 +50,9 @@ description: agent-spec 갱신, 구현 스펙 업데이트, 완료 기능 스펙
- spec과 코드/계약이 충돌하면 코드/계약을 우선하고 spec을 수정한다.
3. **영향 판정**
- 현재 동작, 범위, 주요 흐름, 책임 경계, 계약 링크, 코드 진입점, 설정/데이터/이벤트, 검증, 한계 중 바뀐 항목을 식별한다.
- 기능 목록, 범위, 주요 흐름, 계약 링크, 설정/데이터/이벤트, 검증, 한계 중 바뀐 항목을 식별한다.
- 기능 이해에 필요한 최소 책임 설명이 바뀐 경우만 spec에 반영한다.
- 코드 배치, 구현 진입점, 유지할 패턴, 금지 사항 변경은 domain rule 갱신 대상으로 본다.
- 변경이 테스트 fixture, 내부 리팩터링, 문구 정리처럼 현재 구현 spec에 영향을 주지 않으면 `Spec update not needed: <사유>`를 남긴다.
- 판단 불가이면 spec을 추정 갱신하지 않고 `Spec blocked: <필요 evidence>`로 보고한다.
@ -58,12 +60,15 @@ description: agent-spec 갱신, 구현 스펙 업데이트, 완료 기능 스펙
- `mode=check-only`이면 쓰지 않고 갱신 후보만 보고한다.
- 영향이 있는 spec 문서만 수정한다.
- frontmatter `status``source_evidence`를 현재 evidence에 맞게 보강한다.
- 표준 섹션 순서를 유지한다.
- `rules-agent-spec.md`의 기본 섹션 기준을 따른다.
- 기능 목록은 `기능``설명` 중심으로 유지한다. 기능별 `상태` 칼럼은 기본 추가하지 않는다.
- `주요 흐름`은 긴 텍스트보다 Mermaid `sequenceDiagram` 또는 `flowchart`를 우선 고려한다.
- `코드 진입점` 섹션은 추가하지 않는다. 기존 spec에 있으면 현재 기준에 맞춰 제거하거나 `source_evidence`로 옮긴다.
- 계약 원문을 복제하지 않고 링크만 보강한다.
- 변경 기록에 날짜, 변경 근거, 관련 Milestone/complete.log/코드 경로를 남긴다.
5. **index 동기화**
- spec 상태, 읽는 조건, path, 주요 evidence가 바뀌었으면 `agent-spec/index.md`의 Spec Map을 갱신한다.
- spec 상태, 읽는 조건, path, 주요 근거가 바뀌었으면 `agent-spec/index.md`의 Spec Map을 갱신한다.
- 새 spec 문서가 필요하면 `create-spec` 대상으로 보고하고 index를 추정 갱신하지 않는다.
- 폐기된 spec은 활성 문서에 남기지 않고 archive log로 이동할 후보로 보고한다. 명시 요청 없이 archive 이동하지 않는다.
@ -77,7 +82,9 @@ description: agent-spec 갱신, 구현 스펙 업데이트, 완료 기능 스펙
- [ ] `agent-spec/index.md`에서 관련 spec만 읽었는가
- [ ] 코드/계약/테스트 기준으로 현재 동작을 재확인했는가
- [ ] spec 문서의 표준 섹션과 frontmatter가 유지되는가
- [ ] spec 문서의 기본 섹션 기준과 frontmatter가 유지되는가
- [ ] 기능 목록이 기능/설명 중심이며 불필요한 상태 칼럼이나 과한 상세 설명을 만들지 않았는가
- [ ] 코드 진입점, 패키지 배치, 도메인별 금지 사항을 spec 본문에 반복하지 않았는가
- [ ] index의 Spec Map이 갱신한 spec 상태와 일치하는가
- [ ] 계약 원문을 복제하지 않았는가
- [ ] 갱신/불필요/create 필요/차단 중 하나의 결과가 명확한가
@ -114,3 +121,4 @@ description: agent-spec 갱신, 구현 스펙 업데이트, 완료 기능 스펙
- 매칭되지 않는 spec을 광범위하게 읽거나 전부 갱신하지 않는다.
- archive spec을 명시 요청 없이 읽거나 갱신하지 않는다.
- complete.log나 roadmap 문구만으로 현재 동작을 단정하지 않는다.
- 코드 진입점, 구현 배치, 도메인 간 상세 책임 경계, 유지할 패턴, 금지 사항을 domain rule 대신 agent-spec에 길게 쓰지 않는다.

View file

@ -0,0 +1,111 @@
---
spec_doc_type: spec
spec_id: control/control-plane-operations
status: 부분
source_evidence:
- type: contract
path: agent-contract/inner/control-plane-edge-wire.md
notes: Control Plane-Edge proto-socket TCP 계약
- type: contract
path: agent-contract/inner/client-control-plane-wire.md
notes: Client-Control Plane proto-socket WebSocket 계약
- type: code
path: apps/control-plane/internal/wire/edge_server.go
notes: Control Plane Edge TCP server, hello, status request, command dispatch
- type: code
path: apps/edge/internal/controlplane/connector.go
notes: Edge outbound connector, hello, status response, command event relay
- type: code
path: apps/control-plane/cmd/control-plane/http_edge_handlers.go
notes: Control Plane HTTP edge registry/status/events/commands view
- type: code
path: apps/client/lib/control_plane_status_repository.dart
notes: Flutter client HTTP status repository
- type: code
path: apps/client/lib/iop_wire/client_wire_client.dart
notes: Flutter proto-socket Client hello baseline
- type: test
path: apps/control-plane/internal/wire/edge_server_test.go
notes: Control Plane-Edge wire 검증
---
# 스펙: Control Plane 운영 기능
## 목적
Control Plane과 Client가 Edge 운영 상태를 어떻게 관찰하고 명령을 전달하는지 설명한다.
## 기능 목록
| 기능 | 설명 |
|------|------|
| Control Plane server | HTTP health/readiness endpoint, Client proto-socket WebSocket endpoint, Edge proto-socket TCP endpoint를 함께 시작한다. |
| Client hello wire | `/client` WebSocket proto-socket에서 `ClientHelloRequest`/`ClientHelloResponse` baseline을 제공한다. |
| Edge outbound enrollment | Edge가 Control Plane TCP wire로 outbound 연결하고 `EdgeHelloRequest`를 보낸다. `edge_id`가 비어 있으면 거부된다. |
| Edge connection registry | Control Plane은 Edge connection을 in-memory로 관리하고 reconnect stale cleanup을 connection token으로 방지한다. |
| Edge status request | Control Plane이 connected Edge에 `EdgeStatusRequest`를 보내 node/provider snapshot을 받는다. |
| Edge command dispatch | Control Plane이 `EdgeCommandRequest`를 connected Edge에 보내고 response와 lifecycle event를 bounded audit view에 기록한다. |
| Edge/Fleet HTTP view | `/edges`, `/edges/{id}`, `/edges/{id}/status`, `/edges/{id}/events`, `/edges/{id}/operations`, `/edges/{id}/commands`와 fleet status 계열을 제공한다. |
| Flutter status repository | Flutter Client가 HTTP repository로 Edge/fleet status, events, operations, command response를 가져온다. |
| Flutter proto-socket client | Flutter proto-socket client는 현재 hello baseline을 지원한다. |
| IOP console package | `packages/flutter/iop_console`은 embeddable console shell/panel contract를 제공한다. |
## 범위
- 포함: Control Plane process endpoints, Edge outbound enrollment, Edge registry, status request/response, command dispatch/event audit, Client hello wire, Flutter status repository.
- 제외: Control Plane이 Edge config/state canonical store가 되는 기능, Node 직접 연결/스케줄링, durable audit DB, 정책/권한 model, full UI 정의 동기화.
## 주요 흐름
```mermaid
sequenceDiagram
participant Client
participant CP as Control Plane
participant Edge
Edge->>CP: EdgeHelloRequest
CP->>CP: connection registry 갱신
Client->>CP: HTTP edge/fleet status
CP->>Edge: EdgeStatusRequest
Edge-->>CP: EdgeStatusResponse
CP-->>Client: status view
Client->>CP: command request
CP->>Edge: EdgeCommandRequest
Edge-->>CP: command response/event
CP-->>Client: command result
```
## 계약
- `iop.control-plane-edge-wire`: `agent-contract/inner/control-plane-edge-wire.md`
- `iop.client-control-plane-wire`: `agent-contract/inner/client-control-plane-wire.md`
- proto 원문: `proto/iop/control.proto`
## 설정/데이터/이벤트
- Control Plane config는 `configs/control-plane.yaml``apps/control-plane/cmd/control-plane/main.go` config loader를 기준으로 한다.
- Client WS listen은 `IOP_WIRE_LISTEN`, Edge TCP listen은 `IOP_EDGE_WIRE_LISTEN`으로 override할 수 있다.
- Edge connector 설정은 `configs/edge.yaml``control_plane` 섹션이다.
- Edge registry recent node events와 command audit는 bounded in-memory buffer다. durable audit store가 아니다.
- Client build-time endpoint는 `IOP_CONTROL_PLANE_HTTP_URL`, `IOP_CONTROL_PLANE_WIRE_URL` Dart define으로 주입된다.
## 검증
- `go test ./apps/control-plane/internal/wire`
- `go test ./apps/control-plane/cmd/control-plane`
- `go test ./apps/edge/internal/controlplane`
- `make test-control-plane-edge-wire`
- `make client-test` - Flutter 환경과 dependency가 준비되어 있을 때 실행한다.
## 한계와 주의사항
- Control Plane은 현재 MVP/scaffold 성격이 강하며 DB/Redis 설정은 예약되어 있다.
- Client-Control Plane proto-socket wire는 hello baseline이고, 운영 상태 조회는 현재 HTTP repository가 담당한다.
- Edge/command/event registry는 in-memory bounded view다. audit, 권한, durable history는 별도 설계가 필요하다.
- Control Plane status/command 응답에 Node address, token, transport internals를 넣지 않는다.
- Control Plane이 Node를 직접 연결하거나 스케줄링하는 구조를 만들지 않는다.
## 변경 기록
- 2026-07-07: 현재 Control Plane/Client 코드와 wire 계약 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.

48
agent-spec/index.md Normal file
View file

@ -0,0 +1,48 @@
---
spec_doc_type: index
status: 활성
---
# 구현 스펙 색인
## 목적
이 디렉터리는 IOP의 현재 구현을 빠르게 파악하기 위한 living spec이다.
AI agent가 작업 전에 읽는 지도이기도 하지만, 사람도 "지금 무엇이 어디까지 구현됐는지" 확인할 수 있어야 한다.
로드맵 완료 이력, SDD 설계 논의, 계약 원문, 사람용 가이드를 대체하지 않는다. 최종 기준은 항상 코드, `agent-contract/`, 테스트, 설정 예시다.
## 읽기 규칙
- 먼저 아래 "영역별 요약"으로 현재 찾는 주제를 고른다.
- 필요한 작업에서만 이 index를 읽고, 매칭되는 spec 문서만 읽는다.
- `archive/**`는 과거 비교, 복원, 특정 근거 확인 요청이 있을 때만 읽는다.
- API, wire protocol, config/event schema, 프로세스 간 계약 원문은 `agent-contract/`를 따른다.
- 코드 배치, 구현 진입점, 도메인 간 상세 책임 경계는 domain rule을 따른다.
## 영역별 요약
- 실행 경로: Edge와 Node 사이의 등록, 실행, 이벤트, 취소, command 흐름은 `runtime/edge-node-execution`에서 본다.
- 런타임 라우팅/설정: provider-pool, `models[]`, `nodes[].providers[]`, live config refresh는 `runtime/provider-pool-config-refresh`에서 본다.
- 외부 HTTP 입력: OpenAI-compatible 호출은 `input/openai-compatible-surface`, A2A JSON-RPC 호출은 `input/a2a-json-rpc-surface`에서 본다.
- 운영 제어: Control Plane, Edge enrollment, fleet/edge status, Flutter Client 상태 소비는 `control/control-plane-operations`에서 본다.
## 스펙 목록
| id | 상태 | 언제 읽나 | path | 주요 근거 |
|----|------|-----------|------|-----------|
| `runtime/edge-node-execution` | 부분 | Edge-Node TCP/protobuf transport, Node 등록, run/cancel/command, adapter 실행, Node local run store를 확인할 때 | `agent-spec/runtime/edge-node-execution.md` | `agent-contract/inner/edge-node-runtime-wire.md`, `apps/edge/internal/service/run_dispatch.go`, `apps/node/internal/node/node.go` |
| `runtime/provider-pool-config-refresh` | 부분 | `models[]`, `nodes[].providers[]`, provider-pool dispatch, long-context admission, Edge/Node config refresh를 확인할 때 | `agent-spec/runtime/provider-pool-config-refresh.md` | `agent-contract/inner/edge-config-runtime-refresh.md`, `packages/go/config/config.go`, `apps/edge/internal/configrefresh/classify.go` |
| `input/openai-compatible-surface` | 부분 | `/v1/models`, `/v1/chat/completions`, `/v1/responses`, OpenAI-compatible auth/metadata/workspace/tool handling, 외부 `model` route를 확인할 때 | `agent-spec/input/openai-compatible-surface.md` | `agent-contract/outer/openai-compatible-api.md`, `apps/edge/internal/openai/chat_handler.go`, `apps/edge/internal/openai/responses_handler.go` |
| `input/a2a-json-rpc-surface` | 부분 | Edge A2A JSON-RPC, `message/send`, `tasks/get`, `tasks/cancel`, A2A task store와 bearer auth를 확인할 때 | `agent-spec/input/a2a-json-rpc-surface.md` | `agent-contract/outer/a2a-json-rpc-api.md`, `apps/edge/internal/input/a2a/server.go`, `apps/edge/internal/input/a2a/task_store.go` |
| `control/control-plane-operations` | 부분 | Control Plane-Edge wire, Client-Control Plane wire, Control Plane HTTP Edge/fleet status view, Flutter Client status consumer를 확인할 때 | `agent-spec/control/control-plane-operations.md` | `agent-contract/inner/control-plane-edge-wire.md`, `agent-contract/inner/client-control-plane-wire.md`, `apps/control-plane/internal/wire/edge_server.go` |
## 작성 규칙
- 한국어 설명을 우선하고, 코드/계약 식별자는 원문을 유지한다.
- 현재 구현 기준으로 작성한다.
- 기능 목록과 주요 흐름을 먼저 파악할 수 있게 작성한다.
- 코드/계약/테스트 evidence를 우선한다.
- 계약 원문은 복제하지 않고 링크한다.
- 코드 진입점과 도메인룰 성격의 상세 경계는 반복하지 않는다.
- 불확실한 내용은 단정하지 않고 `부분`, `불명확`, `확인 필요`로 남긴다.

View file

@ -0,0 +1,102 @@
---
spec_doc_type: spec
spec_id: input/a2a-json-rpc-surface
status: 부분
source_evidence:
- type: contract
path: agent-contract/outer/a2a-json-rpc-api.md
notes: A2A JSON-RPC 외부 HTTP 계약
- type: code
path: apps/edge/internal/input/a2a/server.go
notes: A2A HTTP server, JSON-RPC method dispatch, auth, SubmitRun 연동
- type: code
path: apps/edge/internal/input/a2a/task_store.go
notes: in-memory task store와 RunEvent drain
- type: code
path: apps/edge/internal/input/a2a/types.go
notes: JSON-RPC envelope와 A2A task/message/artifact DTO
- type: test
path: apps/edge/internal/input/a2a/server_test.go
notes: A2A handler 동작 검증
- type: test
path: apps/edge/internal/input/a2a/task_store_test.go
notes: task store drain 상태 검증
---
# 스펙: A2A JSON-RPC 입력 표면
## 목적
Edge가 A2A JSON-RPC 요청을 받아 내부 `adapter + target` 실행으로 넘기는 현재 MVP 동작을 설명한다.
## 기능 목록
| 기능 | 설명 |
|------|------|
| A2A HTTP server | `a2a.enabled=true`이면 Edge input manager가 A2A HTTP server를 시작한다. 기본 RPC path는 `/a2a`다. |
| agent card | `GET /.well-known/agent.json`으로 현재 agent card를 제공한다. |
| bearer auth | `a2a.bearer_token`이 있으면 matching bearer authorization header를 요구한다. |
| JSON-RPC method 처리 | JSON-RPC 2.0 envelope를 검증하고 `message/send`, `tasks/get`, `tasks/cancel`만 처리한다. |
| message/send 실행 | text parts를 newline으로 이어 prompt를 만들고 Edge service `SubmitRun`을 호출한다. |
| blocking task | `configuration.blocking`이 true이거나 생략되면 HTTP 요청 안에서 run stream을 drain한 뒤 최종 task snapshot을 반환한다. |
| background task | non-blocking 요청은 working snapshot을 먼저 반환하고 background goroutine이 run stream을 drain한다. |
| task 조회 | `tasks/get`이 process-local task store의 task snapshot을 반환한다. |
| task 취소 | `tasks/cancel`은 working task에 대해 service `CancelRun`을 호출한다. |
| task artifact | completed task는 adapter output delta를 text artifact 하나에 누적한다. |
## 범위
- 포함: A2A HTTP listener, agent card, bearer auth, JSON-RPC envelope, message text extraction, blocking/background task drain, task get/cancel.
- 제외: A2A streaming, durable task persistence, OpenAI-compatible chat 대체 표면, provider-pool model catalog route, full A2A spec 호환.
## 주요 흐름
```mermaid
sequenceDiagram
participant Caller
participant A2A as A2A server
participant Service as Edge service
participant Store as TaskStore
Caller->>A2A: message/send(text parts)
A2A->>Service: SubmitRun(prompt)
Service-->>A2A: run id + stream
A2A->>Store: task working 저장
alt blocking
A2A->>A2A: run stream drain
A2A-->>Caller: final task snapshot
else non-blocking
A2A-->>Caller: working task snapshot
A2A->>A2A: background drain
end
```
## 계약
- `iop.a2a-json-rpc-api`: `agent-contract/outer/a2a-json-rpc-api.md`
- 내부 실행 wire: `agent-contract/inner/edge-node-runtime-wire.md`
## 설정/데이터/이벤트
- `configs/edge.yaml``a2a` 섹션이 listener, path, node ref, adapter, target, session id, timeout, bearer token을 제공한다.
- A2A run metadata에는 현재 `source=a2a``blocking=true` 또는 `blocking=false`가 들어간다. 이 metadata는 OpenAI-compatible request metadata 계약과 별개인 내부 run metadata다.
- TaskStore는 run event `delta`, `complete`, `error`, `cancelled`와 node disconnect를 관찰해 task status를 갱신한다.
## 검증
- `go test ./apps/edge/internal/input/a2a`
- `go test ./apps/edge/internal/input`
- `go test ./apps/edge/internal/service`
## 한계와 주의사항
- task state는 메모리에만 있고 Edge 재시작 시 사라진다.
- agent card URL은 현재 listen/path 기반 단순 표현이다. reverse proxy/public URL 계약은 별도로 확정해야 한다.
- A2A 표면은 현재 configured adapter/target으로만 run을 보낸다. request별 provider-pool model route는 이 spec의 현재 동작이 아니다.
- streaming capability는 agent card에서 false다.
- OpenAI-compatible chat/completions 대체 표면으로 쓰지 않는다.
## 변경 기록
- 2026-07-07: 현재 코드와 A2A 계약 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.

View file

@ -0,0 +1,105 @@
---
spec_doc_type: spec
spec_id: input/openai-compatible-surface
status: 부분
source_evidence:
- type: contract
path: agent-contract/outer/openai-compatible-api.md
notes: OpenAI-compatible 외부 HTTP 계약
- type: code
path: apps/edge/internal/openai/routes.go
notes: OpenAI-compatible route와 bearer auth 처리
- type: code
path: apps/edge/internal/openai/chat_handler.go
notes: Chat Completions request validation, route dispatch, tool/reasoning 정책
- type: code
path: apps/edge/internal/openai/responses_handler.go
notes: Responses API request validation, metadata/workspace 처리, non-stream completion
- type: code
path: apps/edge/internal/openai/run_result.go
notes: RunEvent stream을 OpenAI-compatible result로 수집
- type: test
path: apps/edge/internal/openai/server_test.go
notes: OpenAI-compatible route, provider-pool, workspace, tool handling 검증
---
# 스펙: OpenAI-Compatible 입력 표면
## 목적
Edge가 OpenAI-compatible HTTP 요청을 받아 내부 `adapter + target` 실행으로 넘기는 현재 동작을 설명한다.
## 기능 목록
| 기능 | 설명 |
|------|------|
| OpenAI-compatible HTTP server | `openai.enabled=true`이면 Edge input manager가 `/healthz`, `/v1/models`, `/v1/chat/completions`, `/v1/responses`, `/api/` route를 제공한다. |
| bearer auth | `openai.bearer_token`이 있으면 matching bearer authorization header를 요구한다. |
| model catalog | `/v1/models`는 provider-pool `models[]`, legacy `openai.model_routes[]`, `openai.models` 또는 `openai.target` 순서로 노출 모델을 만든다. |
| model dispatch | request `model`은 provider-pool catalog, legacy model route, single target fallback 순서로 해석된다. |
| provider-pool handoff | provider-pool catalog에 model이 있으면 service 요청은 `ProviderPool=true`로 전달되고 adapter/target은 provider selection 이후 확정된다. |
| legacy route 변환 | legacy route는 외부 `model`을 route entry의 `adapter`, `target`, `node`, `session_id`, queue policy로 변환한다. |
| metadata/workspace 처리 | `metadata.workspace``RunRequest.workspace`로 분리하고, 일반 metadata는 최대 16개 string key/value만 허용한다. |
| Chat Completions | `/v1/chat/completions`는 non-streaming과 streaming SSE를 지원한다. |
| Responses API | `/v1/responses`는 현재 string input의 non-streaming 요청만 지원한다. |
| strict output | strict output이 켜져 있으면 XML completion contract 기반 instruction 또는 prompt prefix를 추가할 수 있다. |
| tool call 처리 | Chat Completions `tools`는 provider native metadata 복원 또는 text tool-call synthesis/validation 경로를 사용한다. |
| cancel 전파 | HTTP caller timeout/cancel이 cancel-worthy error이면 Node `CancelRun`으로 전파한다. |
## 범위
- 포함: OpenAI-compatible HTTP auth, request validation, route resolution, metadata/workspace 처리, chat/responses 변환, provider-pool dispatch handoff, tool/reasoning/strict output 처리.
- 제외: OpenAI 원문 API 전체 호환, legacy `/v1/completions`, A2A JSON-RPC, Node adapter별 provider HTTP 세부, Control Plane 운영 API.
## 주요 흐름
```mermaid
sequenceDiagram
participant Caller
participant OpenAI as OpenAI handler
participant Service as Edge service
participant Runtime as Edge-Node runtime
Caller->>OpenAI: chat/responses request(model)
OpenAI->>OpenAI: auth, metadata, route 검증
OpenAI->>Service: SubmitRun(adapter/target or ProviderPool)
Service->>Runtime: RunRequest
Runtime-->>Service: RunEvent stream
Service-->>OpenAI: run stream
OpenAI-->>Caller: OpenAI-compatible response or SSE
```
## 계약
- `iop.openai-compatible-api`: `agent-contract/outer/openai-compatible-api.md`
- 내부 실행 wire: `agent-contract/inner/edge-node-runtime-wire.md`
- config/provider pool: `agent-contract/inner/edge-config-runtime-refresh.md`
## 설정/데이터/이벤트
- `configs/edge.yaml``openai` 섹션이 listener, bearer token, legacy adapter/target, model routes, strict output을 제공한다.
- top-level `models[]`가 있으면 OpenAI model list와 provider-pool dispatch에서 legacy route보다 우선한다.
- OpenAI request의 `metadata.workspace`는 absolute path가 필요한 route에서만 필수 검증된다.
- run metadata에는 `openai_model`, `openai_stream`, `strict_output`, `estimated_input_tokens`, `context_class`가 들어갈 수 있다.
- Node complete event metadata의 `openai_tool_calls``openai_text_tool_fallback`은 response tool call 복원에 쓰인다.
## 검증
- `go test ./apps/edge/internal/openai`
- `go test ./apps/edge/internal/service`
- `make test-openai-ollama`
- provider별 실제 runtime smoke는 환경별 agent-test/dev 또는 dev-corp profile을 따른다.
## 한계와 주의사항
- `/v1/responses`는 현재 non-streaming string input만 지원한다.
- `/v1/completions`는 제공하지 않는다.
- OpenAI-compatible request에 provider/Ollama 전용 root field를 추가하지 않는다.
- workspace는 prompt 본문에 섞지 않고 metadata에서 분리한다.
- text tool-call synthesis는 요청 `tools[]` schema를 기준으로만 수행한다. 자연어 추론으로 tool call을 만들지 않는다.
- private token이나 endpoint 원문은 tracked spec/docs에 남기지 않는다.
## 변경 기록
- 2026-07-07: 현재 코드와 OpenAI-compatible 계약 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.

View file

@ -0,0 +1,144 @@
---
spec_doc_type: spec
spec_id: runtime/edge-node-execution
status: 부분
source_evidence:
- type: contract
path: agent-contract/inner/edge-node-runtime-wire.md
notes: Edge-Node register, run stream, cancel, node command, config refresh wire 계약
- type: code
path: proto/iop/runtime.proto
notes: RunRequest, RunEvent, CancelRequest, NodeCommandRequest, RegisterRequest, NodeConfigPayload 원문
- type: code
path: apps/edge/internal/transport/server.go
notes: Edge TCP proto-socket server, node register handshake, event relay
- type: code
path: apps/edge/internal/service/run_dispatch.go
notes: surface-neutral SubmitRun, direct dispatch, cancel request 생성
- type: code
path: apps/node/internal/node/node.go
notes: Node transport handler, adapter 실행, cancel, command, config refresh 처리
- type: test
path: apps/edge/internal/transport/server_test.go
notes: Edge transport server 단위 검증
- type: test
path: apps/node/internal/node/node_test.go
notes: Node 실행 처리 단위 검증
---
# 스펙: Edge-Node 실행 경로
## 목적
Edge와 Node 사이에 현재 구현된 실행 기능을 기능 단위로 정리한다. 코드 배치 규칙이나 도메인별 작업 지침은 domain rule을 따른다.
## 기능 목록
| 기능 | 설명 |
|------|------|
| Node token 등록 | Node가 Edge TCP proto-socket endpoint에 연결한 뒤 `RegisterRequest.token`으로 등록한다. |
| Node config payload 전달 | Edge가 token에 매칭되는 node record를 찾아 `NodeConfigPayload``RegisterResponse`에 담아 내려준다. |
| 등록 실패 처리 | unknown token, duplicate connection, config payload build failure를 register response와 node lifecycle event로 표현한다. |
| 실행 요청 전달 | Edge service가 `SubmitRun` 요청을 `RunRequest`로 만들어 선택된 Node에 보낸다. 명시 node가 없고 연결 node가 1개면 single-node fallback을 사용한다. |
| adapter 실행 | Node가 `RunRequest.adapter`로 adapter instance를 찾고 adapter `Execute`를 호출한다. admission은 adapter `Capabilities().MaxConcurrency` 기준이다. |
| 실행 이벤트 스트림 | Node adapter가 낸 start, delta, reasoning_delta, complete, error, cancelled 이벤트를 `RunEvent`로 Edge에 relay한다. |
| terminal event 합성 | adapter가 terminal event 없이 종료하면 Node가 terminal event를 합성한다. |
| run cancel | Edge가 `CancelRequest`를 보내면 Node run manager가 active run context를 cancel한다. |
| logical session 종료 | adapter가 `SessionTerminator`를 구현한 경우 `TERMINATE_SESSION`으로 session을 종료한다. 모든 adapter 공통 기능은 아니다. |
| Node command | capabilities, transport status, usage status, session list, ollama API 계열 조회/제어성 command를 실행 요청과 분리해 처리한다. |
| Node local run store | Node가 run id, adapter, target, session id, background, status, timestamps, error를 SQLite에 기록한다. |
| Edge event fanout | Edge event bus가 run event와 node lifecycle event를 in-process subscriber에게 fanout한다. |
## 범위
- 포함: Edge-Node TCP/protobuf transport, register handshake, run/cancel/command, Node adapter execution, Edge event bus fanout, Node local run store.
- 제외: OpenAI-compatible/A2A HTTP request shape, Control Plane 운영 wire, provider-pool config refresh 상세, durable global history/audit.
## 주요 흐름
### Node 등록
```mermaid
sequenceDiagram
participant Node
participant EdgeTransport as Edge transport
participant NodeStore as Edge NodeStore
Node->>EdgeTransport: TCP connect
Node->>EdgeTransport: RegisterRequest(token)
EdgeTransport->>NodeStore: token으로 NodeRecord 조회
alt token valid
EdgeTransport->>EdgeTransport: NodeConfigPayload 생성
EdgeTransport-->>Node: RegisterResponse(accepted=true, config)
EdgeTransport->>EdgeTransport: live registry 등록
else token invalid or duplicate
EdgeTransport-->>Node: RegisterResponse(accepted=false, reason)
end
```
### 실행 요청과 이벤트
```mermaid
sequenceDiagram
participant Caller
participant EdgeService as Edge service
participant EdgeTransport as Edge transport
participant Node
participant Adapter
Caller->>EdgeService: SubmitRun(adapter, target, input)
EdgeService->>EdgeService: Node 선택
EdgeService->>EdgeTransport: RunRequest
EdgeTransport->>Node: RunRequest
Node->>Node: adapter instance resolve
Node->>Adapter: Execute(spec)
Adapter-->>Node: RuntimeEvent(delta/start/complete)
Node-->>EdgeTransport: RunEvent
EdgeTransport-->>Caller: run stream
```
### 취소와 session 종료
```mermaid
sequenceDiagram
participant EdgeService as Edge service
participant Node
participant Adapter
alt cancel run
EdgeService->>Node: CancelRequest(CANCEL_RUN, run_id)
Node->>Node: active run context cancel
else terminate session
EdgeService->>Node: CancelRequest(TERMINATE_SESSION, adapter, target, session_id)
Node->>Adapter: TerminateSession(target, session_id)
end
```
## 계약
- `iop.edge-node-runtime-wire`: `agent-contract/inner/edge-node-runtime-wire.md`
- proto 원문: `proto/iop/runtime.proto`
## 설정/데이터/이벤트
- Edge의 node source of truth는 `configs/edge.yaml``packages/go/config``nodes[]` 구조다.
- `RunEvent`는 adapter execution stream이고, `EdgeNodeEvent`는 node lifecycle/control event다.
- Node local DB는 기본 `file:iop.db?cache=shared&mode=rwc`로 열린다.
- heartbeat는 Edge와 Node transport 양쪽에서 30초 interval, 45초 wait 기준을 사용한다.
## 검증
- `go test ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/node`
- `go test ./apps/node/internal/transport ./apps/node/internal/node ./apps/node/internal/router ./apps/node/internal/adapters ./apps/node/internal/store`
- `make test-e2e` - Edge-Node와 OpenAI 보조 smoke를 함께 실행한다. runtime path 변경 시 사용자 흐름 검증을 대체하지 않는다.
## 한계와 주의사항
- mTLS helper는 존재하지만 현재 Edge-Node transport 설정에는 연결되어 있지 않다.
- `TERMINATE_SESSION`은 모든 adapter에 공통으로 보장되는 기능이 아니다.
- Node store는 전역 query/audit API가 아니다. 상위 운영 이력은 별도 설계가 필요하다.
## 변경 기록
- 2026-07-07: 현재 코드, 계약, README 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.

View file

@ -0,0 +1,115 @@
---
spec_doc_type: spec
spec_id: runtime/provider-pool-config-refresh
status: 부분
source_evidence:
- type: contract
path: agent-contract/inner/edge-config-runtime-refresh.md
notes: Edge config, provider pool, config refresh, Node payload 연결 계약
- type: code
path: packages/go/config/config.go
notes: Edge config struct, provider/model validation, adapter normalization
- type: code
path: configs/edge.yaml
notes: provider-pool 권장 설정 예시와 live refresh 설정 예시
- type: code
path: apps/edge/internal/service/model_queue.go
notes: provider/resource capacity, priority, queue, long-context slot admission
- type: code
path: apps/edge/internal/configrefresh/classify.go
notes: dry-run/apply classification과 changed path report 생성
- type: code
path: apps/edge/internal/bootstrap/runtime.go
notes: mutable config apply, runtime snapshot 교체, Node refresh push
- type: test
path: packages/go/config/config_test.go
notes: config load/validation 검증
- type: test
path: apps/edge/internal/configrefresh/classify_test.go
notes: refresh classification 검증
---
# 스펙: Provider Pool과 Config Refresh
## 목적
Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, 어떤 설정 변경이 재시작 없이 반영되는지 설명한다.
## 기능 목록
| 기능 | 설명 |
|------|------|
| model catalog | `models[].id`는 외부 OpenAI-compatible `model` key이자 provider-pool `ModelGroupKey`다. |
| provider mapping | `models[].providers`는 provider id를 실제 served model name으로 매핑한다. |
| node provider catalog | `nodes[].providers[]`는 Node 아래 resource/provider catalog이며 provider id는 Edge config에서 전역 유일해야 한다. |
| config validation | config load가 provider id 참조, served model membership, numeric bounds, long-context budget을 검증한다. |
| provider 후보 필터링 | dispatch는 connected node의 provider 후보 중 catalog match, enabled, healthy/available, capacity 조건을 만족하는 후보만 사용한다. |
| capacity/priority dispatch | in-flight가 capacity 미만인 후보를 고르고, 동률이면 낮은 `priority`와 round-robin을 적용한다. |
| long-context admission | estimated input token이 threshold 이상이면 `context_class=long`으로 분류하고, provider long slot이 있으면 일반 capacity slot과 함께 점유한다. |
| config refresh dry-run/apply | loopback admin HTTP `POST /refresh`가 candidate config를 dry-run 또는 apply한다. |
| refresh classification | listener, Edge identity, bootstrap path, adapter structural 변경 등은 restart-required로 분류한다. |
| mutable apply | 적용 가능한 변경은 Edge `Cfg`, `NodeStore`, service/input model catalog, OpenAI long-context threshold를 copy-on-write로 교체한다. |
| Node config refresh push | 변경이 있으면 Edge가 연결된 Node에 node-specific `NodeConfigRefreshRequest`를 push한다. |
| Node registry swap | Node는 refresh payload로 새 adapter registry를 만들고 router registry를 swap한다. old registry stop은 active run이 있으면 drain 이후로 지연한다. |
## 범위
- 포함: Edge config load/default/validation, provider-pool dispatch, queue admission, long-context admission, config refresh classification/apply, Node config refresh payload.
- 제외: 개별 adapter의 provider API 호출 세부, OpenAI HTTP request/response shape, Control Plane 원격 config 변경 UX, private credential 관리.
## 주요 흐름
```mermaid
sequenceDiagram
participant Caller
participant Service as Edge service
participant Queue as Provider queue
participant Node
Caller->>Service: SubmitRun(model)
Service->>Queue: provider 후보 선택
Queue-->>Service: adapter + served target
Service->>Node: RunRequest(adapter, target)
participant Operator
participant Refresh as Config refresh
Operator->>Refresh: POST /refresh(apply)
Refresh->>Refresh: load, validate, classify
Refresh->>Node: NodeConfigRefreshRequest
```
## 계약
- `iop.edge-config-runtime-refresh`: `agent-contract/inner/edge-config-runtime-refresh.md`
- `iop.edge-node-runtime-wire`: `agent-contract/inner/edge-node-runtime-wire.md`
- proto 원문: `proto/iop/runtime.proto`
## 설정/데이터/이벤트
- `long_context_threshold_tokens` 기본 예시는 `100000`이고 0 이하 값은 config load에서 거부된다.
- provider `enabled=false`는 dispatch pool에서 제외하지만 adapter process lifecycle 변경을 의미하지 않는다.
- provider capacity, priority, max queue, queue timeout, enabled toggle, model generation policy는 live apply 대상으로 분류된다.
- Edge listener, control plane, openai/a2a listener, bootstrap artifact path, node 추가/삭제, node token/alias, adapter 설정 변경은 restart-required 대상이다.
- refresh result는 changed nodes/providers/models와 restart-required paths를 stable non-nil slice로 보고한다.
## 검증
- `go test ./packages/go/config`
- `go test ./apps/edge/internal/configrefresh`
- `go test ./apps/edge/internal/service`
- `go test ./apps/edge/internal/node`
- `go test ./apps/node/internal/adapters ./apps/node/internal/node`
## 한계와 주의사항
- provider health는 현재 config/provider snapshot 기반이다. 모든 runtime에 대한 active health probe가 완성된 것은 아니다.
- refresh admin API는 operator-local 표면이다. 접근 제어 없이 public interface에 노출하지 않는다.
- adapter structural 변경은 contract상 restart-required로 분류된다. Node handler가 registry swap을 지원하더라도 Edge refresh classifier가 허용한 변경만 apply해야 한다.
- no-change apply는 runtime snapshot을 교체하지만 Node push는 생략한다.
- `NodeRuntimeConfig.concurrency`는 legacy metadata이며 provider-pool admission의 node-wide capacity로 쓰지 않는다.
- credential, private endpoint, bearer token 원문은 tracked config/docs/spec에 남기지 않는다.
## 변경 기록
- 2026-07-07: 현재 코드, 계약, config 예시 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.