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
321d3af53b
[03-Developer] #226 Catalog Gallery 구현
...
- Drift schema v2: Protocols.category CHECK 6→7 (light_circadian/sleep/movement/
nutrition/focus_cognition/recovery_stress/emotion_relationship). schemaVersion
1→2 + onUpgrade migrateV1ToV2 (DROP+CREATE+reseed flag 클리어).
- protocols.json 34 항목 v2 재분류 (1차 효과 기준). emotion_relationship 0 매핑.
- 도메인: DisplayCategory enum (8) + CatalogItem sealed (Protocol/Break/Diet).
- 데이터: CatalogRepository.all/byId/referencesByIds (3 source 통합).
- 상태: catalog_providers.dart (catalogItems / groupedByCategory / refsByIds).
- UI: ProtocolGalleryScreen (카테고리 칩 + 카드 그리드) + ProtocolPreviewScreen
(모든 필드 + reference 펼치기 + "내 습관으로" disabled placeholder) +
CatalogCard / CategoryChipRow / ReferenceExpandCard. HabitListScreen 빈
상태 CTA + AppBar 액션.
- 테스트: migration_v1_to_v2 3건 + display_category 5건 + catalog_repository
9건 + gallery widget 3건 + preview widget 3건 = 23 신규. 기존 88 회귀 0,
flutter analyze 0 issues. 110 passed / 1 skipped.
설계서: docs/design/226-catalog-gallery/{README, fn-catalog_repository,
fn-migration_v1_to_v2}.md + ADR-0004.
Refs #226
2026-06-12 17:20:13 +09:00
14632e11df
[05-Designer] #218 UX 다듬기 — RAM 게이트 문구 + 옵트아웃 표현
...
Round 2 QA PASS 후 user-facing 문구 3건 정리.
1) AC-6 RAM 게이트 안내: "이 단말의 RAM 이 부족합니다 (필요: 4GB 이상)"
→ "이 단말에서는 AI 도움을 사용할 수 없어요 (RAM 4GB 이상 필요)".
Planner spec 톤과 align. "부족합니다" (비난 어조) → "사용할 수 없어요"
(정보 제공 톤). 안내문 끝 마침표 제거.
2) ModelAvailability.missing 메시지가 RAM 게이트 active 상태에서 "위
토글을 켜면" 안내를 표시해 모순 발생. meetsRam=false 분기 추가 →
"이 단말은 모델을 받을 수 없어요 (RAM 4GB 이상 필요)" 노출.
3) _confirmOptOut 보조 텍스트 "다시 켜면 다시 다운로드해야 합니다"
→ "다시 켜면 처음부터 다운로드합니다". "다시" 중복 제거 + 호흡 정리.
기능 동작 변화 0. analyze clean, 88/88 통과.
Refs #218
2026-06-12 15:58:54 +09:00
f71d132fa3
[03-Developer] #218 Dev round 2 — AC-6 RAM 4GB gate + AC-10 docs cleanup
...
QA round 1 (commit 9a9eb2a ) FAIL 시 누락된 두 AC 보강.
AC-6: device_info_plus 만으론 4GB 임계 측정 불가 (isLowRamDevice 는
~1GB 기준). MethodChannel `life_helper/device_caps` 신설 + MainActivity.kt
에서 ActivityManager.MemoryInfo.totalMem 노출. data/ai/device_capabilities.dart
는 DeviceCapabilities abstract + PlatformDeviceCapabilities + 4 GiB
임계. deviceMeetsAiRamProvider (FutureProvider<bool>, fail-closed).
SettingsScreen 토글 disabled + "RAM 부족" 안내 (RAM < 4GB).
AC-10: docs/reference/215-ai-frame-suggest.md 의 OQ-1/placeholder
6곳을 실 구현 표현으로 갱신. §8 알려진 제약 = AC-6 device gate +
AC-7 실 단말 E2E + F1 unload + #221 corpus 평가. §9 다음 단계 =
#219~#222 follow-up 목록. 신규 테스트 합계 41 / 전체 88 통과.
테스트: device_capabilities_test.dart 7 신규 (kAiMinRamBytes 동등,
null/0/3.9GB/4GB-1/4GB/8GB 경계). flutter analyze 무이슈, 전체 88 통과
(71 기존 + 10 gemma + 7 RAM gate).
Architect 설계서 §4 의 "RAM 4GB 차단 = AC-9 재활용" 문구는 사실 #215
미구현 사항이라 본 라운드에서 신규 추가했음을 README 에 명기.
Refs #218
2026-06-12 15:45:14 +09:00
9a9eb2abd5
[Developer] #218 Real Gemma 4 E2B integration via flutter_gemma 0.16.5
...
Implements the OQ-1 follow-up to #215 v0.2.0: replace the placeholder
GemmaLlmService stub with a real flutter_gemma 0.16.5 backend driving
Gemma 4 E2B (litert-community/gemma-4-E2B-it-litert-lm, 2.41GB).
Highlights:
- GemmaLlmService.load → FlutterGemma.initialize + installModel.fromFile +
getActiveModel; idempotent + FileSystemException on missing file.
- generateStructured uses Gemma 4 native function calling via
createChat(tools: [Tool(...)], toolChoice: required). Stream parsed by
collectFunctionCall — first FCR wins, ParallelFCR first-call wins,
TextResponse/ThinkingResponse skipped, errors sanitized to prevent
prompt leakage.
- main.dart wires _LazyLlmService adapter that resolves to GemmaLlmService
when ModelLifecycle reports ready, MockLlmService otherwise.
- ai_providers.dart pins real model URL + SHA-256 (181938...39a63c).
- F2 hardening: ModelLifecycle.purge wraps each delete + meta remove in
try/catch so a single OS-level flake cannot block opt-out.
- Android: INTERNET / FOREGROUND_SERVICE / POST_NOTIFICATIONS permissions
+ R8 proguard-rules.pro keeping MediaPipe / LiteRT / TFLite / protobuf
JNI entry points (release builds otherwise crash on first inference).
Design-First: fn-gemma_llm_service.md updated to v2 — §C
(_appendSchemaInstruction) deprecated after reading flutter_gemma
0.16.5 source (Gemma 4 SDK injects tool declarations via template;
prompt-side append would double-wrap).
Tests:
- 10 new unit tests for collectFunctionCall covering all 8 fn-spec
cases + 2 ParallelFunctionCallResponse paths.
- All 81 existing tests still pass.
- flutter analyze: 0 issues.
Refs #218
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-06-12 15:18:08 +09:00
71e8c3dd53
[Designer] #215 Polish AI settings + frame suggestion surfaces
...
- frame_suggestion_dialog: hide exception detail in error path, redesign
candidate card as Card+InkWell with L2/L3 colored level badge (secondary
vs primary), remove confidence % surface.
- settings_screen: download tile gains state label + colored progress text,
rounded LinearProgressIndicator, FilledButton.tonalIcon for resume/retry.
_friendlyError() maps internal codes (network:/http /stream:/sha mismatch)
to user-readable Korean. Opt-in/out dialogs reorganized with _Bullet rows;
beta disclaimer reworded; _describe() friendlier copy.
Polish only — no behavior change. analyze 0, 71 tests pass, APK 10.3s.
Refs #215
2026-06-12 13:07:30 +09:00
1e019c6dc7
[Developer] #215 AC2/AC4/AC6 fixes after QA reject
...
QA 1차 (커밋 6ab4c0d 검증) 에서 3건 AC 미충족 → 03-Developer 반려.
본 커밋은 그 3건을 해결한다.
AC6 — _AiSuggestButton 가시성 분기 분리:
- optIn=false → 숨김 유지
- optIn=true && !ready → 노출 + disabled + Tooltip("AI 도움을 먼저 켜주세요")
- optIn=true && ready → enabled
AC5 보완: 후보의 c.level 직접 전달 (이전 "나는" 휴리스틱 제거).
FrameSuggestionDialog.show 반환 타입 String? → FrameCandidate?.
AC4 — L2:2 + L3:1 분포 강제:
- few_shot prompt 에 "정확히 L2 2개 + L3 1개" 명시
- suggestFrame 결과를 _shapeDistribution(l2Quota=2, l3Quota=1) 로 후처리
- 부족분은 패딩 X (graceful: UI 가 더 적은 카드만 표시)
AC2 — 다운로드 진행률 + 일시정지/재개 UI:
- ModelDownloadController (StateNotifier<DownloadProgress?>)
· start() / pause() / resume() / cancel()
· pause() 는 subscription 만 cancel, .tmp + meta_kv 유지 → resume 시 Range header 로 이어받음
- AiSettingsController.setOptIn(true) → controller.start() 자동 호출
- SettingsScreen 에 _DownloadProgressTile 추가
· LinearProgressIndicator + bytes/total + 일시정지/재개/다시 시도 토글
회귀 테스트 9건 신규:
- test/ui/ai_suggest_button_visibility_test.dart (4): AC6 4상태 (hidden / disabled+tooltip × missing/downloading / enabled)
- test/state/model_download_controller_test.dart (3): opt-in→start, pause→paused, cancel→idle
- test/domain/ai/suggest_frame_test.dart (+3): AC4 분포 케이스 3개 (기존 take(3) 테스트 대체)
검증:
- flutter analyze → No issues found
- flutter test → 71 tests pass (62 → 71, +9 신규)
- flutter build apk --debug → 성공 (8.8s)
OQ-1 (모델 URL+SHA) 미해결 유지. MockLlmService 기본 주입 + placeholder URL 다운로드는 여전히 실패하지만, UI/스트림 wiring 은 모두 검증됨.
Refs #215
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-06-12 12:30:16 +09:00
6ab4c0da7d
[Developer] #215 AI frame-suggest vertical slice (mock LlmService)
...
설계서대로 구현. flutter_gemma 실제 통합은 OQ-1 (모델 URL+SHA) 확정 후.
v1은 LlmService 추상 + ModelLifecycle (다운로드/SHA/purge) + Riverpod
providers + 다이얼로그 + Settings 화면까지. main.dart 가 MockLlmService 를
override 해 모든 경로가 graceful (suggest 결과는 빈 리스트).
추가:
- lib/data/ai/{llm_service,gemma_llm_service,model_lifecycle}.dart
- lib/domain/ai/{frame_candidate,few_shot_builder,parse_response,suggest_frame}.dart
- lib/state/ai_providers.dart (aiSettings + modelAvailability + frameSuggestions)
- lib/ui/screens/settings_screen.dart (opt-in 토글 + 모델 상태 표시)
- lib/ui/widgets/frame_suggestion_dialog.dart (후보 3개 카드 + 다시 시도)
- HabitCreateScreen: "AI 제안" 버튼 (opt-in + ready 일 때만 노출)
- MetaDao.remove(key) 추가 (purge 용)
테스트 31개 신규 추가 (총 62개 통과):
- test/domain/ai/{suggest_frame, few_shot_builder, parse_response}_test.dart
- test/data/ai/model_lifecycle_test.dart (download/SHA/purge/availability)
flutter analyze 0 issue, flutter build apk --debug 통과.
Refs #215
2026-06-12 12:08:25 +09:00
8fe6a8f378
[Developer] #204 Phase 1 MVP — Flutter app skeleton complete
...
- Drift 21 tables (8 catalog + 11 user + habit_dose_variants + meta_kv)
with R1~R10 CHECK constraints and 19 indexes
- 8 hand-crafted seed JSON catalogs in app/assets/seed/
(refs 84, protocols 34, methodologies 21, frame_patterns 30,
reward_menu_items 30, break_protocols 8, common_frames 5, diet_patterns 5)
- 6 domain functions: recommend_variant, compute_streak,
validate_frame_level, active_habit_quota, weekly_minimum_ratio,
seed_importer (transactional, idempotent)
- 4 vertical-slice Riverpod screens: HabitList, HabitCreate, CheckIn, Streak
- 31 unit tests passing; flutter analyze clean
- OQ-5 streak semantics: missing entry ≠ explicit blank
(missing = end of history; only TrackerValue.blank triggers Never-miss-twice)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-06-12 10:33:03 +09:00