appsok/agent-task/m-logcat-console/02+01_console_stream/PLAN-local-G06.md

9.8 KiB

LOGCAT_STREAM 계획

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

CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채우는 것은 필수입니다. 구현 후 검증을 실행하고 실제 내용과 출력을 기록한 뒤 active 파일을 그대로 두고 리뷰 준비를 보고하세요. 최종 판정, log rename, complete.log, archive 이동은 code-review-skill 전용입니다. 구현이 사용자 결정, 사용자 소유 외부 환경, 범위 충돌로 막히면 review stub의 사용자 리뷰 요청 섹션에 근거를 기록하고 중단하세요. 직접 질문, 채팅 선택지, request_user_input, USER_REVIEW.md 작성, archive, complete.log 작성은 금지입니다. 후속 에이전트가 재실행이나 산출물 수집으로 닫을 수 있는 증거 공백은 사용자 리뷰 요청이 아닙니다.

배경

Console 화면은 현재 샘플 로그만 렌더링하고 실제 device 선택이나 ADB stream과 연결되지 않습니다. Devices 화면의 logcat 버튼도 no-op이라 사용자가 설치 후 바로 로그를 볼 수 없습니다. 01_logcat_process의 session API 위에 shell/device 선택과 console stream lifecycle을 얹어 stream, lifecycle Task를 완료 가능한 단위로 만듭니다.

사용자 리뷰 요청 흐름

구현 중 blocker는 active review stub의 사용자 리뷰 요청 섹션에 기록합니다. 구현 에이전트는 사용자에게 직접 질문하지 않으며, code-review가 blocker 타당성을 검증하고 실제 USER_REVIEW.md 작성 여부를 결정합니다.

Roadmap Targets

  • Milestone: agent-roadmap/phase/usable-mvp/milestones/logcat-console.md
  • Task ids:
    • stream: 선택 device의 adb logcat stream을 시작하고 화면에 append한다.
    • lifecycle: 화면 이탈 또는 device 변경 시 logcat process를 정리한다.
  • Completion mode: check-on-pass

분석 결과

읽은 파일

  • agent-roadmap/current.md
  • agent-roadmap/phase/usable-mvp/PHASE.md
  • agent-roadmap/phase/usable-mvp/milestones/logcat-console.md
  • agent-ops/rules/project/domain/device-console/rules.md
  • agent-test/local/rules.md
  • agent-test/local/device-console-smoke.md
  • lib/src/services/adb_service.dart
  • lib/src/features/console/console_page.dart
  • lib/src/features/app_shell.dart
  • lib/src/app.dart
  • lib/src/features/devices/devices_page.dart
  • lib/src/models/adb_device.dart
  • pubspec.yaml
  • test/adb_service_test.dart
  • test/widget_test.dart
  • test/console_page_test.dart

테스트 환경 규칙

  • test_env: local
  • agent-test/local/rules.md 존재 및 읽음.
  • 매칭 profile: agent-test/local/device-console-smoke.md
  • 적용 명령: remote runner 기준 flutter analyze, flutter test; ADB process stream은 dispose 없이 남지 않아야 함.
  • 이 plan은 fake stream/session으로 widget lifecycle을 검증하고, 실제 ADB runtime은 보조 smoke 후보로 남긴다.

테스트 커버리지 공백

  • ConsolePage가 live stream을 append하는 test 없음. 새 widget test 필요.
  • 화면 이탈/device 변경 시 session stop이 호출되는 test 없음. fake session stop counter로 검증해야 한다.
  • 실제 adb logcat runtime smoke는 자동 unit test로 대체할 수 없다. remote runner에서 adb devices -l은 보조 확인으로 기록한다.

심볼 참조

  • renamed/removed symbol: none.
  • ConsolePage call site: lib/src/features/app_shell.dart:201-205.
  • device logcat button: lib/src/features/devices/devices_page.dart:368-372.
  • AdbService default wiring: lib/src/app.dart:49, lib/src/app.dart:150-158.

분할 판단

  • split decision policy를 먼저 평가했다.
  • 공유 task group: m-logcat-console
  • 이 subtask는 02+01_console_stream이며 predecessor 01agent-task/m-logcat-console/01_logcat_process/complete.log 또는 archive matching complete.log가 필요하다.
  • 현재 확인 결과 predecessor complete.log는 없음. 구현 시작 전 01_logcat_process PASS 완료가 필요하다.
  • 03+02_auto_scroll은 이 plan의 live console UI에 의존한다.

범위 결정 근거

  • auto-scroll의 pause-aware scroll positioning은 제외하고 03+02_auto_scroll에서 처리한다.
  • package/tag/text filter, level filter, export/clipboard, clear button은 filter 에픽 소속이므로 제외한다.
  • macOS entitlements와 bundled adb 배포는 변경하지 않는다.

빌드 등급

  • build/review: local-G06. UI wiring과 lifecycle test가 필요하지만, fake session과 widget tests로 범위를 제어할 수 있다.

