Matthias Nott
9 days ago 90fc31a938afac0f6910c7947c6ecba0adebfea4
lib/services/message_store.dart
....@@ -6,6 +6,7 @@
66 import 'package:path_provider/path_provider.dart';
77
88 import '../models/message.dart';
9
+import 'trace_service.dart';
910
1011 /// Per-session JSON file persistence with debounced saves.
1112 class MessageStore {
....@@ -59,6 +60,8 @@
5960
6061 /// Write directly to disk, bypassing debounce. For critical saves.
6162 static Future<void> writeDirect(String sessionId, List<Message> messages) async {
63
+ // Cancel ALL pending debounce to prevent race with frozen iOS timers
64
+ _debounceTimer?.cancel();
6265 _pendingSaves.remove(sessionId);
6366 await _writeSession(sessionId, messages);
6467 }
....@@ -85,9 +88,11 @@
8588 final file = File('${dir.path}/${_fileForSession(sessionId)}');
8689 // Strip heavy fields for persistence
8790 final lightMessages = messages.map((m) => m.toJsonLight()).toList();
88
- await file.writeAsString(jsonEncode(lightMessages));
91
+ final json = jsonEncode(lightMessages);
92
+ await file.writeAsString(json);
93
+ TraceService.instance.addTrace('MsgStore WRITE', '${sessionId.substring(0, 8)}: ${messages.length} msgs');
8994 } catch (e) {
90
- // Silently fail - message persistence is best-effort
95
+ TraceService.instance.addTrace('MsgStore WRITE ERROR', '${sessionId.substring(0, 8)}: $e');
9196 }
9297 }
9398
....@@ -130,11 +135,14 @@
130135
131136 final jsonStr = await file.readAsString();
132137 final List<dynamic> jsonList = jsonDecode(jsonStr) as List<dynamic>;
133
- return jsonList
138
+ final msgs = jsonList
134139 .map((j) => _messageFromJson(j as Map<String, dynamic>))
135140 .where((m) => !m.isEmptyVoice && !m.isEmptyText)
136141 .toList();
142
+ TraceService.instance.addTrace('MsgStore LOAD', '${sessionId.substring(0, 8)}: ${msgs.length} msgs');
143
+ return msgs;
137144 } catch (e) {
145
+ TraceService.instance.addTrace('MsgStore LOAD ERROR', '${sessionId.substring(0, 8)}: $e');
138146 return [];
139147 }
140148 }