- Add legacy alias support for backward compatibility - Update ProtocolBuffer message definitions with new fields - Implement fullname-based message routing - Add alias fallback logic in all language clients (Dart, Go, Kotlin, Python, TypeScript) - Update test suites for alias and fullname validation - Add protocol sync verification tools - Update documentation (PORTING_GUIDE, PROTOCOL, VERSIONING) - Add agent task documentation for protocol evolution
10 KiB
Plan - ALIAS
이 파일을 읽는 구현 에이전트에게
이 plan은 full-name foundation 완료 후 legacy simple-name 수신 alias를 모든 지원 언어의 parser/listener/request/pending response 경로에 일관되게 적용한다. 구현 후 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 내용으로 채운다. 사용자 결정이 필요한 blocker만 review stub의 사용자 리뷰 요청에 기록한다.
배경
마일스톤은 새 송신 기본값을 full proto name으로 바꾸되 기존 simple-name peer의 수신 호환성은 보존한다. 현재 Go/Kotlin/Python/TypeScript dispatch와 pending response 비교는 exact string lookup이므로 alias 규칙을 중앙화하지 않으면 parser만 통과하고 listener/request/response가 실패하는 부분 호환 상태가 된다.
사용자 리뷰 요청 흐름
구현 중 blocker는 active review stub의 사용자 리뷰 요청 섹션에 기록한다. 직접 사용자 질문은 금지이며, code-review가 USER_REVIEW.md 작성 여부를 판단한다.
Roadmap Targets
- Milestone:
agent-roadmap/milestones/protocol-evolution-compatibility.md - Task ids:
legacy-alias: parser lookup, listener/request handler routing, response type matching, pending expected type 비교에 동일 alias 규칙 적용
- Completion mode: check-on-pass
분석 결과
읽은 파일
agent-ops/rules/project/rules.mdagent-ops/rules/common/rules-roadmap.mdagent-ops/skills/common/plan/SKILL.mdagent-test/local/rules.mdagent-test/local/proto-socket-full-matrix.mdagent-roadmap/milestones/protocol-evolution-compatibility.mddart/lib/src/communicator.dart,dart/test/communicator_test.dartgo/communicator.go,go/test/communicator_test.gokotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt,kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.ktpython/proto_socket/communicator.py,python/test/test_communicator.pytypescript/src/communicator.ts,typescript/test/communicator.test.tsPROTOCOL.md,VERSIONING.md,PORTING_GUIDE.md
테스트 환경 규칙
test_env=local이다. 전체 protocol/API 호환성 변경이므로 최종 검증은 bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all이다. focused 중간 검증은 각 언어 unit test를 사용하되, 실행하지 못한 runtime은 명령과 차단 사유를 review stub에 기록한다.
테스트 커버리지 공백
- Dart에는 package-qualified receive 테스트가 있으나 canonical alias collision 검사는 없다.
- Go/Kotlin/Python/TypeScript는 simple alias receive, request handler alias, response alias, collision 초기화 실패 테스트가 부족하다.
- parser alias만 추가하면
go/communicator.go:480-486,kotlin/.../Communicator.kt:421-427,python/.../communicator.py:519-524,typescript/src/communicator.ts:585-589의 pending expected type 비교가 계속 실패한다.
심볼 참조
- 새 helper 후보: alias expansion/canonicalization helper per language.
- 변경 call site: parser map initialization,
AddListener/addListener,AddRequestListener/addRequestListener, dispatch lookup,_handle_response/handleResponse,parse.
분할 판단
분할 정책을 평가했다. 이 plan은 02+01_legacy_alias이며 predecessor 01_proto_fullname_foundation의 complete.log가 필요하다. 현재 작성 시점에는 predecessor가 missing이므로 구현 시작 전 agent-task/m-protocol-evolution-compatibility/01_proto_fullname_foundation/complete.log 또는 archive의 01_* complete.log를 확인해야 한다. 테스트 matrix 확장은 03+01,02_fullname_tests가 맡는다.
범위 결정 근거
이 plan은 alias 구현과 focused unit regression만 다룬다. Proto package/generated binding 수정은 predecessor 범위이며, cross-language scenario matrix 확장과 roadmap fullname-tests 완료는 후속 plan 범위다.
빌드 등급
cloud-G07: string identity가 parser, dispatch, pending correlation, public typed helpers를 관통하는 다중 언어 호환성 변경이다.
구현 체크리스트
- 구현 시작 전
01_proto_fullname_foundationcomplete.log로 predecessor 완료를 확인한다. - 각 언어에 canonical full name과 legacy simple name을 같은 identity group으로 다루는 helper를 추가한다.
- parser map 등록 시 full/simple alias를 모두 등록하고, simple alias가 서로 다른 full name으로 충돌하면 initialize 단계에서 실패시킨다.
- listener/request handler 등록과 상호 배타 검사, inbound dispatch, pending response expected type 비교가 같은 alias 규칙을 사용하게 한다.
- 각 언어 focused unit test로 simple legacy receive와 alias collision을 검증한다.
- CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
[ALIAS-1] Alias Registry Helpers
문제: current lookup은 exact key 중심이다.
// go/communicator.go:497-503
parser := c.parserMap[typeName]
if parser == nil {
return nil, fmt.Errorf("protobuf parser is not registered for type %s", typeName)
}
해결 방법: full name에서 마지막 segment를 simple alias로 계산하는 helper와 alias group lookup을 만든다. initialize에서 parserMap을 full/simple key로 normalize하되, 같은 simple alias가 다른 parser/full name으로 매핑되면 panic/error로 실패한다.
수정 파일 및 체크리스트:
go/communicator.gokotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.ktpython/proto_socket/communicator.pytypescript/src/communicator.tsdart/lib/src/communicator.dart
테스트 작성: 각 언어 communicator unit에 collision test를 추가한다.
중간 검증:
go test ./...
cd kotlin && ./gradlew test
cd python && python3 -m pytest -q
cd typescript && npm run check && npm test
dart test test/communicator_test.dart
[ALIAS-2] Routing And Pending Matching
문제: dispatch와 pending response expected type 비교가 exact string이면 legacy simple-name response가 실패한다.
// typescript/src/communicator.ts:580-589
if (typeName !== pending.expectedTypeName) {
pending.reject(
new Error(
`response type mismatch for nonce ${responseNonce}: expected ${pending.expectedTypeName}, got ${typeName}`,
# python/proto_socket/communicator.py:375-376
req_handler = self._req_handlers.get(item.type_name)
listeners = list(self._handlers.get(item.type_name, []))
해결 방법: incoming wire type을 canonical group으로 resolve한 뒤 parser, handler, listener, pending expected type 비교에 같은 canonical value를 사용한다. Error message는 original wire value와 expected canonical value를 모두 포함한다.
수정 파일 및 체크리스트:
go/communicator.gokotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.ktpython/proto_socket/communicator.pytypescript/src/communicator.tsdart/lib/src/communicator.dart
테스트 작성: request handler가 full name으로 등록되어도 incoming simple name을 처리하고, pending request expected full name이 incoming simple response를 수락하는 unit test를 추가한다.
중간 검증:
rg --sort path "typeName !=|expectedTypeName|expected_type_name|reqHandlers\\[|handlers\\[" go kotlin python typescript dart
[ALIAS-3] HeartBeat Alias Consistency
문제: HeartBeat parser/listener는 각 언어에서 별도 자동 등록되며 alias에서 빠지기 쉽다.
// dart/lib/src/protobuf_client.dart:52-55
parserMap.addAll({
(HeartBeat).toString(): HeartBeat.fromBuffer,
});
해결 방법: HeartBeat도 proto_socket.HeartBeat와 HeartBeat alias를 같은 registry helper로 등록한다. 자동 heartbeat listener 등록도 canonical helper를 통해 등록한다.
수정 파일 및 체크리스트:
dart/lib/src/protobuf_client.dartdart/lib/src/ws_protobuf_client_io.dartdart/lib/src/ws_protobuf_client_web.dartgo/communicator.gokotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.ktpython/proto_socket/communicator.pytypescript/src/communicator.ts
테스트 작성: focused HeartBeat alias unit test는 있으면 추가하고, 없으면 전체 heartbeat tests가 canonical helper를 통해 통과하는지 기록한다.
중간 검증:
dart test test/communicator_test.dart test/socket_test.dart
go test ./...
cd kotlin && ./gradlew test
cd python && python3 -m pytest -q
cd typescript && npm run check && npm test
의존 관계 및 구현 순서
02+01_legacy_alias는 sibling 01_proto_fullname_foundation의 complete.log가 있어야 시작한다. active 후보는 agent-task/m-protocol-evolution-compatibility/01_proto_fullname_foundation/complete.log, archive 후보는 agent-task/archive/*/*/m-protocol-evolution-compatibility/01_*/complete.log다.
수정 파일 요약
| 파일 | 항목 |
|---|---|
dart/lib/src/communicator.dart, dart/lib/src/protobuf_client.dart, dart/lib/src/ws_protobuf_client_io.dart, dart/lib/src/ws_protobuf_client_web.dart |
ALIAS-1, ALIAS-2, ALIAS-3 |
go/communicator.go |
ALIAS-1, ALIAS-2, ALIAS-3 |
kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt |
ALIAS-1, ALIAS-2, ALIAS-3 |
python/proto_socket/communicator.py |
ALIAS-1, ALIAS-2, ALIAS-3 |
typescript/src/communicator.ts |
ALIAS-1, ALIAS-2, ALIAS-3 |
*/test/*communicator* |
ALIAS-1, ALIAS-2, ALIAS-3 |
최종 검증
dart test test/communicator_test.dart
go test ./...
cd kotlin && ./gradlew test
cd python && python3 -m pytest -q
cd typescript && npm run check && npm test
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all
모든 코드 변경 완료 후 반드시 CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.