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 logcatstream을 시작하고 화면에 append한다.lifecycle: 화면 이탈 또는 device 변경 시 logcat process를 정리한다.
- Completion mode: check-on-pass
분석 결과
읽은 파일
agent-roadmap/current.mdagent-roadmap/phase/usable-mvp/PHASE.mdagent-roadmap/phase/usable-mvp/milestones/logcat-console.mdagent-ops/rules/project/domain/device-console/rules.mdagent-test/local/rules.mdagent-test/local/device-console-smoke.mdlib/src/services/adb_service.dartlib/src/features/console/console_page.dartlib/src/features/app_shell.dartlib/src/app.dartlib/src/features/devices/devices_page.dartlib/src/models/adb_device.dartpubspec.yamltest/adb_service_test.darttest/widget_test.darttest/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 logcatruntime smoke는 자동 unit test로 대체할 수 없다. remote runner에서adb devices -l은 보조 확인으로 기록한다.
심볼 참조
- renamed/removed symbol: none.
ConsolePagecall site:lib/src/features/app_shell.dart:201-205.- device logcat button:
lib/src/features/devices/devices_page.dart:368-372. AdbServicedefault 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이며 predecessor01은agent-task/m-logcat-console/01_logcat_process/complete.log또는 archive matchingcomplete.log가 필요하다. - 현재 확인 결과 predecessor complete.log는 없음. 구현 시작 전
01_logcat_processPASS 완료가 필요하다. 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로 주입한다.DevicesPagelogcat 버튼이 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또는 archiveagent-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 ),
해결 방법
DevicesPage에 ValueChanged<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:onLogcatRequestedprop과 ready device button enablement 추가.lib/src/features/app_shell.dart: selected console device state와 navigation handoff 추가.lib/src/app.dart:AdbService.startLogcatstarter를 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];
해결 방법
ConsolePage를 StatefulWidget으로 바꾸고 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의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.