docs: update domain rules and project rules with current guidelines

This commit is contained in:
toki 2026-07-15 07:34:17 +09:00
parent 7ca329ac9e
commit 91a676b237
7 changed files with 116 additions and 36 deletions

View file

@ -1,23 +1,25 @@
---
domain: client
last_rule_review_commit: 49872ae120627c47175194e837d90f8915d67397
last_rule_updated_at: 2026-06-01
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# client
## 목적 / 책임
IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint를 소비해 운영 상태를 표시하고, Flutter Web/Desktop/Mobile shell, Client-Control Plane proto-socket client, client-side integration host를 관리한다.
IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint를 소비해 Edge/Node 운영 상태와 command/event view를 표시하고, Flutter Web/Desktop/Mobile shell, Client-Control Plane proto-socket client, Nexo notification integration host를 관리한다.
## 포함 경로
- `apps/client/lib/` — Flutter app source, build-time client config, proto-socket wire client, generated Dart proto 사용, client integration code
- `apps/client/lib/src/integrations/` — client-side external integration host와 Mattermost-compatible push integration
- `apps/client/lib/` — Flutter app source, build-time client config, Control Plane HTTP status repository/controller, proto-socket wire client, generated Dart proto 사용, client integration code
- `apps/client/lib/iop_wire/` — Client-Control Plane proto-socket client와 parser map
- `apps/client/lib/widgets/` — Edge/Node/runtime/execution-log 운영 panel widget
- `apps/client/lib/src/integrations/` — client-side external integration host와 Nexo notification integration
- `packages/flutter/iop_console/` — IOP-owned embeddable Flutter console package, left-rail shell, agent panel widget
- `apps/client/test/` — Flutter widget/config/wire/integration 테스트
- `apps/client/web/` — Flutter Web shell과 web asset
- `apps/client/assets/` — Flutter asset placeholder와 local-only Mattermost smoke credential mount 지점
- `apps/client/assets/` — Flutter asset placeholder
- `apps/client/android/` — Android runner와 Firebase 설정 표면
- `apps/client/ios/` — iOS runner scaffold
- `apps/client/macos/` — macOS runner scaffold
@ -47,10 +49,14 @@ IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint
- `ClientConfig``--dart-define` 기반 Control Plane HTTP/WS URL 설정
- `ClientWireClient` — Control Plane `/client` WebSocket proto-socket client와 hello request helper
- `clientParserMap` — Client-Control Plane proto message parser map
- `ControlPlaneStatusController` / `ControlPlaneStatusRepository` — Control Plane HTTP status/operation view 로딩과 UI state 관리
- `EdgeRegistryView` / `EdgeStatusResponseView` / `FleetStatusResponseView` / `EdgeOperationsResponseView` — Control Plane JSON view를 client-side DTO로 정규화
- `EdgesPanel` / `NodesPanel` / `RuntimePanel` / `ExecutionLogsPanel` — 운영 상태를 스캔 가능한 panel UI로 표시하는 widget
- `apps/client/lib/gen/proto/iop/*.dart``make proto-dart`로 생성되는 Dart protobuf binding
- `MattermostPushHostIntegration` / `MattermostPushPluginClient` — Nexo messaging / Mattermost-compatible push integration host
- `NexoNotificationHostIntegration` / `NexoNotificationPluginClient` / `NexoNotificationClient` — Nexo messaging notification stream integration host
- `IopConsoleShell` — IOP 단독 앱과 외부 임베더가 공유할 수 있는 좌측 rail console shell
- `IopAgentPanel` — 공통 `agent_shell` package를 사용한 IOP 운영 agent panel scaffold
- `IopConsoleConfig` / `IopCapabilityPack` / `IopConsoleOverview` — IOP console package의 embeddable configuration, capability, overview widget boundary
- `apps/client/Dockerfile` — sibling `proto-socket/dart` path dependency를 포함해 Flutter Web artifact를 빌드하는 이미지
## 유지할 패턴
@ -58,10 +64,11 @@ IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint
- Client는 Control Plane을 통해 Edge/Node 운영 상태를 조회한다. Client에서 Edge-Node TCP transport나 Node execution 경로에 직접 붙지 않는다.
- Client-Control Plane native 경계는 `/client` WebSocket proto-socket과 `ClientHelloRequest`/`ClientHelloResponse` baseline을 따른다.
- Client-Control Plane wire 상세는 `agent-contract/inner/client-control-plane-wire.md`를 기준으로 확인한다.
- Control Plane HTTP 상태 조회는 repository/controller/DTO 경계에서 처리하고, panel widget이 raw JSON parsing이나 endpoint path 조립을 직접 소유하지 않도록 유지한다.
- Control Plane URL은 `IOP_CONTROL_PLANE_HTTP_URL`, `IOP_CONTROL_PLANE_WIRE_URL` `--dart-define`으로 주입한다. 실제 환경값이나 private endpoint를 tracked source에 고정하지 않는다.
- Dart protobuf binding은 `proto/iop/*.proto`에서 생성한다. proto 계약 변경 시 `make proto-dart` 산출물과 Go 생성물 갱신 여부를 함께 확인한다.
- `apps/client/lib/gen/proto/iop/*.dart` 생성물은 사람이 직접 수정하지 않는다.
- Mattermost/Nexo 연동은 `lib/src/integrations/` 아래 통합 모듈로 둔다. IOP client app shell을 NomadCode 전용 UX로 바꾸지 않는다.
- Nexo notification 연동은 `lib/src/integrations/` 아래 통합 모듈로 둔다. Mattermost-compatible 인증/등록/서버 책임은 Nexo 쪽 경계에 남기고 IOP client app shell을 NomadCode 전용 UX로 바꾸지 않는다.
- `packages/flutter/iop_console`은 IOP UI의 공개 Flutter widget/package 경계다. IOP 단독 앱은 이 package를 mount하고, 외부 소비자는 이 package 또는 동등한 IOP-owned widget boundary를 통해 조립한다.
- `agent_shell`은 제품 중립 chat/agent interaction shell로만 사용한다. IOP client에는 IOP 운영/유지보수 capability와 panel widget을 담고, NomadCode의 workbench/right-rail layout은 가져오지 않는다.
- IOP UI를 NomadCode에 제공해야 할 때는 IOP-owned widget/package 경계로 노출하고, NomadCode product shell 내부 구현을 IOP client에 복제하지 않는다.
@ -73,6 +80,7 @@ IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint
- **platform-common**: protobuf 원본 계약은 platform-common이 소유한다. Client는 해당 계약에서 생성된 Dart binding을 사용한다.
- **agent-shell**: `agent_shell` sibling package는 공통 chat/agent shell widget과 message model만 제공한다. IOP-specific operation semantics와 Control Plane 연동은 client domain에 남긴다.
- **platform-common**: `packages/flutter/iop_console`은 Flutter UI package이므로 Go 공통 설정/proto/helper 패키지와 섞지 않는다.
- **Nexo**: Nexo/Mattermost-compatible notification auth, registration, server integration은 외부 integration boundary에 두고, client domain은 notification stream 소비와 UI 표시만 담당한다.
- **NomadCode**: NomadCode는 IOP의 중요한 UI 소비자일 수 있지만, IOP client는 NomadCode 전용 navigation, workspace, web context UX를 소유하지 않는다.
- **testing**: client test/build target, `scripts/dev/web.sh`, compose 기반 local dev 검증 기준은 testing domain rule을 따른다.
- **edge/node**: Client는 Edge와 Node를 직접 제어하지 않고 Control Plane 표면을 통해 관찰/명령한다.
@ -83,5 +91,5 @@ IOP의 공식 Flutter client UI/UX 영역이다. Control Plane HTTP/WS endpoint
- Client를 NomadCode 전용 shell, project workspace, diff/PR/branch/commit UX 중심으로 만들지 않는다.
- NomadCode right rail, workspace tab, web context 조작 UX를 IOP client domain에 직접 구현하지 않는다.
- `apps/client/lib/gen/proto/iop/*.dart` 생성 파일을 직접 수정하지 않는다.
- Mattermost smoke credential 같은 local/private 값을 tracked asset이나 README에 기록하지 않는다.
- Nexo/Mattermost smoke credential 같은 local/private 값을 tracked asset이나 README에 기록하지 않는다.
- Control Plane server 상태 저장, Edge registry, run dispatch, stream relay 구현을 client domain으로 끌어오지 않는다.

