385 lines
20 KiB
Markdown
385 lines
20 KiB
Markdown
# 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를 직접 연결하지 않는다.
|