proto-socket/agent-task/quality_improvements/plan_0.log

237 lines
7.5 KiB
Text

<!-- task=quality_improvements plan=0 tag=REFACTOR -->
# Quality Improvements — 구현 품질 정리
## 이 파일을 읽는 구현 에이전트에게
각 항목의 체크리스트를 완료로 표시하고, 중간 검증 명령을 실제로 실행한 뒤 출력을 `CODE_REVIEW.md`의 `검증 결과` 섹션에 붙여넣으세요. 최종 검증까지 모두 통과한 후 `CODE_REVIEW.md` 완성 여부 표를 `[x]`로 채우세요.
## 배경
코드베이스 전반 평가에서 발견된 사소하지만 일관성을 깨는 네 가지 문제를 수정합니다. PROTOCOL.md 상태 표가 이미 완료된 TypeScript·Python을 Planned로 표기하고 있고, Python `Communicator._shutdown`이 외부에서 private 메서드로 직접 호출되며, Kotlin `nextNonce()`가 불필요하게 public으로 노출됩니다. 또한 VERSIONING.md에 `nonce` int32 overflow 정책이 빠져있습니다.
## 의존 관계 및 구현 순서
REFACTOR-2(Python) → REFACTOR-3(Kotlin) → REFACTOR-1(PROTOCOL.md) → REFACTOR-4(VERSIONING.md) 순서로 진행합니다. 코드 변경 후 문서 업데이트.
---
### [REFACTOR-1] PROTOCOL.md 구현 상태 표 업데이트
**문제**
[PROTOCOL.md:183-184](../PROTOCOL.md) — TypeScript와 Python이 "Planned"로 기재되어 있으나 두 언어 모두 구현 완료 상태입니다.
```markdown
| TypeScript | Planned | `typescript/` | ← 183번 줄
| Python | Planned | `python/` | ← 184번 줄
```
**해결 방법**
두 행의 `Planned` → `Available`로 교체합니다.
```markdown
| TypeScript | Available | `typescript/` |
| Python | Available | `python/` |
```
**수정 파일 및 체크리스트**
- [x] `PROTOCOL.md` — 183번 줄 `TypeScript | Planned` → `TypeScript | Available`
- [x] `PROTOCOL.md` — 184번 줄 `Python | Planned` → `Python | Available`
**테스트 작성**
문서 전용 변경이므로 테스트 불필요.
**중간 검증**
```bash
grep "TypeScript\|Python" PROTOCOL.md | grep "Planned"
# 출력 없음이 정상
grep "TypeScript\|Python" PROTOCOL.md | grep "Available"
# TypeScript | Available, Python | Available 두 줄 출력
```
---
### [REFACTOR-2] Python `_shutdown` → `shutdown` 공개 메서드 전환
**문제**
[python/toki_socket/base_client.py:51](../python/toki_socket/base_client.py) — `BaseClient.close()`가 `Communicator`의 private 메서드를 직접 호출합니다.
```python
self.communicator._shutdown() # ← 51번 줄, private 접근
```
Go/TypeScript/Kotlin은 모두 `shutdown()` public 메서드를 노출합니다. Python만 `_shutdown()` 형태여서 API 일관성이 깨집니다.
**해결 방법**
`communicator.py`에서 `_shutdown` → `shutdown`으로 이름을 바꾸고, `close()` 내부 self 호출도 함께 수정합니다. `base_client.py`도 맞춰 업데이트합니다.
Before (`communicator.py:67`):
```python
def _shutdown(self) -> None:
```
After:
```python
def shutdown(self) -> None:
```
Before (`communicator.py:83`):
```python
self._shutdown()
```
After:
```python
self.shutdown()
```
Before (`base_client.py:51`):
```python
self.communicator._shutdown()
```
After:
```python
self.communicator.shutdown()
```
**수정 파일 및 체크리스트**
- [x] `python/toki_socket/communicator.py:67` — `def _shutdown` → `def shutdown`
- [x] `python/toki_socket/communicator.py:83` — `self._shutdown()` → `self.shutdown()`
- [x] `python/toki_socket/base_client.py:51` — `self.communicator._shutdown()` → `self.communicator.shutdown()`
**테스트 작성**
기존 [python/test/test_communicator.py:94](../python/test/test_communicator.py) `test_shutdown()`은 `communicator.close()`를 통해 간접 검증합니다. 직접 `shutdown()`을 호출하는 케이스가 없으므로, public 메서드를 직접 검증하는 테스트를 한 건 추가합니다.
- 파일: `python/test/test_communicator.py`
- 테스트명: `test_shutdown_public_method`
- 단언 목표: `communicator.shutdown()` 직접 호출 후 `is_alive() == False`
**중간 검증**
```bash
cd python && python -m pytest test/test_communicator.py -v
# PASSED test_shutdown_public_method 포함 전체 통과
```
---
### [REFACTOR-3] Kotlin `nextNonce()` 접근자를 `internal`로 좁히기
**문제**
[kotlin/src/main/kotlin/com/tokilabs/toki_socket/Communicator.kt:92](../kotlin/src/main/kotlin/com/tokilabs/toki_socket/Communicator.kt) — `nextNonce()`가 public으로 선언됩니다.
```kotlin
fun nextNonce(): Int = nonce.incrementAndGet() // ← 92번 줄
```
Go는 소문자(`nextNonce`) 패키지 전용, TypeScript는 `private nextNonce()`. Kotlin만 외부에서 nonce를 증가시킬 수 있어 의도치 않은 상태 오염이 가능합니다.
`addRequestListenerTyped`와 `sendRequestTyped`는 같은 파일 내 top-level 함수로, `internal`이면 접근 가능합니다.
**해결 방법**
Before (`Communicator.kt:92`):
```kotlin
fun nextNonce(): Int = nonce.incrementAndGet()
```
After:
```kotlin
internal fun nextNonce(): Int = nonce.incrementAndGet()
```
**수정 파일 및 체크리스트**
- [x] `kotlin/src/main/kotlin/com/tokilabs/toki_socket/Communicator.kt:92` — `fun nextNonce` → `internal fun nextNonce`
**테스트 작성**
Kotlin 테스트(`src/test/`)는 `nextNonce()`를 직접 호출하지 않으므로 테스트 변경 불필요. `internal` 키워드는 같은 모듈 내 테스트에서는 계속 접근 가능하므로 기존 테스트 깨짐 없음.
**중간 검증**
```bash
cd kotlin && ./gradlew test
# BUILD SUCCESSFUL, 0 failures
```
---
### [REFACTOR-4] VERSIONING.md에 nonce overflow 정책 추가
**문제**
[VERSIONING.md](../VERSIONING.md) — `nonce`는 `int32` 타입으로 ~21억 메시지 후 overflow합니다. 현재 문서에 overflow 시 동작이 명시되지 않아, 새 언어 구현자가 wrapping·연결 재시작 여부를 독자적으로 판단해야 합니다.
**해결 방법**
`VERSIONING.md`의 "Non-breaking Protocol Changes" 섹션 바로 아래에 `## nonce Overflow` 항목을 추가합니다.
```markdown
## nonce Overflow
`nonce`와 `responseNonce` 필드는 protobuf `int32`(부호 있는 32비트)입니다.
단일 연결에서 약 21억 회 송신 후 overflow가 발생합니다.
현재 정책:
- 프로토콜은 overflow를 정의하지 않는다. 단일 연결에서 int32 한계에 도달하는 경우는 현실적이지 않다.
- 구현체는 overflow에 대한 복구 논리를 추가하지 않는다.
- 만약 미래에 overflow 처리가 필요해지면 프로토콜 버전을 올리고 wrap-around 여부를 명시한다.
```
**수정 파일 및 체크리스트**
- [x] `VERSIONING.md` — "Non-breaking Protocol Changes" 섹션 아래에 `## nonce Overflow` 항목 추가
**테스트 작성**
문서 전용 변경이므로 테스트 불필요.
**중간 검증**
```bash
grep -A 10 "nonce Overflow" VERSIONING.md
# 추가된 섹션 출력
```
---
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `PROTOCOL.md` | REFACTOR-1 |
| `python/toki_socket/communicator.py` | REFACTOR-2 |
| `python/toki_socket/base_client.py` | REFACTOR-2 |
| `python/test/test_communicator.py` | REFACTOR-2 |
| `kotlin/src/main/kotlin/com/tokilabs/toki_socket/Communicator.kt` | REFACTOR-3 |
| `VERSIONING.md` | REFACTOR-4 |
## 최종 검증
```bash
# Python 전체 테스트
cd python && python -m pytest -v
# 모든 테스트 PASSED
# Kotlin 전체 테스트
cd kotlin && ./gradlew test
# BUILD SUCCESSFUL
# 문서 확인
grep "TypeScript\|Python" PROTOCOL.md | grep "Available"
grep "nonce Overflow" VERSIONING.md
# 두 항목 모두 출력
```