# Plan - API ## 이 파일을 읽는 구현 에이전트에게 구현이 끝나면 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 검증을 실행하고, active 파일은 그대로 둔 채 리뷰 준비를 보고한다. 최종 판정, log rename, `complete.log` 작성, task archive 이동은 code-review 전용이다. 사용자만 결정할 수 있는 외부 환경, secret, 범위 충돌로 막히면 리뷰 stub의 `사용자 리뷰 요청`에 정확한 증거와 재개 조건을 남기고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. ## 배경 ADB runtime resolution과 AppSok 전용 server port는 서비스 레벨에 들어갔다. 사용자가 실제로 어떤 ADB를 쓰는지, bundle fallback이 발생했는지, server port가 무엇인지 볼 수 있는 진단 표시는 아직 없다. 이 작업은 bundle 작업이 PASS된 뒤 실행 경로, version, hash, server port, fallback 여부를 settings/device surface에 노출한다. ## 사용자 리뷰 요청 흐름 구현 중 차단 사유는 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 요청 타당성과 `USER_REVIEW.md` 작성 여부를 판단한다. ## Roadmap Targets - Milestone: `agent-roadmap/phase/usable-mvp/milestones/usb-install.md` - Task ids: - `adb-diagnostics`: ADB 실행 경로, bundled version, runtime hash, server port, fallback 여부를 진단 정보로 표시한다. - Completion mode: check-on-pass ## 분석 결과 ### 읽은 파일 - `agent-roadmap/current.md` - `agent-roadmap/phase/usable-mvp/PHASE.md` - `agent-roadmap/phase/usable-mvp/milestones/usb-install.md` - `agent-ops/rules/project/domain/device-console/rules.md` - `agent-ops/rules/project/domain/macos-platform/rules.md` - `agent-test/local/rules.md` - `agent-test/local/device-console-smoke.md` - `agent-test/local/macos-platform-smoke.md` - `agent-test/local/macos-remote-build-smoke.md` - `lib/src/services/adb_service.dart` - `lib/src/features/settings/settings_page.dart` - `lib/src/features/app_shell.dart` - `test/adb_service_test.dart` - `test/widget_test.dart` - `pubspec.yaml` - `macos/Runner.xcodeproj/project.pbxproj` - `macos/Runner/DebugProfile.entitlements` - `macos/Runner/Release.entitlements` ### 테스트 환경 규칙 - test_env: `local` - env rules: `agent-test/local/rules.md` present and read. 기본 완료 evidence는 standard remote Mac runner `toki@toki-labs.com` checkout `$HOME/docker/services/code-server/data/volume/workspace/appsok`. - matched profiles: - `agent-test/local/device-console-smoke.md`: `flutter analyze`, `flutter test`; ADB runtime evidence는 remote runner 기준. - `agent-test/local/macos-platform-smoke.md`: macOS bundle/runtime 관련 확인이 남아 있으면 remote `flutter build macos`. - `agent-test/local/macos-remote-build-smoke.md`: predecessor bundle evidence를 신뢰하려면 remote checkout/build 상태를 확인. - 적용 명령: - `flutter analyze` - `flutter test` - `flutter test test/adb_service_test.dart` - `flutter test test/widget_test.dart` - remote runner: `zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze'` - remote runner: `zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter test'` - `<확인 필요>` 값 없음. Hash 구현에 새 dependency가 필요하면 `pubspec.yaml`에 명시하고 `flutter pub get` 결과를 기록한다. ### 테스트 커버리지 공백 - Runtime path/source/server port: `test/adb_service_test.dart`가 service-level behavior를 커버한다. - Runtime version/hash collection: 테스트 없음. 새 unit test가 필요하다. - Settings or status UI diagnostics display: 현재 `test/widget_test.dart`는 `ADB 대기` placeholder만 확인한다. 새 widget test가 필요하다. - Real bundled version/hash: predecessor `01_adb_bundle`의 remote evidence와 이 작업의 service test를 함께 본다. ### 심볼 참조 - Renamed/removed symbols: none expected. - Existing ADB UI references: - `lib/src/features/settings/settings_page.dart:85-103`: ADB section has only path field/search placeholder. - `lib/src/features/app_shell.dart:313-316`: top status pill is fixed `ADB 대기`. - `test/widget_test.dart:780-782`: status placeholder assertions. ### 분할 판단 - split decision policy evaluated. - Shared task group: `agent-task/m-usb-install/` - This plan directory is `02+01_adb_diagnostics`, so predecessor index `01` is required. - Required predecessor: `agent-task/m-usb-install/01_adb_bundle/complete.log` or matching archived `agent-task/archive/*/*/m-usb-install/01_adb_bundle/complete.log`. - Current state: predecessor `complete.log` missing. Do not implement until predecessor is PASS-complete. - Split is required because diagnostics should report the final bundle path/version/hash from the packaged runtime, not a speculative path. ### 범위 결정 근거 - Include: diagnostics data model/service method, version command, runtime hash, fallback/source/server port display, focused tests. - Exclude: actual bundle copy, nested binary signing, device list from live ADB, logcat console, custom adb picker persistence. - Keep UI restrained: settings page or ADB status area should show compact technical diagnostics, not a landing or explanatory page. ### 빌드 등급 - `local-G06`: bounded service/UI/test work after bundle predecessor completes; process and hash behavior need explicit tests but do not require broad architecture changes. ## 구현 체크리스트 - [ ] `01_adb_bundle` predecessor `complete.log`가 active 또는 archive 경로에 있는지 확인한다. - [ ] ADB diagnostics model/service method를 추가해 executable path, source, version, runtime hash, server port, fallback 여부를 수집한다. - [ ] settings 또는 shell ADB surface에 diagnostics를 표시하고 compact viewport overflow가 없도록 한다. - [ ] version/hash collection unit test와 diagnostics UI widget test를 추가한다. - [ ] `flutter analyze`, `flutter test`, `flutter test test/adb_service_test.dart`, `flutter test test/widget_test.dart`를 실행한다. - [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. ## 의존 관계 및 구현 순서 `02+01_adb_diagnostics`는 directory name 기준으로 `01_adb_bundle`에 의존한다. 구현 시작 전 다음 중 하나를 확인한다. - active: `agent-task/m-usb-install/01_adb_bundle/complete.log` - archive: `agent-task/archive/*/*/m-usb-install/01_adb_bundle/complete.log` 둘 다 없으면 구현하지 말고 review stub의 `사용자 리뷰 요청`이 아니라 계획 대비 변경 사항에 "predecessor incomplete"를 기록하고 멈춘다. ### [API-1] Collect ADB Runtime Diagnostics #### 문제 - `lib/src/services/adb_service.dart:231-250` has path/source/server port/fallback fields but no version/hash diagnostics. - `pubspec.yaml` currently has no hash helper dependency, so runtime hash needs either a new package or a deterministic implementation. #### 해결 방법 Before: ```dart // lib/src/services/adb_service.dart:231 class AdbRuntime { const AdbRuntime({ required this.executablePath, required this.source, required this.serverPort, ``` After: ```dart class AdbRuntimeDiagnostics { const AdbRuntimeDiagnostics({ required this.runtime, required this.version, required this.sha256, required this.versionError, }); } ``` - Add `AdbRuntimeDiagnostics` and `AdbService.collectDiagnostics()`. - Run `adb version` through the resolved executable and same `ADB_SERVER_PORT` environment. - Compute SHA-256 of the resolved executable. If adding `package:crypto`, update `pubspec.yaml` and `pubspec.lock` intentionally; otherwise keep implementation small and tested. - Redact nothing except avoid logging private paths outside diagnostics UI/task logs if a user-owned custom path contains sensitive account names. #### 수정 파일 및 체크리스트 - [ ] `lib/src/services/adb_service.dart`: add diagnostics model and collection method. - [ ] `test/adb_service_test.dart`: add version/hash/failure tests. - [ ] `pubspec.yaml`, `pubspec.lock`: update only if using a hash dependency. #### 테스트 작성 - Add unit tests in `test/adb_service_test.dart`: - successful `adb version` is captured. - hash is stable for a temp executable file. - non-zero `adb version` records error without throwing if UI should still show path/source. #### 중간 검증 ```bash flutter test test/adb_service_test.dart ``` Expected: all ADB service tests pass. ### [API-2] Display Diagnostics #### 문제 - `lib/src/features/settings/settings_page.dart:85-103` shows an ADB path text field and search button, but no resolved path, source, version, hash, server port, or fallback state. - `lib/src/features/app_shell.dart:313-316` shows fixed `ADB 대기`, so users cannot see fallback/system mode. - `test/widget_test.dart:780-782` asserts only the placeholder label. #### 해결 방법 Before: ```dart // lib/src/features/settings/settings_page.dart:85 Text('ADB', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 14), Row( children: [ Expanded( child: TextField( ``` After: ```dart SettingsPage( adbDiagnosticsLoader: () => AdbService().collectDiagnostics(), ) ``` - Inject a diagnostics loader with a deterministic test fake. - Show compact rows for executable source/path, version, SHA-256 short prefix, server port, fallback state. - Keep controls stable at compact viewport; use ellipsis for paths/hash. - If diagnostics collection fails, show a concise failure state while preserving path/source if available. #### 수정 파일 및 체크리스트 - [ ] `lib/src/features/settings/settings_page.dart`: add diagnostics loader and display. - [ ] `lib/src/features/app_shell.dart`: pass diagnostics loader or ADB summary if needed. - [ ] `test/widget_test.dart`: add diagnostics display and compact viewport coverage. #### 테스트 작성 - Add widget tests in `test/widget_test.dart`: - settings page renders source/path/version/hash/port/fallback from fake diagnostics. - compact viewport has no Flutter overflow exception. - existing `ADB 대기` assertion is updated only if the top status label intentionally changes. #### 중간 검증 ```bash flutter test test/widget_test.dart ``` Expected: widget tests pass without overflow exceptions. ## 수정 파일 요약 | 파일 | 항목 | |------|------| | `lib/src/services/adb_service.dart` | API-1 | | `test/adb_service_test.dart` | API-1 | | `pubspec.yaml` | API-1, only if hash dependency is added | | `pubspec.lock` | API-1, only if hash dependency is added | | `lib/src/features/settings/settings_page.dart` | API-2 | | `lib/src/features/app_shell.dart` | API-2, only if shell summary changes | | `test/widget_test.dart` | API-2 | ## 최종 검증 ```bash flutter analyze flutter test flutter test test/adb_service_test.dart flutter test test/widget_test.dart ``` 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.