View file

@ -1,14 +1,14 @@
---
domain: control-plane
last_rule_review_commit: 49872ae120627c47175194e837d90f8915d67397
last_rule_updated_at: 2026-06-03
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# control-plane
## 목적 / 책임
여러 Edge를 연결하고 운영 제어할 제어면 영역이다. Control Plane은 Edge를 제어하기 쉽게 만드는 attachable layer이며, Edge의 실질 설정과 상태 원본을 소유하지 않는다. 현재는 health/readiness와 Edge registry 조회 HTTP, 환경별 설정 로딩, Client proto-socket WebSocket, Edge proto-socket TCP 연결 baseline을 제공하며, Node 직접 연결이나 직접 스케줄링은 책임으로 삼지 않는다.
여러 Edge를 연결하고 운영 제어할 제어면 영역이다. Control Plane은 Edge를 제어하기 쉽게 만드는 attachable layer이며, Edge의 실질 설정과 상태 원본을 소유하지 않는다. 현재는 health/readiness, Edge registry/status/event/operation HTTP view, fleet status/command fan-out, 환경별 설정 로딩, Client proto-socket WebSocket, Edge proto-socket TCP 연결 baseline을 제공하며, Node 직접 연결이나 직접 스케줄링은 책임으로 삼지 않는다.
## 포함 경로
@ -16,6 +16,7 @@ last_rule_updated_at: 2026-06-03
- `apps/control-plane/internal/wire/` — Control Plane wire protocol 상수, Client WebSocket endpoint, Edge TCP server와 in-memory Edge registry
- `apps/control-plane/README.md` — Control Plane 현재 상태와 계획된 운영 책임 설명
- `apps/control-plane/Dockerfile` — Control Plane 배포용 이미지 빌드 표면
- `apps/control-plane/Dockerfile.runtime` — Control Plane runtime 이미지 표면
## 제외 경로
@ -32,15 +33,18 @@ last_rule_updated_at: 2026-06-03
- `rootCmd()` / `serveCmd()``control-plane serve` command와 기본 config path 구성
- `controlPlaneConfig` — HTTP listen, Client wire listen, Edge wire listen, DB, Redis, logging 설정 구조
- `loadConfig()` / `applyEnvOverrides()` — YAML 설정 로딩과 `IOP_*` 환경 변수 override
- `run()` — health/readiness/Edge registry HTTP server, Client WS server, Edge TCP server lifecycle 조립
- `registerEdgeRegistryHandlers()``/edges`, `/edges/{edge_id}`, `/edges/{edge_id}/events` JSON 조회 endpoint
- `run()` — health/readiness/Edge registry/fleet HTTP server, Client WS server, Edge TCP server lifecycle 조립
- `registerEdgeRegistryHandlers()``/edges`, `/edges/{edge_id}`, `/edges/{edge_id}/status`, `/edges/{edge_id}/events`, `/edges/{edge_id}/operations`, `/edges/{edge_id}/commands` JSON endpoint
- `registerFleetHandlers()` / `fleetService``/fleet/status``/fleet/commands` fan-out, bounded concurrency, short status cache
- `edgeRegistryView` / `edgeStatusResponseView` / `fleetEdgeView` / `edgeCommandRecordView` — HTTP JSON 응답용 Control Plane view DTO
- `wire.Protocol` — Control Plane 통신 표준을 `protobuf-socket`으로 고정하는 상수
- `wire.Endpoint` — reserved wire endpoint 설정 타입
- `wire.ClientServer``/client` WebSocket proto-socket hello 요청을 처리하는 서버 구현
- `wire.EdgeServer` — Edge outbound TCP proto-socket 연결을 수락하고 hello/status/event 흐름을 처리하는 서버 구현
- `wire.EdgeRegistry` — Edge connection view와 최근 node lifecycle event relay를 보관하는 in-memory registry
- `wire.EdgeRegistry` — Edge connection view, 최근 node lifecycle event relay, 최근 Edge command request/result/event를 보관하는 in-memory registry
- `wire.EdgeParserMap()` — Control Plane-Edge wire message parser map
- `wire.EdgeServer.RequestStatus()` — 연결된 Edge에 `EdgeStatusRequest`를 보내 Edge-owned node snapshot을 조회하는 helper
- `wire.EdgeServer.SendCommand()` — 연결된 Edge에 `EdgeCommandRequest`를 보내고 typed response를 받는 helper
## 유지할 패턴
@ -53,8 +57,10 @@ last_rule_updated_at: 2026-06-03
- 브라우저/앱 경계는 WebSocket/WSS proto-socket을 사용할 수 있다. Edge-Node TCP transport 기준을 이 경계에 억지로 적용하지 않는다.
- Control Plane-Edge native wire는 Edge가 outbound로 연결하는 TCP proto-socket 경계로 둔다. Client WebSocket listener와 Edge TCP listener를 혼동하지 않는다.
- Control Plane-Edge wire 상세는 `agent-contract/inner/control-plane-edge-wire.md`, Client-Control Plane wire 상세는 `agent-contract/inner/client-control-plane-wire.md`를 기준으로 확인한다.
- Edge registry는 현재 in-memory connection/control view이다. durable history, audit, 정책 저장소를 이 registry에 섞지 않는다.
- Edge registry는 현재 in-memory connection/control view이다. 최근 node event와 command record/event는 운영 화면용 bounded view이며, durable history, audit, 정책 저장소를 이 registry에 섞지 않는다.
- Edge status 조회는 Edge가 보고한 `EdgeStatusResponse`를 관찰한다. Control Plane에서 Node address, token, transport internals, Edge 설정 원본을 직접 소유하지 않는다.
- Edge command와 fleet command는 Control Plane이 Edge-owned operation을 wire로 요청하는 표면이다. command semantics는 Edge service/operation boundary에 두고, Control Plane은 fan-out, timeout, view rendering, 최소 record만 담당한다.
- Fleet status fan-out은 bounded concurrency와 짧은 cache를 사용해 연결 Edge를 관찰한다. cache는 freshness 최적화일 뿐 source of truth가 아니며 disconnected view는 registry 상태를 즉시 반영한다.
- `ScheduleRequest`/`ScheduleResponse`는 legacy placeholder로만 취급하고, 새 orchestration 계약은 Edge-owned runtime state를 우회하지 않도록 다시 설계한다.
- Control Plane 설정에 실제 환경값, credential, private endpoint를 tracked 문서에 쓰지 않는다. 환경별 값은 private rule 라우팅을 따른다.
- proto 계약을 바꾸면 `proto/iop/*.proto`를 먼저 수정하고 Go 생성물을 명령으로 갱신한다.
@ -72,6 +78,8 @@ last_rule_updated_at: 2026-06-03
- Edge 설정, Node registry, runtime/automation 상태의 원본 저장소를 Control Plane에 만들지 않는다.
- Edge-local registry, run dispatch, stream relay 구현을 Control Plane으로 복제하지 않는다.
- Edge가 보고하지 않은 Node address/token/scheduling 필드를 Control Plane status API에 만들지 않는다.
- Edge command/fleet command 구현에서 Node transport internals를 직접 조립하거나 Control Plane에서 Node command request를 직접 소유하지 않는다.
- `/fleet/status` cache나 Edge operation record를 durable state, audit 원장, Edge 설정 원본처럼 사용하지 않는다.
- Control Plane 도입만을 이유로 Edge-local CLI bootstrap/config/진단 fallback을 제품 기본 계약에서 제외하거나 제거하지 않는다. 축소는 별도 roadmap 결정과 대체 fallback 기준이 있을 때만 다룬다.
- gRPC를 Control Plane 기본 wire protocol로 도입하지 않는다.
- 실제 DB/Redis credential이나 환경별 endpoint를 tracked docs/rules에 기록하지 않는다.

