appsok/agent-task/m-logcat-console/03+02_auto_scroll/PLAN-local-G05.md

7.5 KiB

LOGCAT_SCROLL 계획

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

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

배경

Live logcat stream은 새 로그가 계속 들어오기 때문에 console의 scroll 정책이 명확해야 합니다. 사용자가 pause한 상태에서 자동으로 바닥으로 끌려가면 디버깅 중 읽던 위치를 잃습니다. 02+01_console_stream으로 live append가 들어온 뒤, pause-aware auto-scroll을 별도 리뷰 단위로 구현합니다.

사용자 리뷰 요청 흐름

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

Roadmap Targets

  • Milestone: agent-roadmap/phase/usable-mvp/milestones/logcat-console.md
  • Task ids:
    • auto-scroll: 새 로그가 들어올 때 자동 스크롤하되 pause 상태에서는 사용자의 위치를 유지한다.
  • 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.
  • 이 plan은 widget-level scroll behavior가 핵심이므로 test/console_page_test.dart를 중간 검증으로 둔다.

테스트 커버리지 공백

  • 새 로그 append 시 bottom auto-scroll test 없음.
  • pause 상태에서 scroll offset이 유지되는 test 없음.
  • clear/export/filter는 이 plan의 대상이 아니므로 coverage 공백으로 남긴다.

심볼 참조

  • renamed/removed symbol: none.
  • pause button 현재 위치: lib/src/features/console/console_page.dart:46-50.
  • log list 현재 위치: lib/src/features/console/console_page.dart:69-88.

분할 판단

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

범위 결정 근거

  • stream, lifecycle02+01_console_stream 책임이며 여기서는 이미 live append가 있다고 가정한다.
  • query/level filter, clear, export는 filter 에픽 소속이므로 제외한다.
  • 실제 ADB device smoke는 scroll logic 검증의 필수 조건이 아니므로 widget test로 판단한다.

빌드 등급

  • build/review: local-G05. UI state와 scroll controller 동작만 다루며 fake stream 기반 widget test로 검증 가능하다.

구현 체크리스트

  • ConsolePageScrollController와 pause 상태를 추가하고 새 로그 append 후 unpaused 상태에서 bottom으로 이동한다.
  • pause/resume 버튼이 auto-scroll 정책을 제어하고 pause 중 사용자 scroll offset을 유지한다.
  • test/console_page_test.dart에서 unpaused auto-scroll과 paused offset 유지 동작을 검증한다.
  • flutter test test/console_page_test.dart를 실행한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

의존 관계 및 구현 순서

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

LOGCAT_SCROLL-1 Pause-Aware Auto Scroll

문제

console_page.dart의 pause 버튼은 no-op이고 console_page.dart의 log list는 controller 없이 렌더링된다.

46  IconButton.filledTonal(
47    tooltip: '일시정지',
48    onPressed: () {},
49    icon: const Icon(Icons.pause),
50  ),
69  child: ListView.builder(
70    padding: const EdgeInsets.all(16),
71    itemCount: _logLines.length,
72    itemBuilder: (context, index) {

해결 방법

ScrollController_isPaused를 도입한다. stream line append 후 WidgetsBinding.instance.addPostFrameCallback에서 unpaused일 때만 animateTo/maxScrollExtent 또는 jumpTo를 실행한다. pause 중에는 기존 offset을 건드리지 않는다.

void _appendLine(String line) {
  setState(() => _lines.add(line));
  if (!_isPaused) {
    WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
  }
}

수정 파일 및 체크리스트

  • lib/src/features/console/console_page.dart: ScrollController, _isPaused, pause/resume icon/tooltip 상태 추가.
  • lib/src/features/console/console_page.dart: append 후 unpaused auto-scroll과 paused no-scroll 적용.
  • test/console_page_test.dart: fake stream으로 scroll behavior 검증 추가.

테스트 작성

  • 작성: test/console_page_test.dart
  • 테스트 이름 후보:
    • auto-scrolls to the newest log while running
    • keeps user scroll position while paused
  • assertion: unpaused append 후 list bottom marker가 보이고, pause 후 추가 line이 들어와도 pre-pause scroll offset이 유지된다.

중간 검증

flutter test test/console_page_test.dart

예상: console focused widget tests 통과.

수정 파일 요약

파일 항목
lib/src/features/console/console_page.dart LOGCAT_SCROLL-1
test/console_page_test.dart LOGCAT_SCROLL-1

최종 검증

flutter analyze
flutter test test/console_page_test.dart

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

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