구현 체크리스트

  • AppSokApp에서 logcat session starter를 AppSokShell로 주입한다.
  • DevicesPage logcat 버튼이 ready device를 console 선택 상태로 넘기고 콘솔 탭으로 이동하게 한다.
  • ConsolePage가 선택 device의 logcat stream을 시작하고 화면에 append하며 dispose/device 변경 시 session을 정리한다.
  • flutter test test/widget_test.dart test/console_page_test.dart를 실행한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

의존 관계 및 구현 순서

  • Directory dependency: 02+01_console_stream -> 01_logcat_process
  • 구현 전 agent-task/m-logcat-console/01_logcat_process/complete.log 또는 archive agent-task/archive/*/*/m-logcat-console/01_logcat_process/complete.log가 있어야 한다. 현재는 없음.

LOGCAT_STREAM-1 Shell Device Selection

문제

devices_page.dart의 logcat 버튼은 no-op이고, app_shell.dart는 console을 const ConsolePage()로 고정한다.

368  _CompactIconButton(
369    tooltip: 'logcat',
370    icon: Icons.terminal,
371    onPressed: () {},
372  ),
201  const _ShellPage(
202    label: '콘솔',
203    icon: Icons.terminal_outlined,
204    selectedIcon: Icons.terminal,
205    child: ConsolePage(),
206  ),

해결 방법

DevicesPageValueChanged<AdbDevice>? onLogcatRequested를 추가하고 ready device의 logcat 버튼만 활성화한다. AppSokShell_selectedConsoleDevice를 저장하고 _selectedIndex = 2로 이동하며, ConsolePage에 device와 starter를 전달한다.

void _handleLogcatRequested(AdbDevice device) {
  setState(() {
    _selectedConsoleDevice = device;
    _selectedIndex = 2;
  });
}

수정 파일 및 체크리스트

  • lib/src/features/devices/devices_page.dart: onLogcatRequested prop과 ready device button enablement 추가.
  • lib/src/features/app_shell.dart: selected console device state와 navigation handoff 추가.
  • lib/src/app.dart: AdbService.startLogcat starter를 shell에 전달.
  • test/widget_test.dart: ready device logcat 버튼이 console로 이동하고 device label을 표시하는 test 추가.

테스트 작성

  • 작성: test/widget_test.dart
  • 테스트 이름 후보: ready device logcat button opens console for that device
  • assertion: ready device button tap 후 navigation marker는 콘솔, selected device serial/display name이 console에 표시된다.

중간 검증

flutter test test/widget_test.dart

예상: shell/device widget tests 통과.

LOGCAT_STREAM-2 Live Stream Lifecycle

문제

console_page.dart_logLines 정적 목록만 사용하고, stream subscription이나 dispose cleanup이 없다.

69  child: ListView.builder(
70    padding: const EdgeInsets.all(16),
71    itemCount: _logLines.length,
72    itemBuilder: (context, index) {
73      final line = _logLines[index];

해결 방법

ConsolePageStatefulWidget으로 바꾸고 AdbLogcatSessionStarter? logcatStarter, AdbDevice? device를 받는다. initState/didUpdateWidget에서 device가 바뀌면 기존 subscription/session을 정리하고 새 stream을 시작한다. append buffer는 MVP에서 1000줄 정도로 cap을 두어 무한 메모리 증가를 막는다.

class ConsolePage extends StatefulWidget {
  const ConsolePage({super.key, this.device, this.logcatStarter});

  final AdbDevice? device;
  final AdbLogcatSessionStarter? logcatStarter;
}

수정 파일 및 체크리스트

  • lib/src/features/console/console_page.dart: Stateful conversion, stream start/append, error state, stop/dispose 처리.
  • test/console_page_test.dart: fake session stream append와 dispose stop 검증 추가.
  • test/widget_test.dart: navigation away 또는 device 변경 시 stop counter 증가 검증 추가.

테스트 작성

  • 작성: test/console_page_test.dart, test/widget_test.dart
  • assertion: stream line이 화면에 append되고, widget dispose/device change 후 fake session stopCalls == 1.

중간 검증

flutter test test/console_page_test.dart test/widget_test.dart

예상: console focused test와 shell widget tests 통과.

수정 파일 요약

파일 항목
lib/src/app.dart LOGCAT_STREAM-1
lib/src/features/app_shell.dart LOGCAT_STREAM-1
lib/src/features/devices/devices_page.dart LOGCAT_STREAM-1
lib/src/features/console/console_page.dart LOGCAT_STREAM-2
test/widget_test.dart LOGCAT_STREAM-1, LOGCAT_STREAM-2
test/console_page_test.dart LOGCAT_STREAM-2

최종 검증

flutter analyze
flutter test test/widget_test.dart test/console_page_test.dart

예상: analyzer issue 없음, targeted widget tests 통과.

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