Add RoadFlare personal rideshare network + Phase 5-6 infrastructure#37
Merged
variablefate merged 66 commits intomainfrom Feb 4, 2026
Merged
Add RoadFlare personal rideshare network + Phase 5-6 infrastructure#37variablefate merged 66 commits intomainfrom
variablefate merged 66 commits intomainfrom
Conversation
Implements the complete RoadFlare system allowing riders to build a personal network of favorite drivers. Drivers keep 100% of fares, calculated using real-time location for accuracy. New Nostr events: - Kind 30011: Rider's followed drivers list (NIP-44 encrypted) - Kind 30012: Driver's RoadFlare state (keypair, followers, muted) - Kind 30014: Driver location broadcast (NIP-44 to shared keypair) - Kind 3186: Ephemeral key share (driver → follower) - Kind 3188: Key acknowledgement (rider → driver) Features: - RoadFlare tab in both rider and driver apps - QR code driver profile sharing - Real-time driver location with encrypted broadcasts - Shared Nostr keypair model (single encryption per broadcast) - Key rotation on follower removal - DND mode for drivers (persists until explicit toggle) - Follower approval workflow with stale key detection - Post-ride "Add to Favorites" prompt - RoadFlare-tagged ride offers (Kind 3173 with roadflare tag) - Sync adapters for cross-device state recovery - Background RoadFlare alert service for drivers - Fare calculation using exact driver distance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace DND toggle with OFFLINE → ROADFLARE_ONLY → AVAILABLE driver states. Remove all DND infrastructure from data models, serialization, sync adapters, UI, and documentation. Fix subscription leak in onCleared(), remove dead RideOfferEvent.createRoadflare(), extract shared processIncomingOffer() helper, and reuse decryptRoadflareLocation across rider screens.
Remove hardcoded $2.50 base fee and $5.00 minimum from RoadFlare fare calculation. Minimum now comes from remote config (roadflareMinimumFareUsd) with $5.00 default. Fallback is flat 5000 sats when no BTC price available. Add roadflareMinimumFareUsd to AdminConfig and RemoteConfigManager cache.
…, refund safety - Add ensureWalletReady() pre-check before ride offers to verify/clean NIP-60 proofs - Replace single-retry cleanup in lockForRide with 3-attempt loop - Add 120s clock skew buffer to HTLC refund timing (fixes mint rejection) - Keep PendingHtlc status as LOCKED on refund failure instead of FAILED - Reduce HTLC locktime from 2 hours to 15 minutes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…d HTLC refund changes
…ailable - Reorder DriverStatusBadge conditions to check explicit OFFLINE before staleness - Remove drivers from selection sheet when OFFLINE status received - Pass isDriverOnline from DriverViewModel to RoadflareTab for accurate status - Add locationless Kind 30173 events for ROADFLARE_ONLY mode drivers - ROADFLARE_ONLY drivers now publish availability without location/geohash (invisible to geographic search but trackable by pubkey subscription) - Handle missing location gracefully in DriverAvailabilityEvent.parse()
- Make location nullable in DriverAvailabilityEvent.create() (null = ROADFLARE_ONLY mode) - Add status parameter to NostrService.broadcastAvailability() - Remove redundant methods: createOffline(), createWithoutLocation(), broadcastOffline(), broadcastAvailabilityWithoutLocation() - Update DriverViewModel to use unified method with explicit parameters Reduces ~80 lines of code duplication while maintaining the same behavior.
cancelRide() was setting local state to OFFLINE but not broadcasting a Kind 30173 offline event, causing riders/followers to see stale "available" status. Now broadcasts locationless offline event to match the UI state.
NostrService: - Merge sendRideOffer() and sendRoadflareOffer() into unified method - New signature: sendRideOffer(driverPubKey, driverAvailabilityEventId?, ...) - driverAvailabilityEventId is null for RoadFlare offers RiderViewModel bug fixes: - Fix #1 (wrong fare): Store fareEstimate/fareEstimateWithFees in RoadFlare state updates - Fix #2 (boost fails): Add roadflareTargetDriverPubKey/Location fallback in boostDirectOffer() - Fix #3 (countdown skipped): Reset directOfferTimedOut=false in all send methods RiderUiState: - Add roadflareTargetDriverPubKey and roadflareTargetDriverLocation fields for tracking RoadFlare target driver info needed by boost functionality
…r names Architecture refactor: - paymentHash now sent in Kind 3175 confirmation instead of Kind 3173 offer - Fixes boost bug where resending offer overwrote driver's paymentHash with null - HTLC is now locked AFTER acceptance using driver's wallet pubkey - Driver extracts paymentHash from confirmation.paymentHash in subscribeToConfirmation() RoadFlare UX improvement: - FollowedDriversRepository now persists driver names to SharedPreferences - Names load instantly on app startup (no pubkey flash) - Cleanup on unfollow prevents orphaned cache entries Files changed: - RideConfirmationEvent: Added paymentHash + escrowToken fields - RideOfferEvent: Removed paymentHash from create() - NostrService: Updated sendRideOffer() and confirmRide() signatures - RiderViewModel: Pass paymentHash in confirmRide() not sendRideOffer() - DriverViewModel: Extract paymentHash from confirmation, not offer - FollowedDriversRepository: Persist name cache to SharedPreferences
…osed - Exclude sensitive SharedPrefs from cloud/device backup (both apps) - Restrict user-installed CAs to debug builds only (both apps) - Crypto self-test now aborts connection on hash_to_curve failure - Remove deprecated :app module from settings.gradle.kts
- Delete app/ directory (deprecated, unused, outdated event kinds) - Remove hash_to_curve runtime test (validated during development)
Security hardening: - Verify all event signatures at relay level before processing - Add expected pubkey validation for critical ride events: - RideAcceptanceEvent (wallet_pubkey for P2PK escrow) - RideConfirmationEvent (payment_hash, escrow_token) - DriverRideStateEvent (settlement, preimage) - RiderRideStateEvent (PIN verification) Uses Quartz library's event.verify() for Schnorr signature validation.
- Add bounded message channel (capacity=256) for ordered processing - Connection generation tracking prevents stale callback corruption - Synchronized blocks for state+socket coherence - Early shouldReconnect check prevents post-disconnect reconnects - Atomic StateFlow.update for events/notices lists
- Fix backup rules to exclude correct SharedPreferences filenames (ridestr_secure_keys.xml, ridestr_wallet_keys.xml, etc.) - Add privacy-sensitive data to backup exclusions (ride history, saved locations, vehicles) - Nostr sync is recovery path - Wire expectedDriverPubKey validation in subscribeToAcceptance() - Wire expectedRiderPubKey validation in subscribeToConfirmation() - Update RiderViewModel call sites for direct offer acceptance - Update DriverViewModel call sites for confirmation subscription
Document recent security improvements: - Backup exclusions (420f54b): correct SharedPrefs filenames + privacy data - Pubkey validation (420f54b): expectedDriverPubKey/expectedRiderPubKey wiring - WebSocket concurrency (0e658f6): bounded channel, generation tracking - Signature verification (d7c9064): relay-level event.verify()
- Add ensureRoadflareStateSynced() for cross-device sync on go-online - Reject stale/out-of-order Kind 30014 events with timestamp tracking - Add staleness filter to RoadFlare selection sheet (10-min freshness) - Add auto key refresh request (status="stale" in Kind 3188) - Handle key refresh requests in driver MainActivity - Add status parameter to RoadflareKeyAckEvent.create() and publishRoadflareKeyAck()
Previously ensureRoadflareStateSynced() only fetched from Nostr when local state was completely empty. This caused issues when two devices had different RoadFlare keys - the phone would keep its stale local key instead of syncing the newer one from Nostr. Now the function always fetches from Nostr on go-online and compares keyUpdatedAt timestamps. If Nostr has newer data, it replaces local state. This ensures cross-device consistency when the same driver account is used on multiple devices.
- Replace wholesale state replacement with union merge strategy - Merge follower lists (union by pubkey, prefer approved + higher keyVersionSent) - Merge muted lists (union, never auto-unmute from sync) - Clamp keyVersionSent to selected key version to prevent invalid claims - Add retry on null fetch before pushing local state - Clear muted list when rider unfollows (enables safe union) - Add background refresh after sync to detect unfollowed riders - Add syncTriggeredRefresh SharedFlow for MainActivity observer
Extract refreshRoadflareFollowers() as local suspend function and use it for both UI refresh button and sync-triggered background refresh. Fixes codex review findings: - Background refresh now adds new followers (was missing) - Background refresh now fetches display names (was missing) - Removes code duplication between UI and background refresh paths
Adds debug section to Driver app's Developer Options showing: - Local key version and timestamp - Nostr sync status (match/mismatch detection) - Check, Sync, and Rotate Key buttons Helps diagnose cross-device key sync issues. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HtlcRefundOutcome sealed class for detailed failure diagnostics - Add wallet key validation to catch mismatch after wallet restore - Add getActiveKeysetFromMint() to fix keyset mismatch after mint switch - Add failureReason field to HtlcRefundInfo for UI display - Auto-backup wallet key to NIP-60 after connect - Auto-backup wallet key before HTLC creation (protects existing users) - Fix help text from "2 hours" to "15 min + 2 min buffer" - Add comprehensive diagnostic logging for HTLC refunds - Use java.util.Date instead of java.time.Instant for API safety
NUT-14 requires 64-hex preimage in witness. Some mints don't verify the hash (allowing zeros workaround), but if they fix this, refunds would fail. Now storing preimage when creating HTLCs so refunds can use the real preimage if mints enforce hash verification. - Add preimage field to PendingHtlc - Thread preimage through lockForRide() → PendingHtlc → refund - Fallback to zeros for old HTLCs without stored preimage - Validate preimage format (64 hex chars) before storing
- CLAUDE.md: Update "HTLC Refund Gap" to "HTLC Refund Preimage Storage" (fixed) - common README: Add preimage storage note to HTLC Locktime & Refund Flow section - cashu-wallet SKILL: Update PendingHtlc data model, creation/refund flows
- Add comprehensive offer type comparison (Direct, Broadcast, RoadFlare) - Document RoadFlare architecture: encryption model, follower lifecycle, key rotation - Add payment methods section with HTLC preimage storage details - Add Mermaid diagrams for ride flows and state machines - Update Kind 3188 with status values (received vs stale) and refresh flow - Document driver availability states and state machine entry points - Consolidate RoadFlare status detection documentation
…recoverable HTLCs - HTLC refund: Try spec-compliant first (no preimage), retry with zeros fallback if mint requires it - Gate debug logging behind BuildConfig.DEBUG in CashuBackend, RoadFlare files - Remove HTLC secret logging for security - Add IRRECOVERABLE status for HTLCs that cannot be refunded (wallet key mismatch) - Add acknowledgeIrrecoverableHtlc() to clear stuck HTLCs from pending sats - Add "Clear" button in WalletSettings for HTLCs locked >30min - Keyset selection: prefer explicit active=true, fall back to first sat keyset with warning Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Propagate actual HTTP response code (e.g., 429, 500) instead of hard-coded 400 in MintRejected failure. This improves error messages and debugging when HTLC refunds fail due to rate limiting or server errors. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When multiple drivers are contacted in a RoadFlare batch and a non-first driver accepts, update the state to reflect the actual accepting driver instead of keeping the stale first-driver reference.
If PIN verification is triggered multiple times, don't create a new deposit invoice if one already exists. This fixes a race condition where the rider pays the first invoice but the driver tracks the second (unpaid) quote, causing the payment to fail.
Fixes stale deposit state blocking new cross-mint rides. The guard in shareDepositInvoice() checks pendingDepositQuoteId != null to prevent duplicate invoices, but this field wasn't cleared on all ride-end paths. Added clearing to: cancelRide(), finishAndGoOnline(), cancelCurrentRide(), bridge claim failure/exception, completeRideInternal(), handleConfirmationTimeout(), and clearAcceptedOffer(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…reset - Wrap 18 sensitive log statements (preimage, paymentHash, escrowToken, secret) with BuildConfig.DEBUG checks to prevent partial secrets from appearing in release logcat - Add walletStorage.clearCounters() call in resetWallet() to prevent NUT-13 derivation desync when importing new mnemonic after reset
When restoring vehicles from backup, the addVehicle() logic forced the first vehicle to be primary (since list was empty after clear), while subsequent vehicles kept their backup isPrimary value. This caused multiple vehicles to be marked as primary. Added VehicleRepository.restoreFromBackup() that: - Bypasses addVehicle() to avoid the forced primary logic - Normalizes the primary flag to ensure exactly one vehicle is primary - Handles edge cases: no primary (make first primary), multiple primaries (keep only the first one marked) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ters Clears orphaned activeVehicleId after vehicle restore from another device, preventing incorrect "Last used" badge. Also deletes deprecated VehicleSyncAdapter and SavedLocationSyncAdapter (superseded by ProfileSyncAdapter). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Wire sound/vibration settings to DriverOnlineService, RiderActiveService, and RoadflareListenerService (Finding 1) - Keep "Ride cancelled" notification until next action (Finding 2) - Add driverOnlineStatus tracking to prevent duplicate RoadFlare notifications when DriverViewModel is active (Finding 3) - Make RoadFlare request notifications dismissible and auto-cancel on app resume (Finding 4) - Add notification permission check and request flow for RoadFlare alerts on Android 13+ (Finding 5) - Add RoadflareOnly status with proper notification text (Finding 6) - Route notifications to proper channels (RIDE_UPDATE, RIDE_CANCELLED) based on status type (Finding 7)
- Make DriverOnlineService authoritative for driverOnlineStatus - Set status in onStartCommand (closes race window with RoadflareListenerService) - Clear stale status in onCreate/onDestroy - Channel selection now checks alertStack.isNotEmpty() first - Chat and ride request alerts both route to CHANNEL_RIDE_REQUEST - Remove redundant ViewModel status updates (service is single source of truth)
Phase 3 notification refactor: - Add AlertType sealed interface for unified alert types - Add NotificationCoordinator for centralized status/alert management - Add NotificationTextProvider interface with driver/rider implementations - Wire services to use coordinator, eliminating ~150 lines of duplication - Preserve critical behaviors: status-driven clearing, NewRequest two-layer, priority regression fix (Cancelled is high-priority without alerts) Fix Roadflare-only race condition (Codex finding #1): - Add startRoadflareOnly() that sets ROADFLARE_ONLY immediately - Avoids race window where start() sets AVAILABLE then updateStatus() sets ROADFLARE_ONLY (~50-200ms window where requests were dropped) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add debug logging to Kind 3186 parsing (wrong recipient, expired, decrypt fail) - Add debug logging to NostrService.publishRoadflareKeyShare - Request key refresh when rider has no key (null) for a driver (rate-limited) - Refactor MainActivity RoadFlare handler logging Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When transitioning from ROADFLARE_ONLY to AVAILABLE via proceedGoOnline(), the service status was not being updated. The notification showed "RoadFlare only" while UI was AVAILABLE, and dedup logic in RoadflareListenerService failed (status still ROADFLARE_ONLY instead of AVAILABLE). Fix: Call DriverOnlineService.updateStatus(Available) in wasRoadflareOnly branch. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change card background from primaryContainer to surfaceVariant for better dark mode visibility on: - Driver: "Arrived at Pickup" screen - Rider: "Your driver has arrived" screen Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Reset RoadFlare on-ride status in completeRideInternal() so driver broadcasts ONLINE instead of ON_RIDE after completing a ride - Preserve pre-ride mode (ROADFLARE_ONLY vs AVAILABLE) and restore it when driver clicks "Stay Online" after ride completion - Clear stageBeforeRide in all cancellation paths to prevent stale mode restoration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug fixes (payment safety critical): - cancelRide(): Add timeout job cancellation before coroutine - cancelCurrentRide(): Add profile unsubscribe + escrow state clearing - performCancellationCleanup(): Add timeout + profile cleanup - handleConfirmationTimeout(): Add profile unsubscribe Quick wins: - Unify staleness threshold to 5 min (was 10 min in RiderModeScreen) - Add SoundManager overloads that take SettingsManager directly - Simplify 10 sound/vibration call sites in both services Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Keep availability subscription open through DRIVER_ACCEPTED stage until driver sends EN_ROUTE_PICKUP. This allows rider to detect if driver goes offline during the acceptance handshake window. Changes: - Remove early closeDriverAvailabilitySubscription() from confirmRide() and autoConfirmRide() - subscription now stays open - Add closeDriverAvailabilitySubscription() to EN_ROUTE_PICKUP handler when driver has acknowledged the ride - Add closeDriverAvailabilitySubscription() to handleDriverCancellation() to prevent subscription leaks - Extend availability callback to handle DRIVER_ACCEPTED stage and call handleDriverCancellation() when driver goes offline - Add DRIVER_ACCEPTED to cancellation subscription stage filter Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 ViewModel deduplication: Extract common patterns into reusable utilities in common/util/. PeriodicRefreshJob: Encapsulates periodic coroutine refresh pattern with proper lifecycle management (start/stop). Used for chat message polling. RideHistoryBuilder: Helper functions for ride history creation - extractCounterpartyFirstName(), toDistanceMiles(), currentTimestampSeconds(). Reduces duplication across 7 history creation sites. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move duplicated UI code from both apps into common module: - KeyBackupScreen.kt: Key backup display (moved from both apps) - ProfileSetupContent.kt: Profile editing form with wrapper pattern - OnboardingComponents.kt: KeySetupScreen, BackupReminderScreen - SettingsComponents.kt: SettingsSwitchRow, SettingsNavigationRow, SettingsActionRow The wrapper/content pattern allows app-specific ViewModels while sharing UI implementation. App screens now call common content composables with role-specific customization (e.g., "Tell drivers about yourself"). Saves ~735 lines of duplicated code across both apps. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ganization NostrService decomposition (35% reduction, 2893→1888 lines): - Extract NostrCryptoHelper (6 NIP-44 encryption methods) - Extract ProfileBackupService (profile, history, backup methods) - Extract RoadflareDomainService (16 RoadFlare methods) - All methods delegate to domain services for backward compatibility Payment code organization: - Extract CashuTokenCodec for stateless token encoding/decoding - Add region comments to CashuBackend (13 sections with HTLC invariants) - Add region comments to WalletService (11 sections with flow invariants) - Add correlation ID logging [RIDE xxxxxxxx] for payment tracing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update CONNECTIONS.md and RIDER_VIEWMODEL.md docs - Update rider-app README - Minor fix to PeriodicRefreshJob Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add NostrCryptoHelper, ProfileBackupService, RoadflareDomainService to Nostr Layer table - Add CashuTokenCodec to Payment System table - Add new domain service connections to Connections Table - Note region organization in WalletService and CashuBackend descriptions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- CONNECTIONS.md: Updated architecture diagram with domain services (NostrCryptoHelper, ProfileBackupService, RoadflareDomainService, CashuTokenCodec), added Phase 5 section header, updated Nostr Layer and Payment System dependency trees - PAYMENT_ARCHITECTURE.md: Added CashuTokenCodec to file structure, documented Phase 5 reorganization (region comments, correlation IDs), added Layer 1.5 CashuTokenCodec section - RIDER_VIEWMODEL.md: Added correlation ID logging to ride request flow - DRIVER_VIEWMODEL.md: Added correlation ID logging to completion flow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 83 unit tests for payment crypto (PaymentCrypto, CashuCrypto, CashuTokenCodec) - Configure Robolectric for Android-dependent test code - Add COMPATIBILITY_CONTRACTS.md documenting API stability requirements - Add PAYMENT_SAFETY.md with modification checklist and HTLC invariants - Document correlation ID design in PAYMENT_ARCHITECTURE.md Test files verify NUT-00 hash_to_curve, NUT-13 deterministic derivation, BIP-39 seed generation, token encoding round-trips, and HTLC secret parsing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace nullable return types with sealed classes for rich error information: - lockForRide() returns LockResult (Success/Failure variants) - claimHtlcPayment() returns HtlcClaimResult (Success/Failure variants) Failure variants include: NotConnected, InsufficientBalance, ProofsSpent, PreimageMismatch, MintRejected, and others with relevant context data. Updated callers in RiderViewModel and DriverViewModel to use exhaustive when expressions for proper error handling and logging. Added 22 unit tests for the new sealed classes (105 total tests pass). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MintApi interface to abstract HTTP transport for testability - Add OkHttpMintApi production implementation - Add HtlcSwapOutcome and HtlcClaimOutcome sealed classes to CashuBackend - Wire error variants: MintUnreachable, SwapRejected, TokenParseFailed, SignatureFailed, MintRejected - Update WalletService to map CashuBackend outcomes to WalletService result types - Add FakeMintApi for test injection - Add CashuBackendErrorTest with 26 tests covering all outcome types This enables proper error propagation (no more lost error context), test injection via FakeMintApi, and compile-time exhaustiveness checking. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add RelayManager.awaitConnected() to centralize the 15-second relay connection wait logic with optional logging tag - Refactor ProfileBackupService, RoadflareDomainService, NostrService, RemoteConfigManager to use awaitConnected() instead of duplicated loops - Update PAYMENT_ARCHITECTURE.md to reflect NUT-11 signature format (sign only secret, not secret+C) - Pass event kinds to deleteEvents() for proper NIP-09 deletion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HtlcClaimResult.Failure.MintUnreachable for network failures - Wire MintUnreachable in WalletService claimHtlcPayment() - Add CashuBackend.setTestState() and testActiveKeyset for test injection - Route verifyProofsBalance() through effectiveMintApi - Expand CashuBackendErrorTest with MockK integration tests - Add test dependencies: mockk, androidx.test.core, kotlinx-coroutines-test - Update documentation for Phase 6 test infrastructure (138 tests) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract Nip60Store interface from Nip60WalletSync to enable test injection for verifying proof safety invariants. The interface abstracts 11 NIP-60 operations used by WalletService. New test infrastructure: - FakeNip60Store: Test double with call log for order verification - MainDispatcherRule: JUnit rule for coroutine dispatcher override - ProofConservationTest: 10 contract tests for proof safety - FakeNip60StoreTest: 26 unit tests for the test double Key contracts verified: - Proofs remain retrievable until explicitly deleted - Republish-before-delete order invariant (prevents proof loss) - Failed publishes are counted for retry verification - Proof selection filters by mint URL (multi-mint safety) Total payment tests: 180 (all passing) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update test count from 138 to 181 tests across all docs - Add Nip60Store interface documentation (testable abstraction) - Add FakeNip60Store test double documentation - Add ProofConservationTest contract tests documentation - Add MainDispatcherRule for coroutine testing - Update per-file test counts to match actual values - Document publish-before-delete verification pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This branch adds the RoadFlare feature - a personal rideshare network where riders can build trusted relationships with specific drivers. Also includes major infrastructure improvements from Phase 5-6.
RoadFlare Feature
Phase 5: NostrService Domain Decomposition
NostrCryptoHelper.kt- NIP-44 encryption utilitiesProfileBackupService.kt- Profile and history backupRoadflareDomainService.kt- All RoadFlare Nostr methodsPhase 6: Payment Test Harness
FakeMintApi- Mock mint HTTP API with queue-based responsesFakeNip60Store- Mock NIP-60 storage with call ordering verificationNip60Storeinterface for testable NIP-60 operationsCashuTokenCodecextraction for stateless token operationsSecurity Hardening
Stability Fixes
Other Improvements
Test plan
./gradlew testStats
🤖 Generated with Claude Code