<!-- task=m-install-session-history/02+01_current_result_ui plan=0 tag=REFACTOR -->

# Plan - REFACTOR

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

이 작업은 구현 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채워야 완료된다. 검증을 실행하고 실제 출력과 구현 메모를 남긴 뒤 active 파일을 유지한 채 리뷰 준비 상태로 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope conflict 없이는 사용자에게 직접 묻지 말고, 차단 시 review stub의 `사용자 리뷰 요청`에 증거를 남긴다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다.

## 배경

Milestone은 최근 설치 목록을 만들지 않고 현재 설치 결과와 실패 요약만 보여주기로 축소되었다. `01_install_result_model`이 현재 설치 결과 모델을 제공하면 DevicesPage 결과 배너는 artifact/build/device 맥락을 함께 보여줄 수 있다.

## 사용자 리뷰 요청 흐름

구현 중 사용자만 결정할 수 있는 차단이 생기면 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션을 채우고 멈춘다. 구현 에이전트는 chat에서 직접 질문하거나 `request_user_input`을 호출하지 않는다. code-review가 차단 타당성을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/workflow-integration/milestones/install-session-history.md`
- Task ids:
  - `recent-list`: 최근 설치 목록 대신 현재 설치 결과와 실패 요약을 표시한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/workflow-integration/milestones/install-session-history.md`
- `agent-ops/rules/project/domain/app-shell/rules.md`
- `agent-ops/rules/project/domain/artifact-flow/rules.md`
- `agent-ops/rules/project/domain/device-console/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/app-shell-smoke.md`
- `agent-test/local/artifact-flow-smoke.md`
- `agent-test/local/device-console-smoke.md`
- `lib/src/features/app_shell.dart`
- `lib/src/features/devices/devices_page.dart`
- `lib/src/models/pending_install.dart`
- `lib/src/models/adb_device.dart`
- `lib/src/services/adb_service.dart`
- `test/widget_test.dart`
- `analysis_options.yaml`

### 테스트 환경 규칙

`test_env=local`을 적용한다. app-shell/device-console smoke 기준으로 remote runner `flutter analyze`와 `flutter test`가 완료 evidence다. 현재 checkout에서는 `git diff --check`와 `flutter test test/widget_test.dart`를 focused preflight로 사용한다.

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

- 현재 결과 UI: 기존 테스트는 success/failure output 표시만 확인하고, build number, job, artifact 표시 여부는 확인하지 않는다. widget regression 추가 필요.
- serial masking: `history` Epic 범위에서는 model 중심 표시만 다루고, copy report masking은 `report` Epic에서 별도 검증한다.

### 심볼 참조

- 전제 변경: `InstallAttemptResult` 모델과 `DevicesPage.lastInstallAttempt`는 `01_install_result_model` PASS 후 존재해야 한다.
- UI 참조: `_InstallResultBanner`는 [devices_page.dart](/config/workspace/appsok/lib/src/features/devices/devices_page.dart:600)에 있다. 관련 widget keys는 `install-result-banner`, `install-result-label`, `install-result-output`이다.

### 분할 판단

Split 정책을 먼저 평가했다. 이 task group은 `agent-task/m-install-session-history/`이고, 이 subtask는 `02+01_current_result_ui`로 `01_install_result_model`에 의존한다. 구현 전 `agent-task/m-install-session-history/01_install_result_model/complete.log` 또는 matching archive `complete.log`가 있어야 한다. 현재 작성 시점에는 predecessor가 아직 active plan 상태라 missing으로 기록한다.

### 범위 결정 근거

이 작업은 DevicesPage의 현재 결과 표시만 다룬다. clipboard 복사, 오류 메시지 masking, logcat 출력 축약은 `report` Epic 범위로 제외한다. 저장된 최근 세션 목록, 보관 기간, 삭제 버튼, 저장된 세션 재실행은 이번 MVP에서 제외되어 구현하지 않는다.

### 빌드 등급

`local-G04`: UI 표시와 widget regression 중심이며, predecessor completion이 있으면 bounded change다.

## 의존 관계 및 구현 순서

`02+01_current_result_ui`는 같은 task group의 `01_install_result_model` 완료 후 시작한다. 구현 전 `agent-task/m-install-session-history/01_install_result_model/complete.log` 또는 `agent-task/archive/*/*/m-install-session-history/01_install_result_model/complete.log`를 확인한다.

## 구현 체크리스트

- [ ] `01_install_result_model` predecessor `complete.log`를 확인한다.
- [ ] `_InstallResultBanner`가 `InstallAttemptResult`를 받아 artifact file name, build number, job name, device display name, result summary를 표시하게 한다.
- [ ] 실패 결과에서 stdout/stderr 전체 dump 대신 현재 배너에 들어갈 짧은 실패 요약을 유지하되, 원문 저장이나 logcat 저장을 추가하지 않는다.
- [ ] `test/widget_test.dart`에 현재 설치 결과 배너가 build/artifact/device/result 맥락을 표시하는 regression을 추가한다.
- [ ] `git diff --check`, `flutter analyze`, `flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] 현재 설치 결과 배너 확장

#### 문제

[devices_page.dart](/config/workspace/appsok/lib/src/features/devices/devices_page.dart:637)의 결과 label은 device와 exit code만 보여준다. 현재 Milestone 범위에는 현재 선택된 Jenkins job/build/artifact와 device 표시 정보가 포함되어 있으나, 최근 설치 목록을 만들지 않는 대신 현재 배너가 그 맥락을 담아야 한다.

#### 해결 방법

Before [devices_page.dart](/config/workspace/appsok/lib/src/features/devices/devices_page.dart:637):

```dart
Text(
  key: const ValueKey('install-result-label'),
  isSuccess
      ? '${device.displayName}에 설치 성공'
      : '${device.displayName}에 설치 실패 (exit ${result.exitCode})',
```

After:

```dart
Text(
  key: const ValueKey('install-result-label'),
  isSuccess
      ? '${attempt.device.displayName} 설치 성공'
      : '${attempt.device.displayName} 설치 실패 (exit ${attempt.result.exitCode})',
```

배너 하위 metadata 줄에 `#7 · android-app · app-release.apk` 형식의 `attempt.pendingInstall` 정보를 표시한다. output 줄은 현재 실행 stdout/stderr만 보여주고 저장하지 않는다. serial 원문을 새로 표시하지 않는다.

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

- [ ] `lib/src/features/devices/devices_page.dart` 결과 배너 입력과 metadata UI 변경
- [ ] `test/widget_test.dart` regression 추가

#### 테스트 작성

`test/widget_test.dart`의 실패/성공 설치 결과 테스트 중 하나에 build number/job/artifact 표시 assertion을 추가하거나 새 test를 만든다. 실패 결과에서 저장된 최근 목록이 아니라 현재 결과 배너만 나타난다는 점을 key와 text로 확인한다.

#### 중간 검증

```bash
flutter test test/widget_test.dart
```

기대 결과: widget test 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/src/features/devices/devices_page.dart` | REFACTOR-1 |
| `test/widget_test.dart` | REFACTOR-1 |

## 최종 검증

```bash
git diff --check
flutter analyze
flutter test
```

remote runner 완료 evidence가 필요하면 아래 명령을 같은 순서로 실행한다.

```bash
ssh toki@toki-labs.com
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze'
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter test'
```

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