View file

@ -1,7 +1,7 @@
---
domain: edge
last_rule_review_commit: f59ecea97ead497d352779fe7d33a74166dc0fc9
last_rule_updated_at: 2026-06-21
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# edge
@ -12,9 +12,12 @@ last_rule_updated_at: 2026-06-21
## 포함 경로
- `apps/edge/cmd/edge/` — edge CLI 진입점과 serve/console/config/env/setup/node/nodes/smoke 커맨드
- `apps/edge/cmd/edge/` — edge CLI thin entrypoint와 serve/console runtime wiring
- `apps/edge/internal/bootstrap/` — fx 의존성 주입과 서버 시작/종료 lifecycle
- `apps/edge/internal/configrefresh/` — Edge config 후보 로딩, 변경 분류, dry-run/apply 평가
- `apps/edge/internal/controlplane/` — Edge에서 Control Plane으로 outbound 연결하는 proto-socket connector
- `apps/edge/internal/edgecmd/` — config/env/setup/bootstrap/node/nodes/smoke/version CLI command 구현
- `apps/edge/internal/edgevalidate/` — Edge config 구조와 provider/model/adapter 참조 검증
- `apps/edge/internal/events/` — run/node event in-process fanout bus
- `apps/edge/internal/input/` — OpenAI-compatible/A2A 입력 서버 lifecycle 관리
- `apps/edge/internal/node/` — 연결된 node registry와 node 선택
@ -23,6 +26,7 @@ last_rule_updated_at: 2026-06-21
- `apps/edge/internal/service/` — console/HTTP 입력 표면이 공유하는 실행·명령 application service
- `apps/edge/internal/transport/` — node 연결 수락, RegisterRequest/Response 처리, run event 수신
- `apps/edge/README.md` — edge 실행 흐름과 운영 표면 설명
- `apps/edge/Dockerfile` — Edge 배포용 이미지 빌드 표면
## 제외 경로
@ -41,24 +45,31 @@ last_rule_updated_at: 2026-06-21
- `node.NodeStore` — 사전 등록된 `NodeRecord`를 token/ID로 조회; 설정 파일에서 seed
- `node.NodeRecord` — 사전 등록된 node 정의 (ID, alias, token, adapter/runtime config)
- `node.BuildConfigPayload()``NodeRecord`의 adapter 설정을 proto `NodeConfigPayload`로 변환하는 mapper
- `rootCmd()` / `resolveConfigPath()` — bundle-local `edge.yaml`, binary-adjacent config, repo-dev fallback을 처리하는 CLI entrypoint
- `edgecmd.NewRoot()` / `edgecmd.LoadEdgeConfig()` — bundle-local `edge.yaml`, binary-adjacent config, repo-dev fallback을 처리하는 CLI command root와 config loader
- `config init` / `config check` / `config print` — bundle-local Edge 설정 생성·검증·출력 command
- `config refresh` — Edge refresh admin API에 dry-run/apply 요청을 보내 runtime mutable config를 갱신하는 command
- `env` — config discovery, advertise host, log path, node bootstrap URL, OpenAI/A2A URL을 서버 기동 없이 출력하는 진단 command
- `node register``edge.yaml``nodes[]`를 보존형 YAML patch로 추가/갱신하고 one-line bootstrap command를 출력하는 command
- `nodes list` — 설정된 node record를 offline/configured 상태로 조회하는 command
- `smoke openai``/healthz`, `/v1/models`, `/v1/chat/completions`를 확인하는 OpenAI-compatible 진단 command
- `smoke openai``/healthz`, `/v1/models`, `/v1/chat/completions`, `/v1/responses`를 확인하는 OpenAI-compatible 진단 command
- `bootstrap.Module` — fx lifecycle에 `bootstrap.Runtime` start/stop을 연결
- `bootstrap.Runtime` — logger, registry, node store, event bus, service, transport server, input manager, artifact server, Control Plane connector를 묶는 실행 조립체
- `bootstrap.Runtime` — logger, registry, node store, event bus, service, transport server, input manager, artifact server, refresh admin server, Control Plane connector를 묶는 실행 조립체
- `bootstrap.ArtifactServer` — Node bootstrap artifact를 제공하는 Edge-local HTTP server
- `bootstrap.RefreshAdminServer` / `bootstrap.Runtime.RefreshConfig()` — Edge-local config refresh dry-run/apply HTTP 표면과 runtime config swap
- `configrefresh.Classify()` / `configrefresh.Evaluate()` — Edge config 변경을 rejected/applied/restart_required로 분류하고 candidate config를 산출
- `edgevalidate.ValidateEdgeConfig()` — provider/model/adapter 참조와 mock surface 설정을 포함한 Edge config 검증
- `controlplane.Connector` — Control Plane TCP wire에 outbound로 연결하고 hello/status/event relay를 처리하는 connector
- `controlplane.StatusProvider` — Control Plane status request에 답할 Edge-owned node snapshot provider boundary
- `events.Bus``RunEvent``EdgeNodeEvent` subscriber fanout 및 bounded replay
- `service.Service` — node 선택, run dispatch, cancel/terminate-session, node command 요청을 표면 중립 DTO로 제공
- `service.Service` — node 선택, run dispatch, provider pool admission, provider tunnel routing, cancel/terminate-session, node/edge command 요청을 표면 중립 DTO로 제공
- `service.NodeSnapshot` — Control Plane status response에 쓰는 Edge-owned node snapshot DTO
- `service.RunHandle` — foreground run event stream과 dispatch metadata를 함께 들고 있는 handle
- `service.modelQueueManager` — provider/model group capacity, queue, long-context slot admission과 release를 관리
- `service.SubmitProviderPool()` / `service.SubmitProviderTunnel()` — OpenAI-compatible provider-pool 요청을 단일 admission 후 normalized run 또는 raw provider tunnel로 dispatch
- `service.ExecuteCommand()` — Control Plane `EdgeCommandRequest`를 Edge-owned operation으로 실행하고 command event를 emit
- `service.NodeCommandView` / `UsageStatusView` — console/HTTP/RPC surface가 공유할 수 있는 node command 결과 DTO
- `input.Manager` — OpenAI-compatible 서버와 A2A 서버 lifecycle 소유자
- `openai.Server``/v1/models`, `/v1/chat/completions`, SSE stream, strict output policy, Ollama API passthrough를 `service`로 연결하는 HTTP 표면
- `openai.Server``/v1/models`, `/v1/chat/completions`, `/v1/responses`, SSE stream, strict output/tool validation, usage metering, principal token auth, provider pool/passthrough, Ollama API passthrough를 `service`로 연결하는 HTTP 표면
- `a2a.Server` / `a2a.TaskStore` — A2A `message/send`, `tasks/get`, `tasks/cancel`과 task 상태 보관
- `opsconsole.Run` — edge-local console loop와 slash command 처리
- `opsconsole.EventRouter` — run/node event를 edge console 출력으로 라우팅
@ -71,6 +82,7 @@ last_rule_updated_at: 2026-06-21
- 공식 local/field 운영 UX는 `iop-edge` command 표면에 모은다. repo helper script나 README 절차를 공식 사용자 경로로 승격하지 않는다.
- `iop-edge` command 표면은 bootstrap, bundle-local config, env/config 진단, node 등록 command 발급, smoke, Control Plane 없는 단일 Edge 유지보수 범위로 유지한다. 후속 specialized agent enrollment command도 같은 local/field fallback 원칙을 따른다. 상시 multi-edge 운영 UI/API 역할을 CLI에 확대하지 않는다.
- `config init`은 bundle-local `edge.yaml` template을 만들고, `env`는 서버를 기동하지 않고 effective environment를 설명해야 한다.
- CLI command 지원 로직은 `apps/edge/internal/edgecmd`에 두고 `apps/edge/cmd/edge`는 cobra root 조립, serve/console runtime wiring 같은 얇은 entrypoint로 유지한다.
- `node register`는 사용자에게 대상 OS에 맞는 완성된 bootstrap URL과 실제 token 값을 포함한 한 줄 명령을 출력하는 경로를 유지한다. Linux/macOS는 `curl -fsSL ... | bash -s ...`, Windows native는 PowerShell `.ps1` bootstrap과 `Start-IopNode`를 기준으로 한다. 사용자가 기본 경로에서 `node.yaml`을 직접 만들거나 `iop-node serve --config ...`를 직접 실행하게 하지 않는다.
- bootstrap 사용자 기본 명령은 완성된 bootstrap URL과 positional token 하나만 포함한다. Edge address, artifact URL, target/platform, install/config path, metrics port, workspace path 같은 값은 Edge 설정이나 bootstrap script 기본값에 굽고, 사용자가 직접 추가 설정해야 하는 경우에는 기본 명령과 분리된 optional override로만 안내한다.
- 사용자에게 실행 방법을 안내할 때는 placeholder 형식을 쓰지 않는다. token 같은 secret을 현재 채널에 표시할 수 없으면 runnable command처럼 꾸미지 말고, 먼저 안전한 secret 전달 절차를 끝낸 뒤 실제 값이 들어간 완성 명령만 제공한다.
@ -80,9 +92,13 @@ last_rule_updated_at: 2026-06-21
- Registry는 동시성 안전성을 유지하고 외부로 내부 map을 노출하지 않는다.
- NodeStore는 설정 파일에서 한 번 seed되며 런타임 중 변경하지 않는다; token 중복·빈 token은 LoadFromConfig에서 즉시 거부한다.
- adapter config 변환(mapper)은 `node.BuildConfigPayload()`에서만 수행하고 transport 레이어에 변환 로직을 두지 않는다.
- config refresh는 `configrefresh`가 후보 config를 검증·분류하고, runtime mutable 변경만 `Runtime.RefreshConfig()`에서 service/node store/openai catalog에 반영한다. listener address, Edge identity, bootstrap artifact dir처럼 restart가 필요한 변경을 live apply로 조용히 적용하지 않는다.
- 내부 실행 요청은 `adapter + target`으로 표현한다. 외부 API 호환 경계의 `model` 표현을 edge 내부 책임 전체로 확장하지 않는다.
- ops console과 HTTP 입력 표면은 `apps/edge/internal/service`를 호출하는 얇은 어댑터로 유지한다. node 선택, run dispatch, command request 생성은 service 계층에서 공유한다.
- OpenAI-compatible 경계의 `model`과 A2A 경계의 `Task`/JSON-RPC 표현은 입력 표면 안에서만 유지하고, edge 내부 실행은 `service.SubmitRun()``adapter + target` 요청으로 변환한다.
- provider pool에서는 top-level `models[]`의 id를 canonical model group key로 보고, `models[].providers``nodes[].providers[]`를 통해 provider id별 served model로 rewrite한다. caller metadata나 request body의 임의 field가 provider 선택권을 갖지 않게 한다.
- OpenAI-compatible raw passthrough는 `ProviderTunnelRequest`/`ProviderTunnelFrame` 경계와 `service.SubmitProviderTunnel()`을 통해서만 수행한다. HTTP handler가 node transport client에 직접 provider tunnel message를 쓰지 않는다.
- OpenAI principal token auth는 raw token을 config에 저장하지 않고 `principal_tokens[].token_hash_sha256`과 resolved principal metadata만 사용한다. caller-supplied metadata의 `iop_principal_*` 값은 인증된 principal을 덮어쓸 수 없다.
- OpenAI-compatible `/v1/models``openai.models`를 우선하고, 없으면 `openai.target`을 advertised model로 사용한다. 내부 target override와 외부 model echo 정책을 혼동하지 않는다.
- OpenAI/Ollama passthrough성 옵션은 입력 표면에서 명시적으로 변환하고, node adapter의 Ollama 실행 계약을 우회하지 않는다.
- OpenAI-compatible, A2A, Edge-Node, Control Plane connector, config/runtime refresh 계약 상세는 `agent-contract/index.md`에서 매칭 문서를 확인하고 README/rules에 schema 본문을 반복하지 않는다.
@ -92,7 +108,7 @@ last_rule_updated_at: 2026-06-21
- Control Plane status 응답은 `service.Service``ListNodeSnapshots()` 같은 Edge-owned 표면에서 만든다. connector가 registry나 transport internals를 직접 읽어 제품 계약을 만들지 않는다.
- Control Plane node lifecycle event relay는 `events.Bus` 구독으로 수행하고, event metadata에는 필요한 Edge identity만 보강한다.
- CLI, ops console, HTTP/A2A 입력 표면, Control Plane wire connector가 같은 Edge operation을 노출할 때는 `service.Service` 같은 표면 중립 application service로 수렴시킨다. registry 변경, run dispatch, command request 로직을 표면별로 복제하지 않는다.
- `apps/edge/cmd/edge/**`, `apps/edge/internal/bootstrap/**`, `apps/edge/internal/controlplane/**`, `apps/edge/internal/transport/**`, `apps/edge/internal/service/**`, `apps/edge/internal/events/**`, `apps/edge/internal/input/**`, `apps/edge/internal/openai/**`, `apps/edge/internal/opsconsole/**`, `apps/edge/internal/node/**`, console/HTTP/Control Plane 입출력, run/node event relay를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
- `apps/edge/cmd/edge/**`, `apps/edge/internal/bootstrap/**`, `apps/edge/internal/configrefresh/**`, `apps/edge/internal/controlplane/**`, `apps/edge/internal/edgecmd/**`, `apps/edge/internal/edgevalidate/**`, `apps/edge/internal/transport/**`, `apps/edge/internal/service/**`, `apps/edge/internal/events/**`, `apps/edge/internal/input/**`, `apps/edge/internal/openai/**`, `apps/edge/internal/opsconsole/**`, `apps/edge/internal/node/**`, console/HTTP/Control Plane 입출력, run/node event relay를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
## 다른 도메인과의 경계
@ -109,6 +125,8 @@ last_rule_updated_at: 2026-06-21
- Control Plane 구현 전이라도 Node를 Control Plane에 직접 연결하는 경로를 edge 도메인에 추가하지 않는다.
- Control Plane을 Edge 설정, Node registry, runtime/automation 상태의 원본 저장소로 전제하지 않는다.
- Control Plane connector에서 Node token, Node address, transport client 내부 상태를 Control Plane status 계약으로 노출하지 않는다.
- config refresh에서 `restart_required`로 분류된 변경을 runtime에 부분 적용하지 않는다.
- OpenAI-compatible provider pool에서 authenticated principal, provider auth header, workspace 검증을 우회하거나 caller metadata로 대체하지 않는다.
- Control Plane 도입만을 이유로 `iop-edge config`, `env`, `node register`, `nodes list`, `smoke`, `setup` 같은 local/field fallback command 경로를 제거하거나 제품 기본 계약에서 제외하지 않는다. 축소는 별도 roadmap 결정과 대체 fallback 기준이 있을 때만 다룬다.
- `node register`와 bootstrap UX에 named environment parameter 조합을 기본 사용자 경로로 노출하지 않는다.
- bootstrap 안내를 `IOP_*=` 환경 변수 나열, shell wrapper, 원격 token 조회, 수동 `node.yaml` 작성, 수동 `iop-node serve --config ...` 흐름으로 길게 만들지 않는다. 이런 값은 디버그/고급 override 문서로만 분리한다.

