diff --git a/PROTOCOL.md b/PROTOCOL.md index e800851..ce7ad4c 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -101,6 +101,33 @@ Changing heartbeat timing semantics, response behavior, or disconnect rules is a --- +## Optional Capability Announcement + +Implementations may define an application-level `ProtoSocketHello` message, or an equivalent project-specific hello message, to announce protocol and implementation capabilities after connection open. + +This message is optional and non-blocking in protocol `0.1`: + +- It is a normal `PacketBase` payload sent through the existing `typeName` routing path. +- It must not be required before normal messages, requests, responses, or heartbeats can flow. +- Peers that do not recognize its `typeName` may ignore it according to their normal unknown-message policy. +- Implementations must not treat a missing hello message as a protocol error in `0.1`. + +Recommended payload fields: + +```protobuf +message ProtoSocketHello { + string protocolVersion = 1; // e.g. "0.1" + repeated string capabilities = 2; // stable capability tokens + map implementation = 3; // optional language/library metadata +} +``` + +Capability tokens should be stable ASCII strings such as `std_error.v1` or `ws.wss`. Application-specific tokens should use a project prefix to avoid collisions. + +Promoting this message to a required handshake is a future protocol-version decision and is not part of protocol `0.1`. + +--- + ## typeName Convention `typeName` uses the protobuf full message name on the send side. @@ -167,6 +194,30 @@ Requester Responder - Both sides can be requester and responder simultaneously on the same connection - For a given `typeName` on one connection, register it with either `addListener` or `addRequestListener`, not both. Mixed registration is ambiguous and rejected by the Dart and Go implementations. +### Standard Error Response Convention + +Implementations may define a `ProtoSocketError` message, or an equivalent project-specific error message, for request handlers that fail before producing the expected response. + +Recommended payload fields: + +```protobuf +message ProtoSocketError { + string code = 1; // stable machine-readable error code + string message = 2; // safe human-readable message + string detail = 3; // optional non-sensitive detail + string debug = 4; // optional local/debug-only detail +} +``` + +When used as a request failure response: + +- The packet's `responseNonce` should be set to the failing request's `nonce`. +- The packet's `typeName` should identify the error message, for example `proto_socket.ProtoSocketError` if this becomes a shared common message in a future schema. +- A requester that understands the convention should complete the pending request with a typed error instead of waiting for timeout. +- A requester that does not understand the convention may see an expected-response type mismatch or may continue to timeout, depending on its current response handling. + +Protocol `0.1` does not require every request handler failure to send an error response. Adding a common error message to the canonical proto schema requires parser map updates and cross-language tests before it can become a shared compatibility contract. + --- ## Receive Ordering and Backpressure @@ -195,6 +246,12 @@ A single receive coordinator dequeues packets one at a time and dispatches them: **Ordering guarantee**: for a given connection, listeners and request handlers are invoked strictly in packet arrival order. Automatic responses are enqueued into the write queue in the same order their triggering requests were dispatched. +### Response Correlation Path + +Packets with `responseNonce > 0` complete an already-pending request and do not invoke listeners or request handlers. Implementations may therefore complete those pending requests through a direct correlation path before or instead of the listener/request-handler FIFO queue. + +This response path does not weaken the listener/request-handler ordering guarantee: packets that dispatch to `addListener` or `addRequestListener` must still be processed in arrival order, and automatic responses produced by request handlers must still be enqueued in request-dispatch order. Implementations that enqueue response packets in the same inbound queue must produce equivalent pending-request completion semantics. + ### Close, Drain, and Cancel - When `Close()` is called, the implementation stops accepting new inbound packets and drains the already-enqueued packets in the inbound queue before tearing down the receive coordinator. diff --git a/VERSIONING.md b/VERSIONING.md index 2a4d7f1..e99a638 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -10,6 +10,8 @@ Proto Socket tracks protocol compatibility separately from language package vers `0.1` is the current compatibility contract for the checked-in available implementations. The wire format does not carry a protocol version field yet; compatibility is verified by shared proto definitions, unit tests, and cross-language tests. +Protocol `0.1` also allows optional application-level convention messages for capability announcement and request error reporting. These conventions do not change the required handshake or the `PacketBase` wire fields unless they are promoted in a later protocol version. + ## Protocol Version The protocol version describes the wire-format and behavior contract that every language implementation must satisfy: @@ -61,9 +63,27 @@ Examples of non-breaking changes: - Adding optional fields to application messages when older peers can ignore them. - Adding a new language implementation that passes the existing protocol and cross-language tests. - Tightening tests or documentation without changing wire behavior. +- Adding an optional hello/capability message that peers may ignore and that is not required before normal traffic. +- Adding an optional standard error response convention, provided older peers can still fail by timeout or existing response type-mismatch behavior. Backward-compatible message additions require updated parser maps and cross-language tests before release. +## Optional Capability Announcement + +`ProtoSocketHello`, or an equivalent project-specific message, is a candidate convention for announcing: + +- `protocolVersion` +- stable `capabilities` tokens +- optional implementation metadata + +In protocol `0.1`, this message is not a required handshake. A peer must be able to send and receive normal messages without first receiving a hello/capability message. Making a hello message mandatory, changing connection readiness semantics, or disconnecting older peers that do not send it requires a protocol-version review. + +## Standard Error Response Convention + +`ProtoSocketError`, or an equivalent project-specific message, is a candidate convention for request handler failures. A supported error response should carry the original request nonce in `responseNonce`, a stable error code, a safe message, and optional detail/debug fields. + +In protocol `0.1`, implementations may continue to report handler failure as timeout, response type mismatch, or implementation-specific errors. Requiring all handlers to emit a shared error response, or requiring every requester to treat a particular error message type specially, requires parser map updates, cross-language tests, and compatibility review. + ## nonce Overflow `nonce` and `responseNonce` fields are protobuf `int32` values (signed 32-bit). diff --git a/agent-roadmap/milestones/protocol-evolution-compatibility.md b/agent-roadmap/milestones/protocol-evolution-compatibility.md index d4bf943..5bcb443 100644 --- a/agent-roadmap/milestones/protocol-evolution-compatibility.md +++ b/agent-roadmap/milestones/protocol-evolution-compatibility.md @@ -59,10 +59,10 @@ wire message identity를 full proto name으로 정렬하고, legacy simple name 현재 `PacketBase`의 단순성을 유지하면서, future protocol capability를 안전하게 추가할 수 있는 경계를 만든다. -- [ ] [hello-cap] `ProtoSocketHello` 또는 동등한 비차단 version/capability message 후보를 `PROTOCOL.md`와 `VERSIONING.md`에 문서화한다. 후보 payload에는 `protocolVersion`, `capabilities`, 선택적 implementation metadata를 포함한다. 구버전 peer가 모르면 무시할 수 있는 경로로 두고, 이 마일스톤에서 필수 handshake로 승격하지 않는다. -- [ ] [std-error] `ProtoSocketError` 또는 동등한 표준 오류 응답 convention을 문서화한다. 후보 payload에는 stable error code, message, 선택적 detail/debug field를 포함한다. request handler 실패가 timeout만으로 보이지 않게 하되, 구버전 peer와의 mismatch 처리를 명시하고, 이 마일스톤에서 모든 handler가 오류 응답을 강제 송신하도록 바꾸지는 않는다. +- [x] [hello-cap] `ProtoSocketHello` 또는 동등한 비차단 version/capability message 후보를 `PROTOCOL.md`와 `VERSIONING.md`에 문서화한다. 후보 payload에는 `protocolVersion`, `capabilities`, 선택적 implementation metadata를 포함한다. 구버전 peer가 모르면 무시할 수 있는 경로로 두고, 이 마일스톤에서 필수 handshake로 승격하지 않는다. +- [x] [std-error] `ProtoSocketError` 또는 동등한 표준 오류 응답 convention을 문서화한다. 후보 payload에는 stable error code, message, 선택적 detail/debug field를 포함한다. request handler 실패가 timeout만으로 보이지 않게 하되, 구버전 peer와의 mismatch 처리를 명시하고, 이 마일스톤에서 모든 handler가 오류 응답을 강제 송신하도록 바꾸지는 않는다. - [ ] [nonce-boundary] nonce wrap 시 pending request nonce와 충돌하지 않도록 active pending nonce skip 정책과 boundary 테스트를 보강한다. -- [ ] [ordering-doc] response completion이 pending correlation 경로로 queue를 우회할 수 있음을 `Receive Ordering and Backpressure` 계약에 명확히 기록한다. listener/request handler dispatch FIFO 보장과 구분한다. +- [x] [ordering-doc] response completion이 pending correlation 경로로 queue를 우회할 수 있음을 `Receive Ordering and Backpressure` 계약에 명확히 기록한다. listener/request handler dispatch FIFO 보장과 구분한다. ## 완료 리뷰 @@ -90,4 +90,4 @@ wire message identity를 full proto name으로 정렬하고, legacy simple name - 선행 작업: 프로토콜 기준선 - 후속 작업: 필요 시 protocol `0.2` 또는 `1.0` compatibility release planning - 확인 필요: 없음 -- 작업 현황 동기화(2026-06-16): `01_proto_fullname_foundation`, `02+01_legacy_alias`, `03+01,02_fullname_tests`가 모두 PASS 완료되어 `proto-package-sync`, `fullname-type`, `legacy-alias`, `fullname-tests`를 반영했다. 근거는 `agent-task/archive/2026/06/m-protocol-evolution-compatibility/01_proto_fullname_foundation/complete.log`, `agent-task/archive/2026/06/m-protocol-evolution-compatibility/02+01_legacy_alias/complete.log`, `agent-task/archive/2026/06/m-protocol-evolution-compatibility/03+01,02_fullname_tests/complete.log`다. 다음 미완료 범위는 evolution Epic의 `hello-cap`, `std-error`, `nonce-boundary`, `ordering-doc`이다. +- 작업 현황 동기화(2026-06-16): `01_proto_fullname_foundation`, `02+01_legacy_alias`, `03+01,02_fullname_tests`가 모두 PASS 완료되어 `proto-package-sync`, `fullname-type`, `legacy-alias`, `fullname-tests`를 반영했다. 근거는 `agent-task/archive/2026/06/m-protocol-evolution-compatibility/01_proto_fullname_foundation/complete.log`, `agent-task/archive/2026/06/m-protocol-evolution-compatibility/02+01_legacy_alias/complete.log`, `agent-task/archive/2026/06/m-protocol-evolution-compatibility/03+01,02_fullname_tests/complete.log`다. evolution Epic의 `hello-cap`, `std-error`, `ordering-doc`는 `PROTOCOL.md`/`VERSIONING.md` 문서 반영과 `tools/check_proto_sync.sh` PASS로 직접 완료 처리했다. 남은 미완료 범위는 `nonce-boundary`이며, 구현 계획은 `agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/`, `agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/`, `agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/`에 split 작성했다. diff --git a/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/CODE_REVIEW-local-G04.md b/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/CODE_REVIEW-local-G04.md new file mode 100644 index 0000000..9519d1e --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/CODE_REVIEW-local-G04.md @@ -0,0 +1,144 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-06-16 +task=m-protocol-evolution-compatibility/04+03_nonce_contract, plan=0, tag=API + +## Archive Evidence Snapshot + +- `agent-task/archive/2026/06/m-protocol-evolution-compatibility/03+01,02_fullname_tests/complete.log`: `fullname-tests` PASS, full matrix record `agent-test/runs/20260616-123431-proto-socket-full-matrix.md`. +- predecessor `03` 완료가 `04+03_nonce_contract` split 의존성을 충족한다. + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-local-G04.md` -> `code_review_local_G04_N.log`, `PLAN-local-G04.md` -> `plan_local_G04_M.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-protocol-evolution-compatibility/04+03_nonce_contract/`로 이동한다. +4. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] Nonce Contract 문서화 | [ ] | +| [API-2] Porting 기준 정렬 | [ ] | + +## 구현 체크리스트 + +- [ ] `PROTOCOL.md`의 `nonce` 섹션에 active pending nonce skip 정책과 all-positive-nonces-pending 예외를 명시한다. +- [ ] `VERSIONING.md`의 `nonce Overflow` 정책에 pending 충돌 회피와 호환성 기준을 반영한다. +- [ ] `PORTING_GUIDE.md`의 nonce 공통 구조 설명을 pending skip 기준으로 보강한다. +- [ ] `tools/check_proto_sync.sh`와 `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다. +- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- `nonce` 계약이 active pending request nonce skip을 명확히 요구하는지 확인한다. +- 포팅 가이드가 새 언어 구현 기준으로 충분한지 확인한다. +- proto schema를 변경하지 않았는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +필수 규칙: +- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다. +- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다. +- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다. + +### API-1 중간 검증 +```bash +$ tools/check_proto_sync.sh +(output) +``` + +### API-2 중간 검증 +```bash +$ git diff --check +(output) +``` + +### 최종 검증 +```bash +$ tools/check_proto_sync.sh +$ git diff --check +(output) +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +## 섹션 소유권 + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive, complete.log, or task-directory archive move steps | +| Archive Evidence Snapshot | Fixed at stub creation | Implementing agent uses it as default prior-loop context | +| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only | +| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[x]` only; final checkbox is mandatory | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Review focus areas | +| 검증 결과 | Implementing agent | Fill command output only | diff --git a/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/PLAN-local-G04.md b/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/PLAN-local-G04.md new file mode 100644 index 0000000..34fe68a --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/PLAN-local-G04.md @@ -0,0 +1,185 @@ + + +# Plan - API + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션 작성까지가 구현의 마지막 단계다. 검증을 실행하고 실제 출력/결과를 기록한 뒤 active 파일을 유지한 채 리뷰를 요청한다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 범위 충돌이 생기면 직접 질문하지 말고 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 남긴다. 후속 에이전트가 재실행으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다. + +## 배경 + +`nonce-boundary`는 wrap 직후 `1`로 돌아가는 기존 정책만으로는 부족하다. 오래 열린 연결에서 nonce wrap 시점에 낮은 nonce의 `sendRequest`가 아직 pending이면 새 outbound packet nonce가 pending correlation key와 충돌할 수 있다. 먼저 문서 계약을 `active pending nonce skip`으로 고정해 언어별 구현이 같은 기준을 따르게 한다. + +## 사용자 리뷰 요청 흐름 + +구현 중 차단은 active `CODE_REVIEW-local-G04.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 채팅으로 사용자에게 직접 질문하지 않으며, code-review가 해당 요청의 타당성을 판단하고 필요할 때 `USER_REVIEW.md`를 작성한다. + +## Archive Evidence Snapshot + +- `agent-task/archive/2026/06/m-protocol-evolution-compatibility/03+01,02_fullname_tests/complete.log`: `fullname-tests` PASS, full matrix record `agent-test/runs/20260616-123431-proto-socket-full-matrix.md`. +- predecessor `03` 완료가 `04+03_nonce_contract` split 의존성을 충족한다. + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/ROADMAP.md` +- `agent-roadmap/milestones/protocol-evolution-compatibility.md` +- `agent-ops/rules/project/rules.md` +- `agent-ops/rules/common/rules-roadmap.md` +- `agent-ops/rules/project/domain/protocol/rules.md` +- `agent-ops/skills/common/router.md` +- `agent-ops/skills/common/plan/SKILL.md` +- `agent-ops/skills/common/update-roadmap/SKILL.md` +- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` +- `agent-test/local/rules.md` +- `agent-test/local/protocol-smoke.md` +- `agent-test/local/proto-socket-full-matrix.md` +- `PROTOCOL.md` +- `VERSIONING.md` +- `PORTING_GUIDE.md` +- `dart/lib/src/communicator.dart` +- `dart/test/communicator_test.dart` +- `go/communicator.go` +- `go/communicator_nonce_test.go` +- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt` +- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt` +- `python/proto_socket/communicator.py` +- `python/test/test_communicator.py` +- `typescript/src/communicator.ts` +- `typescript/test/communicator.test.ts` + +### 테스트 환경 규칙 + +- test_env: `local` +- 적용 규칙: `agent-test/local/rules.md`를 읽었다. +- 매칭 프로필: `agent-test/local/protocol-smoke.md`, `agent-test/local/proto-socket-full-matrix.md` +- 이 문서-only 선행 작업의 필수 검증은 `tools/check_proto_sync.sh`와 `git diff --check`다. +- full matrix는 구현 rollout이 끝나는 `06+04,05_nonce_kotlin_python_ts`에서 실행한다. + +### 테스트 커버리지 공백 + +- 문서 변경 자체는 `tools/check_proto_sync.sh`와 diff whitespace로 확인한다. +- active pending nonce skip 동작은 코드 테스트가 필요하며 이 plan에서는 작성하지 않는다. 해당 공백은 05/06 계획에서 닫는다. + +### 심볼 참조 + +- renamed/removed symbol: none + +### 분할 판단 + +- split decision policy를 먼저 평가했다. +- 공유 task group: `agent-task/m-protocol-evolution-compatibility/` +- `04+03_nonce_contract`: predecessor `03` archive complete log로 충족됨. +- `05+04_nonce_dart_go`: predecessor `04` 필요, 계획 작성 시점에는 미충족. +- `06+04,05_nonce_kotlin_python_ts`: predecessors `04`, `05` 필요, 계획 작성 시점에는 미충족. +- 계약 문서와 언어별 구현은 위험과 검증 단위가 달라 분리한다. + +### 범위 결정 근거 + +- 이 plan은 `PROTOCOL.md`, `VERSIONING.md`, `PORTING_GUIDE.md`만 수정한다. +- 언어별 communicator와 테스트는 05/06에서 수정한다. +- canonical proto schema는 변경하지 않는다. + +### 빌드 등급 + +- `local-G04`: 문서 계약 갱신이며 검증은 deterministic smoke로 충분하다. + +## 구현 체크리스트 + +- [ ] `PROTOCOL.md`의 `nonce` 섹션에 active pending nonce skip 정책과 all-positive-nonces-pending 예외를 명시한다. +- [ ] `VERSIONING.md`의 `nonce Overflow` 정책에 pending 충돌 회피와 호환성 기준을 반영한다. +- [ ] `PORTING_GUIDE.md`의 nonce 공통 구조 설명을 pending skip 기준으로 보강한다. +- [ ] `tools/check_proto_sync.sh`와 `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +이 task는 `03+01,02_fullname_tests` 완료 이후 실행한다. 근거는 `agent-task/archive/2026/06/m-protocol-evolution-compatibility/03+01,02_fullname_tests/complete.log`다. + +### [API-1] Nonce Contract 문서화 + +#### 문제 + +[PROTOCOL.md](/config/workspace/proto-socket/PROTOCOL.md:159)는 wrap 후 `1` 재발행만 설명한다. + +```md +159 ## nonce +161 - Starts at `1` per connection +162 - Increments by `1` on every send call (including requests and responses) +163 - Maximum nonce is `2,147,483,647` (`int32` max), the lowest common signed integer max across supported protocol fields +164 - After issuing `2,147,483,647`, implementations reset the internal counter to `0`; the next emitted packet nonce is `1` +165 - `0` is reserved and must not be emitted as `PacketBase.nonce`, because `responseNonce == 0` means "not a response" +``` + +#### 해결 방법 + +`After issuing...` 항목 다음에 후보 nonce가 active pending request nonce와 충돌하면 건너뛰어야 한다는 정책을 추가한다. 모든 양수 int32 nonce가 pending이면 새 outbound packet을 발행하지 말고 오류로 실패해야 한다고 명시한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `PROTOCOL.md`: `## nonce` bullet 보강 +- [ ] `VERSIONING.md`: `## nonce Overflow` 정책 보강 +- [ ] `PORTING_GUIDE.md`: `nonce 단조 증가` 행 보강 + +#### 테스트 작성 + +문서 변경이므로 새 테스트는 작성하지 않는다. 05/06에서 각 언어 boundary regression test를 작성한다. + +#### 중간 검증 + +```bash +tools/check_proto_sync.sh +``` + +기대 결과: `Proto schemas are in sync.` + +### [API-2] Porting 기준 정렬 + +#### 문제 + +[PORTING_GUIDE.md](/config/workspace/proto-socket/PORTING_GUIDE.md:20)는 nonce를 단조 증가로만 설명한다. + +```md +20 | nonce 단조 증가 | `atomic.Int32` | 연결당 1에서 시작, 송신마다 +1. thread-safe하게 구현 | +``` + +#### 해결 방법 + +설명을 `pending request nonce와 충돌하는 후보는 skip`으로 확장하고, thread-safe 구현에서는 candidate 선택과 pending 조회가 같은 임계구역 또는 동등한 안전성을 가져야 한다고 적는다. + +#### 수정 파일 및 체크리스트 + +- [ ] `PORTING_GUIDE.md`: 공통 구조 표의 nonce 행 갱신 + +#### 테스트 작성 + +문서 변경이므로 새 테스트는 작성하지 않는다. + +#### 중간 검증 + +```bash +git diff --check +``` + +기대 결과: 출력 없음, exit code 0. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `PROTOCOL.md` | API-1 | +| `VERSIONING.md` | API-1 | +| `PORTING_GUIDE.md` | API-2 | + +## 최종 검증 + +```bash +tools/check_proto_sync.sh +git diff --check +``` + +기대 결과: proto sync PASS, whitespace error 없음. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/CODE_REVIEW-cloud-G06.md b/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/CODE_REVIEW-cloud-G06.md new file mode 100644 index 0000000..afa4ac3 --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/CODE_REVIEW-cloud-G06.md @@ -0,0 +1,141 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-06-16 +task=m-protocol-evolution-compatibility/05+04_nonce_dart_go, plan=0, tag=API + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-cloud-G06.md` -> `code_review_cloud_G06_N.log`, `PLAN-cloud-G06.md` -> `plan_cloud_G06_M.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-protocol-evolution-compatibility/05+04_nonce_dart_go/`로 이동한다. +4. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] Dart pending nonce skip | [ ] | +| [API-2] Go pending nonce skip | [ ] | + +## 구현 체크리스트 + +- [ ] 04번 predecessor `complete.log`가 존재하는지 확인하고, 없으면 구현을 시작하지 않고 리뷰 stub에 차단 근거를 남긴다. +- [ ] Dart `Communicator.nextNonce()`가 active `_pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정한다. +- [ ] Dart `communicator_test.dart`에 wrap 후 `1`이 pending이면 다음 send/request nonce가 `2`가 되는 regression test를 추가한다. +- [ ] Go `Communicator`의 nonce 선택이 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정한다. +- [ ] Go `communicator_nonce_test.go`에 wrap 후 pending nonce skip regression test를 추가한다. +- [ ] `cd dart && dart test test/communicator_test.dart`, `cd go && go test ./...`, `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다. +- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- Dart와 Go 모두 active pending nonce와 충돌하는 candidate를 skip하는지 확인한다. +- Go call site error handling이 deadlock이나 swallowed error를 만들지 않는지 확인한다. +- Regression tests가 단순 wrap이 아니라 pending collision을 실제로 재현하는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +필수 규칙: +- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다. +- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다. +- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다. + +### API-1 중간 검증 +```bash +$ cd dart && dart test test/communicator_test.dart +(output) +``` + +### API-2 중간 검증 +```bash +$ cd go && go test ./... +(output) +``` + +### 최종 검증 +```bash +$ cd dart && dart test test/communicator_test.dart +$ cd go && go test ./... +$ git diff --check +(output) +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +## 섹션 소유권 + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive, complete.log, or task-directory archive move steps | +| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only | +| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[x]` only; final checkbox is mandatory | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Review focus areas | +| 검증 결과 | Implementing agent | Fill command output only | diff --git a/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/PLAN-cloud-G06.md b/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/PLAN-cloud-G06.md new file mode 100644 index 0000000..0a0426a --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/PLAN-cloud-G06.md @@ -0,0 +1,194 @@ + + +# Plan - API + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-cloud-G06.md`의 구현 에이전트 소유 섹션 작성까지가 구현의 마지막 단계다. 검증을 실행하고 실제 출력/결과를 기록한 뒤 active 파일을 유지한 채 리뷰를 요청한다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 범위 충돌이 생기면 직접 질문하지 말고 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 남긴다. 후속 에이전트가 재실행으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다. + +## 배경 + +Dart와 Go는 현재 `nonce` wrap 후 후보 값이 active pending request nonce인지 확인하지 않는다. 이 작업은 reference 역할을 하는 두 구현에서 pending skip 정책을 먼저 구현하고, 같은 실패 모드를 잡는 boundary regression test를 추가한다. 나머지 언어 rollout과 full matrix는 06번 작업에서 이어간다. + +## 사용자 리뷰 요청 흐름 + +구현 중 차단은 active `CODE_REVIEW-cloud-G06.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 채팅으로 사용자에게 직접 질문하지 않으며, code-review가 해당 요청의 타당성을 판단하고 필요할 때 `USER_REVIEW.md`를 작성한다. + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/ROADMAP.md` +- `agent-roadmap/milestones/protocol-evolution-compatibility.md` +- `agent-ops/rules/project/domain/protocol/rules.md` +- `agent-ops/skills/common/plan/SKILL.md` +- `agent-test/local/rules.md` +- `agent-test/local/proto-socket-full-matrix.md` +- `dart/lib/src/communicator.dart` +- `dart/test/communicator_test.dart` +- `go/communicator.go` +- `go/communicator_nonce_test.go` +- `PROTOCOL.md` +- `VERSIONING.md` +- `PORTING_GUIDE.md` + +### 테스트 환경 규칙 + +- test_env: `local` +- 적용 규칙: `agent-test/local/rules.md`를 읽었다. +- 매칭 프로필: `agent-test/local/proto-socket-full-matrix.md` +- 이 split의 직접 검증은 Dart/Go focused tests다. full matrix는 모든 언어 rollout이 끝나는 06번에서 실행한다. + +### 테스트 커버리지 공백 + +- Dart: 기존 `nonce wraps after int32 max without emitting zero`, `sendRequest matches response at nonce wrap boundary`는 단순 wrap만 검증하고 active pending nonce skip은 검증하지 않는다. +- Go: 기존 `TestNonceWrapsAfterInt32MaxWithoutEmittingZero`, `TestSendRequestNonceWrapsAtInt32Max`는 단순 wrap만 검증하고 active pending nonce skip은 검증하지 않는다. +- Kotlin/Python/TypeScript는 06번에서 다룬다. + +### 심볼 참조 + +- renamed/removed symbol: none +- Go에서 `nextNonce()` 시그니처를 변경한다면 call sites는 [go/communicator.go](/config/workspace/proto-socket/go/communicator.go:305), [go/communicator.go](/config/workspace/proto-socket/go/communicator.go:318), [go/communicator.go](/config/workspace/proto-socket/go/communicator.go:614)이다. + +### 분할 판단 + +- split decision policy를 먼저 평가했다. +- 공유 task group: `agent-task/m-protocol-evolution-compatibility/` +- `04+03_nonce_contract`: 선행 계약 문서 작업. +- `05+04_nonce_dart_go`: 이 plan. predecessor `04`가 필요하며 계획 작성 시점에는 active plan만 있고 `complete.log`는 없다. +- `06+04,05_nonce_kotlin_python_ts`: 04/05 완료 후 실행. +- Dart/Go는 reference 구현 경계이고 Kotlin/Python/TypeScript와 테스트 러너가 달라 별도 리뷰 단위로 분리한다. + +### 범위 결정 근거 + +- 이 plan은 Dart와 Go communicator 및 focused nonce tests만 수정한다. +- Kotlin/Python/TypeScript는 06번에서 수정한다. +- cross-language crosstest 기대값은 바꾸지 않는다. nonce 충돌은 동일 언어 unit boundary로 검증한다. + +### 빌드 등급 + +- `cloud-G06`: protocol/concurrency 성격의 동작 변경이고 Go는 atomic + pending map 경계를 함께 검토해야 한다. + +## 구현 체크리스트 + +- [ ] 04번 predecessor `complete.log`가 존재하는지 확인하고, 없으면 구현을 시작하지 않고 리뷰 stub에 차단 근거를 남긴다. +- [ ] Dart `Communicator.nextNonce()`가 active `_pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정한다. +- [ ] Dart `communicator_test.dart`에 wrap 후 `1`이 pending이면 다음 send/request nonce가 `2`가 되는 regression test를 추가한다. +- [ ] Go `Communicator`의 nonce 선택이 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정한다. +- [ ] Go `communicator_nonce_test.go`에 wrap 후 pending nonce skip regression test를 추가한다. +- [ ] `cd dart && dart test test/communicator_test.dart`, `cd go && go test ./...`, `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +`05+04_nonce_dart_go`는 디렉터리명 기준 predecessor `04`를 요구한다. 구현 전 `agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/complete.log` 또는 matching archive complete log를 확인한다. + +### [API-1] Dart pending nonce skip + +#### 문제 + +[dart/lib/src/communicator.dart](/config/workspace/proto-socket/dart/lib/src/communicator.dart:69)는 max 뒤 `1`로 돌아가지만 `_pendingRequests`를 보지 않는다. + +```dart +69 int nextNonce() { +70 if (_nonce >= maxNonce) { +71 _nonce = 0; +72 } +73 _nonce += 1; +74 return _nonce; +75 } +``` + +[dart/lib/src/communicator.dart](/config/workspace/proto-socket/dart/lib/src/communicator.dart:210)는 이 값을 바로 pending key로 등록한다. + +```dart +210 final requestNonce = nextNonce(); +213 _pendingRequests[requestNonce] = _PendingRequest( +``` + +#### 해결 방법 + +`nextNonce()`에서 후보 nonce를 만들고 `_pendingRequests.containsKey(candidate)`이면 계속 진행한다. 최대 `maxNonce`번 시도해도 후보가 없으면 `StateError('no available nonce: all positive int32 nonces are pending')`를 던진다. 이 메서드는 `send`, `sendRequest`, 자동 response가 공통으로 사용하므로 모든 outbound nonce가 active pending key를 피한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `dart/lib/src/communicator.dart`: bounded candidate loop 추가 +- [ ] `dart/test/communicator_test.dart`: pending skip regression 추가 + +#### 테스트 작성 + +`dart/test/communicator_test.dart`에 새 테스트를 추가한다. 절차: nonce를 `maxNonce`, pending request key `1`을 만든 뒤 응답하지 않은 상태에서 `send()` 또는 두 번째 `sendRequest()`를 호출해 새 packet nonce가 `2`인지 확인한다. 기존 pending request는 timeout이 길게 걸리지 않게 `closeForTest()`로 정리한다. + +#### 중간 검증 + +```bash +cd dart && dart test test/communicator_test.dart +``` + +기대 결과: communicator tests PASS. + +### [API-2] Go pending nonce skip + +#### 문제 + +[go/communicator.go](/config/workspace/proto-socket/go/communicator.go:187)는 atomic counter만 보고 후보 nonce를 반환한다. + +```go +187 func (c *Communicator) nextNonce() int32 { +188 for { +189 current := c.nonce.Load() +190 var next int32 +191 if current >= MaxNonce { +192 next = 1 +193 } else { +194 next = current + 1 +195 } +196 if c.nonce.CompareAndSwap(current, next) { +197 return next +198 } +199 } +200 } +``` + +#### 해결 방법 + +Go는 `pendingRequests`가 mutex로 보호되므로 candidate 확정 시 pending map 확인도 안전하게 수행한다. 권장 구현은 `nextNonce() (int32, error)`로 바꾸고, 후보가 pending에 있으면 다음 후보를 계속 찾는다. `Send`, `SendRequest`, `AddRequestListenerTyped`의 response path는 새 error를 처리해야 한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `go/communicator.go`: `nextNonce` pending skip 및 call site error 처리 +- [ ] `go/communicator_nonce_test.go`: pending skip regression 추가 + +#### 테스트 작성 + +`go/communicator_nonce_test.go`에 `TestNextNonceSkipsActivePendingAfterWrap`를 추가한다. 절차: nonce를 `MaxNonce`, pending request key `1`을 만든 뒤 다음 send/request가 nonce `2`를 발행하는지 확인한다. 직접 map을 조작하는 대신 첫 `SendRequestTyped`를 시작해 pending `1`을 만들고 응답하지 않은 상태에서 `Send`를 호출한다. + +#### 중간 검증 + +```bash +cd go && go test ./... +``` + +기대 결과: root/go test packages PASS. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `dart/lib/src/communicator.dart` | API-1 | +| `dart/test/communicator_test.dart` | API-1 | +| `go/communicator.go` | API-2 | +| `go/communicator_nonce_test.go` | API-2 | + +## 최종 검증 + +```bash +cd dart && dart test test/communicator_test.dart +cd go && go test ./... +git diff --check +``` + +기대 결과: Dart communicator tests PASS, Go tests PASS, whitespace error 없음. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/CODE_REVIEW-cloud-G07.md b/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/CODE_REVIEW-cloud-G07.md new file mode 100644 index 0000000..0d14b73 --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/CODE_REVIEW-cloud-G07.md @@ -0,0 +1,158 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-06-16 +task=m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts, plan=0, tag=API + +## Roadmap Targets + +- Milestone: `agent-roadmap/milestones/protocol-evolution-compatibility.md` +- Task ids: + - `nonce-boundary`: nonce wrap 시 pending request nonce와 충돌하지 않도록 active pending nonce skip 정책과 boundary 테스트를 보강한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-cloud-G07.md` -> `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` -> `plan_cloud_G07_M.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/`로 이동한다. +4. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] Kotlin pending nonce skip | [ ] | +| [API-2] Python pending nonce skip | [ ] | +| [API-3] TypeScript pending nonce skip | [ ] | + +## 구현 체크리스트 + +- [ ] 04번과 05번 predecessor `complete.log`가 모두 존재하는지 확인하고, 없으면 구현을 시작하지 않고 리뷰 stub에 차단 근거를 남긴다. +- [ ] Kotlin `Communicator.nextNonce()`가 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression test를 추가한다. +- [ ] Python `Communicator.next_nonce()`가 active `_pending_requests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression test를 추가한다. +- [ ] TypeScript `Communicator.nextNonce()`가 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression 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`과 `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다. +- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- Kotlin/Python/TypeScript가 같은 pending skip 의미를 구현하는지 확인한다. +- 새 테스트가 pending collision을 실제로 만든 뒤 다음 nonce가 `2`로 넘어가는지 확인한다. +- full matrix record가 실제 PASS이고 `nonce-boundary` Roadmap Targets를 체크할 근거가 충분한지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +필수 규칙: +- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다. +- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다. +- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다. + +### API-1 중간 검증 +```bash +$ cd kotlin && ./gradlew test +(output) +``` + +### API-2 중간 검증 +```bash +$ cd python && python3 -m pytest -q +(output) +``` + +### API-3 중간 검증 +```bash +$ cd typescript && npm run check && npm test +(output) +``` + +### 최종 검증 +```bash +$ 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 +$ git diff --check +(output) +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +## 섹션 소유권 + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive, complete.log, or task-directory archive move steps | +| Roadmap Targets | Fixed at stub creation | Implementing agent must not modify; code-review copies it into `complete.log` as Roadmap Completion only on PASS | +| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only | +| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[x]` only; final checkbox is mandatory | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Review focus areas | +| 검증 결과 | Implementing agent | Fill command output only | diff --git a/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/PLAN-cloud-G07.md b/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/PLAN-cloud-G07.md new file mode 100644 index 0000000..b10cc29 --- /dev/null +++ b/agent-task/m-protocol-evolution-compatibility/06+04,05_nonce_kotlin_python_ts/PLAN-cloud-G07.md @@ -0,0 +1,233 @@ + + +# Plan - API + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션 작성까지가 구현의 마지막 단계다. 검증을 실행하고 실제 출력/결과를 기록한 뒤 active 파일을 유지한 채 리뷰를 요청한다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 범위 충돌이 생기면 직접 질문하지 말고 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 남긴다. 후속 에이전트가 재실행으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다. + +## 배경 + +04번 계약과 05번 Dart/Go 기준 구현이 완료되면 Kotlin, Python, TypeScript도 같은 pending nonce skip 정책으로 정렬해야 한다. 이 작업은 남은 세 언어의 boundary regression test를 추가하고 full matrix로 cross-language 호환성을 확인한다. PASS 시 현재 마일스톤의 `nonce-boundary` Task 완료 근거가 된다. + +## 사용자 리뷰 요청 흐름 + +구현 중 차단은 active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 채팅으로 사용자에게 직접 질문하지 않으며, code-review가 해당 요청의 타당성을 판단하고 필요할 때 `USER_REVIEW.md`를 작성한다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/milestones/protocol-evolution-compatibility.md` +- Task ids: + - `nonce-boundary`: nonce wrap 시 pending request nonce와 충돌하지 않도록 active pending nonce skip 정책과 boundary 테스트를 보강한다. +- Completion mode: check-on-pass + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/ROADMAP.md` +- `agent-roadmap/milestones/protocol-evolution-compatibility.md` +- `agent-ops/rules/project/domain/protocol/rules.md` +- `agent-ops/skills/common/plan/SKILL.md` +- `agent-test/local/rules.md` +- `agent-test/local/proto-socket-full-matrix.md` +- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt` +- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt` +- `python/proto_socket/communicator.py` +- `python/test/test_communicator.py` +- `typescript/src/communicator.ts` +- `typescript/test/communicator.test.ts` +- `PROTOCOL.md` +- `VERSIONING.md` +- `PORTING_GUIDE.md` + +### 테스트 환경 규칙 + +- test_env: `local` +- 적용 규칙: `agent-test/local/rules.md`를 읽었다. +- 매칭 프로필: `agent-test/local/proto-socket-full-matrix.md` +- 직접 검증: Kotlin/Python/TypeScript focused tests. +- 최종 검증: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all` + +### 테스트 커버리지 공백 + +- Kotlin: 기존 `testNonceWrapsAfterIntMaxWithoutEmittingZero`, `testSendRequestNonceWrapsAtInt32Max`는 active pending nonce skip을 검증하지 않는다. +- Python: 기존 `test_nonce_wraps_after_int32_max_without_emitting_zero`, `test_send_request_nonce_wraps_at_int32_max`는 active pending nonce skip을 검증하지 않는다. +- TypeScript: 기존 `nonce wraps after int32 max without emitting zero`, `sendRequest nonce wraps at int32 max`는 active pending nonce skip을 검증하지 않는다. +- full matrix는 cross-language smoke를 보장하지만 wrap boundary 자체는 focused unit tests가 담당한다. + +### 심볼 참조 + +- renamed/removed symbol: none +- Kotlin `nextNonce()` call sites: [Communicator.kt](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:304), [Communicator.kt](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:316), [Communicator.kt](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:683) +- Python `next_nonce()` call sites: [communicator.py](/config/workspace/proto-socket/python/proto_socket/communicator.py:306), [communicator.py](/config/workspace/proto-socket/python/proto_socket/communicator.py:319), [communicator.py](/config/workspace/proto-socket/python/proto_socket/communicator.py:549) +- TypeScript `nextNonce()` call sites: [communicator.ts](/config/workspace/proto-socket/typescript/src/communicator.ts:404), [communicator.ts](/config/workspace/proto-socket/typescript/src/communicator.ts:419), [communicator.ts](/config/workspace/proto-socket/typescript/src/communicator.ts:610) + +### 분할 판단 + +- split decision policy를 먼저 평가했다. +- 공유 task group: `agent-task/m-protocol-evolution-compatibility/` +- `06+04,05_nonce_kotlin_python_ts`: 이 plan. predecessor `04`, `05`가 모두 필요하며 계획 작성 시점에는 active plan만 있고 `complete.log`는 없다. +- 06번은 최종 rollout과 full matrix를 포함하므로 `Roadmap Targets`를 가진다. + +### 범위 결정 근거 + +- 이 plan은 Kotlin/Python/TypeScript communicator와 focused tests를 수정한다. +- Dart/Go는 05번 완료 결과를 전제로 하며 이 plan에서 다시 수정하지 않는다. +- proto schema와 crosstest expected count는 변경하지 않는다. + +### 빌드 등급 + +- `cloud-G07`: 세 async runtime에 같은 protocol/concurrency 정책을 적용하고 full matrix evidence까지 수집한다. + +## 구현 체크리스트 + +- [ ] 04번과 05번 predecessor `complete.log`가 모두 존재하는지 확인하고, 없으면 구현을 시작하지 않고 리뷰 stub에 차단 근거를 남긴다. +- [ ] Kotlin `Communicator.nextNonce()`가 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression test를 추가한다. +- [ ] Python `Communicator.next_nonce()`가 active `_pending_requests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression test를 추가한다. +- [ ] TypeScript `Communicator.nextNonce()`가 active `pendingRequests` 키와 충돌하는 후보 nonce를 건너뛰도록 수정하고 regression 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`과 `git diff --check`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +`06+04,05_nonce_kotlin_python_ts`는 디렉터리명 기준 predecessors `04`, `05`를 요구한다. 구현 전 다음 중 하나로 각각의 완료를 확인한다. + +- `agent-task/m-protocol-evolution-compatibility/04+03_nonce_contract/complete.log` 또는 matching archive complete log +- `agent-task/m-protocol-evolution-compatibility/05+04_nonce_dart_go/complete.log` 또는 matching archive complete log + +### [API-1] Kotlin pending nonce skip + +#### 문제 + +[Communicator.kt](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:234)는 atomic counter만 보고 후보 nonce를 반환한다. + +```kotlin +234 internal fun nextNonce(): Int { +235 while (true) { +236 val current = nonce.get() +237 val next = if (current >= MAX_NONCE) 1 else current + 1 +238 if (nonce.compareAndSet(current, next)) return next +239 } +240 } +``` + +#### 해결 방법 + +후보를 CAS로 확보한 뒤 `rwLock.read { pendingRequests.containsKey(candidate) }`를 확인하고, pending이면 다음 후보를 찾는다. 모든 positive int32 nonce가 pending인 경우 `IllegalStateException`을 던진다. + +#### 수정 파일 및 체크리스트 + +- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt`: pending skip 구현 +- [ ] `kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt`: skip regression 추가 + +#### 테스트 작성 + +`testNextNonceSkipsActivePendingAfterWrap`를 추가한다. nonce를 `Int.MAX_VALUE`, 첫 request로 pending `1`을 만든 뒤 다음 send가 nonce `2`를 발행하는지 확인한다. + +#### 중간 검증 + +```bash +cd kotlin && ./gradlew test +``` + +기대 결과: BUILD SUCCESSFUL. + +### [API-2] Python pending nonce skip + +#### 문제 + +[communicator.py](/config/workspace/proto-socket/python/proto_socket/communicator.py:186)는 wrap 후 `1`을 반환하지만 `_pending_requests`를 확인하지 않는다. + +```python +186 def next_nonce(self) -> int: +187 if self._nonce >= MAX_NONCE: +188 self._nonce = 0 +189 self._nonce += 1 +190 return self._nonce +``` + +#### 해결 방법 + +`next_nonce()`에서 bounded loop를 사용해 candidate가 `_pending_requests`에 있으면 skip한다. asyncio 단일 event loop 내 상태 변경이므로 별도 lock은 추가하지 않는다. 후보가 없으면 `RuntimeError` 또는 `ValueError`로 실패한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `python/proto_socket/communicator.py`: pending skip 구현 +- [ ] `python/test/test_communicator.py`: skip regression 추가 + +#### 테스트 작성 + +`test_next_nonce_skips_active_pending_after_wrap`를 추가한다. `_nonce = MAX_NONCE`, 첫 `send_request`로 pending `1`을 만들고, 응답 전 `send()`를 호출해 두 번째 packet nonce가 `2`인지 확인한다. + +#### 중간 검증 + +```bash +cd python && python3 -m pytest -q +``` + +기대 결과: pytest PASS. + +### [API-3] TypeScript pending nonce skip + +#### 문제 + +[communicator.ts](/config/workspace/proto-socket/typescript/src/communicator.ts:284)는 wrap 후 `1`을 반환하지만 `pendingRequests`를 확인하지 않는다. + +```ts +284 private nextNonce(): number { +285 if (this.nonce >= Communicator.MAX_NONCE) { +286 this.nonce = 0; +287 } +288 this.nonce += 1; +289 return this.nonce; +290 } +``` + +#### 해결 방법 + +`nextNonce()`에서 bounded loop를 사용해 candidate가 `pendingRequests.has(candidate)`이면 skip한다. JavaScript event loop 상태라 별도 mutex는 추가하지 않는다. 후보가 없으면 `Error`를 던지고 send/sendRequest promise가 reject되게 한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `typescript/src/communicator.ts`: pending skip 구현 +- [ ] `typescript/test/communicator.test.ts`: skip regression 추가 + +#### 테스트 작성 + +`nextNonce skips active pending request nonce after wrap`를 추가한다. private state cast로 `nonce = MAX_NONCE`, 첫 `sendRequest`로 pending `1`을 만들고 두 번째 send가 nonce `2`를 발행하는지 확인한다. + +#### 중간 검증 + +```bash +cd typescript && npm run check && npm test +``` + +기대 결과: typecheck/test PASS. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt` | API-1 | +| `kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt` | API-1 | +| `python/proto_socket/communicator.py` | API-2 | +| `python/test/test_communicator.py` | API-2 | +| `typescript/src/communicator.ts` | API-3 | +| `typescript/test/communicator.test.ts` | API-3 | + +## 최종 검증 + +```bash +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 +git diff --check +``` + +기대 결과: Kotlin/Python/TypeScript focused tests PASS, full matrix PASS, whitespace error 없음. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.