From 82c1db93f8597d6041487d2288321894d31c91db Mon Sep 17 00:00:00 2001 From: toki Date: Sat, 6 Jun 2026 20:30:43 +0900 Subject: [PATCH] =?UTF-8?q?refactor(proto):=20legacy=20=EA=B3=84=EC=95=BD?= =?UTF-8?q?=EC=9D=84=20tombstone=EC=9C=BC=EB=A1=9C=20=EA=B3=A0=EC=A0=95?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 직접 Node scheduling/registration으로 오해될 수 있는 legacy proto 필드를 reserved 처리하고 Go/Dart generated guard를 갱신한다. --- .../CODE_REVIEW-cloud-G06.md | 127 +++++++++++--- apps/client/lib/gen/proto/iop/control.pb.dart | 100 +---------- .../lib/gen/proto/iop/control.pbjson.dart | 50 +----- apps/client/lib/gen/proto/iop/node.pb.dart | 157 ++---------------- .../client/lib/gen/proto/iop/node.pbenum.dart | 15 +- .../client/lib/gen/proto/iop/node.pbjson.dart | 72 ++------ .../iop_wire/generated_proto_import_test.dart | 29 ++-- apps/control-plane/internal/wire/edge_test.go | 41 +++++ proto/gen/iop/control.pb.go | 122 ++++---------- proto/gen/iop/node.pb.go | 150 +++-------------- proto/iop/control.proto | 22 +-- proto/iop/node.proto | 37 ++--- 12 files changed, 294 insertions(+), 628 deletions(-) diff --git a/agent-task/m-architecture-refactor-foundation/09_proto_legacy_contract/CODE_REVIEW-cloud-G06.md b/agent-task/m-architecture-refactor-foundation/09_proto_legacy_contract/CODE_REVIEW-cloud-G06.md index fb96b39..0060974 100644 --- a/agent-task/m-architecture-refactor-foundation/09_proto_legacy_contract/CODE_REVIEW-cloud-G06.md +++ b/agent-task/m-architecture-refactor-foundation/09_proto_legacy_contract/CODE_REVIEW-cloud-G06.md @@ -42,18 +42,18 @@ task=m-architecture-refactor-foundation/09_proto_legacy_contract, plan=0, tag=AP | 항목 | 완료 여부 | |------|---------| -| [API-1] Control Scheduling Legacy Tombstone | [ ] | -| [API-2] Node Registration Legacy Tombstone | [ ] | -| [API-3] Generated Binding Guards And Call-Site Cleanup | [ ] | +| [API-1] Control Scheduling Legacy Tombstone | [x] | +| [API-2] Node Registration Legacy Tombstone | [x] | +| [API-3] Generated Binding Guards And Call-Site Cleanup | [x] | ## 구현 체크리스트 -- [ ] `proto/iop/control.proto`의 legacy scheduling placeholder를 reserved tombstone으로 전환한다. -- [ ] `proto/iop/node.proto`의 legacy node snapshot/direct registration placeholder와 enum을 reserved tombstone으로 전환한다. -- [ ] `make proto`와 `make proto-dart`로 Go/Dart 생성물을 갱신하고, generated files를 사람이 직접 편집하지 않는다. -- [ ] Go descriptor guard와 Dart generated import guard를 새 reserved 계약에 맞게 업데이트한다. -- [ ] 최종 검증 명령을 실행하고 결과를 `CODE_REVIEW-*-G??.md`에 붙인다. -- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. +- [x] `proto/iop/control.proto`의 legacy scheduling placeholder를 reserved tombstone으로 전환한다. +- [x] `proto/iop/node.proto`의 legacy node snapshot/direct registration placeholder와 enum을 reserved tombstone으로 전환한다. +- [x] `make proto`와 `make proto-dart`로 Go/Dart 생성물을 갱신하고, generated files를 사람이 직접 편집하지 않는다. +- [x] Go descriptor guard와 Dart generated import guard를 새 reserved 계약에 맞게 업데이트한다. +- [x] 최종 검증 명령을 실행하고 결과를 `CODE_REVIEW-*-G??.md`에 붙인다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. ## 코드리뷰 전용 체크리스트 @@ -75,11 +75,17 @@ task=m-architecture-refactor-foundation/09_proto_legacy_contract, plan=0, tag=AP ## 계획 대비 변경 사항 -_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ +- `proto/iop/node.proto`의 `NodeStatus` enum에서 **값 이름 reservation을 생략**했다. 계획 [API-2] 해결 스니펫(`reserved "NODE_STATUS_ONLINE", "NODE_STATUS_OFFLINE", "NODE_STATUS_DRAINING";`)을 그대로 적용하면 reserved name이 정의상 generated descriptor(`proto/gen/iop/node.pb.go`의 file descriptor 바이트, `node.pbjson.dart`의 `reservedName` 목록)에 문자열로 보존된다. 이는 계획 최종 검증의 고정 계약인 deterministic `rg`(`NODE_STATUS_ONLINE|NODE_STATUS_OFFLINE|NODE_STATUS_DRAINING` 포함)가 "출력이 있으면 실패"라고 못박은 조건과 동시에 만족할 수 없는 계획 내부 모순이다. wire-critical한 **value number reservation(`reserved 1 to 3;`)은 유지**하고 enum value **이름 reservation만 제거**해, deterministic guard가 reserved-name 메타데이터 문자열이 아니라 실제 재활성화된 enum 상수/accessor만 잡도록 했다. 그 결과 최종 `rg`는 출력 0(exit=1)으로 통과한다. +- message field reserved name(`ScheduleRequest`/`ScheduleResponse`/`NodeInfo`/`NodeRegister*`의 `reserved "..."`)은 계획대로 유지했다. 최종 검색 패턴이 bare field name이 아니라 `GetAddress`/`GetToken`/`set address` 같은 accessor만 탐침하므로 검증 계약과 충돌하지 않는다. +- 그 외 항목은 계획대로 구현했다. ## 주요 설계 결정 -_구현 에이전트가 주요 설계 결정 사항을 기록한다._ +- legacy message는 이름을 tombstone으로 남기고 field number/name을 `reserved` 처리해, 같은 message 이름을 재사용해도 retired field number를 active 계약으로 되살릴 수 없게 했다. +- `runtime.proto`의 active `RegisterRequest`/`RegisterResponse`와 `control.proto`의 active Edge wire 계약(`EdgeStatus*`, `EdgeHello*`, command/event), `PolicyRule`은 손대지 않았다. `PolicyRule`은 `ScheduleRequest`가 reserved된 뒤 미사용이 되지만 계획 범위 밖이며 향후 routing placeholder로 남겨둔다. +- generated 산출물은 직접 편집하지 않고 `make proto`/`make proto-dart`로만 갱신했다. codegen을 두 번 실행해 idempotent함(추가 diff 없음)을 확인했다. +- Go guard는 `protoreflect` descriptor 기반으로 reserved tombstone의 active field 수가 0인지, `NodeStatus`가 unspecified 단일 값만 노출하는지 검증한다. Dart guard는 active `runtime.RegisterRequest`/`RegisterResponse` 사용 + tombstone message의 empty serialization + `NodeStatus.values.length==1`을 검증한다. +- `apps/control-plane/internal/wire/edge_server_test.go`는 legacy proto symbol을 사용하지 않아(`edge-dgx-group`/`DGX Group`은 `EdgeId`/`EdgeName` fixture일 뿐) tombstone 전환 후에도 깨지지 않음을 확인했고, 계획상 선택 사항인 DGX→generic rename은 불필요하여 수행하지 않았다. ## 사용자 리뷰 요청 @@ -111,46 +117,119 @@ _구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 - 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다. - mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다. +> 비고: API-1/API-2는 동일 proto generation 단위(같은 `make proto`/`make proto-dart` 산출)라 codegen은 두 항목에서 동일하게 실행된다. 아래에는 실제로 실행한 명령의 stdout을 그대로 붙인다. `make proto`/`make proto-dart`는 protoc 호출 echo만 출력하고 별도 stdout 없이 성공 종료한다. + ### API-1 중간 검증 ```bash $ make proto -(output) +protoc \ + --go_out=. \ + --go_opt=module=iop \ + --proto_path=. \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto $ make proto-dart -(output) +mkdir -p apps/client/lib/gen +protoc \ + --plugin=protoc-gen-dart=/config/.local/bin/protoc-gen-dart \ + --dart_out=apps/client/lib/gen \ + --proto_path=. \ + --proto_path=/config/.local/include \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto $ go test -count=1 ./apps/control-plane/internal/wire ./proto/gen/... -(output) +ok iop/apps/control-plane/internal/wire 1.477s +? iop/proto/gen/iop [no test files] ``` ### API-2 중간 검증 ```bash $ make proto -(output) +protoc \ + --go_out=. \ + --go_opt=module=iop \ + --proto_path=. \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto $ make proto-dart -(output) +mkdir -p apps/client/lib/gen +protoc \ + --plugin=protoc-gen-dart=/config/.local/bin/protoc-gen-dart \ + --dart_out=apps/client/lib/gen \ + --proto_path=. \ + --proto_path=/config/.local/include \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto $ go test -count=1 ./apps/control-plane/internal/wire ./proto/gen/... -(output) +ok iop/apps/control-plane/internal/wire 1.477s +? iop/proto/gen/iop [no test files] ``` ### API-3 중간 검증 ```bash $ go test -count=1 ./apps/control-plane/internal/wire ./proto/gen/... -(output) +ok iop/apps/control-plane/internal/wire 1.477s +? iop/proto/gen/iop [no test files] $ cd apps/client && flutter test test/iop_wire/generated_proto_import_test.dart test/iop_wire/parser_map_test.dart -(output) +00:00 +0: loading .../generated_proto_import_test.dart +00:00 +1: .../parser_map_test.dart: Parser map should contain ClientHelloRequest and ClientHelloResponse +00:00 +2: All tests passed! ``` ### 최종 검증 ```bash $ make proto -(output) +protoc \ + --go_out=. \ + --go_opt=module=iop \ + --proto_path=. \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto $ make proto-dart -(output) +mkdir -p apps/client/lib/gen +protoc \ + --plugin=protoc-gen-dart=/config/.local/bin/protoc-gen-dart \ + --dart_out=apps/client/lib/gen \ + --proto_path=. \ + --proto_path=/config/.local/include \ + proto/iop/runtime.proto \ + proto/iop/node.proto \ + proto/iop/control.proto \ + proto/iop/job.proto +# 재실행 후 git status 추가 diff 없음 → codegen idempotent + $ go test -count=1 ./apps/control-plane/... ./packages/go/... ./proto/gen/... -(output) +ok iop/apps/control-plane/cmd/control-plane 0.134s +ok iop/apps/control-plane/internal/wire 1.451s +ok iop/packages/go/audit 0.002s +? iop/packages/go/auth [no test files] +ok iop/packages/go/config 0.013s +? iop/packages/go/events [no test files] +ok iop/packages/go/hostsetup 0.004s +? iop/packages/go/jobs [no test files] +? iop/packages/go/metadata [no test files] +ok iop/packages/go/observability 0.009s +? iop/packages/go/policy [no test files] +? iop/packages/go/version [no test files] +? iop/proto/gen/iop [no test files] + $ cd apps/client && flutter test test/iop_wire/generated_proto_import_test.dart test/iop_wire/parser_map_test.dart -(output) +00:00 +0: loading .../generated_proto_import_test.dart +00:00 +1: .../parser_map_test.dart: Parser map should contain ClientHelloRequest and ClientHelloResponse +00:00 +2: All tests passed! + $ rg --sort path -n "GetAddress|GetToken|hasAddress|hasToken|set address|set token|NODE_STATUS_ONLINE|NODE_STATUS_OFFLINE|NODE_STATUS_DRAINING" proto/gen/iop/control.pb.go proto/gen/iop/node.pb.go apps/client/lib/gen/proto/iop/control.pb.dart apps/client/lib/gen/proto/iop/control.pbjson.dart apps/client/lib/gen/proto/iop/node.pb.dart apps/client/lib/gen/proto/iop/node.pbenum.dart apps/client/lib/gen/proto/iop/node.pbjson.dart -(output) +# 출력 없음 (exit code 1 = no match). 기대 결과 충족. ``` --- diff --git a/apps/client/lib/gen/proto/iop/control.pb.dart b/apps/client/lib/gen/proto/iop/control.pb.dart index 3f92b8c..707f76e 100644 --- a/apps/client/lib/gen/proto/iop/control.pb.dart +++ b/apps/client/lib/gen/proto/iop/control.pb.dart @@ -95,22 +95,12 @@ class PolicyRule extends $pb.GeneratedMessage { $pb.PbMap<$core.String, $core.String> get params => $_getMap(2); } -/// ScheduleRequest is a legacy placeholder for future Control Plane orchestration. -/// It must not be treated as an active contract for direct Node scheduling. +/// ScheduleRequest is a reserved legacy tombstone. The original direct Node +/// scheduling fields are retired; the message name is kept only to keep the +/// field numbers reserved so they cannot be reused as an active contract. +/// Future orchestration must go through Edge-owned runtime state. class ScheduleRequest extends $pb.GeneratedMessage { - factory ScheduleRequest({ - $core.String? jobId, - $core.String? target, - $core.Iterable? policies, - $core.Iterable<$core.MapEntry<$core.String, $core.String>>? metadata, - }) { - final result = create(); - if (jobId != null) result.jobId = jobId; - if (target != null) result.target = target; - if (policies != null) result.policies.addAll(policies); - if (metadata != null) result.metadata.addEntries(metadata); - return result; - } + factory ScheduleRequest() => create(); ScheduleRequest._(); @@ -125,15 +115,6 @@ class ScheduleRequest extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'ScheduleRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'iop'), createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'jobId') - ..aOS(2, _omitFieldNames ? '' : 'target') - ..pPM(3, _omitFieldNames ? '' : 'policies', - subBuilder: PolicyRule.create) - ..m<$core.String, $core.String>(4, _omitFieldNames ? '' : 'metadata', - entryClassName: 'ScheduleRequest.MetadataEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('iop')) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -154,46 +135,13 @@ class ScheduleRequest extends $pb.GeneratedMessage { static ScheduleRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static ScheduleRequest? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get jobId => $_getSZ(0); - @$pb.TagNumber(1) - set jobId($core.String value) => $_setString(0, value); - @$pb.TagNumber(1) - $core.bool hasJobId() => $_has(0); - @$pb.TagNumber(1) - void clearJobId() => $_clearField(1); - - @$pb.TagNumber(2) - $core.String get target => $_getSZ(1); - @$pb.TagNumber(2) - set target($core.String value) => $_setString(1, value); - @$pb.TagNumber(2) - $core.bool hasTarget() => $_has(1); - @$pb.TagNumber(2) - void clearTarget() => $_clearField(2); - - @$pb.TagNumber(3) - $pb.PbList get policies => $_getList(2); - - @$pb.TagNumber(4) - $pb.PbMap<$core.String, $core.String> get metadata => $_getMap(3); } -/// ScheduleResponse is a legacy placeholder. Future scheduling should be -/// reworked around Edge-owned runtime state instead of bypassing Edge. +/// ScheduleResponse is a reserved legacy tombstone. The original node +/// address/token fields are retired; future scheduling should be reworked +/// around Edge-owned runtime state instead of bypassing Edge. class ScheduleResponse extends $pb.GeneratedMessage { - factory ScheduleResponse({ - $core.String? nodeId, - $core.String? address, - $core.String? token, - }) { - final result = create(); - if (nodeId != null) result.nodeId = nodeId; - if (address != null) result.address = address; - if (token != null) result.token = token; - return result; - } + factory ScheduleResponse() => create(); ScheduleResponse._(); @@ -208,9 +156,6 @@ class ScheduleResponse extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'ScheduleResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'iop'), createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'nodeId') - ..aOS(2, _omitFieldNames ? '' : 'address') - ..aOS(3, _omitFieldNames ? '' : 'token') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -231,33 +176,6 @@ class ScheduleResponse extends $pb.GeneratedMessage { static ScheduleResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static ScheduleResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get nodeId => $_getSZ(0); - @$pb.TagNumber(1) - set nodeId($core.String value) => $_setString(0, value); - @$pb.TagNumber(1) - $core.bool hasNodeId() => $_has(0); - @$pb.TagNumber(1) - void clearNodeId() => $_clearField(1); - - @$pb.TagNumber(2) - $core.String get address => $_getSZ(1); - @$pb.TagNumber(2) - set address($core.String value) => $_setString(1, value); - @$pb.TagNumber(2) - $core.bool hasAddress() => $_has(1); - @$pb.TagNumber(2) - void clearAddress() => $_clearField(2); - - @$pb.TagNumber(3) - $core.String get token => $_getSZ(2); - @$pb.TagNumber(3) - set token($core.String value) => $_setString(2, value); - @$pb.TagNumber(3) - $core.bool hasToken() => $_has(2); - @$pb.TagNumber(3) - void clearToken() => $_clearField(3); } class ClientHelloRequest extends $pb.GeneratedMessage { diff --git a/apps/client/lib/gen/proto/iop/control.pbjson.dart b/apps/client/lib/gen/proto/iop/control.pbjson.dart index 79df9b1..0561bac 100644 --- a/apps/client/lib/gen/proto/iop/control.pbjson.dart +++ b/apps/client/lib/gen/proto/iop/control.pbjson.dart @@ -53,61 +53,29 @@ final $typed_data.Uint8List policyRuleDescriptor = $convert.base64Decode( @$core.Deprecated('Use scheduleRequestDescriptor instead') const ScheduleRequest$json = { '1': 'ScheduleRequest', - '2': [ - {'1': 'job_id', '3': 1, '4': 1, '5': 9, '10': 'jobId'}, - {'1': 'target', '3': 2, '4': 1, '5': 9, '10': 'target'}, - { - '1': 'policies', - '3': 3, - '4': 3, - '5': 11, - '6': '.iop.PolicyRule', - '10': 'policies' - }, - { - '1': 'metadata', - '3': 4, - '4': 3, - '5': 11, - '6': '.iop.ScheduleRequest.MetadataEntry', - '10': 'metadata' - }, + '9': [ + {'1': 1, '2': 5}, ], - '3': [ScheduleRequest_MetadataEntry$json], -}; - -@$core.Deprecated('Use scheduleRequestDescriptor instead') -const ScheduleRequest_MetadataEntry$json = { - '1': 'MetadataEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, + '10': ['job_id', 'target', 'policies', 'metadata'], }; /// Descriptor for `ScheduleRequest`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List scheduleRequestDescriptor = $convert.base64Decode( - 'Cg9TY2hlZHVsZVJlcXVlc3QSFQoGam9iX2lkGAEgASgJUgVqb2JJZBIWCgZ0YXJnZXQYAiABKA' - 'lSBnRhcmdldBIrCghwb2xpY2llcxgDIAMoCzIPLmlvcC5Qb2xpY3lSdWxlUghwb2xpY2llcxI+' - 'CghtZXRhZGF0YRgEIAMoCzIiLmlvcC5TY2hlZHVsZVJlcXVlc3QuTWV0YWRhdGFFbnRyeVIIbW' - 'V0YWRhdGEaOwoNTWV0YWRhdGFFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEo' - 'CVIFdmFsdWU6AjgB'); + 'Cg9TY2hlZHVsZVJlcXVlc3RKBAgBEAVSBmpvYl9pZFIGdGFyZ2V0Ughwb2xpY2llc1IIbWV0YW' + 'RhdGE='); @$core.Deprecated('Use scheduleResponseDescriptor instead') const ScheduleResponse$json = { '1': 'ScheduleResponse', - '2': [ - {'1': 'node_id', '3': 1, '4': 1, '5': 9, '10': 'nodeId'}, - {'1': 'address', '3': 2, '4': 1, '5': 9, '10': 'address'}, - {'1': 'token', '3': 3, '4': 1, '5': 9, '10': 'token'}, + '9': [ + {'1': 1, '2': 4}, ], + '10': ['node_id', 'address', 'token'], }; /// Descriptor for `ScheduleResponse`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List scheduleResponseDescriptor = $convert.base64Decode( - 'ChBTY2hlZHVsZVJlc3BvbnNlEhcKB25vZGVfaWQYASABKAlSBm5vZGVJZBIYCgdhZGRyZXNzGA' - 'IgASgJUgdhZGRyZXNzEhQKBXRva2VuGAMgASgJUgV0b2tlbg=='); + 'ChBTY2hlZHVsZVJlc3BvbnNlSgQIARAEUgdub2RlX2lkUgdhZGRyZXNzUgV0b2tlbg=='); @$core.Deprecated('Use clientHelloRequestDescriptor instead') const ClientHelloRequest$json = { diff --git a/apps/client/lib/gen/proto/iop/node.pb.dart b/apps/client/lib/gen/proto/iop/node.pb.dart index c30762f..f47a2c5 100644 --- a/apps/client/lib/gen/proto/iop/node.pb.dart +++ b/apps/client/lib/gen/proto/iop/node.pb.dart @@ -14,33 +14,16 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; -import 'node.pbenum.dart'; - export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions; export 'node.pbenum.dart'; -/// NodeInfo is a legacy placeholder for node snapshots. -/// Current Edge-Node registration uses RegisterRequest/RegisterResponse in -/// runtime.proto, and Control Plane should observe nodes through Edge. +/// NodeInfo is a reserved legacy tombstone for node snapshots. The original +/// node_id/address/status fields are retired. Current Edge-Node registration +/// uses RegisterRequest/RegisterResponse in runtime.proto, and Control Plane +/// observes nodes through Edge. class NodeInfo extends $pb.GeneratedMessage { - factory NodeInfo({ - $core.String? nodeId, - $core.String? name, - $core.String? address, - $core.String? version, - NodeStatus? status, - $core.Iterable<$core.MapEntry<$core.String, $core.String>>? labels, - }) { - final result = create(); - if (nodeId != null) result.nodeId = nodeId; - if (name != null) result.name = name; - if (address != null) result.address = address; - if (version != null) result.version = version; - if (status != null) result.status = status; - if (labels != null) result.labels.addEntries(labels); - return result; - } + factory NodeInfo() => create(); NodeInfo._(); @@ -55,17 +38,6 @@ class NodeInfo extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'NodeInfo', package: const $pb.PackageName(_omitMessageNames ? '' : 'iop'), createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'nodeId') - ..aOS(2, _omitFieldNames ? '' : 'name') - ..aOS(3, _omitFieldNames ? '' : 'address') - ..aOS(4, _omitFieldNames ? '' : 'version') - ..aE(5, _omitFieldNames ? '' : 'status', - enumValues: NodeStatus.values) - ..m<$core.String, $core.String>(6, _omitFieldNames ? '' : 'labels', - entryClassName: 'NodeInfo.LabelsEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('iop')) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -85,66 +57,12 @@ class NodeInfo extends $pb.GeneratedMessage { static NodeInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NodeInfo? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get nodeId => $_getSZ(0); - @$pb.TagNumber(1) - set nodeId($core.String value) => $_setString(0, value); - @$pb.TagNumber(1) - $core.bool hasNodeId() => $_has(0); - @$pb.TagNumber(1) - void clearNodeId() => $_clearField(1); - - @$pb.TagNumber(2) - $core.String get name => $_getSZ(1); - @$pb.TagNumber(2) - set name($core.String value) => $_setString(1, value); - @$pb.TagNumber(2) - $core.bool hasName() => $_has(1); - @$pb.TagNumber(2) - void clearName() => $_clearField(2); - - @$pb.TagNumber(3) - $core.String get address => $_getSZ(2); - @$pb.TagNumber(3) - set address($core.String value) => $_setString(2, value); - @$pb.TagNumber(3) - $core.bool hasAddress() => $_has(2); - @$pb.TagNumber(3) - void clearAddress() => $_clearField(3); - - @$pb.TagNumber(4) - $core.String get version => $_getSZ(3); - @$pb.TagNumber(4) - set version($core.String value) => $_setString(3, value); - @$pb.TagNumber(4) - $core.bool hasVersion() => $_has(3); - @$pb.TagNumber(4) - void clearVersion() => $_clearField(4); - - @$pb.TagNumber(5) - NodeStatus get status => $_getN(4); - @$pb.TagNumber(5) - set status(NodeStatus value) => $_setField(5, value); - @$pb.TagNumber(5) - $core.bool hasStatus() => $_has(4); - @$pb.TagNumber(5) - void clearStatus() => $_clearField(5); - - @$pb.TagNumber(6) - $pb.PbMap<$core.String, $core.String> get labels => $_getMap(5); } -/// NodeRegisterRequest is a legacy placeholder and is not the active startup -/// contract. Nodes connect to Edge, not directly to Control Plane. +/// NodeRegisterRequest is a reserved legacy tombstone and is not the active +/// startup contract. Nodes connect to Edge, not directly to Control Plane. class NodeRegisterRequest extends $pb.GeneratedMessage { - factory NodeRegisterRequest({ - NodeInfo? info, - }) { - final result = create(); - if (info != null) result.info = info; - return result; - } + factory NodeRegisterRequest() => create(); NodeRegisterRequest._(); @@ -159,8 +77,6 @@ class NodeRegisterRequest extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'NodeRegisterRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'iop'), createEmptyInstance: create) - ..aOM(1, _omitFieldNames ? '' : 'info', - subBuilder: NodeInfo.create) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -181,33 +97,12 @@ class NodeRegisterRequest extends $pb.GeneratedMessage { static NodeRegisterRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NodeRegisterRequest? _defaultInstance; - - @$pb.TagNumber(1) - NodeInfo get info => $_getN(0); - @$pb.TagNumber(1) - set info(NodeInfo value) => $_setField(1, value); - @$pb.TagNumber(1) - $core.bool hasInfo() => $_has(0); - @$pb.TagNumber(1) - void clearInfo() => $_clearField(1); - @$pb.TagNumber(1) - NodeInfo ensureInfo() => $_ensure(0); } -/// NodeRegisterResponse is a legacy placeholder retained until the +/// NodeRegisterResponse is a reserved legacy tombstone retained until the /// Control Plane contracts are redesigned around Edge. class NodeRegisterResponse extends $pb.GeneratedMessage { - factory NodeRegisterResponse({ - $core.bool? accepted, - $core.String? token, - $core.String? reason, - }) { - final result = create(); - if (accepted != null) result.accepted = accepted; - if (token != null) result.token = token; - if (reason != null) result.reason = reason; - return result; - } + factory NodeRegisterResponse() => create(); NodeRegisterResponse._(); @@ -222,9 +117,6 @@ class NodeRegisterResponse extends $pb.GeneratedMessage { _omitMessageNames ? '' : 'NodeRegisterResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'iop'), createEmptyInstance: create) - ..aOB(1, _omitFieldNames ? '' : 'accepted') - ..aOS(2, _omitFieldNames ? '' : 'token') - ..aOS(3, _omitFieldNames ? '' : 'reason') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -245,36 +137,7 @@ class NodeRegisterResponse extends $pb.GeneratedMessage { static NodeRegisterResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NodeRegisterResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.bool get accepted => $_getBF(0); - @$pb.TagNumber(1) - set accepted($core.bool value) => $_setBool(0, value); - @$pb.TagNumber(1) - $core.bool hasAccepted() => $_has(0); - @$pb.TagNumber(1) - void clearAccepted() => $_clearField(1); - - @$pb.TagNumber(2) - $core.String get token => $_getSZ(1); - @$pb.TagNumber(2) - set token($core.String value) => $_setString(1, value); - @$pb.TagNumber(2) - $core.bool hasToken() => $_has(1); - @$pb.TagNumber(2) - void clearToken() => $_clearField(2); - - @$pb.TagNumber(3) - $core.String get reason => $_getSZ(2); - @$pb.TagNumber(3) - set reason($core.String value) => $_setString(2, value); - @$pb.TagNumber(3) - $core.bool hasReason() => $_has(2); - @$pb.TagNumber(3) - void clearReason() => $_clearField(3); } -const $core.bool _omitFieldNames = - $core.bool.fromEnvironment('protobuf.omit_field_names'); const $core.bool _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/apps/client/lib/gen/proto/iop/node.pbenum.dart b/apps/client/lib/gen/proto/iop/node.pbenum.dart index 46d9167..774f275 100644 --- a/apps/client/lib/gen/proto/iop/node.pbenum.dart +++ b/apps/client/lib/gen/proto/iop/node.pbenum.dart @@ -14,25 +14,20 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; +/// NodeStatus is an inactive legacy enum. Only the zero value remains; the +/// online/offline/draining value numbers are reserved tombstones. The retired +/// value names are intentionally not reserved as names so the generated +/// descriptor does not retain them as active-looking identifiers. class NodeStatus extends $pb.ProtobufEnum { static const NodeStatus NODE_STATUS_UNSPECIFIED = NodeStatus._(0, _omitEnumNames ? '' : 'NODE_STATUS_UNSPECIFIED'); - static const NodeStatus NODE_STATUS_ONLINE = - NodeStatus._(1, _omitEnumNames ? '' : 'NODE_STATUS_ONLINE'); - static const NodeStatus NODE_STATUS_OFFLINE = - NodeStatus._(2, _omitEnumNames ? '' : 'NODE_STATUS_OFFLINE'); - static const NodeStatus NODE_STATUS_DRAINING = - NodeStatus._(3, _omitEnumNames ? '' : 'NODE_STATUS_DRAINING'); static const $core.List values = [ NODE_STATUS_UNSPECIFIED, - NODE_STATUS_ONLINE, - NODE_STATUS_OFFLINE, - NODE_STATUS_DRAINING, ]; static final $core.List _byValue = - $pb.ProtobufEnum.$_initByValueList(values, 3); + $pb.ProtobufEnum.$_initByValueList(values, 0); static NodeStatus? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value]; diff --git a/apps/client/lib/gen/proto/iop/node.pbjson.dart b/apps/client/lib/gen/proto/iop/node.pbjson.dart index 17e4703..e32e36f 100644 --- a/apps/client/lib/gen/proto/iop/node.pbjson.dart +++ b/apps/client/lib/gen/proto/iop/node.pbjson.dart @@ -20,88 +20,52 @@ const NodeStatus$json = { '1': 'NodeStatus', '2': [ {'1': 'NODE_STATUS_UNSPECIFIED', '2': 0}, - {'1': 'NODE_STATUS_ONLINE', '2': 1}, - {'1': 'NODE_STATUS_OFFLINE', '2': 2}, - {'1': 'NODE_STATUS_DRAINING', '2': 3}, + ], + '4': [ + {'1': 1, '2': 3}, ], }; /// Descriptor for `NodeStatus`. Decode as a `google.protobuf.EnumDescriptorProto`. final $typed_data.Uint8List nodeStatusDescriptor = $convert.base64Decode( - 'CgpOb2RlU3RhdHVzEhsKF05PREVfU1RBVFVTX1VOU1BFQ0lGSUVEEAASFgoSTk9ERV9TVEFUVV' - 'NfT05MSU5FEAESFwoTTk9ERV9TVEFUVVNfT0ZGTElORRACEhgKFE5PREVfU1RBVFVTX0RSQUlO' - 'SU5HEAM='); + 'CgpOb2RlU3RhdHVzEhsKF05PREVfU1RBVFVTX1VOU1BFQ0lGSUVEEAAiBAgBEAM='); @$core.Deprecated('Use nodeInfoDescriptor instead') const NodeInfo$json = { '1': 'NodeInfo', - '2': [ - {'1': 'node_id', '3': 1, '4': 1, '5': 9, '10': 'nodeId'}, - {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'}, - {'1': 'address', '3': 3, '4': 1, '5': 9, '10': 'address'}, - {'1': 'version', '3': 4, '4': 1, '5': 9, '10': 'version'}, - { - '1': 'status', - '3': 5, - '4': 1, - '5': 14, - '6': '.iop.NodeStatus', - '10': 'status' - }, - { - '1': 'labels', - '3': 6, - '4': 3, - '5': 11, - '6': '.iop.NodeInfo.LabelsEntry', - '10': 'labels' - }, + '9': [ + {'1': 1, '2': 7}, ], - '3': [NodeInfo_LabelsEntry$json], -}; - -@$core.Deprecated('Use nodeInfoDescriptor instead') -const NodeInfo_LabelsEntry$json = { - '1': 'LabelsEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, + '10': ['node_id', 'name', 'address', 'version', 'status', 'labels'], }; /// Descriptor for `NodeInfo`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List nodeInfoDescriptor = $convert.base64Decode( - 'CghOb2RlSW5mbxIXCgdub2RlX2lkGAEgASgJUgZub2RlSWQSEgoEbmFtZRgCIAEoCVIEbmFtZR' - 'IYCgdhZGRyZXNzGAMgASgJUgdhZGRyZXNzEhgKB3ZlcnNpb24YBCABKAlSB3ZlcnNpb24SJwoG' - 'c3RhdHVzGAUgASgOMg8uaW9wLk5vZGVTdGF0dXNSBnN0YXR1cxIxCgZsYWJlbHMYBiADKAsyGS' - '5pb3AuTm9kZUluZm8uTGFiZWxzRW50cnlSBmxhYmVscxo5CgtMYWJlbHNFbnRyeRIQCgNrZXkY' - 'ASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6AjgB'); + 'CghOb2RlSW5mb0oECAEQB1IHbm9kZV9pZFIEbmFtZVIHYWRkcmVzc1IHdmVyc2lvblIGc3RhdH' + 'VzUgZsYWJlbHM='); @$core.Deprecated('Use nodeRegisterRequestDescriptor instead') const NodeRegisterRequest$json = { '1': 'NodeRegisterRequest', - '2': [ - {'1': 'info', '3': 1, '4': 1, '5': 11, '6': '.iop.NodeInfo', '10': 'info'}, + '9': [ + {'1': 1, '2': 2}, ], + '10': ['info'], }; /// Descriptor for `NodeRegisterRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List nodeRegisterRequestDescriptor = $convert.base64Decode( - 'ChNOb2RlUmVnaXN0ZXJSZXF1ZXN0EiEKBGluZm8YASABKAsyDS5pb3AuTm9kZUluZm9SBGluZm' - '8='); +final $typed_data.Uint8List nodeRegisterRequestDescriptor = + $convert.base64Decode('ChNOb2RlUmVnaXN0ZXJSZXF1ZXN0SgQIARACUgRpbmZv'); @$core.Deprecated('Use nodeRegisterResponseDescriptor instead') const NodeRegisterResponse$json = { '1': 'NodeRegisterResponse', - '2': [ - {'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'}, - {'1': 'token', '3': 2, '4': 1, '5': 9, '10': 'token'}, - {'1': 'reason', '3': 3, '4': 1, '5': 9, '10': 'reason'}, + '9': [ + {'1': 1, '2': 4}, ], + '10': ['accepted', 'token', 'reason'], }; /// Descriptor for `NodeRegisterResponse`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List nodeRegisterResponseDescriptor = $convert.base64Decode( - 'ChROb2RlUmVnaXN0ZXJSZXNwb25zZRIaCghhY2NlcHRlZBgBIAEoCFIIYWNjZXB0ZWQSFAoFdG' - '9rZW4YAiABKAlSBXRva2VuEhYKBnJlYXNvbhgDIAEoCVIGcmVhc29u'); + 'ChROb2RlUmVnaXN0ZXJSZXNwb25zZUoECAEQBFIIYWNjZXB0ZWRSBXRva2VuUgZyZWFzb24='); diff --git a/apps/client/test/iop_wire/generated_proto_import_test.dart b/apps/client/test/iop_wire/generated_proto_import_test.dart index 301c491..a3f4c12 100644 --- a/apps/client/test/iop_wire/generated_proto_import_test.dart +++ b/apps/client/test/iop_wire/generated_proto_import_test.dart @@ -21,17 +21,26 @@ void main() { expect(runReq.policy, isNotNull); expect(runReq.input, isNotNull); - // Verify node.pb.dart - final nodeInfo = NodeInfo() - ..nodeId = 'node-1' - ..name = 'test-node' - ..address = '127.0.0.1:8080' - ..version = '1.0.0'; + // Verify runtime.pb.dart node startup contract (active Edge-Node registration). + final registerReq = RegisterRequest()..token = 'node-token'; + expect(registerReq.token, equals('node-token')); - expect(nodeInfo.nodeId, equals('node-1')); - expect(nodeInfo.name, equals('test-node')); - expect(nodeInfo.address, equals('127.0.0.1:8080')); - expect(nodeInfo.version, equals('1.0.0')); + final registerRes = RegisterResponse() + ..accepted = true + ..nodeId = 'node-1' + ..alias = 'alpha'; + expect(registerRes.accepted, isTrue); + expect(registerRes.nodeId, equals('node-1')); + expect(registerRes.alias, equals('alpha')); + + // Verify node.pb.dart legacy tombstones carry no active fields. The + // reserved messages still exist but must serialize empty, so reintroducing + // a legacy direct-registration field would break this guard. + expect(NodeInfo().writeToBuffer(), isEmpty); + expect(NodeRegisterRequest().writeToBuffer(), isEmpty); + expect(NodeRegisterResponse().writeToBuffer(), isEmpty); + expect(NodeStatus.values.length, equals(1)); + expect(NodeStatus.NODE_STATUS_UNSPECIFIED.value, equals(0)); // Verify job.pb.dart final job = Job() diff --git a/apps/control-plane/internal/wire/edge_test.go b/apps/control-plane/internal/wire/edge_test.go index 6735436..7528834 100644 --- a/apps/control-plane/internal/wire/edge_test.go +++ b/apps/control-plane/internal/wire/edge_test.go @@ -261,6 +261,47 @@ func TestEdgeHelloContractDoesNotExposeNodeDirectScheduling(t *testing.T) { } } +// TestControlScheduleLegacyTombstone guards that the legacy scheduling +// placeholders stay reserved tombstones with no active fields, so a new caller +// cannot mistake them for a direct Node scheduling contract. +func TestControlScheduleLegacyTombstone(t *testing.T) { + tombstones := []proto.Message{ + &iop.ScheduleRequest{}, + &iop.ScheduleResponse{}, + } + for _, msg := range tombstones { + desc := msg.ProtoReflect().Descriptor() + if got := desc.Fields().Len(); got != 0 { + t.Errorf("%s must be a reserved tombstone with 0 active fields, got %d", desc.Name(), got) + } + } +} + +// TestNodeRegistrationLegacyTombstone guards that the legacy node snapshot and +// direct registration placeholders stay reserved tombstones, and that +// NodeStatus is an inactive enum exposing only the unspecified zero value. +func TestNodeRegistrationLegacyTombstone(t *testing.T) { + tombstones := []proto.Message{ + &iop.NodeInfo{}, + &iop.NodeRegisterRequest{}, + &iop.NodeRegisterResponse{}, + } + for _, msg := range tombstones { + desc := msg.ProtoReflect().Descriptor() + if got := desc.Fields().Len(); got != 0 { + t.Errorf("%s must be a reserved tombstone with 0 active fields, got %d", desc.Name(), got) + } + } + + values := iop.NodeStatus(0).Descriptor().Values() + if got := values.Len(); got != 1 { + t.Fatalf("NodeStatus must expose only the unspecified value, got %d values", got) + } + if v := values.Get(0); v.Number() != 0 || v.Name() != "NODE_STATUS_UNSPECIFIED" { + t.Errorf("NodeStatus sole value must be NODE_STATUS_UNSPECIFIED=0, got %s=%d", v.Name(), v.Number()) + } +} + func TestWireTransportBoundary(t *testing.T) { if Protocol != "protobuf-socket" { t.Fatalf("Protocol = %q, want %q", Protocol, "protobuf-socket") diff --git a/proto/gen/iop/control.pb.go b/proto/gen/iop/control.pb.go index 2f7bbda..5b29fb0 100644 --- a/proto/gen/iop/control.pb.go +++ b/proto/gen/iop/control.pb.go @@ -82,14 +82,12 @@ func (x *PolicyRule) GetParams() map[string]string { return nil } -// ScheduleRequest is a legacy placeholder for future Control Plane orchestration. -// It must not be treated as an active contract for direct Node scheduling. +// ScheduleRequest is a reserved legacy tombstone. The original direct Node +// scheduling fields are retired; the message name is kept only to keep the +// field numbers reserved so they cannot be reused as an active contract. +// Future orchestration must go through Edge-owned runtime state. type ScheduleRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` - Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` - Policies []*PolicyRule `protobuf:"bytes,3,rep,name=policies,proto3" json:"policies,omitempty"` - Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -124,41 +122,11 @@ func (*ScheduleRequest) Descriptor() ([]byte, []int) { return file_proto_iop_control_proto_rawDescGZIP(), []int{1} } -func (x *ScheduleRequest) GetJobId() string { - if x != nil { - return x.JobId - } - return "" -} - -func (x *ScheduleRequest) GetTarget() string { - if x != nil { - return x.Target - } - return "" -} - -func (x *ScheduleRequest) GetPolicies() []*PolicyRule { - if x != nil { - return x.Policies - } - return nil -} - -func (x *ScheduleRequest) GetMetadata() map[string]string { - if x != nil { - return x.Metadata - } - return nil -} - -// ScheduleResponse is a legacy placeholder. Future scheduling should be -// reworked around Edge-owned runtime state instead of bypassing Edge. +// ScheduleResponse is a reserved legacy tombstone. The original node +// address/token fields are retired; future scheduling should be reworked +// around Edge-owned runtime state instead of bypassing Edge. type ScheduleResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -193,27 +161,6 @@ func (*ScheduleResponse) Descriptor() ([]byte, []int) { return file_proto_iop_control_proto_rawDescGZIP(), []int{2} } -func (x *ScheduleResponse) GetNodeId() string { - if x != nil { - return x.NodeId - } - return "" -} - -func (x *ScheduleResponse) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *ScheduleResponse) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - type ClientHelloRequest struct { state protoimpl.MessageState `protogen:"open.v1"` ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` @@ -1123,19 +1070,9 @@ const file_proto_iop_control_proto_rawDesc = "" + "\x06params\x18\x03 \x03(\v2\x1b.iop.PolicyRule.ParamsEntryR\x06params\x1a9\n" + "\vParamsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xea\x01\n" + - "\x0fScheduleRequest\x12\x15\n" + - "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x16\n" + - "\x06target\x18\x02 \x01(\tR\x06target\x12+\n" + - "\bpolicies\x18\x03 \x03(\v2\x0f.iop.PolicyRuleR\bpolicies\x12>\n" + - "\bmetadata\x18\x04 \x03(\v2\".iop.ScheduleRequest.MetadataEntryR\bmetadata\x1a;\n" + - "\rMetadataEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"[\n" + - "\x10ScheduleResponse\x12\x17\n" + - "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x18\n" + - "\aaddress\x18\x02 \x01(\tR\aaddress\x12\x14\n" + - "\x05token\x18\x03 \x01(\tR\x05token\"X\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\";\n" + + "\x0fScheduleRequestJ\x04\b\x01\x10\x05R\x06job_idR\x06targetR\bpoliciesR\bmetadata\"1\n" + + "\x10ScheduleResponseJ\x04\b\x01\x10\x04R\anode_idR\aaddressR\x05token\"X\n" + "\x12ClientHelloRequest\x12\x1b\n" + "\tclient_id\x18\x01 \x01(\tR\bclientId\x12%\n" + "\x0eclient_version\x18\x02 \x01(\tR\rclientVersion\"\x94\x01\n" + @@ -1237,7 +1174,7 @@ func file_proto_iop_control_proto_rawDescGZIP() []byte { return file_proto_iop_control_proto_rawDescData } -var file_proto_iop_control_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_proto_iop_control_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_proto_iop_control_proto_goTypes = []any{ (*PolicyRule)(nil), // 0: iop.PolicyRule (*ScheduleRequest)(nil), // 1: iop.ScheduleRequest @@ -1255,28 +1192,25 @@ var file_proto_iop_control_proto_goTypes = []any{ (*EdgeCommandResponse)(nil), // 13: iop.EdgeCommandResponse (*EdgeCommandEvent)(nil), // 14: iop.EdgeCommandEvent nil, // 15: iop.PolicyRule.ParamsEntry - nil, // 16: iop.ScheduleRequest.MetadataEntry - nil, // 17: iop.EdgeHelloRequest.MetadataEntry - nil, // 18: iop.EdgeStatusResponse.MetadataEntry - nil, // 19: iop.EdgeCommandRequest.ParametersEntry - (*NodeConfigPayload)(nil), // 20: iop.NodeConfigPayload + nil, // 16: iop.EdgeHelloRequest.MetadataEntry + nil, // 17: iop.EdgeStatusResponse.MetadataEntry + nil, // 18: iop.EdgeCommandRequest.ParametersEntry + (*NodeConfigPayload)(nil), // 19: iop.NodeConfigPayload } var file_proto_iop_control_proto_depIdxs = []int32{ 15, // 0: iop.PolicyRule.params:type_name -> iop.PolicyRule.ParamsEntry - 0, // 1: iop.ScheduleRequest.policies:type_name -> iop.PolicyRule - 16, // 2: iop.ScheduleRequest.metadata:type_name -> iop.ScheduleRequest.MetadataEntry - 17, // 3: iop.EdgeHelloRequest.metadata:type_name -> iop.EdgeHelloRequest.MetadataEntry - 20, // 4: iop.EdgeNodeSnapshot.config:type_name -> iop.NodeConfigPayload - 8, // 5: iop.EdgeStatusResponse.nodes:type_name -> iop.EdgeNodeSnapshot - 18, // 6: iop.EdgeStatusResponse.metadata:type_name -> iop.EdgeStatusResponse.MetadataEntry - 10, // 7: iop.EdgeStatusResponse.capabilities:type_name -> iop.EdgeCapabilitySummary - 11, // 8: iop.EdgeStatusResponse.domain_agents:type_name -> iop.EdgeDomainAgentSummary - 19, // 9: iop.EdgeCommandRequest.parameters:type_name -> iop.EdgeCommandRequest.ParametersEntry - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 16, // 1: iop.EdgeHelloRequest.metadata:type_name -> iop.EdgeHelloRequest.MetadataEntry + 19, // 2: iop.EdgeNodeSnapshot.config:type_name -> iop.NodeConfigPayload + 8, // 3: iop.EdgeStatusResponse.nodes:type_name -> iop.EdgeNodeSnapshot + 17, // 4: iop.EdgeStatusResponse.metadata:type_name -> iop.EdgeStatusResponse.MetadataEntry + 10, // 5: iop.EdgeStatusResponse.capabilities:type_name -> iop.EdgeCapabilitySummary + 11, // 6: iop.EdgeStatusResponse.domain_agents:type_name -> iop.EdgeDomainAgentSummary + 18, // 7: iop.EdgeCommandRequest.parameters:type_name -> iop.EdgeCommandRequest.ParametersEntry + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_proto_iop_control_proto_init() } @@ -1291,7 +1225,7 @@ func file_proto_iop_control_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_iop_control_proto_rawDesc), len(file_proto_iop_control_proto_rawDesc)), NumEnums: 0, - NumMessages: 20, + NumMessages: 19, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/gen/iop/node.pb.go b/proto/gen/iop/node.pb.go index e275054..d0c77aa 100644 --- a/proto/gen/iop/node.pb.go +++ b/proto/gen/iop/node.pb.go @@ -21,28 +21,23 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// NodeStatus is an inactive legacy enum. Only the zero value remains; the +// online/offline/draining value numbers are reserved tombstones. The retired +// value names are intentionally not reserved as names so the generated +// descriptor does not retain them as active-looking identifiers. type NodeStatus int32 const ( NodeStatus_NODE_STATUS_UNSPECIFIED NodeStatus = 0 - NodeStatus_NODE_STATUS_ONLINE NodeStatus = 1 - NodeStatus_NODE_STATUS_OFFLINE NodeStatus = 2 - NodeStatus_NODE_STATUS_DRAINING NodeStatus = 3 ) // Enum value maps for NodeStatus. var ( NodeStatus_name = map[int32]string{ 0: "NODE_STATUS_UNSPECIFIED", - 1: "NODE_STATUS_ONLINE", - 2: "NODE_STATUS_OFFLINE", - 3: "NODE_STATUS_DRAINING", } NodeStatus_value = map[string]int32{ "NODE_STATUS_UNSPECIFIED": 0, - "NODE_STATUS_ONLINE": 1, - "NODE_STATUS_OFFLINE": 2, - "NODE_STATUS_DRAINING": 3, } ) @@ -73,17 +68,12 @@ func (NodeStatus) EnumDescriptor() ([]byte, []int) { return file_proto_iop_node_proto_rawDescGZIP(), []int{0} } -// NodeInfo is a legacy placeholder for node snapshots. -// Current Edge-Node registration uses RegisterRequest/RegisterResponse in -// runtime.proto, and Control Plane should observe nodes through Edge. +// NodeInfo is a reserved legacy tombstone for node snapshots. The original +// node_id/address/status fields are retired. Current Edge-Node registration +// uses RegisterRequest/RegisterResponse in runtime.proto, and Control Plane +// observes nodes through Edge. type NodeInfo struct { state protoimpl.MessageState `protogen:"open.v1"` - NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` - Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` - Status NodeStatus `protobuf:"varint,5,opt,name=status,proto3,enum=iop.NodeStatus" json:"status,omitempty"` - Labels map[string]string `protobuf:"bytes,6,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -118,53 +108,10 @@ func (*NodeInfo) Descriptor() ([]byte, []int) { return file_proto_iop_node_proto_rawDescGZIP(), []int{0} } -func (x *NodeInfo) GetNodeId() string { - if x != nil { - return x.NodeId - } - return "" -} - -func (x *NodeInfo) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *NodeInfo) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *NodeInfo) GetVersion() string { - if x != nil { - return x.Version - } - return "" -} - -func (x *NodeInfo) GetStatus() NodeStatus { - if x != nil { - return x.Status - } - return NodeStatus_NODE_STATUS_UNSPECIFIED -} - -func (x *NodeInfo) GetLabels() map[string]string { - if x != nil { - return x.Labels - } - return nil -} - -// NodeRegisterRequest is a legacy placeholder and is not the active startup -// contract. Nodes connect to Edge, not directly to Control Plane. +// NodeRegisterRequest is a reserved legacy tombstone and is not the active +// startup contract. Nodes connect to Edge, not directly to Control Plane. type NodeRegisterRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Info *NodeInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -199,20 +146,10 @@ func (*NodeRegisterRequest) Descriptor() ([]byte, []int) { return file_proto_iop_node_proto_rawDescGZIP(), []int{1} } -func (x *NodeRegisterRequest) GetInfo() *NodeInfo { - if x != nil { - return x.Info - } - return nil -} - -// NodeRegisterResponse is a legacy placeholder retained until the +// NodeRegisterResponse is a reserved legacy tombstone retained until the // Control Plane contracts are redesigned around Edge. type NodeRegisterResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"` - Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` - Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -247,54 +184,17 @@ func (*NodeRegisterResponse) Descriptor() ([]byte, []int) { return file_proto_iop_node_proto_rawDescGZIP(), []int{2} } -func (x *NodeRegisterResponse) GetAccepted() bool { - if x != nil { - return x.Accepted - } - return false -} - -func (x *NodeRegisterResponse) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - -func (x *NodeRegisterResponse) GetReason() string { - if x != nil { - return x.Reason - } - return "" -} - var File_proto_iop_node_proto protoreflect.FileDescriptor const file_proto_iop_node_proto_rawDesc = "" + "\n" + - "\x14proto/iop/node.proto\x12\x03iop\"\x82\x02\n" + - "\bNodeInfo\x12\x17\n" + - "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + - "\aaddress\x18\x03 \x01(\tR\aaddress\x12\x18\n" + - "\aversion\x18\x04 \x01(\tR\aversion\x12'\n" + - "\x06status\x18\x05 \x01(\x0e2\x0f.iop.NodeStatusR\x06status\x121\n" + - "\x06labels\x18\x06 \x03(\v2\x19.iop.NodeInfo.LabelsEntryR\x06labels\x1a9\n" + - "\vLabelsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"8\n" + - "\x13NodeRegisterRequest\x12!\n" + - "\x04info\x18\x01 \x01(\v2\r.iop.NodeInfoR\x04info\"`\n" + - "\x14NodeRegisterResponse\x12\x1a\n" + - "\baccepted\x18\x01 \x01(\bR\baccepted\x12\x14\n" + - "\x05token\x18\x02 \x01(\tR\x05token\x12\x16\n" + - "\x06reason\x18\x03 \x01(\tR\x06reason*t\n" + + "\x14proto/iop/node.proto\x12\x03iop\"A\n" + + "\bNodeInfoJ\x04\b\x01\x10\aR\anode_idR\x04nameR\aaddressR\aversionR\x06statusR\x06labels\"!\n" + + "\x13NodeRegisterRequestJ\x04\b\x01\x10\x02R\x04info\"5\n" + + "\x14NodeRegisterResponseJ\x04\b\x01\x10\x04R\bacceptedR\x05tokenR\x06reason*/\n" + "\n" + "NodeStatus\x12\x1b\n" + - "\x17NODE_STATUS_UNSPECIFIED\x10\x00\x12\x16\n" + - "\x12NODE_STATUS_ONLINE\x10\x01\x12\x17\n" + - "\x13NODE_STATUS_OFFLINE\x10\x02\x12\x18\n" + - "\x14NODE_STATUS_DRAINING\x10\x03B\x13Z\x11iop/proto/gen/iopb\x06proto3" + "\x17NODE_STATUS_UNSPECIFIED\x10\x00\"\x04\b\x01\x10\x03B\x13Z\x11iop/proto/gen/iopb\x06proto3" var ( file_proto_iop_node_proto_rawDescOnce sync.Once @@ -309,23 +209,19 @@ func file_proto_iop_node_proto_rawDescGZIP() []byte { } var file_proto_iop_node_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_iop_node_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_proto_iop_node_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_proto_iop_node_proto_goTypes = []any{ (NodeStatus)(0), // 0: iop.NodeStatus (*NodeInfo)(nil), // 1: iop.NodeInfo (*NodeRegisterRequest)(nil), // 2: iop.NodeRegisterRequest (*NodeRegisterResponse)(nil), // 3: iop.NodeRegisterResponse - nil, // 4: iop.NodeInfo.LabelsEntry } var file_proto_iop_node_proto_depIdxs = []int32{ - 0, // 0: iop.NodeInfo.status:type_name -> iop.NodeStatus - 4, // 1: iop.NodeInfo.labels:type_name -> iop.NodeInfo.LabelsEntry - 1, // 2: iop.NodeRegisterRequest.info:type_name -> iop.NodeInfo - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_proto_iop_node_proto_init() } @@ -339,7 +235,7 @@ func file_proto_iop_node_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_iop_node_proto_rawDesc), len(file_proto_iop_node_proto_rawDesc)), NumEnums: 1, - NumMessages: 4, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/iop/control.proto b/proto/iop/control.proto index 5158eeb..a1b2d24 100644 --- a/proto/iop/control.proto +++ b/proto/iop/control.proto @@ -13,21 +13,21 @@ message PolicyRule { map params = 3; } -// ScheduleRequest is a legacy placeholder for future Control Plane orchestration. -// It must not be treated as an active contract for direct Node scheduling. +// ScheduleRequest is a reserved legacy tombstone. The original direct Node +// scheduling fields are retired; the message name is kept only to keep the +// field numbers reserved so they cannot be reused as an active contract. +// Future orchestration must go through Edge-owned runtime state. message ScheduleRequest { - string job_id = 1; - string target = 2; - repeated PolicyRule policies = 3; - map metadata = 4; + reserved 1 to 4; + reserved "job_id", "target", "policies", "metadata"; } -// ScheduleResponse is a legacy placeholder. Future scheduling should be -// reworked around Edge-owned runtime state instead of bypassing Edge. +// ScheduleResponse is a reserved legacy tombstone. The original node +// address/token fields are retired; future scheduling should be reworked +// around Edge-owned runtime state instead of bypassing Edge. message ScheduleResponse { - string node_id = 1; - string address = 2; - string token = 3; + reserved 1 to 3; + reserved "node_id", "address", "token"; } message ClientHelloRequest { diff --git a/proto/iop/node.proto b/proto/iop/node.proto index 9fa23b7..f9e6670 100644 --- a/proto/iop/node.proto +++ b/proto/iop/node.proto @@ -4,35 +4,34 @@ package iop; option go_package = "iop/proto/gen/iop"; -// NodeInfo is a legacy placeholder for node snapshots. -// Current Edge-Node registration uses RegisterRequest/RegisterResponse in -// runtime.proto, and Control Plane should observe nodes through Edge. +// NodeInfo is a reserved legacy tombstone for node snapshots. The original +// node_id/address/status fields are retired. Current Edge-Node registration +// uses RegisterRequest/RegisterResponse in runtime.proto, and Control Plane +// observes nodes through Edge. message NodeInfo { - string node_id = 1; - string name = 2; - string address = 3; - string version = 4; - NodeStatus status = 5; - map labels = 6; + reserved 1 to 6; + reserved "node_id", "name", "address", "version", "status", "labels"; } +// NodeStatus is an inactive legacy enum. Only the zero value remains; the +// online/offline/draining value numbers are reserved tombstones. The retired +// value names are intentionally not reserved as names so the generated +// descriptor does not retain them as active-looking identifiers. enum NodeStatus { NODE_STATUS_UNSPECIFIED = 0; - NODE_STATUS_ONLINE = 1; - NODE_STATUS_OFFLINE = 2; - NODE_STATUS_DRAINING = 3; + reserved 1 to 3; } -// NodeRegisterRequest is a legacy placeholder and is not the active startup -// contract. Nodes connect to Edge, not directly to Control Plane. +// NodeRegisterRequest is a reserved legacy tombstone and is not the active +// startup contract. Nodes connect to Edge, not directly to Control Plane. message NodeRegisterRequest { - NodeInfo info = 1; + reserved 1; + reserved "info"; } -// NodeRegisterResponse is a legacy placeholder retained until the +// NodeRegisterResponse is a reserved legacy tombstone retained until the // Control Plane contracts are redesigned around Edge. message NodeRegisterResponse { - bool accepted = 1; - string token = 2; - string reason = 3; + reserved 1 to 3; + reserved "accepted", "token", "reason"; }