feat: PR2 — provider integration, invariants, fallback reconnect gating#6
Open
mrmidi wants to merge 1 commit into
Open
feat: PR2 — provider integration, invariants, fallback reconnect gating#6mrmidi wants to merge 1 commit into
mrmidi wants to merge 1 commit into
Conversation
mrmidi
force-pushed
the
pr2/provider-integration
branch
4 times, most recently
from
July 21, 2026 06:08
99308c4 to
a74e27f
Compare
Provider invariants: - ProviderInvariant enum (bridgeReplacementOverlap, multipleNativeClients, incompleteNativeTeardown). Logged once per type via logInvariantOnce(). - replaceWebSocketClient checks for overlap and incomplete teardown. - No manual activeBridgeCount — uses existing native status fields. Generation ownership for pending reads: - pendingReadGeneration captured when calling readPackets. - Stale batch (old generation) dropped after reconnect instead of being sent through the new bridge. Final native status preservation: - lastNativeStatus / lastNativeStatusGeneration stored before detaching a client. currentSnapshot() falls back to saved status when no live client is attached. currentSnapshot() outside lock: - Swift fields copied under stateLock, bridge reference copied, lock released, then native status queried outside the lock. TunnelRuntimeSnapshot enrichment: - All PR1A–1C native fields: socket buffers, lifecycle counters, queue diagnostics, disconnect code/origin, active operations, stop cleanup status. Stop-origin plumbing: - replaceWebSocketClient accepts stopOrigin parameter (default .swiftTunnelStop). All call sites use correct origin. VPNService fallback reconnect: - Cancellable Task replaces boolean guard. Cancelled on connected/connecting/reasserting/disconnect(). - FallbackReconnectDecision: doNotReconnect / reconnectNow / recheckAfter(seconds). Fresh heartbeat (< 45s) defers recheck. - Rechecks NE status after sleeping. - Budget off-by-one fixed: check before decrement, N allows N attempts. Tests: 24/24 passed. Debug build succeeded.
mrmidi
force-pushed
the
pr2/provider-integration
branch
from
July 21, 2026 06:43
a74e27f to
6bf7e82
Compare
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.
PR2 — Wrapper/Provider Integration
Base:
pr1c/teardown-ownership(stacked PR chain)Files: 6 — 468+/63-
Provider invariants
ProviderInvariantenum:multipleNativeClients,incompleteNativeTeardownlogInvariantOnce()Bridge lifecycle safety
replaceWebSocketClientreturnsBool, acceptsexpectedGenerationWebsocketClientBridgehas one-shot lifecycle latch (created→started→stopped)stop()wins,start()is permanently rejected — no resurrectionstartWebSocketusesstopCurrent: true, stopOrigin: .swiftReconnectPacket read ownership
PacketReadToken(session:generation:)with process-lifetimetunnelSessionpendingReadToken == nilguard)stopTunneldoes NOT clear pending-read stateFinal native status preservation
lastNativeStatuscaptured AFTER stop/join (not before)currentSnapshot()queries native status outsidestateLockTunnelRuntimeSnapshot — all PR1A–1C fields
16 new fields: socket buffers, lifecycle counters, queue diagnostics, disconnect code/origin, active operations, stop cleanup status
VPNService fallback reconnect
Task<Void, Never>?(cancelled on connected/connecting/reasserting/disconnect)FallbackReconnectDecision: doNotReconnect / reconnectNow / recheckAfterlocalStopInitiator,nativeDisconnectCode,nativeStopOrigin)app_disconnect,system_stop)Heartbeat typed fields
Optional backward-compatible fields on
TunnelProviderHeartbeat. Old persisted heartbeats still decode.Verification
Stack