<!-- task=14+ops_command_smoke plan=1 tag=REVIEW_E2ECMD -->

# Plan - REVIEW_E2ECMD

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

**필수: 구현 마지막에는 반드시 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 명령 출력으로 채운다.** 이 follow-up은 code review WARN에서 나온 smoke assertion hardening만 처리한다. `scripts/e2e-smoke.sh` 외 소스 변경은 필요하지 않다.

## 배경

이전 구현은 `/capabilities`, `/transport`, `/sessions`를 smoke command sequence에 추가했고 기본 mock E2E는 통과했다. 리뷰에서는 두 가지 assertion 약점을 확인했다.

- persistent real profile이 추가되면 `IS_PERSISTENT=1`이 되지만 session assertion은 `persistent:fake-cat/session2`로 고정되어 false fail 가능성이 있다.
- `/capabilities` payload marker인 `adapter = cli`는 `/transport` 출력에도 존재하여 capabilities payload 검증으로는 약하다.

## 의존 관계 및 구현 순서

- 선행 archive: `agent-task/14+ops_command_smoke/code_review_cloud_G07_0.log`, `agent-task/14+ops_command_smoke/plan_cloud_G07_0.log`
- 선행 complete: `agent-task/14_e2e_temp_workspace/complete.log`
- 이 follow-up은 `scripts/e2e-smoke.sh`의 assertion만 조정한다.

## 분석 결과

### 읽은 파일

- `scripts/e2e-smoke.sh`
- `configs/edge.yaml`
- `apps/node/internal/adapters/cli/cli.go`
- `apps/edge/internal/opsconsole/status.go`

### 리뷰 발견 사항

- `scripts/e2e-smoke.sh:80-82`는 real profile block에서 `persistent: true`를 감지해 `IS_PERSISTENT=1`로 설정할 수 있다.
- `scripts/e2e-smoke.sh:103-106`은 real profile temp console target을 `$PROFILE`로 둔다.
- `apps/node/internal/adapters/cli/cli.go:224-240`은 session list entry를 실제 target 기반 `persistent:<target>/<session>` 형식으로 만든다.
- `apps/edge/internal/opsconsole/status.go:88-100`은 result map key를 stable sorted line으로 출력하므로 `targets = <target>`은 capabilities-specific marker로 쓸 수 있다.

## 구현 체크리스트

- [ ] [REVIEW_E2ECMD-1] `scripts/e2e-smoke.sh`에서 mock/real 공통 `TARGET` 기반으로 persistent `/sessions` entry를 검증한다.
- [ ] [REVIEW_E2ECMD-2] `/capabilities` assertion을 `/transport` 출력과 겹치지 않는 command-specific marker로 강화한다.
- [ ] 중간 검증과 최종 검증 명령을 모두 실행하고 실제 stdout/stderr를 CODE_REVIEW에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_E2ECMD-1] persistent session target assertion 수정

#### 문제

현재 script는 mock branch에서 `TARGET="fake-cat"`을 설정하지만 real branch에서는 `TARGET`을 설정하지 않는다. 동시에 `IS_PERSISTENT`는 real branch에서도 true가 될 수 있고, assertion은 `persistent:fake-cat/session2`로 고정되어 있다.

Before:

```bash
if [ "$IS_PERSISTENT" -eq 1 ]; then
    check_grep "persistent:fake-cat/session2" "$EDGE_OUT" "/sessions entry for session2 not found"
fi
```

After:

```bash
# real branch also sets TARGET="$PROFILE"
if [ "$IS_PERSISTENT" -eq 1 ]; then
    check_grep "persistent:${TARGET}/session2" "$EDGE_OUT" "/sessions entry for session2 not found"
fi
```

#### 해결 방법

- real profile branch에서 `TARGET="$PROFILE"`을 설정한다.
- persistent session assertion은 하드코딩된 `fake-cat` 대신 `$TARGET`을 사용한다.
- mock config의 profile 이름으로 남는 `fake-cat` 문자열은 허용하지만 assertion hardcode는 제거한다.

