[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
This commit is contained in:
@@ -44,17 +44,25 @@ class _AiSection extends ConsumerWidget {
|
||||
final settings = ref.watch(aiSettingsProvider);
|
||||
final availability = ref.watch(modelAvailabilityProvider);
|
||||
final download = ref.watch(modelDownloadControllerProvider);
|
||||
final ramOk = ref.watch(deviceMeetsAiRamProvider);
|
||||
final optIn = settings.maybeWhen(data: (v) => v, orElse: () => false);
|
||||
// #218 AC-6: gate the toggle when device RAM < 4GB. Default fail-closed
|
||||
// (null → disabled) so the user can't trip download on an undersized
|
||||
// device while the platform call is in flight.
|
||||
final meetsRam = ramOk.maybeWhen(data: (v) => v, orElse: () => false);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SwitchListTile(
|
||||
title: const Text('AI 도움 켜기'),
|
||||
subtitle: const Text(
|
||||
'Gemma 4 E2B 모델 ≈ 2.4GB. 모든 처리는 단말에서 일어납니다.',
|
||||
subtitle: Text(
|
||||
meetsRam
|
||||
? 'Gemma 4 E2B 모델 ≈ 2.4GB. 모든 처리는 단말에서 일어납니다.'
|
||||
: '이 단말의 RAM 이 부족합니다 (필요: 4GB 이상).',
|
||||
),
|
||||
value: optIn,
|
||||
onChanged: (v) async {
|
||||
value: meetsRam && optIn,
|
||||
onChanged: meetsRam
|
||||
? (v) async {
|
||||
if (v) {
|
||||
final ok = await _confirmOptIn(context);
|
||||
if (ok != true) return;
|
||||
@@ -70,7 +78,8 @@ class _AiSection extends ConsumerWidget {
|
||||
SnackBar(content: Text('공간 확보됨 ${_fmtMB(freed)}')),
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
: null,
|
||||
),
|
||||
availability.when(
|
||||
loading: () => const ListTile(title: Text('상태 확인 중...')),
|
||||
|
||||
Reference in New Issue
Block a user