<!-- task=m-performance-hotspot-optimization/10_dart_isolate_gateway_contract plan=0 tag=REFACTOR -->

# Plan - REFACTOR

## 이 파일을 읽는 구현 에이전트에게

`CODE_REVIEW-cloud-G08.md` 작성까지가 구현 완료다. 구현 중 사용자 결정이 필요하면 review stub의 `사용자 리뷰 요청`에 근거를 남기고 멈춘다. 직접 사용자에게 묻거나 review/archive/complete 절차를 실행하지 않는다.

## 배경

`IsolateInboundGateway`는 long-running isolate와 seq reorder는 갖췄지만 `SendPort.send()` 무제한 mailbox, decode error reorder hang, cleanup evidence 공백이 남아 있다. 실제 transport 연결 전 gateway contract를 먼저 hardening해야 이후 TCP/WS 단일 수신 경로가 안정된다.

## 사용자 리뷰 요청 흐름

사용자만 결정할 항목은 active `CODE_REVIEW-cloud-G08.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 검증 재실행으로 해소 가능한 증거 공백은 user-review가 아니다.

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/performance-hotspot-optimization.md`
- Task ids:
  - `dart-isolate-backpressure`: bounded backpressure와 backlog 계측
  - `dart-isolate-error-ordering`: decode error ordered result와 disconnect semantics
  - `dart-isolate-cleanup`: lifecycle cleanup hard gate
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- 공통/로드맵/plan/test 규칙 파일 일체
- `agent-roadmap/milestones/performance-hotspot-optimization.md`
- `agent-ops/rules/project/domain/dart/rules.md`
- `agent-test/local/dart-smoke.md`
- `agent-test/local/proto-socket-performance-baseline.md`
- `dart/lib/src/inbound_gateway.dart`
- `dart/lib/src/inbound_gateway_io.dart`
- `dart/lib/src/inbound_gateway_web.dart`
- `dart/lib/src/communicator.dart`
- `dart/lib/src/base_client.dart`
- `dart/test/communicator_test.dart`
- `dart/bench/stress.dart`
- `../dart-app-core/lib/platform/isolate_manager.dart`
- `../dart-app-core/lib/data/isolate_data.dart`

### 테스트 환경 규칙

`test_env=local`. Dart 구현 변경은 `dart-smoke` 필수 명령을 따른다. 성능/backlog row가 필요하므로 `proto-socket-performance-baseline`의 `run_performance.sh --quick`과 focused `run_stress.sh --quick --lang dart --transport tcp,ws --profile payload`를 사용한다.

### 테스트 커버리지 공백

- backpressure: 현재 `Communicator.onReceivedData` inbound queue capacity test는 있으나 gateway mailbox capacity test는 없다.
- error ordering: malformed frame이 isolate worker에서 exception을 던질 때 ordered result를 내는 테스트가 없다.
- cleanup: `communicator.close()` 후 gateway close는 있으나 repeated start/submit/close residual backlog 계측이 없다.

### 심볼 참조

변경 후보: `InboundGateway.submit`(`dart/lib/src/inbound_gateway.dart:53-55`), `DecodedFrame`(`:22-35`), `FrameReorderBuffer`(`:66-83`), `Communicator.onReceivedFrame`(`dart/lib/src/communicator.dart:262-273`), `IsolateInboundGateway.submit`(`dart/lib/src/inbound_gateway_io.dart:65-69`), `SyncInboundGateway.submit`(`dart/lib/src/inbound_gateway.dart:104-118`).

### 분할 판단

공유 task group은 `m-performance-hotspot-optimization`이다. 이 plan은 independent `10_dart_isolate_gateway_contract`다. 실제 transport 연결은 `11+10`, large payload transfer는 `12+10,11`로 나눈다. contract가 먼저 PASS되어야 transport path가 무제한 mailbox/error hang을 제품 경로로 확산하지 않는다.

### 범위 결정 근거

이 plan은 gateway interface와 unit tests만 다룬다. `ProtobufClient`/`WsProtobufClient` 기본 수신 경로 연결은 제외하고 `11+10`에서 처리한다. `TransferableTypedData` 최적화와 performance row 반영은 `12+10,11`에서 처리한다.

### 빌드 등급

`cloud-G08`. concurrency contract, isolate lifecycle, ordered error semantics가 hard-to-review failure mode다.

## 구현 체크리스트

