# Proto Socket

Proto Socket은 여러 언어와 플랫폼 사이에서 양방향 통신을 하기 위한 바이너리 소켓 프로토콜 라이브러리다.

Protocol Buffers 직렬화, TCP 4바이트 빅엔디안 길이 프리픽스 프레이밍, WebSocket 바이너리 프레임, 타입 기반 메시지 라우팅, 요청-응답 상관관계, 내장 하트비트를 제공한다.

---

## 현재 상태

현재 프로토콜 `0.1`의 사용 가능 호환 구현은 Dart, Go, Kotlin, Python, TypeScript다.

이 프로젝트는 안정화와 유지보수 단계에 있다. 현재 릴리즈 표준은 이 저장소를 Git ref/tag 기준으로 소비하는 방식이며, package registry 배포는 현재 목표가 아니다. C#과 Swift는 계획된 대상이지만, 실제 수요가 생기기 전까지 구현을 미룬다.

프로토콜이나 구현을 바꿀 때는 아래 내부 로컬 검증 매트릭스를 안정성 gate로 사용한다. 현재 주 사용 방식은 Git 기반 소비이므로, CI/CD runner 연결은 기본 운영 모델이 아니며 이 프로젝트 규모와 배포 방식에서는 설계상 과하다. Coverage는 라인 수치가 아니라 프로토콜 계약의 모든 필수 시나리오가 매트릭스에 포함되어 PASS인지로 판단한다.

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all
```

### 검증 스냅샷

다른 프로젝트나 에이전트가 도입 여부를 빠르게 판단할 때는 아래 표 자체를 현재 공개 snapshot으로 본다. 원본 실행 기록은 `agent-test/runs/` 아래의 로컬 산출물이라 저장소에는 포함하지 않는다. 절대 throughput/latency는 local host와 runtime 상태에 의존하므로, 회귀 판단은 같은 host/runtime/profile에서 생성한 결과끼리 비교한다.

| 항목 | 최신 근거 | 결과 | 해석 |
|------|-----------|------|------|
| 기능 호환성 | 로컬 기록 `20260618-072542-proto-socket-full-matrix.md`, ref `59511b9` | PASS | proto sync, 동일 언어 테스트, 20개 native cross-language 방향, Dart.web/Dart.web(WSS) client coverage가 모두 통과했다. |
| 성능/안정성 quick 재검증 | 로컬 기록 `20260618-003346-proto-socket-performance-quick.md`, ref `1a91f49` | PASS | same-language, cross-language, TypeScript gateway quick profile이 모두 통과했다. baseline 비교가 없어 regression 판정은 `SKIPPED`다. |
| 성능/안정성 full baseline 후보 | 로컬 기록 `20260614-123328-proto-socket-performance-full.md`, ref `29ea189` | PASS | full profile 기준 same-language, cross-language, TypeScript gateway 성능/안정성 측정이 모두 통과했다. |
| 최신 full 안정성 hard gate | 로컬 기록 `20260618-144710-proto-socket-stress-full.md`, `20260618-205424-proto-socket-stress-full-cross.md`, `20260618-210208-proto-socket-stress-full.md`, ref `50ef8b2` | PASS | same-language, cross-language, TypeScript gateway full stress에서 timeout, nonce mismatch, response type mismatch, FIFO violation, pending leak가 모두 0이다. |
| 최신 full 성능 회귀 비교 | 로컬 기록 `20260618-144710-proto-socket-performance-full.md`, ref `50ef8b2` | WARN | baseline 대비 throughput 20% 이상 하락 또는 p99 25% 이상 악화 row가 96개 있었다. 기능/호환성/안정성 실패가 아니라 local host/runtime 상태에 민감한 성능 비교 경고로 보고, 완료 차단 항목으로 보지 않는다. |

성능 full 기록의 대표 수치는 다음과 같다.

| 축 | 대표 결과 |
|----|-----------|
| 30분 sustained | Dart TCP 40k rps, TypeScript TCP 33k rps, Kotlin TCP 27k rps, Go TCP 15.6k rps, Python TCP 12.2k rps 수준 |
| 1024 clients 병렬 | Go TCP 209k rps/p99 133ms, Kotlin TCP 70k rps/p99 219ms, TypeScript TCP 47k rps/p99 76ms |
| 1MB payload | Python TCP 463 rps/p99 17ms, Go TCP 415 rps/p99 20ms, Kotlin TCP 351 rps/p99 46ms |
| TypeScript gateway | in-process gateway는 TCP/WS p99 1.7-3.2ms 수준, `worker_threads` gateway는 p99 190-203ms 수준이라 저지연 기본값으로 보지 않는다. |

도입 판단은 "얇은 protocol-first 소켓 프레임워크로 충분히 실용적"으로 둔다. 다만 Kotlin WebSocket과 Python high-concurrency row는 다른 구현보다 tail latency가 크므로, 초저지연/초고동시성 제품에서는 해당 언어와 transport 조합을 별도로 재측정한다. 최신 full 성능 회귀 비교의 `WARN`은 correctness 또는 stability failure가 아니라 같은 host/runtime/profile의 상태 차이에 따라 흔들릴 수 있는 참고 경고다. 성능 회귀 없음까지 제품 gate로 확정해야 하는 경우에는 idle 상태의 같은 host에서 `run_performance.sh --full --baseline <이전 performance record>`를 반복 실행해 재현성을 본다.

### 2026-06-19 완료 판단

2026-06-19 기준으로 Proto Socket은 프로토콜 `0.1`과 현재 사용 가능 언어 5종(Dart, Go, Kotlin, Python, TypeScript)에 대해 완료 상태로 둔다. 완료 근거는 최신 전체 기능 매트릭스 PASS, 최신 full 안정성 hard gate PASS, 기존 full baseline PASS, README/PROTOCOL/VERSIONING/PORTING_GUIDE 정합성 점검이다. 최신 full 성능 회귀 비교의 `WARN`은 환경 의존 성능 비교 경고이며 기능/호환성/안정성 완료 판단을 막지 않는다.

이후 작업은 유지보수 모드로 제한한다. 허용 범위는 bug fix, 문서 정정, 테스트 runner 보강, 호환성을 유지하는 작은 구현 수정이다. C#/Swift 같은 새 언어 확장, package registry 배포, protocol/API 변경은 실제 소비 수요와 명시적 재개 요청이 있을 때 별도 작업으로 다시 연다.

프로토콜 또는 공개 API 변경은 호환성 작업으로 다룬다. 관련 문서를 갱신하고, 필요한 경우 protobuf binding을 재생성하며, 전체 검증 매트릭스가 통과해야 한다.

### 런타임 포트와 테스트 포트

Proto Socket은 라이브러리이며 frontend/backend runtime service port를 소유하지 않는다. 애플리케이션 서버가 사용할 host/port는 소비자가 정한다.

README의 `9090` 예시는 소비자 애플리케이션용 샘플 포트이며 test matrix reserved 대역이 아니다. 저장소의 cross-language/cross-runtime runner는 충돌을 줄이기 위해 `29090-29899` local port 대역을 테스트 전용 workspace 예외로 사용한다.

Dart.web 검증은 local Chrome이 없을 때 runner가 구성된 SSH remote browser host에서 실행할 수 있다. WSS 검증은 테스트용 self-signed certificate의 SPKI를 허용하는 Chrome wrapper를 사용하며, tracked 문서에는 credential, token, private endpoint 값을 기록하지 않는다.

---

## 설계 원칙

- core transport layer는 얇고 안정적으로 유지한다.
- 언어 간 통신에 필요한 최소 공통 기반만 제공한다.
- framing, serialization, routing, request-response correlation, heartbeat를 표준화한다.
- Protocol Buffers를 핵심 프로토콜 의존성으로 둔다. 다른 런타임 의존성은 native-first, 좁은 범위, 기능에 비례한 수준으로 유지한다.
- 애플리케이션 의미를 프로토콜 core에 넣지 않는다.
- auth, session, agent workflow, chat, game logic 같은 도메인 관심사는 상위 레이어 구현의 책임이다.
- 수신 처리 계약(inbound queue 순서, receive coordinator, backpressure, close/drain/cancel 정책)은 [PROTOCOL.md](PROTOCOL.md)의 `Receive Ordering and Backpressure` 섹션에 정의하고, 새 언어 구현 기준은 [PORTING_GUIDE.md](PORTING_GUIDE.md)의 `반드시 유지해야 하는 구조` 표를 따른다.

---

## 프로토콜

전체 wire format 명세는 [PROTOCOL.md](PROTOCOL.md)를 본다.

```text
[4-byte big-endian length] [PacketBase protobuf bytes]
```

WebSocket/WSS transport에서는 각 binary frame이 TCP length header 없이 `PacketBase` protobuf payload 하나를 담는다.

프로토콜 호환성은 언어별 package version과 분리해서 추적한다. 자세한 정책은 [VERSIONING.md](VERSIONING.md)를 본다. 패키지를 아직 registry에 배포하지 않더라도, 저장소에 포함된 구현은 문서화된 프로토콜 계약을 지켜야 한다.

---

## 구현체

| 언어　　　 | 상태　　　　| 경로　　　　　　　　　　　 | 사용처　　　　　　　　　　 |
| ------------| -------------| ----------------------------| ----------------------------|
| Dart　　　 | 사용 가능　 | [dart/](dart/)　　　　　　 | Flutter, Dart server　　　 |
| Kotlin　　 | 사용 가능　 | [kotlin/](kotlin/)　　　　 | Android, JVM　　　　　　　 |
| Go　　　　 | 사용 가능　 | [go/](go/)　　　　　　　　 | Server, tooling, scripting |
| TypeScript | 사용 가능　 | [typescript/](typescript/) | Browser, Node.js　　　　　 |
| Python　　 | 사용 가능　 | [python/](python/)　　　　 | Server, tooling, scripting |
| C#　　　　 | 계획 / 보류 | `csharp/`　　　　　　　　　| Unity, .NET　　　　　　　　|
| Swift　　　| 계획 / 보류 | `swift/`　　　　　　　　　 | iOS, macOS　　　　　　　　 |

새 언어 구현은 [PORTING_GUIDE.md](PORTING_GUIDE.md)와 [agent-ops/skills/project/add-proto-socket-crosstest-language/templates/](agent-ops/skills/project/add-proto-socket-crosstest-language/templates/)의 템플릿에서 시작한다. 동일 언어 테스트와 크로스 언어 테스트가 통과한 뒤에만 구현 상태를 사용 가능으로 표시한다.

현재 구현 상태는 이 README를 공개 snapshot으로 본다. 현재 작업 맥락은 [agent-roadmap/current.md](agent-roadmap/current.md)에서 선택하고, 큰 로드맵 방향은 [agent-roadmap/ROADMAP.md](agent-roadmap/ROADMAP.md)에 둔다.

---

## 주요 명령

| 목적 | 명령 | 비고 |
|------|------|------|
| 전체 로컬 검증 | `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all` | proto sync, 동일 언어 테스트, 사용 가능 구현의 크로스 언어 검증을 실행한다. |
| 성능/안정성 full 측정 | `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full` | same-language, cross-language, TypeScript gateway 성능과 stability hard gate를 측정한다. |
| 성능 baseline 비교 | `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --quick --baseline agent-test/runs/<baseline-record>.md` | 같은 host/runtime/profile의 이전 기록과 throughput/p99 회귀 후보를 비교한다. |
| Proto schema sync 확인 | `tools/check_proto_sync.sh` | 언어별 proto copy가 허용된 언어 옵션을 제외하고 `proto/message_common.proto`와 일치하는지 확인한다. |
| Protobuf binding 재생성 | `tools/generate_proto.sh` | canonical proto schema를 바꾼 뒤 실행한다. |
| Dart 테스트 | `cd dart && dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js` | Dart VM/IO 테스트와 web import compile 확인 |
| Go 테스트 | `cd go && go test ./...` | Go 동일 언어 검증 |
| Kotlin 테스트 | `cd kotlin && ./gradlew test` | Kotlin 동일 언어 검증 |
| Python 테스트 | `cd python && python3 -m pytest -q` | Python 동일 언어 검증 |
| TypeScript 확인 | `cd typescript && npm run check && npm test` | TypeScript type check와 테스트 |

---

## 저장소 구조

| 경로 | 역할 |
|------|------|
| [proto/](proto/) | canonical protobuf schema 원본 |
| [dart/](dart/) | Dart / Flutter 구현체와 테스트 |
| [go/](go/) | Go 구현체, 테스트, Go 주도 crosstest |
| [kotlin/](kotlin/) | Kotlin / JVM 구현체와 crosstest |
| [python/](python/) | Python 구현체와 crosstest |
| [typescript/](typescript/) | TypeScript 구현체와 crosstest |
| [tools/](tools/) | proto 생성과 sync helper |
| [examples/](examples/) | 소비자 지향 예제 |
| [agent-ops/](agent-ops/) | 프로젝트 규칙, 로드맵, 반복 agent workflow |

---

## 빠른 시작: Dart

```dart
import 'package:proto_socket/proto_socket.dart';

