feat: add ML-based adaptive timeout prediction using LinearRegressor

Train a linear regression model on actual message delivery times to
predict tighter timeouts, replacing worst-case physics estimates.
Features: path length, message bytes, seconds since last RX, flood mode.
Global model with per-contact blending after 10+ observations per contact.
Falls back to existing physics formula when model has insufficient data.
This commit is contained in:
zjs81
2026-03-14 16:56:11 -07:00
parent 8b280b37be
commit 2ee2358ecc
9 changed files with 683 additions and 20 deletions
+50
View File
@@ -1,4 +1,5 @@
import 'dart:convert';
import '../models/delivery_observation.dart';
import '../models/path_history.dart';
import '../storage/prefs_manager.dart';
@@ -6,6 +7,8 @@ class StorageService {
static const String _pathHistoryPrefix = 'path_history_';
static const String _pendingMessagesKey = 'pending_messages';
static const String _repeaterPasswordsKey = 'repeater_passwords';
static const String _deliveryObservationsKey = 'delivery_observations';
static const String _timeoutModelKey = 'timeout_ml_model';
Future<void> savePathHistory(
String contactPubKeyHex,
@@ -122,4 +125,51 @@ class StorageService {
final prefs = PrefsManager.instance;
await prefs.remove(_repeaterPasswordsKey);
}
Future<void> saveDeliveryObservations(
List<DeliveryObservation> observations,
) async {
final prefs = PrefsManager.instance;
final jsonStr = jsonEncode(observations.map((o) => o.toJson()).toList());
await prefs.setString(_deliveryObservationsKey, jsonStr);
}
Future<List<DeliveryObservation>> loadDeliveryObservations() async {
final prefs = PrefsManager.instance;
final jsonStr = prefs.getString(_deliveryObservationsKey);
if (jsonStr == null) return [];
try {
final list = jsonDecode(jsonStr) as List;
return list
.map(
(e) =>
DeliveryObservation.fromJson(e as Map<String, dynamic>),
)
.toList();
} catch (e) {
return [];
}
}
Future<void> clearDeliveryObservations() async {
final prefs = PrefsManager.instance;
await prefs.remove(_deliveryObservationsKey);
}
Future<void> saveTimeoutModel(String modelJson) async {
final prefs = PrefsManager.instance;
await prefs.setString(_timeoutModelKey, modelJson);
}
Future<String?> loadTimeoutModel() async {
final prefs = PrefsManager.instance;
return prefs.getString(_timeoutModelKey);
}
Future<void> clearTimeoutModel() async {
final prefs = PrefsManager.instance;
await prefs.remove(_timeoutModelKey);
}
}