<!-- task=04+03_a2a_agent_surface plan=1 tag=A2A-review-fix -->

# IOP Edge Input Surface A2A Review Fix Plan

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

이 계획은 `code_review_cloud_G08_0.log`의 FAIL 판정을 해소하기 위한 후속 계획이다. 기존 구현 범위를 넓히지 말고 Required 항목을 먼저 고친 뒤, Suggested 항목은 낮은 위험으로 함께 처리할 수 있을 때만 반영한다.

구현 완료 전 `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다. 리뷰 에이전트 전용 체크리스트는 수정하지 않는다.

## 리뷰 결과 요약

`code_review_cloud_G08_0.log` 판정은 FAIL이다.

Required:

1. `message/send`의 `blocking=false` 경로에서 내부 `*Task` 포인터가 response encoder와 background reducer 사이에 공유되어 data race가 가능하다.
2. `configuration.blocking` omitted 값이 `true` 기본값으로 처리되어야 하지만, non-nil empty configuration 객체에서는 `false`가 된다.

Suggested:

1. `configs/edge.yaml`에 disabled `a2a` 예시를 추가한다.
2. `Service.CancelRun` 테스트가 실제 proto 전송 payload를 검증하도록 보강한다.

## 구현 체크리스트

- [ ] [FIX-1] A2A non-blocking 응답이 store 내부 포인터를 노출하지 않고 안정적인 snapshot을 반환하도록 수정한다.
- [ ] [FIX-2] `configuration.blocking` omitted 값과 explicit false를 구분해 기본값을 계획대로 `true`로 맞춘다.
- [ ] [FIX-3] A2A config 예시와 cancel 전송 테스트를 보강한다.
- [ ] [FIX-4] 대상 테스트, 전체 테스트, A2A race 테스트, bin smoke 검증을 재실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 수정 방향

### [FIX-1] non-blocking Task snapshot 분리

`TaskStore.create`가 내부 map에 저장한 포인터를 그대로 외부 응답에 사용하지 않게 한다. 선택지는 둘 중 하나다.

- `create`는 내부 저장만 수행하고, 응답에는 `get(id)`의 snapshot을 사용한다.
- 또는 `create`가 저장용 포인터와 응답용 deep copy를 분리해 반환한다.

`TaskStore.get`도 `Artifacts.Parts`, `History.Parts`, `Status.Message`까지 필요한 만큼 deep copy해 future caller가 snapshot을 수정해도 내부 상태가 변하지 않게 한다. `blocking=false`이고 handle이 즉시 `delta/complete`를 내보내는 테스트를 추가해 `message/send` 응답은 `working` 또는 적어도 race-free snapshot임을 확인한다. 가능하면 `go test -race ./apps/edge/internal/input/a2a`가 이 경로를 자극하도록 테스트를 구성한다.

### [FIX-2] blocking 기본값 보정

`SendConfig.Blocking`을 `*bool`로 바꾸거나, JSON raw params에서 field presence를 확인하는 작은 helper를 둔다.

기대 동작:

- `configuration` 없음: blocking `true`
- `configuration: {}`: blocking `true`
- `configuration: {"blocking": true}`: blocking `true`
- `configuration: {"blocking": false}`: blocking `false`

위 네 경우를 `server_test.go`에 명시한다.

### [FIX-3] config/test 보강

`configs/edge.yaml`에 `a2a.enabled: false` 예시를 추가한다. 기본 포트/경로/adapter/session/timeout을 보여주되 실제 운영 토큰은 빈 값으로 둔다.

`Service.CancelRun` 테스트는 현재 struct 필드 확인 대신 실제 전송되는 `iop.CancelRequest`의 `RunId`, `Adapter`, `Target`, normalized `SessionId`, `CANCEL_ACTION_CANCEL_RUN`을 검증한다. 기존 fake client/transport helper를 재사용하고 새 production abstraction은 피한다.

## 검증 계획

```bash
go test -count=1 ./packages/config ./apps/edge/internal/input ./apps/edge/internal/input/a2a ./apps/edge/internal/bootstrap ./apps/edge/internal/service
go test -race -count=1 ./apps/edge/internal/input/a2a
go test -count=1 ./...
scripts/e2e-smoke.sh
```

검증 결과에는 `scripts/e2e-smoke.sh`가 보조 smoke임을 명시한다. 직접 bin shell 사용자 흐름이나 full-cycle/real CLI profile을 수행하지 못하면 사유와 남은 위험을 기록한다.
