3.4 KiB
3.4 KiB
Peer Review (Round 3): 콜드스타트 에러 침묵 버그 수정 (commit 7e4cab6) — multi-agent-mux-ui
Scope
50ed0559 리뷰에서 지적한 잔여 결함 — "콜드스타트(한 번도 성공한 적 없는 폴링 실패)가 여전히 완전히 침묵됨, stale_banner.dart:15의 if (!poll.stale) return shrink 게이트가 원인" — 에 대한 수정 커밋 7e4cab6("fix(ui): expose stale banner under cold-start failures when no successful snapshot exists")를 검토했다.
변경 내용 확인
stale_banner.dart 5줄 변경(그 외 파일은 무관한 dart_tool 캐시 바이너리 1개뿐):
final shouldShow = poll.stale || (poll.snapshot == null && poll.error != null);
if (!shouldShow) return const SizedBox.shrink();
...
final lastOkText = lastOk == null
? 'never'
: '...'
내가 50ed0559에서 제안한 수정안과 조건식이 정확히 일치한다 — poll.stale뿐 아니라 poll.snapshot == null && poll.error != null(콜드스타트: 한 번도 성공하지 못했지만 에러는 있는 상태)도 노출 조건에 포함시켰고, lastOkAt == null일 때 문구도 의미 없는 시각 대신 'never'로 분기했다.
검증
- 경로 추적:
main.dart의_DashboardBody는snapshot이 null이어도StaleBanner(poll: poll)를 항상 마운트한다(sessions/count는 각각?? const []/?? 0로 안전 처리) — 배너 표시 조건이 고쳐지면 실제로 화면에 그려질 경로가 이미 존재함을 재확인. - 스트림 도달성:
StatusRepository.watch()는 모든 폴링 실패를 내부에서 흡수해 항상SessionsPoll을 yield하므로(예외를 스트림 밖으로 던지지 않음), RiverpodsessionsPollProvider는 첫 실패 시에도AsyncError가 아니라AsyncData(poll)로 즉시 전이 —DashboardScreen이_ErrorScreen이 아니라_DashboardBody(그리고 그 안의StaleBanner)로 정상 도달함을 재확인. - 실제 렌더링 재현(직접 실행):
SessionsPoll(snapshot: null, stale: false, lastOkAt: null, error: 'StatusFetchException: preflight failed: tmux is missing or not executable')로StaleBanner를 단독 렌더링하는 위젯 테스트를 임시 작성해flutter test로 직접 실행 —'never'텍스트와 에러 메시지('tmux is missing') 문자열이 모두 실제로 화면에 렌더링됨을 확인(테스트는 검증 후 삭제, 저장소에는 남기지 않음 — 리뷰 산출물 오염 방지). 이전 라운드(50ed0559)에서 재현했던 "배너가 전혀 뜨지 않는" 상황이 이제 재현되지 않는다. - 회귀 없음:
dart analyze(mam_core)/flutter analyze(mam_desktop) 모두 No issues found. 기존 6개 테스트(mam_core3 +mam_desktop3) 전부 통과. - 스코프 확인: 이번 커밋은
stale_banner.dart한 파일만 수정 — 이전 라운드에서 요청한 "좁은 범위 수정" 요구와 정확히 일치, 다른 파일에 부작용 없음.
결론
765e2329(pre-flight 체크 누락) → 50ed0559(수정이 잘못된 조건 분기에 적용됨) → 이번 7e4cab6까지 이어진 콜드스타트 에러 침묵 버그가 정확한 근본 원인(단일 if 게이트)에 대한 정밀 수정으로 완전히 해소되었다. 실제 위젯 렌더링까지 직접 실행해 확인했고, 회귀도 없다. M1 스코프에서 더 이상 남은 이슈가 없다.
[VERDICT: PASS]