// 1. message_common.proto에 메시지를 정의하고 protoc로 생성한다.

// 2. client를 구현한다.
class MyClient extends ProtobufClient {
  MyClient(Socket socket) : super(socket, 30, 10, {
    MyMessage.getDefault().info_.qualifiedMessageName: MyMessage.fromBuffer,
  });
}

// 3. server를 구현한다.
class MyServer extends ProtobufServer {
  // 9090 is an application example port, not a proto-socket reserved test port.
  MyServer() : super('0.0.0.0', 9090, (socket) => MyClient(socket));

  @override
  void onClientConnected(ProtobufClient client) {
    client.addListener<MyMessage>((msg) => print('Received: ${msg}'));
  }
}

// 4. server를 시작한다.
final server = MyServer();
await server.start();

// 5. 연결하고 메시지를 보낸다.
final socket = await Socket.connect('localhost', 9090);
final client = MyClient(socket);
await client.send(MyMessage()..text = 'hello');
```

---

## 메시지 타입 추가

canonical proto인 `proto/message_common.proto`를 수정한 뒤, 저장소에 포함된 모든 binding을 재생성한다.

```bash
tools/generate_proto.sh
tools/check_proto_sync.sh
```

Go와 Kotlin proto copy에는 `option go_package`, Java package/class option 같은 언어별 옵션만 추가로 허용한다. 메시지 schema가 `proto/message_common.proto`와 달라지면 `tools/check_proto_sync.sh`가 diff와 함께 실패한다.

---

## 빠른 시작: Go

```go
package main

