iop/agent-task/m-node-resource-model-unification/01_contract_schema/PLAN-cloud-G07.md
toki 135259619e fix(openai): Cline 도구 호출 변환을 지원한다
Cline이 텍스트 XML 블록으로 도구 호출을 내보내는 경우 OpenAI-compatible tool_calls 응답으로 변환해야 클라이언트 실행 루프가 멈추지 않는다.

Node resource model 로드맵과 agent-task 문서는 요청된 전체 변경 범위에 포함한다.
2026-06-27 13:16:49 +09:00

12 KiB

Node Resource Model Contract Plan

이 파일을 읽는 구현 에이전트에게

이 계획을 구현한 뒤에는 반드시 같은 디렉터리의 CODE_REVIEW-cloud-G07.md에서 구현 에이전트 소유 섹션을 실제 구현 내용, 설계 결정, 검증 출력으로 채운다. 구현 중 선택된 Milestone의 구현 잠금 > 결정 필요가 실구현을 막을 때만 review stub의 사용자 리뷰 요청 섹션을 채우고 멈춘다. 직접 사용자에게 질문하거나 선택지를 제시하거나 request_user_input을 호출하지 않는다. 외부 환경, secret, 서비스 준비, 증거 공백은 사용자 리뷰 요청이 아니라 검증/후속 계획으로 기록한다.

배경

현재 config와 wire는 nodes[].adaptersnodes[].providers를 이미 갖고 있지만, 계약 문서는 NodeRuntimeConfig.concurrency를 node-wide 실행 제한으로 정의한다. 사용자가 정리한 방향은 node가 global gate가 아니라 하나의 identity/connection owner이고, provider/CLI 같은 resource가 node 아래에 명시되는 구조다. 첫 단계는 구현 전 계약과 validation 기준을 맞춰 이후 Node/Edge 변경이 같은 의미를 공유하게 하는 것이다.

사용자 리뷰 요청 흐름

구현 중 사용자 리뷰 요청은 선택된 Milestone lock 결정이 직접 막을 때만 CODE_REVIEW-cloud-G07.md사용자 리뷰 요청 섹션에 기록한다. 선택된 Milestone의 구현 잠금은 해제되어 있으므로 기본값은 없음이다.

Roadmap Targets

  • Milestone: agent-roadmap/phase/operational-observability-provider-management/milestones/node-resource-model-unification.md
  • Task ids:
    • contract-schema: Node runtime contract and resource catalog validation
  • Completion mode: check-on-pass

분석 결과

읽은 파일

  • agent-ops/rules/project/rules.md
  • agent-ops/rules/common/rules-roadmap.md
  • agent-ops/skills/common/router.md
  • agent-ops/skills/common/plan/SKILL.md
  • agent-ops/skills/common/_templates/implementation-user-review-request-section.md
  • agent-roadmap/current.md
  • agent-roadmap/phase/operational-observability-provider-management/PHASE.md
  • agent-roadmap/phase/operational-observability-provider-management/milestones/node-resource-model-unification.md
  • agent-roadmap/sdd/operational-observability-provider-management/node-resource-model-unification/SDD.md
  • agent-roadmap/phase/update-plane-self-update-foundation/PHASE.md
  • agent-roadmap/phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md
  • agent-test/local/rules.md
  • agent-test/local/node-smoke.md
  • agent-test/local/edge-smoke.md
  • agent-test/local/platform-common-smoke.md
  • agent-test/dev/inventory.yaml
  • agent-test/dev/edge-smoke.md
  • agent-test/dev/node-smoke.md
  • agent-test/dev/platform-common-smoke.md
  • agent-contract/index.md
  • agent-contract/inner/edge-node-runtime-wire.md
  • agent-contract/inner/control-plane-edge-wire.md
  • agent-contract/inner/edge-config-runtime-refresh.md
  • agent-contract/outer/openai-compatible-api.md
  • proto/iop/runtime.proto
  • proto/iop/control.proto
  • packages/go/config/config.go
  • apps/edge/internal/edgevalidate/validate.go
  • apps/edge/internal/configrefresh/classify.go
  • apps/edge/internal/node/mapper.go
  • apps/node/internal/adapters/config_set.go
  • packages/go/config/config_test.go
  • apps/edge/internal/configrefresh/classify_test.go
  • apps/edge/internal/node/mapper_test.go
  • apps/node/internal/adapters/config_set_test.go