View file

@ -1,7 +1,7 @@
---
domain: node
last_rule_review_commit: f59ecea97ead497d352779fe7d33a74166dc0fc9
last_rule_updated_at: 2026-06-21
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# node
@ -20,6 +20,7 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- `apps/node/internal/transport/` — edge와의 TCP/protobuf 세션 및 메시지 처리
- `apps/node/internal/adapters/` — mock/ollama/vllm/cli 실행 어댑터
- `apps/node/internal/store/` — SQLite 실행 이력 저장
- `apps/node/internal/terminal/` — persistent terminal session과 tail buffer helper
- `apps/node/README.md` — node 실행 흐름과 adapter/session 경계 설명
## 제외 경로
@ -36,12 +37,17 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- `runtime.Router` — 실행 요청을 구체적인 `ExecutionSpec`으로 변환하는 계약
- `runtime.CommandHandler` — adapter별 `NodeCommandRequest` 처리 optional 계약
- `runtime.SessionTerminator` — logical session 종료를 지원하는 optional 계약
- `runtime.ProviderProber` / `runtime.ProviderProbeResult` — provider endpoint와 target availability probe optional 계약
- `runtime.ProviderTunnelAdapter` / `ProviderTunnelRequest` / `ProviderTunnelFrame` — OpenAI-compatible provider raw HTTP/SSE tunnel optional 계약
- `node.Node``transport.Handler` 구현체이자 실행 파이프라인 조정자
- `node.runManager` — run ID 기준 `runHandle`(cancel, done) 등록/해제/취소 관리; `node.Node` 내부에서만 사용
- `node.Node.OnConfigRefresh()` — Edge가 보낸 `NodeConfigRefreshRequest`를 적용하고 adapter registry를 live swap
- `node.Node.OnProviderTunnelRequest()` — provider tunnel 요청을 지원 adapter에 전달하고 tunnel frame을 edge session으로 반환
- `node.sessionSink` — adapter `RuntimeEvent`를 proto `RunEvent`로 변환해 edge session으로 보내는 sink
- `transport.Session` — edge와 연결된 node 세션 및 메시지 처리
- `adapters.Registry` — 어댑터 등록/조회 및 `LifecycleAdapter` start/stop lifecycle 관리 (실패 시 역순 롤백)
- `adapters.LifecycleAdapter` — start/stop lifecycle이 필요한 어댑터의 optional 인터페이스
- `adapters.ConfigSet` / `adapters.DiffConfigSets()` — Edge config payload에서 adapter registry/runtime snapshot을 만들고 refresh diff를 산출
- `adapters.BuildFromPayload()` — edge에서 받은 `NodeConfigPayload``Registry`를 초기화하는 factory
- `adapters/cli.CLI` — one-shot, persistent TUI, persistent-lazy, codex-exec, antigravity-print, opencode-sse profile을 실행하는 CLI adapter
- `adapters/cli.clineJSONEmitter` — Cline JSON output을 `RuntimeEvent` delta/error로 변환하는 emitter
@ -51,6 +57,9 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- `adapters/cli/status` — claude/codex/antigravity CLI 상태 파서 (사용량 한도, reset 시각 등)
- `adapters/cli.lineEmitter` — stdout 한 줄을 파싱해 `RuntimeEvent`를 반환하는 내부 인터페이스; `emitters.go`에서 format별로 등록
- `adapters/ollama.Ollama` — Ollama `/api/chat` streaming, `/api/tags` capabilities, `/api/*` command passthrough를 처리하는 adapter
- `adapters/openai_compat.Adapter` — OpenAI-compatible `/v1/models`, chat completions, provider label/header/options passthrough, provider tunnel을 처리하는 adapter
- `adapters/vllm.Vllm` — vLLM/SGLang류 OpenAI-compatible endpoint를 직접 호출하고 provider tunnel을 처리하는 adapter
- `terminal.Session` / `terminal.TailBuffer` — persistent TUI session I/O, resize/signal/close, visible output buffer helper
- `store.Store` — 실행 상태와 결과 저장
## 유지할 패턴
@ -60,10 +69,12 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- 내부 실행 식별자는 `adapter + target`을 사용한다. 외부 OpenAI-compatible API나 legacy placeholder를 제외하고 `model`을 내부 실행 대표 용어로 되돌리지 않는다.
- Edge-Node runtime wire와 Edge가 내려주는 config payload 계약 상세는 `agent-contract/inner/edge-node-runtime-wire.md``agent-contract/inner/edge-config-runtime-refresh.md`를 기준으로 확인한다.
- 어댑터 추가 시 `runtime.Adapter`를 구현하고 `adapters.BuildFromPayload()` 또는 bootstrap registry에 등록한다.
- 여러 adapter instance는 `adapters.Registry.RegisterKeyed(instanceKey, typeName, adapter)`로 등록하고, router lookup은 instance key를 우선한다. legacy type-name lookup은 단일 instance일 때만 안전하다.
- field Node의 기본 시작 경로는 Edge bootstrap script가 만든 최소 config와 Edge가 RegisterResponse로 내려주는 adapter/runtime payload다. 사용자가 기본 경로에서 node config를 직접 작성하거나 adapter/provider 세부값을 명령줄에 넣는 흐름을 만들지 않는다.
- Node runtime 작업 디렉터리나 store/workspace 경로는 대상 OS에서 쓰기 가능한 기본값이어야 한다. Edge가 특정 node에 `workspace_root`를 내려줄 때 macOS/dev host 절대 경로(`/Users/...`) 같은 값을 Linux/Windows node에 재사용하지 않으며, OS별 경로가 필요하면 Edge 설정에 미리 굽는다.
- 실행 취소는 run ID 기준으로 `runManager`에 등록하고 실행 종료 시 반드시 `deregister`로 해제한다.
- `CancelAction_CANCEL_RUN`은 현재 run 취소, `CancelAction_TERMINATE_SESSION`은 logical session 종료로 구분한다.
- `ProviderTunnelRequest`는 run ID/tunnel ID 기준으로 `runManager`에 등록하고, `ProviderTunnelFrame`은 RunEvent stream과 별도 proto message로 edge에 반환한다. tunnel 지원은 `runtime.ProviderTunnelAdapter`를 구현한 adapter에만 허용한다.
- `NodeCommandRequest`는 실행 요청과 분리해 `USAGE_STATUS`, `CAPABILITIES`, `SESSION_LIST`, `TRANSPORT_STATUS` 같은 조회/제어성 명령으로 처리한다.
- `OLLAMA_API` command는 Ollama adapter 내부의 제한된 `/api/*` passthrough로 처리하고, Edge/OpenAI surface가 node HTTP client를 우회해 직접 Ollama에 붙는 구조로 확장하지 않는다.
- `adapters.Registry`의 start/stop은 bootstrap lifecycle에서만 호출하고 개별 adapter에서 직접 호출하지 않는다.
@ -72,10 +83,13 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- `cline-json`, `opencode-json`, `codex-json`, `claude-json` 같은 provider별 stdout parser는 `adapters/cli` emitter로 등록하고 runtime 공통 이벤트로만 외부에 노출한다.
- CLI logical session은 `(target, session_id)`로 식별한다. Antigravity conversation id, Codex external id, opencode session/server 상태를 전역 target 단위로 공유하지 않는다.
- `response_idle_timeout_ms`, `startup_idle_timeout_ms`, `completion_marker`, `resume_args`, `mode` 같은 CLI profile 설정은 edge config/proto payload를 통해 주입하고 node 코드에 target별 상수를 늘리지 않는다.
- config refresh는 `adapters.BuildConfigSet()`로 next registry를 만들고 start 성공 후 router registry를 live swap한다. 기존 in-flight run은 old adapter snapshot으로 마무리하고, old registry stop은 active run drain 뒤에 처리한다.
- Node-wide runtime concurrency는 admission source로 되살리지 않는다. per-adapter `Capabilities().MaxConcurrency`가 adapter gate capacity의 기준이다.
- Ollama adapter는 내부 target을 model 이름으로 사용하고, `context_size``options.num_ctx`의 강제 소유값으로 주입한다. 요청 input에 명시된 `options.num_ctx`가 있어도 Edge-owned `context_size`가 항상 우선한다. `context_size`가 0이면 request 값을 그대로 사용한다.
- vLLM/openai_compat adapter는 OpenAI-compatible provider endpoint를 호출하되, Edge가 선택한 served model target과 provider header/auth/passthrough 정책을 보존한다.
- `RuntimeEvent`는 start/delta/reasoning_delta/complete/error/cancelled 타입을 유지하고, adapter별 streaming 표현을 node 외부로 새 이벤트 체계로 노출하지 않는다.
- node 내부 변경은 가능한 대상 패키지 테스트를 먼저 추가하거나 갱신한다.
- `apps/node/cmd/node/**`, `apps/node/internal/bootstrap/**`, `apps/node/internal/transport/**`, `apps/node/internal/node/**`, `apps/node/internal/router/**`, `apps/node/internal/adapters/**`, `apps/node/internal/store/**`의 실행 요청/응답/stream/cancel/status/session 경로를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
- `apps/node/cmd/node/**`, `apps/node/internal/bootstrap/**`, `apps/node/internal/transport/**`, `apps/node/internal/node/**`, `apps/node/internal/router/**`, `apps/node/internal/adapters/**`, `apps/node/internal/terminal/**`, `apps/node/internal/store/**`의 실행 요청/응답/stream/cancel/status/session/config-refresh/provider-tunnel 경로를 바꾼 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
## 다른 도메인과의 경계
@ -88,6 +102,8 @@ Edge에 연결되어 실제 adapter execution을 수행하는 IOP 노드 에이
- node 도메인 내부에서 gRPC, WebSocket 기본 transport, actor/FSM/plugin framework를 새 기본 구조로 도입하지 않는다.
- `proto/gen/iop/*.pb.go` 생성 파일을 직접 수정하지 않는다.
- 새 어댑터 구현을 `node.Node`에 직접 분기문으로 박아 넣지 않는다.
- provider tunnel 지원을 RunEvent delta에 섞거나 OpenAI-compatible raw response를 node stdout parser처럼 취급하지 않는다.
- config refresh 중 old registry를 in-flight run이 끝나기 전에 stop해 기존 실행을 끊지 않는다.
- edge-local console, OpenAI-compatible HTTP, A2A 같은 입력 표면 책임을 node로 끌어오지 않는다.
- placeholder 상태인 control-plane/worker 책임을 node에 임시로 흡수하지 않는다.
- CLI provider별 session/conversation 상태를 `runtime` 공통 인터페이스로 성급히 승격하지 않는다. provider 세부 상태는 `adapters/cli` 내부에 둔다.