import (
	"context"
	"net"
	"time"

	"google.golang.org/protobuf/proto"

	protoSocket "git.toki-labs.com/toki/proto-socket/go"
	"git.toki-labs.com/toki/proto-socket/go/packets"
)

func parserMap() protoSocket.ParserMap {
	return protoSocket.ParserMap{
		protoSocket.TypeNameOf(&packets.TestData{}): func(b []byte) (proto.Message, error) {
			m := &packets.TestData{}
			return m, proto.Unmarshal(b, m)
		},
	}
}

func main() {
	ctx := context.Background()

	// 9090 is an application example port, not a proto-socket reserved test port.
	server := protoSocket.NewTcpServer("127.0.0.1", 9090, func(conn net.Conn) *protoSocket.TcpClient {
		return protoSocket.NewTcpClient(conn, 30, 10, parserMap())
	})
	server.OnClientConnected = func(client *protoSocket.TcpClient) {
		protoSocket.AddRequestListenerTyped[*packets.TestData, *packets.TestData](
			&client.Communicator,
			func(req *packets.TestData) (*packets.TestData, error) {
				return &packets.TestData{Index: req.GetIndex(), Message: "echo: " + req.GetMessage()}, nil
			},
		)
	}
	if err := server.Start(ctx); err != nil {
		panic(err)
	}
	defer server.Stop()

	client, err := protoSocket.DialTcp(ctx, "127.0.0.1", 9090, 30, 10, parserMap())
	if err != nil {
		panic(err)
	}
	defer client.Close()

	res, err := protoSocket.SendRequestTyped[*packets.TestData, *packets.TestData](
		&client.Communicator,
		&packets.TestData{Index: 1, Message: "hello"},
		2*time.Second,
	)
	if err != nil {
		panic(err)
	}
	println(res.GetMessage())
}
```

Go 구현체는 다음 표면도 제공한다.

- TCP: `NewTcpServer`, `DialTcp`, `NewTcpServerTLS`, `DialTcpTLS`
- WebSocket: `NewWsServer`, `NewWsServerWithOptions`, `DialWs`, `NewWsServerTLS`, `NewWsServerTLSWithOptions`, `DialWss`
- Shared helpers: `Send`, `SendRequest`, `AddListenerTyped`, `AddRequestListenerTyped`, `Broadcast`

다른 저장소에서 이 모듈을 사용하는 복사 가능한 scaffold가 필요하면 [examples/go-module-consumer/](examples/go-module-consumer/)를 본다.

---

## 테스트 실행

개발과 문제 재현을 위한 로컬 명령은 이 문서에 정리한다. 반복 가능한 저장소 로컬 검증 진입점은 다음 명령이다.

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all
```