#### 수정 파일 및 체크리스트

- [ ] `scripts/e2e-smoke.sh` real branch에 `TARGET="$PROFILE"` 설정
- [ ] `persistent:${TARGET}/session2` assertion 사용
- [ ] session assertion error message는 기존 의미를 유지

#### 테스트 작성

- shell smoke가 테스트다. 별도 Go unit test는 추가하지 않는다.

#### 중간 검증

```bash
bash -n scripts/e2e-smoke.sh
! rg -n "persistent:fake-cat/session2" scripts/e2e-smoke.sh
```

Expected: both commands exit 0. `rg`는 assertion hardcode를 찾지 못해야 한다.

### [REVIEW_E2ECMD-2] capabilities-specific assertion 강화

#### 문제

현재 `/capabilities` marker로 쓰는 `adapter = cli`는 `/transport` 결과에도 출력된다. `/capabilities` header는 존재하지만 payload key가 빠져도 `/transport`의 `adapter = cli` 때문에 marker assertion이 통과할 수 있다.

Before:

```bash
check_grep "\\[node-test-node-capabilities\\]" "$EDGE_OUT" "/capabilities output not found"
check_grep "adapter = cli" "$EDGE_OUT" "/capabilities adapter not found"
```

After:

```bash
check_grep "\\[node-test-node-capabilities\\]" "$EDGE_OUT" "/capabilities output not found"
check_grep "targets = ${TARGET}" "$EDGE_OUT" "/capabilities targets not found"
```

#### 해결 방법

- temp smoke config는 mock/real 모두 profile 하나만 노출하므로 capabilities result의 `targets` 값은 `$TARGET`과 일치해야 한다.
- 기존 `adapter = cli` assertion은 유지해도 되지만, capabilities-specific assertion으로 `targets = $TARGET`을 반드시 추가한다.
- grep 출력 확인 명령에도 `targets = fake-cat`을 포함해 review evidence가 새 marker를 보여주게 한다.

#### 수정 파일 및 체크리스트

- [ ] `/capabilities` assertion에 `targets = ${TARGET}` 추가 또는 기존 marker 교체
- [ ] 최종 grep evidence에 `targets = fake-cat` 포함
- [ ] `/transport`와 `/sessions` 기존 marker는 유지

#### 테스트 작성

- shell smoke 검증으로 대체한다.

#### 중간 검증

```bash
IOP_E2E_IDLE_SECONDS=2 make test-e2e > /tmp/iop-e2ecmd-smoke.log 2>&1
grep -E "\\[node-test-node-(capabilities|transport|sessions)\\]|targets = fake-cat|connected = true|sessions =" /tmp/iop-e2ecmd-smoke.log
```

Expected: command headers, `targets = fake-cat`, transport connected marker, sessions marker가 모두 출력된다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `scripts/e2e-smoke.sh` | REVIEW_E2ECMD-1, REVIEW_E2ECMD-2 |
| `agent-task/14+ops_command_smoke/CODE_REVIEW-cloud-G07.md` | evidence 기록 |

## 최종 검증

```bash
test -f agent-task/14_e2e_temp_workspace/complete.log
bash -n scripts/e2e-smoke.sh
! rg -n "persistent:fake-cat/session2" scripts/e2e-smoke.sh
IOP_E2E_IDLE_SECONDS=2 make test-e2e > /tmp/iop-e2ecmd-smoke.log 2>&1
grep -E "\\[node-test-node-(capabilities|transport|sessions)\\]|targets = fake-cat|connected = true|sessions =" /tmp/iop-e2ecmd-smoke.log
go test -count=1 ./apps/edge/internal/opsconsole ./apps/edge/internal/service ./apps/node/internal/node ./apps/node/internal/adapters/cli
git diff --check
```

Expected: all commands exit 0. The grep output must include `/capabilities` header and `targets = fake-cat`.

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