View file

@ -1,18 +1,19 @@
---
domain: platform-common
last_rule_review_commit: 49872ae120627c47175194e837d90f8915d67397
last_rule_updated_at: 2026-06-01
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# platform-common
## 목적 / 책임
여러 앱이 공유하는 설정, 인증, 이벤트 helper, host setup, 정책, 메타데이터, 작업 상태, 관측성, 버전, protobuf 계약을 관리한다. 앱별 구현보다 안정적인 공통 계약과 작은 유틸리티를 제공하며, 내부 실행 계약은 `adapter + target` 방향을 우선한다.
여러 앱이 공유하는 설정, 인증, 감사 event envelope, 이벤트 helper, host setup, 정책, 메타데이터, 작업 상태, 관측성, 버전, protobuf 계약을 관리한다. 앱별 구현보다 안정적인 공통 계약과 작은 유틸리티를 제공하며, 내부 실행 계약은 `adapter + target` 방향을 우선한다.
## 포함 경로
- `packages/go/auth/` — mTLS 인증 설정 helper
- `packages/go/audit/` — 공통 audit event envelope, event type, policy decision baseline
- `packages/go/config/` — 앱 설정 struct, 기본값, YAML 로딩
- `packages/go/events/` — 공통 EdgeNodeEvent 생성 helper와 lifecycle 상수
- `packages/go/hostsetup/` — edge/node systemd 설치 준비와 기본 설정 템플릿
@ -39,9 +40,14 @@ last_rule_updated_at: 2026-06-01
- `config.NodeConfig` / `config.EdgeConfig` — node/edge 앱 설정 계약
- `config.EdgeInfo` / `config.EdgeControlPlaneConf` — Edge identity와 Control Plane outbound connector 설정 계약
- `config.EdgeServerConf` / `config.EdgeBootstrapConf` — Edge listen/advertise host와 artifact bootstrap URL 설정 계약
- `config.EdgeRefreshConf` — Edge-local runtime config refresh admin server 설정 계약
- `config.EdgeOpenAIConf` / `config.EdgeA2AConf` / `config.EdgeConsoleConf` — edge 입력 표면과 console 기본 설정 계약
- `config.OpenAIPrincipalTokenConf` / `config.EdgeOpenAIProviderAuthConf` — OpenAI-compatible caller principal token hash mapping과 provider auth forwarding 설정 계약
- `config.ModelCatalogEntry` / `config.NodeProviderConf` — provider pool model catalog와 node provider candidate 설정 계약
- `config.CLIProfileConf` / `config.CompletionMarkerConf` — CLI adapter profile, mode, resume args, completion marker 설정 계약
- `config.OllamaConf` — Ollama base URL과 context size 설정 계약
- `config.OllamaConf` / `config.VllmConf` / `config.OpenAICompatConf` — provider endpoint, capacity, queue, timeout 설정 계약
- `config.NormalizeAgentKind()` / `config.NormalizeProviderType()` — agent kind와 provider type canonicalization helper
- `audit.Event` / `audit.EventType` / `audit.PolicyDecision` — 실행, terminal, bootstrap event와 정책 판단 공통 envelope
- `auth.LoadServerTLS` / `auth.LoadClientTLS` — mTLS TLS config 생성
- `events.NewEdgeNodeEvent()` — node/edge lifecycle event envelope 생성
- `hostsetup.Run()` / `hostsetup.EdgeSpec()` / `hostsetup.NodeSpec()` / `hostsetup.EdgeBundleConfigTemplate()` — systemd unit, 설정 파일, bundle-local edge config, 데이터 디렉터리 준비
@ -49,9 +55,14 @@ last_rule_updated_at: 2026-06-01
- `policy.Engine` — 정책 적용/검증 계약
- `jobs.Job` — 비동기 작업 상태 placeholder; 내부 실행 대상은 `target`으로 표현
- `proto/iop/*.proto` — 앱 간 메시지 원본 계약
- `Job` / `JobListRequest` / `JobListResponse` — worker/job 상태 조회 placeholder protobuf 계약
- `ProviderTunnelRequest` / `ProviderTunnelFrame` — Edge-Node provider raw tunnel protobuf 계약
- `NodeConfigRefreshRequest` / `NodeConfigRefreshResponse` — Edge runtime config refresh를 node에 전달하는 protobuf 계약
- `ProviderSnapshot` / `AgentUsageStatus` — Edge/Control Plane status와 node command result에 쓰는 runtime 상태 계약
- `ClientHelloRequest` / `ClientHelloResponse` — Client-Control Plane hello baseline 계약
- `EdgeHelloRequest` / `EdgeHelloResponse` — Edge가 Control Plane으로 연결할 때 쓰는 hello baseline 계약
- `EdgeStatusRequest` / `EdgeStatusResponse` / `EdgeNodeSnapshot` — Control Plane이 Edge-owned node snapshot을 조회하는 wire 계약
- `EdgeCommandRequest` / `EdgeCommandResponse` / `EdgeCommandEvent` — Control Plane이 Edge-owned operation을 요청하고 결과/event를 관찰하는 wire 계약
- 상세 계약 라우팅은 `agent-contract/index.md`를 따르고, schema 원본은 `proto/iop/*.proto``packages/go/config/config.go`를 우선한다.
## 유지할 패턴
@ -64,17 +75,21 @@ last_rule_updated_at: 2026-06-01
- 생성 파일(`proto/gen/iop/*.pb.go`)은 사람이 직접 편집하지 않는다.
- Edge-Node, Control Plane-Edge, Client-Control Plane, config/runtime refresh 계약 상세는 `agent-contract/inner/**` 문서를 기준으로 확인하고 domain rule에는 소유권과 금지 사항만 둔다.
- 공통 패키지는 작고 명확한 계약을 유지하고 앱별 정책을 과도하게 끌어올리지 않는다.
- audit package는 공통 event envelope와 validation/redaction baseline까지만 제공한다. durable audit store, retention executor, query API는 앱/운영면 설계에서 별도로 둔다.
- 공통 event helper는 envelope 생성과 상수 정의까지만 담당하고, edge 내부 fanout/replay/store 정책은 edge 도메인에 둔다.
- `RunRequest`, `ExecutionSpec`, `NodeCommandRequest`, `CLIProfileConfig`, job/history 계열 계약을 변경할 때 내부 실행 용어는 `target`을 우선하고, `model`은 외부 호환 경계인지 확인한다.
- `RunRequest`, `ExecutionSpec`, `NodeCommandRequest`, `ProviderTunnelRequest`, `CLIProfileConfig`, job/history 계열 계약을 변경할 때 내부 실행 용어는 `target`을 우선하고, `model`은 외부 호환 경계인지 확인한다.
- provider pool/config refresh schema를 바꾸면 `models[]`, `nodes[].providers[]`, adapter instance config, `configs/*.yaml`, `agent-contract/inner/edge-config-runtime-refresh.md`를 함께 확인한다.
- raw OpenAI-compatible usage token이나 provider token을 공통 config에 저장하지 않는다. caller principal은 hash/ref/alias로 표현하고 provider auth forwarding 설정은 header 이름과 정책만 담는다.
- Control Plane hello 계열 proto는 Edge/Node scheduling 계약으로 확장하지 않는다.
- Control Plane-Edge status proto는 Edge-owned snapshot을 표현한다. Node address, token, direct scheduling 필드를 싣지 않는다.
- `packages/go/config/**`, `packages/go/events/**`, `packages/go/hostsetup/**`, `configs/**`, `proto/iop/**`처럼 edge-node 실행 설정, setup, lifecycle event, 메시지 계약에 영향을 주는 작업을 한 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
- `packages/go/config/**`, `packages/go/audit/**`, `packages/go/events/**`, `packages/go/hostsetup/**`, `configs/**`, `proto/iop/**`처럼 edge-node 실행 설정, setup, audit/lifecycle event, 메시지 계약에 영향을 주는 작업을 한 뒤에는 `testing` domain rule의 작업 후 검증 기준을 따른다.
## 다른 도메인과의 경계
- **node**: node가 필요로 하는 설정/타입/계약을 제공하지만 실행 파이프라인의 소유자는 node이다.
- **edge**: edge가 필요로 하는 설정/관측성/protobuf 계약을 제공하지만 실행 그룹 제어와 node registry 동작의 소유자는 edge이다.
- **control-plane/client/worker**: 앱별 구현에 필요한 공통 타입만 이 영역으로 승격하고 앱 내부 책임은 각 도메인에 둔다.
- **audit/ops**: audit event type과 envelope는 공통 계약이지만, 저장소/조회/retention 실행 정책은 control-plane 또는 별도 운영 도메인에서 결정한다.
## 금지 사항
@ -82,6 +97,7 @@ last_rule_updated_at: 2026-06-01
- 앱 하나만을 위한 임시 타입을 충분한 근거 없이 공통 패키지로 승격하지 않는다.
- edge fanout bus, web UI state, control-plane session 관리처럼 특정 앱의 운영 상태를 공통 패키지로 끌어올리지 않는다.
- 내부 실행 계약을 확장하면서 `model` 중심 명명을 되살리지 않는다. 외부 API 호환이 필요한 경우 경계와 변환 위치를 명시한다.
- raw token, provider credential, private endpoint 값을 `packages/go/config`, `configs/`, proto 기본값에 넣지 않는다.
- protobuf 생성물을 직접 수정하지 않는다.
- Client Dart protobuf 생성물을 proto 원본과 불일치하게 두지 않는다.
- 설정 파일만 바꾸고 `packages/go/config`의 로딩/default와 불일치하게 두지 않는다.