이 명령은 proto schema sync, 동일 언어 테스트, 크로스 언어 검증을 실행하고, 실패가 있으면 재현 명령과 함께 PASS/FAIL 표를 출력한다. 더 작은 범위만 확인하려면 `--proto`, `--unit`, `--cross`를 사용한다.

외부 CI runner 연동은 이 저장소의 기본 운영 목표가 아니다. 현재 주 사용 방식은 Git 기반 소비와 내부 로컬 매트릭스 결과 확인이며, 이 범위에서는 별도 CI/CD runner 연결을 요구하지 않는다.

Proto schema sync:

```bash
tools/check_proto_sync.sh
```

동일 언어 검증:

```bash
cd dart
dart pub get
dart test
dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js
```

```bash
cd go
go test ./...
```

```bash
cd kotlin
./gradlew test
```

```bash
cd python
python3 -m pytest -q
```

```bash
cd typescript
npm run check
npm test
```

크로스 언어 검증:

```bash
cd go
go run ./crosstest/go_dart.go
go run ./crosstest/go_kotlin.go
go run ./crosstest/go_python.go
go run ./crosstest/go_typescript.go
```

```bash
cd dart
dart run crosstest/dart_go.dart
dart run crosstest/dart_kotlin.dart
dart run crosstest/dart_python.dart
dart run crosstest/dart_typescript.dart
```

