diff --git a/.gitignore b/.gitignore index 37ae0ee..d2317c1 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ play-store/ create_feature_graphic.py # Tool caches and local state +.devenv/ .cachebro/ .osgrep/ third_party/lpcnet_flutter/ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 18e8f43..efeaa9a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -489,7 +489,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -511,7 +511,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -530,7 +530,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -547,7 +547,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -679,7 +679,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -702,7 +702,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 129; + CURRENT_PROJECT_VERSION = 130; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index f3cba8c..8acee1d 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -43,7 +43,7 @@ CFBundleSignature ???? CFBundleVersion - 129 + 130 LSRequiresIPhoneOS ITSAppUsesNonExemptEncryption diff --git a/ios/fastlane/report.xml b/ios/fastlane/report.xml index 914341a..b93922a 100644 --- a/ios/fastlane/report.xml +++ b/ios/fastlane/report.xml @@ -5,22 +5,22 @@ - + - + - + - + diff --git a/lib/services/path_history_service.dart b/lib/services/path_history_service.dart index 5fa10aa..a492793 100644 --- a/lib/services/path_history_service.dart +++ b/lib/services/path_history_service.dart @@ -214,7 +214,9 @@ class PathHistoryService { pathBytes: selection.pathBytes.toList(), hopCount: selection.hopCount, hashSize: selection.hashSize, - source: existing?.source ?? PathRecordSource.learned, + source: success + ? PathRecordSource.learned + : existing?.source ?? PathRecordSource.learned, successCount: (existing?.successCount ?? 0) + (success ? 1 : 0), failureCount: (existing?.failureCount ?? 0) + (success ? 0 : 1), lastRoundTripTimeMs: success diff --git a/pubspec.yaml b/pubspec.yaml index bc3db95..8c77059 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 2026.0324.1+43 +version: 2026.0402.1+44 environment: sdk: ^3.9.2 diff --git a/test/services/path_history_service_test.dart b/test/services/path_history_service_test.dart index 8f16107..05d7df1 100644 --- a/test/services/path_history_service_test.dart +++ b/test/services/path_history_service_test.dart @@ -207,6 +207,42 @@ void main() { }, ); + test( + 'confirmed direct delivery promotes an observed path to learned', + () async { + final service = PathHistoryService(); + final contact = _buildContact( + seed: 4, + pathBytes: [0xAA, 0xBB], + hopCount: 2, + hashSize: 1, + ); + + await service.initialize(); + await service.recordReceivedBytePath(contact.publicKeyHex, [ + 0xBB, + 0xAA, + ], 1); + await service.recordPathResult( + contact.publicKeyHex, + PathSelection( + mode: PathSelectionMode.directHistorical, + pathBytes: Uint8List.fromList([0xAA, 0xBB]), + hopCount: 2, + hashSize: 1, + ), + success: true, + roundTripTimeMs: 150, + ); + + final history = service.historyFor(contact.publicKeyHex); + expect(history.directPaths, hasLength(1)); + expect(history.directPaths.single.source, PathRecordSource.learned); + expect(history.directPaths.single.successCount, 1); + expect(history.directPaths.single.lastRoundTripTimeMs, 150); + }, + ); + test('clear history removes stored direct paths for one contact', () async { final service = PathHistoryService();