- [ ] `InboundGateway.submit`을 bounded acceptance/backpressure가 가능한 async contract로 바꾸고 current call sites를 갱신한다.
- [ ] gateway result model이 decoded frame과 ordered decode error를 같은 seq stream으로 표현하게 한다.
- [ ] `FrameReorderBuffer`에 pending count/clear 또는 snapshot을 추가해 cleanup/backlog evidence를 만들 수 있게 한다.
- [ ] IO/Web gateway가 close 후 pending submit/result stream/reorder state를 남기지 않게 한다.
- [ ] backpressure, ordered error, repeated cleanup tests를 `dart/test/communicator_test.dart`에 추가한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Async submit and bounded backlog

문제: `InboundGateway.submit`은 fire-and-forget void이고(`dart/lib/src/inbound_gateway.dart:53-55`), IO gateway는 `_toWorker?.send([frame.seq, frame.bytes])`로 readiness/backlog 없이 보낸다(`dart/lib/src/inbound_gateway_io.dart:65-69`). `_toWorker`가 아직 null이면 frame이 조용히 drop될 수 있다.

해결 방법:

```dart
// Before
void submit(InboundFrame frame);
```

```dart
// After sketch
Future<void> submit(InboundFrame frame);
int get queuedCount;
int get inFlightCount;
```

ready completer가 끝나기 전 submit은 await하고, capacity 초과 시 earlier result가 release될 때까지 대기한다.

수정 파일 및 체크리스트:
- [ ] `dart/lib/src/inbound_gateway.dart`
- [ ] `dart/lib/src/inbound_gateway_io.dart`
- [ ] `dart/lib/src/inbound_gateway_web.dart`
- [ ] `dart/lib/src/communicator.dart`

테스트 작성: `IsolateInboundGateway submit waits for ready and preserves all frames under capacity pressure` 추가.

중간 검증:

```bash
cd dart && dart test test/communicator_test.dart -r expanded
```

### [REFACTOR-2] Ordered decode error result

문제: `_gatewayEntry`에서 `PacketBase.fromBuffer(bytes)`가 예외를 던지면 worker listener가 error를 stream으로 돌려주지 않는다(`dart/lib/src/inbound_gateway_io.dart:96-106`). seq gap이 생기면 reorder buffer가 이후 frame을 영구 대기시킬 수 있다.

해결 방법: decoded success/error를 같은 seq result로 만들고, `Communicator.onReceivedFrame` 또는 gateway subscription이 error result를 transport close + pending cleanup으로 연결한다. malformed frame 뒤 정상 frame이 reorder buffer에 영구 잔류하지 않도록 error도 release 대상이 되어야 한다.

수정 파일 및 체크리스트:
- [ ] `dart/lib/src/inbound_gateway.dart`: result model
- [ ] `dart/lib/src/inbound_gateway_io.dart`: try/catch result emit
- [ ] `dart/lib/src/communicator.dart`: ordered error handling
- [ ] `dart/test/communicator_test.dart`: malformed frame test

테스트 작성: malformed `PacketBase` bytes가 isolate를 죽이지 않고 connection close/pending cleanup으로 이어지는 테스트를 추가한다.

중간 검증:

```bash
cd dart && dart test test/communicator_test.dart -r expanded
```

### [REFACTOR-3] Cleanup snapshot

문제: `FrameReorderBuffer`는 pending count/clear가 없고(`dart/lib/src/inbound_gateway.dart:66-83`), IO gateway close는 isolate/ReceivePort/controller만 닫는다(`dart/lib/src/inbound_gateway_io.dart:71-80`). cleanup hard gate를 증명할 계측이 없다.

해결 방법: reorder pending count, queued/in-flight count, closed state snapshot을 추가하고 close 후 모두 0인지 테스트한다. repeated start/submit/close loop에서 residual backlog 0을 검증한다.

수정 파일 및 체크리스트:
- [ ] `dart/lib/src/inbound_gateway.dart`
- [ ] `dart/lib/src/inbound_gateway_io.dart`
- [ ] `dart/test/communicator_test.dart`

테스트 작성: repeated 20회 gateway start/submit/close residual counts 0 테스트를 추가한다.

중간 검증:

```bash
cd dart && dart test test/communicator_test.dart -r expanded
```

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `dart/lib/src/inbound_gateway.dart` | REFACTOR-1, REFACTOR-2, REFACTOR-3 |
| `dart/lib/src/inbound_gateway_io.dart` | REFACTOR-1, REFACTOR-2, REFACTOR-3 |
| `dart/lib/src/inbound_gateway_web.dart` | REFACTOR-1 |
| `dart/lib/src/communicator.dart` | REFACTOR-1, REFACTOR-2 |
| `dart/test/communicator_test.dart` | REFACTOR-1, REFACTOR-2, REFACTOR-3 |

## 최종 검증

```bash
cd dart && dart test test/communicator_test.dart -r expanded
cd dart && dart test test/socket_test.dart -r expanded
cd dart && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js
```

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
