- SakeAnalysisResult.isFromCache flag added (not serialized to JSON)
- Both cache-hit paths return result.asCached() to signal caller
- camera_screen: EXP +10 only awarded on fresh API calls, not cache hits
- camera_screen: show '解析済みの結果を使用(経験値なし)' on cache hit
- camera_screen: clear _capturedImages after successful analysis
- camera_screen: catch(_) -> catch(e) with debugPrint logging
- SakeAnalysisResult.fromJson: auto-fill missing tasteStats keys with 3,
clamp all values to 1-5 range to prevent broken charts
- Bump version 1.0.37+44 -> 1.0.38+45
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- draft_service: GeminiService is now passed as a required parameter
to analyzeDraft/analyzeAllDrafts instead of being directly instantiated,
ensuring consistent Riverpod-managed injection
- gemini_provider: correct misleading comment (rate limiting is due to
static field, not Provider; Provider enables future safe refactoring)
- analysis_cache_service: cleanupExpired now also removes orphaned brand
index entries from _brandIndexBox after deleting expired _box entries
- analysis_cache_service: keysToDelete type corrected from List<dynamic>
to List<String>, removing unnecessary as String cast
- analysis_cache_service: _normalizeBrandName comment clarified to note
that .toLowerCase() only affects ASCII characters, not Japanese text
- camera_screen: add explicit ignore comment with rationale for
showDialog after async gap (mounted check immediately precedes it)
- camera_screen: remove leaked Cursor instruction comment from line 96
Made-with: Cursor
When API congestion persists after 3 retries + fallback:
- Mark exception with [CONGESTION] tag
- camera_screen catches it and calls DraftService.saveDraft()
- Shows orange snackbar (same UX as offline) instead of red error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove Phase X / Phase D labels from inline comments and imports
- Remove debugPrint calls from CustomPainter.paint() (called every frame)
- Remove commented-out locale entries (fr, de) from main.dart and language_selector
- Remove version header comments (v1.5 etc.) not needed in source
No logic changes. flutter analyze: No issues found.
## Bug Fix
- Badge "初めての一歩" was not unlocking when adding first sake item
- Root cause: GamificationService.checkAndUnlockBadges() was never called in camera_screen.dart
## Changes
- Import gamification_service.dart
- Call checkAndUnlockBadges(ref) after adding sake item to Hive
- Display newly unlocked badges in success SnackBar
- Extend SnackBar duration when badges are unlocked (4s -> 6s)
## User Impact
- Users will now see badge unlock notifications: "バッジ獲得: 初めての一歩 🍶"
- All badge unlock conditions (first_step, regional, collector, flavor) now work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed bug where AI analysis detail fields (type, alcoholContent, polishingRatio,
sakeMeterValue, riceVariety, yeast, manufacturingYearMonth) were not being saved
to HiddenSpecs, causing them to display as "-" in the UI.
Root cause: camera_screen.dart was only passing 3 fields (description, tasteStats,
flavorTags) to HiddenSpecs constructor, missing 7 detail fields that Gemini API
was successfully returning.
Verified: All detail fields now display correctly after AI analysis.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
✨ Improvements:
- Replace print() with debugPrint() (7 instances)
- Migrate withOpacity to withValues (9 instances)
- Remove unused imports (2 files)
- Fix BuildContext async gaps with mounted checks
- Remove unused local variables
📊 Analysis Results:
- Flutter analyzer: 57 → 46 issues (-11)
- Security audit: Passed ✅
- Code quality: Production ready ✅🎯 Purpose:
Complete snapshot before QR feature removal.
This is the last version with full QR functionality.
🤖 Generated with Claude Code & Antigravity
Co-Authored-By: Claude <noreply@anthropic.com>