SDD 기준

선택된 Milestone은 SDD: 필요이며 agent-roadmap/sdd/operational-observability-provider-management/node-resource-model-unification/SDD.md[승인됨], SDD 잠금 해제 상태다. 이 subtask는 Acceptance Scenario S01, S02와 Milestone Task contract-schema를 대상으로 한다.

Evidence Map은 contract/proto/comment diff, config validation unit test, missing/disabled adapter validation output을 요구한다. 따라서 구현 체크리스트는 NodeRuntimeConfig.concurrency legacy/no-op 계약 정리, nodes[].providers[] resource catalog 문서화, provider adapter reference validation, 관련 regression test를 포함한다.

테스트 환경 규칙

test_env는 기본값 local이다. agent-test/local/rules.md와 matching profile node-smoke, edge-smoke, platform-common-smoke를 읽었다. 이 subtask는 packages/go/**, proto/**, agent-contract/**를 건드리므로 go test -count=1 ./packages/go/... ./proto/gen/...와, proto를 바꾸는 경우 make proto를 적용한다. dev-runtime 문서와 원격 smoke는 이 subtask의 필수 검증이 아니며 04번 subtask가 맡는다.

테스트 커버리지 공백

  • NodeRuntimeConfig.concurrency 의미를 legacy/no-op으로 바꾸는 계약 문구는 문서성 변경이라 unit coverage가 없다.
  • provider adapter reference validation은 config/edgevalidate regression test가 필요하다.
  • ProviderSnapshot을 resource snapshot으로 취급하는 compat 의미는 proto field 추가 없이 문서와 status tests로 검증한다.

심볼 참조

삭제/rename 예정 symbol은 없다. 의미 변경 대상은 NodeRuntimeConfig.concurrency, ProviderSnapshot, nodes[].providers[].adapter, runtime.concurrency 문자열이다.

분할 판단

split policy를 먼저 평가했다. 공유 task group은 m-node-resource-model-unification이다.

  • 01_contract_schema: 계약/config validation 기준.
  • 02+01_node_admission: 01 완료 후 Node admission 의미 변경.
  • 03+01_edge_dispatch_status: 01 완료 후 Edge dispatch/status 의미 변경.
  • 04+01,02,03_dev_runtime_profile: 앞선 세 구현 완료 후 dev-runtime 문서/config/smoke 정리.

이 subtask는 선행 의존성이 없다.

범위 결정 근거

새 외부 API endpoint나 gRPC 도입은 제외한다. proto는 가능하면 field 추가 없이 legacy ProviderSnapshot을 resource snapshot compat surface로 문서화하고, 실제 새 field가 꼭 필요하다고 구현 중 판단될 때만 make proto와 생성물 diff를 포함한다.

빌드 등급

cloud-G07: config/proto/contract 의미가 여러 런타임 경계에 영향을 주며, wrong-local implementation이 dev/runtime status를 깨뜨릴 수 있다.

구현 체크리스트

  • NodeRuntimeConfig.concurrency를 node-wide admission source가 아닌 legacy/compat runtime payload로 계약 문서와 comments에서 정리한다.
  • nodes[].providers[]를 현재 wire의 resource catalog로 해석한다는 compat 기준을 문서화하고, category=cli|api|local_inference가 CLI/provider/resource 구분자임을 명시한다.
  • nodes[].providers[].adapter가 같은 node 안의 enabled adapter instance로 해석되어야 한다는 config validation을 추가한다.
  • provider adapter reference, duplicate/resource category, legacy config compatibility regression test를 추가한다.
  • proto 변경이 발생하면 make proto를 실행하고 generated diff가 원본 proto와 일치하는지 확인한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

[API-1] Runtime Concurrency Contract

문제: agent-contract/inner/edge-node-runtime-wire.mdNodeRuntimeConfig.concurrency를 node-wide 실행 제한으로 정의하고, apps/edge/internal/configrefresh/classify.go:220도 live-applyable node-wide concurrency로 주석화한다. 사용자의 방향과 충돌한다.

해결 방법: contract, proto comment, Go comments를 legacy compatibility payload; provider/resource capacity owns admission 의미로 바꾼다. Wire field를 즉시 제거하지 않는다.

Before:

// proto/iop/runtime.proto:251
message NodeRuntimeConfig {
  int32  concurrency    = 1;
  reserved 2;
}

After:

// NodeRuntimeConfig carries legacy node runtime metadata. Execution admission
// must not use this as a node-wide global gate; provider/resource capacity owns concurrency.
message NodeRuntimeConfig {
  int32 concurrency = 1; // legacy compatibility, 0/unset means no node-wide limit
  reserved 2;
}

수정 파일 및 체크리스트:

  • proto/iop/runtime.proto
  • agent-contract/inner/edge-node-runtime-wire.md
  • agent-contract/inner/edge-config-runtime-refresh.md
  • apps/edge/internal/configrefresh/classify.go
  • apps/edge/internal/configrefresh/classify_test.go

테스트 작성: TestClassifyRuntimeConcurrencyLegacyAppliedOrIgnored 형태로 기존 runtime.concurrency only diff의 기대 의미를 갱신한다. 즉시 제거가 아니면 refresh result는 compat상 applied여도 admission 변경을 뜻하지 않는다고 확인한다.

중간 검증:

go test -count=1 ./apps/edge/internal/configrefresh

[API-2] Resource Catalog Validation

문제: packages/go/config/config.go:112NodeProviderConfAdapter를 문자열로 받지만, LoadEdge의 provider loop(packages/go/config/config.go:512)와 edgevalidate.ValidateEdgeConfig는 adapter가 같은 node의 enabled adapter instance인지 확인하지 않는다. Edge dispatch의 providerDispatchableapps/edge/internal/service/run_dispatch.go:476에서 non-empty만 본다.

해결 방법: edgevalidate 또는 config helper에 provider adapter reference resolver를 추가한다. Exact instance key를 우선하고, type-name route는 enabled instance가 정확히 1개일 때만 허용한다. category=cli resource는 CLI enabled를 요구한다.

수정 파일 및 체크리스트:

  • apps/edge/internal/edgevalidate/validate.go
  • packages/go/config/config.go
  • packages/go/config/config_test.go
  • apps/edge/internal/edgevalidate/*_test.go 또는 기존 test package

테스트 작성: bad adapter, disabled adapter, ambiguous type route, valid CLI resource, valid OpenAI-compatible provider instance를 table test로 추가한다.

중간 검증:

go test -count=1 ./packages/go/config ./apps/edge/internal/edgevalidate

[API-3] Resource Snapshot Compatibility

문제: wire는 proto/iop/runtime.proto:118ProviderSnapshotproto/iop/control.proto:83provider_snapshots만 갖는다. 이름은 provider지만 사용자는 CLI/provider 등 resource 목록을 node 아래에 보고 싶어 한다.

해결 방법: field rename 없이 ProviderSnapshot을 legacy wire name으로 유지하고, 계약 문서에서 category가 resource kind를 나타내며 provider-pool 대상은 models[].providers에 참조된 catalog resource뿐이라고 명시한다. 실제 status 정리는 03번 subtask에서 수행한다.

수정 파일 및 체크리스트:

  • proto/iop/runtime.proto
  • proto/iop/control.proto
  • agent-contract/inner/control-plane-edge-wire.md
  • agent-contract/inner/edge-config-runtime-refresh.md

테스트 작성: proto field 추가가 없으면 새 generated test는 생략한다. 문서/comment-only면 go test regression으로 충분하다.

중간 검증:

go test -count=1 ./proto/gen/...

수정 파일 요약

파일 항목
proto/iop/runtime.proto API-1, API-3
proto/iop/control.proto API-3
agent-contract/inner/edge-node-runtime-wire.md API-1
agent-contract/inner/control-plane-edge-wire.md API-3
agent-contract/inner/edge-config-runtime-refresh.md API-1, API-3
packages/go/config/config.go API-2
packages/go/config/config_test.go API-2
apps/edge/internal/edgevalidate/validate.go API-2
apps/edge/internal/configrefresh/classify.go API-1
apps/edge/internal/configrefresh/classify_test.go API-1

최종 검증

go test -count=1 ./packages/go/... ./proto/gen/... ./apps/edge/internal/configrefresh ./apps/edge/internal/node

Proto 원본을 변경했다면 추가로 실행한다.

make proto
git diff -- proto/gen/iop

모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.