Commit Graph

5 Commits

Author SHA1 Message Date
071afefc54 [06-Reviewer] #311 fileMissing 회복 자동화
SettingsScreen pop 후 ChatScreen state 가 여전히 Failed(fileMissing)
인 회로 — 사용자가 다운로드를 끝내고 돌아와도 ChatScreen 전체를
pop & re-push 해야 회복되는 UX gap.

Navigator.push().then((_) => retry()) 로 SettingsScreen 닫힐 때
자동 retry. quickCheck 다시 → ready 면 load → Ready 회복.
다운로드 안 했으면 다시 Failed 로 떨어져 같은 배너 노출 (일관).

`context.mounted` 가드는 ChatScreen 이 dispose 된 race 대비.

Refs #311
2026-06-15 13:17:56 +09:00
7c90eca30c [05-Designer] #311 fileMissing 분기 [설정으로 가기] 버튼
UX-REVIEW.md §마이크로카피 사전에서 fileMissing 케이스에 [설정으로
가기] 를 명시했으나 Developer 구현은 모든 kind 가 [다시 시도] 였음.
fileMissing 에서 retry 해도 파일이 없어 같은 결과 → 사용자 막힘.

- ChatWarmupFailureKind.fileMissing → SettingsScreen push (다운로드
  재시도 경로 노출)
- ChatWarmupFailureKind.runtime → 기존 retry() 유지 (일시적 회복 가능)

여전히 메시지 본문은 상태 기술만 (AC12), 행동은 버튼이 담당 (UX R5).

Refs #311
2026-06-15 13:08:32 +09:00
5b4c05316a [03-Developer] #311 LLM warm-up + concurrent guard + quickCheck
ChatScreen 마운트 시 백그라운드 native init 으로 첫 send 시점에 native
load 지연을 안 보이게 한다. 12개 AC + UX-Reviewer 의 6개 권고 모두 코드
반영.

핵심 변경:
- `chat_warmup_provider.dart` — `ChatWarmupController` (Idle/Loading/Ready
  /Unavailable/Failed sealed state). fast path (`llm.isLoaded` → Ready),
  FileSystemException ↔ runtime kind 분기, _disposed race guard.
- `model_lifecycle.dart` — `quickCheck()`: 2.4GB SHA-256 hashing 없이
  meta_kv + 파일 존재만 보고 ready 추정 (R4 UX 권고).
- `gemma_llm_service.dart` + `llm_service.dart` — `_loadingFuture` 동시
  호출 가드. 두 caller 가 동시에 load() 해도 native init 은 1 회만.
- `chat_screen.dart` — initState postFrameCallback 에서 warmup.start().
  warmup 상태에 따라 hintText / spinner / 실패 banner 분기.

AC coverage (12개):
- AC1~AC8: ChatWarmupController unit (chat_warmup_test.dart 8 tests).
- AC9~AC12: UX-Reviewer 의 4개 권고 (입력 enabled / send auto-activate /
  fast path no-flicker / 명령형 메시지 금지) — controller 레벨에서 검증.

테스트: 167 passed (1 pre-existing skip). `flutter analyze` clean.

Refs #311

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-15 12:52:50 +09:00
a8446d0c88 [05-Designer] #260 chat UX polish (QA 인수 4건)
QA round 2 인수 노트의 UX 항목 정돈. blocker 아니었음 — Designer 단계
의무 폴리시.

1) ToolCallChatMessage 라벨 한국어화
   - chat_screen.dart: _kToolKoreanLabels 맵 추가. 6 tool 모두 한국어
     라벨 (예: add_habit → '습관 추가'). 미매핑 tool 은 raw name fallback.

2) ConfirmDialog 좁은 화면 reflow
   - confirm_gate.dart: AlertDialog content 를 SingleChildScrollView 로
     감쌈. summary box width=double.infinity (좌측 정렬 안정).

3) Streaming cursor 다크모드 contrast
   - chat_screen.dart: ▍ 문자를 Text.rich 로 분리해 colorScheme.primary
     적용. 다크 모드에서도 onSurface 본문 대비 cursor 가 식별됨.

4) AppBar tooltip 명료성
   - chat_screen.dart: '새 대화' → '새 대화 (이전 기록 비우기)'.
     history reset 의미 명시.

회귀
- 154 passed (1 skip), 회귀 0
- flutter analyze: clean

Refs #260
2026-06-15 10:59:50 +09:00
b1bed4d5ca [03-Developer] #260 in-app tool calling (Gemma 4 multi-turn)
ADR-0005 in-process tool runtime — 6 tools (catalog 2 + tracker 2 +
habit 2), ToolDispatcher with JSON-schema validation + modal ConfirmGate
for destructive ops, multi-turn LlmChatSession abstraction wired to
flutter_gemma 0.16.5 (ToolChoice.auto), ChatSessionController with
MAX_TURNS=4 safety + 8-turn history hint, ChatScreen entry behind AI
opt-in. R3/R7/R8 enforced inside handlers. 41 new tests (envelope,
catalog/tracker/habit tools, dispatcher, controller loop) — 151 total
passing.

Refs #260
2026-06-15 10:42:43 +09:00