View file

@ -1,7 +1,7 @@
---
domain: testing
last_rule_review_commit: f59ecea97ead497d352779fe7d33a74166dc0fc9
last_rule_updated_at: 2026-06-21
last_rule_review_commit: 7ca329ac9e03bf7cfebfac4517559fc1e2f0bca8
last_rule_updated_at: 2026-07-14
---
# testing
@ -17,8 +17,13 @@ last_rule_updated_at: 2026-06-21
- `scripts/dev/node.sh` — repo 내부 node 연결 개발 진단 helper이다. field 사용자 기본 경로로 안내하지 않는다.
- `scripts/dev/web.sh` — repo 내부 Flutter Web client 개발 진단 helper이다. field 배포 기본 경로로 안내하지 않는다.
- `scripts/e2e-smoke.sh` — mock/real profile 기반 보조 edge-node smoke 검증이다.
- `scripts/e2e-openai-cli-workspace.sh` — OpenAI-compatible `/v1/responses` CLI workspace isolation 보조 smoke 검증이다.
- `scripts/e2e-openai-ollama.sh` — OpenAI-compatible Ollama 입력 표면 보조 smoke 검증이다.
- `scripts/e2e-openai-vllm.sh` — OpenAI-compatible vLLM/SGLang류 provider 입력 표면 보조 smoke 검증이다.
- `scripts/e2e-openai-lemonade.sh` — OpenAI-compatible Lemonade/provider API 입력 표면 보조 smoke 검증이다.
- `scripts/e2e-long-context-admission-smoke.sh` — live provider pool long-context admission/capacity 보조 smoke 검증이다.
- `scripts/e2e-control-plane-edge-wire.sh` — Control Plane-Edge wire hello/disconnect 보조 smoke 검증이다.
- `scripts/fixtures/` — E2E smoke 입력 fixture 위치이다.
- `docker-compose.yml` — local dev용 Control Plane, datastore, Flutter Web client stack 조립 표면이다.
## 제외 경로
@ -39,6 +44,9 @@ last_rule_updated_at: 2026-06-21
- client 개발 진단 흐름 검증 — `scripts/dev/web.sh`로 Flutter Web dev server를 띄우고 Control Plane HTTP/WS URL 주입과 `/client` wire 연결 상태를 확인하는 저수준 검증이다.
- 보조 E2E smoke — 임시 설정과 mock adapter로 최소 생존을 빠르게 확인하는 보조 검증이다. 이 결과만으로 완료 처리하지 않는다.
- OpenAI-compatible Ollama smoke — `scripts/e2e-openai-ollama.sh`로 OpenAI HTTP 입력 표면이 edge service와 node adapter 경로로 수렴하는지 확인하는 보조 검증이다.
- OpenAI-compatible CLI workspace smoke — `scripts/e2e-openai-cli-workspace.sh``metadata.workspace`가 CLI 실행 작업 디렉터리로만 쓰이고 repo root/temp parent로 파일이 새지 않는지 확인하는 보조 검증이다.
- OpenAI-compatible provider smoke — `scripts/e2e-openai-vllm.sh``scripts/e2e-openai-lemonade.sh`로 provider API route, request body, expected output을 확인하는 live-dependency 보조 검증이다.
- Long-context admission smoke — `scripts/e2e-long-context-admission-smoke.sh`로 provider pool capacity, queue, long-context slot, Control Plane status snapshot 회복을 live dev provider pool에서 확인하는 보조 검증이다.
- Control Plane-Edge wire smoke — `scripts/e2e-control-plane-edge-wire.sh`로 실제 Control Plane/Edge 프로세스의 Edge hello, 연결 성공, disconnect marker를 확인하는 보조 검증이다.
- compose local dev stack 검증 — `docker-compose.yml` 변경 시 Control Plane, datastore, Flutter Web service의 build/env/healthcheck wiring을 확인하는 검증이다.
- full-cycle 실제 구동 — 비효율적이어도 관련 사용자 명령과 실행 cycle을 한 번씩 실제 entrypoint로 통과시키는 검증이다.
@ -67,6 +75,8 @@ last_rule_updated_at: 2026-06-21
- `make test-e2e`, `scripts/e2e-smoke.sh`, `scripts/e2e-openai-ollama.sh`, `scripts/e2e-control-plane-edge-wire.sh`는 보조 smoke 명령이다. 실행할 수 있으면 보조 확인으로 기록하되, full-cycle 실제 구동이나 field bootstrap 검증을 대체하지 않는다.
- Client-Control Plane wire나 client UI를 바꾸면 `make client-test`를 기본 검증으로 기록한다. Web build/deploy 경로를 바꾸면 `make client-build-web`, `scripts/dev/web.sh`, compose build 중 변경 범위에 맞는 경로를 추가 확인한다.
- Control Plane-Edge wire나 Edge outbound connector를 바꾸면 대상 Go 테스트와 함께 `make test-control-plane-edge-wire`를 보조 검증으로 기록한다. status snapshot, node event relay, HTTP `/edges` 조회를 바꾼 경우 해당 동작을 별도로 확인한다.
- OpenAI-compatible route, `/v1/responses`, CLI workspace handoff, provider tunnel, provider auth, tool validation, usage metering을 바꾸면 대상 Go 테스트와 함께 관련 OpenAI smoke(`test-openai-ollama`, `scripts/e2e-openai-cli-workspace.sh`, `scripts/e2e-openai-vllm.sh`, `scripts/e2e-openai-lemonade.sh`) 중 변경 범위에 맞는 것을 보조 검증으로 기록한다.
- provider pool, model catalog, queue admission, long-context capacity, Control Plane provider snapshot을 바꾸면 `scripts/e2e-long-context-admission-smoke.sh --preflight`와 필요한 `--scenario`를 live 환경 가용성에 따라 실행하고, 실행 불가/실패는 profile별 blocker로 보고한다.
- `iop-edge bootstrap pack`, `make pack-edge`, 내장 artifact server 변경 시 최소 현재 host target build를 실행하고 archive 압축 해제, artifact 폴더 위치, checksum 생성, node bootstrap script가 positional token UX를 유지하는지 확인한다.
- 풀테스트에서는 실제 외부 CLI profile 검증을 필수로 수행한다. 환경, 계정, provider, 원격 endpoint 문제로 호출할 수 없거나 실패한 profile은 누락하지 말고 profile별 실패 또는 blocker로 보고한다.
- 작업 최종 보고에는 실행한 테스트 명령, repo 내부 edge-node 진단 수행 여부, 보조 E2E smoke 수행 여부, full-cycle 실제 구동 수행 여부를 명시한다. 수행하지 못한 필수 검증은 이유와 남은 위험을 함께 적는다.
@ -130,7 +140,9 @@ terminated session default node=test-node
- `make test-e2e`, `scripts/e2e-smoke.sh`, `scripts/e2e-openai-ollama.sh`, `scripts/e2e-control-plane-edge-wire.sh`, 또는 smoke 통과 출력만으로 완료 처리하지 않는다.
- 관련 작업 후 full-cycle 실제 구동을 비용이 크다는 이유만으로 생략하지 않는다.
- 보조 E2E smoke를 외부 CLI 설치, 로그인, 네트워크 계정 상태에 의존하게 만들지 않는다.
- live-dependency smoke(`e2e-openai-vllm`, `e2e-openai-lemonade`, `e2e-long-context-admission-smoke`)가 필요한 작업에서 endpoint/account/token 문제를 성공으로 간주하지 않는다. 실행 불가는 명확한 blocker 또는 남은 위험으로 보고한다.
- 검증을 위해 기본 `configs/*.yaml`을 임시값으로 오염시키지 않는다. 임시 설정 파일이나 환경 변수 override를 사용한다.
- smoke script가 bearer token, provider token, API key를 stdout/stderr, evidence output, tracked fixture에 기록하지 않게 한다.
- 사용자 기본 bootstrap/install 안내에 `IOP_ARTIFACT_BASE_URL=...`, `IOP_EDGE_ADDR=...`, `IOP_NODE_TOKEN=...` 같은 named environment parameter를 요구하지 않는다. 이런 값은 작업자용 디버그/override 경로로만 분리한다.
- 사용자 기본 bootstrap/install 안내에 원격 token 조회, shell quoting이 복잡한 wrapper, 수동 `node.yaml` 생성, 수동 `iop-node serve --config ...` 실행을 섞지 않는다.
- 사용자 기본 bootstrap/install 안내에 angle-bracket placeholder, `YOUR_TOKEN`, `REPLACE_ME` 같은 치환용 값을 넣지 않는다. 실제 값을 제공할 수 없으면 실행 명령을 제시하지 않고 필요한 값의 안전 전달이 먼저 필요하다고 보고한다.

View file

@ -85,12 +85,14 @@
| `configs/**` | platform-common | `agent-ops/rules/project/domain/platform-common/rules.md` |
| `scripts/dev/**` | testing | `agent-ops/rules/project/domain/testing/rules.md` |
| `scripts/e2e-*.sh` | testing | `agent-ops/rules/project/domain/testing/rules.md` |
| `scripts/fixtures/**` | testing | `agent-ops/rules/project/domain/testing/rules.md` |
| `Makefile` | testing | `agent-ops/rules/project/domain/testing/rules.md` |
| `docker-compose.yml` | testing | `agent-ops/rules/project/domain/testing/rules.md` |
## 도메인 후보
- `worker`: `apps/worker/**`가 placeholder를 넘어 작업 큐 소비/재시도/결과 저장을 구현하기 시작할 때 생성한다.
- `agent-client`: `agent-client/**`의 Claude/Pi host-local gateway·install 흐름을 반복 유지보수 대상으로 다루기 시작할 때 `create-domain-rule`로 별도 도메인 룰을 생성한다.
## 스킬 라우팅