```bash
cd kotlin
./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinDartKt
./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinGoKt
./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinPythonKt
./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinTypescriptKt
```

```bash
cd python
python3 crosstest/python_dart.py
python3 crosstest/python_go.py
python3 crosstest/python_kotlin.py
python3 crosstest/python_typescript.py
```

```bash
cd typescript
./node_modules/.bin/tsx crosstest/typescript_dart.ts
./node_modules/.bin/tsx crosstest/typescript_go.ts
./node_modules/.bin/tsx crosstest/typescript_kotlin.ts
./node_modules/.bin/tsx crosstest/typescript_python.ts
```

### Dart.io와 Dart.web E2E 매트릭스

위 표의 `Dart` 열은 Dart VM/IO client를 뜻한다. `Dart.web`은 별도 축이다. 브라우저 WS/WSS client만 가능하며, 브라우저에서는 TCP와 server 역할이 불가능하므로 해당 cell은 `N/A`다. Dart.web WSS는 테스트용 self-signed certificate의 SPKI를 허용하는 Chrome 실행 wrapper로 local/remote 브라우저 검증에 포함한다.

| Server | Dart.io TCP | Dart.io WS | Dart.io TLS TCP | Dart.io WSS | Dart.web WS | Dart.web WSS | Dart.web TCP |
|---|---|---|---|---|---|---|---|
| Dart.io | Covered | Covered | Covered | Covered | Covered | Covered | N/A |
| Go | Covered | Covered | Covered | Covered | Covered | Covered | N/A |
| Kotlin | Covered | Covered | Covered | Covered | Covered | Covered | N/A |
| Python | Covered | Covered | Covered | Covered | Covered | Covered | N/A |
| TypeScript | Covered | Covered | Covered | Covered | Covered | Covered | N/A |

각 Dart.web cell은 server-language runner가 WS와 WSS server를 함께 띄우고, matching browser test file에 대해 `dart test -p chrome`을 실행하며, WS send-push/request-response와 WSS send-push/request-response 4개 시나리오를 검증한다.

```bash
cd dart && dart run crosstest/dart_web.dart
cd go && go run ./crosstest/go_dart_web.go
cd kotlin && ./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinDartWebKt
cd python && python3 crosstest/python_dart_web.py
cd typescript && ./node_modules/.bin/tsx crosstest/typescript_dart_web.ts
```

---

## 작업 맥락

코드나 프로토콜을 변경하기 전에 [agent-ops/rules/project/rules.md](agent-ops/rules/project/rules.md)의 프로젝트 규칙과 해당 경로의 domain rule을 확인한다. 활성 로드맵 창은 [agent-roadmap/current.md](agent-roadmap/current.md)에 있다.

안정화 경계는 다음과 같다.

- 명시적인 호환성 작업 요청이 없으면 프로토콜 `0.1` 동작을 안정적으로 유지한다.
- 유지보수 모드 작업에는 bug fix, 문서 정정, 테스트 강화, 호환성을 유지하는 구현 수정이 포함될 수 있다.
- C#/Swift, package registry release, protocol/API 변경 작업은 구체적인 소비자 수요, 호환성 계획, 전체 검증 매트릭스 통과 조건이 있을 때 별도 작업으로 재개한다. 현재 릴리즈 표준은 Git ref/tag 기준이다.
- 상위 `../oto` workflow가 결정되기 전까지 이 저장소에서 외부 CI/CD runner를 직접 연결하지 않는다.
