# Plan - E2ECMD ## 이 파일을 읽는 구현 에이전트에게 **필수: 구현 마지막에는 반드시 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 명령 출력으로 채운다.** 이 task는 E2E smoke가 `/capabilities`, `/sessions`, `/transport` 명령을 실제 console path로 검증하게 만드는 작업이다. 구현 체크리스트와 review stub의 구현 체크리스트를 모두 완료하고, 중간/최종 검증 출력은 실제 stdout/stderr로 남긴다. review 파일의 `이 파일을 읽는 리뷰 에이전트에게` 아카이브 지시와 `코드리뷰 전용 체크리스트`는 코드리뷰 skill 전용이므로 구현 에이전트가 실행하거나 수정하지 않는다. ## 배경 07번 이후 ops console에는 `/capabilities`, `/sessions`, `/transport`가 구현되어 있지만 `scripts/e2e-smoke.sh`는 아직 `/nodes`, prompt, session/background, terminate, optional `/status`만 실행한다. 새 command surface는 unit test가 있어도 bin-level console wiring과 output formatting이 깨질 수 있다. smoke는 실제 edge/node binary를 쓰므로 이 경로를 최소 한 번씩 통과해야 한다. ## 의존 관계 및 구현 순서 - 선행 task: `agent-task/14_e2e_temp_workspace/complete.log`가 있어야 시작한다. - 이유: 두 task 모두 `scripts/e2e-smoke.sh`를 수정하며, 이 task의 final smoke는 root `iop.db` 격리 fix 위에서 실행되어야 한다. - `agent-task/13_transport_idle_heartbeat`, `agent-task/15_node_command_docs_accuracy`와는 독립이다. ## 분석 결과 ### 읽은 파일 - `scripts/e2e-smoke.sh` - `apps/edge/internal/opsconsole/console.go` - `apps/edge/internal/opsconsole/status.go` - `apps/edge/internal/opsconsole/console_test.go` - `apps/edge/internal/opsconsole/events_test.go` - `apps/edge/internal/service/service.go` - `apps/edge/internal/service/service_test.go` - `apps/node/internal/node/node.go` - `apps/node/internal/adapters/cli/cli.go` ### 테스트 커버리지 공백 - `/capabilities` real console smoke: unit tests cover formatting/service path, but script does not send command. 공백 있음. - `/sessions` real console smoke: unit tests cover command handling, but script does not verify output from real persistent CLI session map. 공백 있음. - `/transport` real console smoke: unit tests cover node command response, but bin-level command path is not in smoke. 공백 있음. ### 심볼 참조 - renamed/removed symbol 없음. - 새 shell assertion helper가 필요하면 call site는 `scripts/e2e-smoke.sh` 내부로 제한한다. ### 범위 결정 근거 - ops console command implementation은 이미 존재하므로 Go service/node logic은 변경하지 않는다. - output format은 `apps/edge/internal/opsconsole/status.go:88-101`의 stable sorted map rendering을 기준으로 검증한다. - `/status` real CLI behavior와 heartbeat idle 문제는 이 task 범위가 아니다. ### 빌드 등급 - Build `cloud-G07`: shell/bin orchestration, stdout parsing, real console command smoke가 포함된다. - Review `cloud-G07`: E2E output assertions가 실제 command 결과를 잡는지 재실행 확인이 필요하다. ## 구현 체크리스트 - [ ] [E2ECMD-1] `scripts/e2e-smoke.sh` command sequence에 `/capabilities`, `/transport`, `/sessions`를 추가한다. - [ ] [E2ECMD-2] smoke assertions에 세 command의 stable output marker를 추가한다. - [ ] 중간 검증과 최종 검증 명령을 모두 실행하고 실제 stdout/stderr를 CODE_REVIEW에 기록한다. - [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. ### [E2ECMD-1] ops console command sequence 확장 #### 문제 `scripts/e2e-smoke.sh:148-162`는 node 등록 후 `/nodes`, prompt, session/background, terminate, optional `/status`만 보낸다. `/capabilities`, `/sessions`, `/transport`는 `apps/edge/internal/opsconsole/console.go:64` help text와 switch cases `console.go:118-129`에 존재하지만 smoke에서 실행되지 않는다. Before: ```bash # scripts/e2e-smoke.sh:148 sleep 3 send_cmd "/nodes" send_cmd "$STRICT_PROMPT" send_cmd "/session session2" send_cmd "/background on" send_cmd "Reply with exactly 'OK' again." send_cmd "/background off" ``` After: ```bash sleep 3 send_cmd "/nodes" send_cmd "/capabilities" send_cmd "/transport" send_cmd "$STRICT_PROMPT" send_cmd "/session session2" send_cmd "/background on" send_cmd "Reply with exactly 'OK' again." send_cmd "/background off" send_cmd "/sessions" ``` #### 해결 방법 - `/capabilities`와 `/transport`는 첫 prompt 전에 실행해 node command path를 먼저 확인한다. - `/sessions`는 `session2` background run 이후, terminate 전 실행한다. persistent mock에서는 `session2`가 session list에 나타나야 한다. - real profile에서도 temp config가 profile 하나만 노출하므로 `/capabilities` target list는 `$TARGET` 기준으로 검증 가능하다. #### 수정 파일 및 체크리스트 - [ ] `scripts/e2e-smoke.sh` command sequence 수정 - [ ] `/sessions`가 persistent terminate보다 먼저 실행되도록 유지 - [ ] optional `/status` 순서는 기존처럼 마지막에 유지 #### 테스트 작성 - shell smoke가 test다. 별도 Go unit test는 추가하지 않는다. #### 중간 검증 ```bash bash -n scripts/e2e-smoke.sh IOP_E2E_IDLE_SECONDS=2 make test-e2e ``` Expected: mock smoke PASS, output에 `[node-test-node-capabilities]`, `[node-test-node-transport]`, `[node-test-node-sessions]`가 있다. ### [E2ECMD-2] stable output assertion 추가 #### 문제 `scripts/e2e-smoke.sh:222-227`의 current assertions는 command-specific output을 확인하지 않는다. `apps/edge/internal/opsconsole/status.go:88-101`는 command result를 `[node-{label}-{command}]` header와 sorted `key = value` lines로 출력하므로 deterministic assertion이 가능하다. Before: ```bash check_grep "test-node" "$EDGE_OUT" "node registration not found" check_grep "start run_id=" "$EDGE_OUT" "run start not found" check_grep "complete run_id=" "$EDGE_OUT" "run completion not found" ``` After: ```bash check_grep "\\[node-test-node-capabilities\\]" "$EDGE_OUT" "/capabilities output not found" check_grep "adapter = cli" "$EDGE_OUT" "/capabilities adapter not found" check_grep "\\[node-test-node-transport\\]" "$EDGE_OUT" "/transport output not found" check_grep "connected = true" "$EDGE_OUT" "/transport connected status not found" check_grep "\\[node-test-node-sessions\\]" "$EDGE_OUT" "/sessions output not found" ``` #### 해결 방법 - `grep` basic regex escaping에 맞게 `[`와 `]`를 escape한다. - `targets = $TARGET` assertion은 real profile target과 mock target 모두에서 안정적이면 추가한다. profile block이 target 하나만 포함되므로 추가 가능해야 한다. - `/sessions`는 non-persistent profile에서 count 0일 수 있으므로 header 존재는 필수, specific session entry는 persistent mock에서만 조건부로 검증한다. #### 수정 파일 및 체크리스트 - [ ] `scripts/e2e-smoke.sh`에 capabilities header/assertion 추가 - [ ] `scripts/e2e-smoke.sh`에 transport header/assertion 추가 - [ ] `scripts/e2e-smoke.sh`에 sessions header/assertion 추가 - [ ] persistent mock이면 `persistent:fake-cat/session2` 또는 equivalent session entry를 검증 #### 테스트 작성 - shell smoke 검증으로 대체한다. `apps/edge/internal/opsconsole/status.go` sorted formatting은 기존 Go tests가 다룬다. #### 중간 검증 ```bash IOP_E2E_IDLE_SECONDS=2 make test-e2e > /tmp/iop-e2ecmd-smoke.log 2>&1 grep -E "\\[node-test-node-(capabilities|transport|sessions)\\]|adapter = cli|connected = true|sessions =" /tmp/iop-e2ecmd-smoke.log ``` Expected: command headers and key outputs are printed. smoke exits 0. ## 수정 파일 요약 | 파일 | 항목 | |------|------| | `scripts/e2e-smoke.sh` | E2ECMD-1, 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 IOP_E2E_IDLE_SECONDS=2 make test-e2e > /tmp/iop-e2ecmd-smoke.log 2>&1 grep -E "\\[node-test-node-(capabilities|transport|sessions)\\]|adapter = cli|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. Go test cache output은 `-count=1` 때문에 허용하지 않는다. The grep output must include all three node command headers. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.