Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
13215f6
feat: add peer browser model
rchatham Aug 8, 2026
d249d9a
feat(demo): exercise Network peer browser flow
rchatham Aug 9, 2026
ebc2226
docs(demo): document Network manual invite usage
rchatham Aug 9, 2026
cbd19d3
docs: defer reusable Network browser UI
rchatham Aug 9, 2026
9823363
docs: define Network stream and resource parity boundary
rchatham Aug 9, 2026
eb9fb0f
docs(security): define Network peer trust roadmap
rchatham Aug 9, 2026
ad86cb5
docs: document Network production setup
rchatham Aug 9, 2026
2eece7f
docs: add Network migration readiness audit
rchatham Aug 9, 2026
b99995f
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 9, 2026
a245daf
Merge remote-tracking branch 'origin/feature/network-migration-browse…
rchatham Aug 9, 2026
88bf5f9
docs(demo): refresh integrated Network walkthrough
rchatham Aug 9, 2026
fb0c2a9
Merge remote-tracking branch 'origin/feature/network-migration-demo-n…
rchatham Aug 9, 2026
e51a905
Merge remote-tracking branch 'origin/feature/network-migration-browse…
rchatham Aug 9, 2026
0c5aa9f
Merge remote-tracking branch 'origin/feature/network-migration-parity…
rchatham Aug 9, 2026
c689c94
Merge remote-tracking branch 'origin/feature/network-migration-trust-…
rchatham Aug 9, 2026
99566f3
Merge remote-tracking branch 'origin/feature/network-migration-local-…
rchatham Aug 9, 2026
5f8ac74
feat(demo): select connection invitation behavior
rchatham Aug 10, 2026
74fb918
Merge remote-tracking branch 'origin/feature/network-migration-demo-n…
rchatham Aug 10, 2026
51c4675
Merge remote-tracking branch 'origin/feature/network-migration-browse…
rchatham Aug 10, 2026
dedf857
Merge remote-tracking branch 'origin/feature/network-migration-parity…
rchatham Aug 10, 2026
97ab620
Merge remote-tracking branch 'origin/feature/network-migration-trust-…
rchatham Aug 10, 2026
cdb3b1d
Merge remote-tracking branch 'origin/feature/network-migration-local-…
rchatham Aug 10, 2026
51732c0
Merge pull request #50 from rchatham/feature/network-migration-readin…
rchatham Aug 10, 2026
4bd6e86
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 11, 2026
b7cf857
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 13, 2026
c9cd290
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 13, 2026
bd2fa6f
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 14, 2026
33a2b83
fix: serialize browser model observation lifecycle
rchatham Aug 14, 2026
f463d1e
Merge remote-tracking branch 'origin/feature/network-migration-networ…
rchatham Aug 14, 2026
14d6f70
fix: clear browser peers when observation stops
rchatham Aug 14, 2026
1f431b9
fix: avoid replaying stale connection events
rchatham Aug 14, 2026
0d2cca9
fix: use one demo discovery state source
rchatham Aug 14, 2026
2a0e55a
docs: note forward-only event listeners
rchatham Aug 14, 2026
b4cb016
merge: integrate PR58 TLS and identifier hardening
rchatham Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Artifacts/peer-browser-network-demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- New: `PeerConnectivityUI` browser peer filtering with discovery metadata
- Compatibility: `foundPeer` remains emitted alongside `foundPeerWithDiscoveryInfo`, so listeners should handle one discovery event to avoid processing the same peer twice
- Compatibility: automatic non-manual invitation policies still emit `.receivedInvitation` for observation, but the event handler is a no-op and policy decisions remain authoritative
- Compatibility: listener registration now observes future connection events only instead of replaying the responder's most recently stored event; state-oriented internal observables still replay their current value
- Packaging: the core target now links both Network.framework and MultipeerConnectivity.framework
- Tooling: the Swift package manifest uses Swift tools 6.0, so SwiftPM consumers need a Swift 6 toolchain (Xcode 16 or newer); the library remains compiled in Swift 5 language mode
- Platforms: the minimum supported versions increase to iOS 13 and macOS 10.15; CocoaPods consumers need an Xcode version with those platform SDKs (Xcode 11 or newer)
Expand Down
170 changes: 126 additions & 44 deletions NetworkBackendGuide.md

Large diffs are not rendered by default.

86 changes: 42 additions & 44 deletions NetworkFrameworkMigrationPlan.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Begin migrating PeerConnectivity away from direct MultipeerConnectivity dependence toward Apple's Network framework while preserving public API compatibility where practical.

> Status: this is the original staged architecture plan. The Network backend is now implemented as an experimental opt-in. Use [NetworkMigrationReadinessAudit.md](NetworkMigrationReadinessAudit.md) for the authoritative checklist governing stable status, a default switch, and MultipeerConnectivity removal.

> Note: the iOS 27 MultipeerConnectivity deprecation claim has not yet been verified against Apple SDK headers or release notes. Treat Network framework migration as proactive risk reduction until confirmed.

## Current State
Expand Down Expand Up @@ -56,9 +58,9 @@ Most public event types are already framework-neutral, which makes an incrementa
| `MCSessionState` / `Peer.Status` | `NWConnection.State` mapping | Must define how `.setup`, `.waiting`, `.preparing`, `.ready`, `.failed`, and `.cancelled` map to existing public statuses/events. |
| `MCPeerID` | New framework-neutral peer identity | Must preserve display name and stable equality semantics. |
| `MCSession.send` | `NWConnection.send` + message framing | Network does not preserve message boundaries automatically. |
| Resource transfer | Custom protocol over `NWConnection` | Later slice; potentially file chunks/progress messages. |
| Stream transfer | Custom stream abstraction or compatibility shim | Later slice; no one-to-one replacement. |
| `MCBrowserViewController` | Custom PeerConnectivityUI browser | Required for UI package. |
| Resource transfer | No Network replacement in the current migration | `sendResourceAtURL` and resource receive events remain MultipeerConnectivity-only. |
| Stream transfer | No Network replacement in the current migration | `sendDataStream` and stream receive events remain MultipeerConnectivity-only. |
| `MCBrowserViewController` | `PeerBrowserModel` + app-owned UI | Reusable PeerConnectivityUI replacement deferred pending app validation. |

Relevant Network framework APIs:

Expand All @@ -78,7 +80,7 @@ Relevant Network framework APIs:
- `NSBonjourServices`
- Network framework is connection-oriented, not an `MCSession`-style symmetric mesh abstraction.
- Peer-to-peer Wi-Fi/Bluetooth/AWDL behavior requires `NWParameters.includePeerToPeer = true` and on-device testing.
- Network-backed transports must keep TLS enabled before any public backend selection is exposed; peer identities remain self-asserted until a later authentication/trust model binds them to TLS identity or app-provided verification.
- Network external-PSK transport pins both its minimum and maximum to TLS 1.2 with no fallback to another TLS version or plaintext. It authenticates shared-key group membership, not an individual peer. Peer identities remain self-asserted until the [Network trust model plan](NetworkTrustModelPlan.md) binds them to pairwise key material, a certificate/pinned key, a signed credential, or app-provided verification.
- Network coordinator state must be serialized and bounded; current wiring keeps handshake timeout and connection caps internal until defaults are validated across CI and device testing. Discovery caps and idle timeouts remain production-hardening follow-ups before accepting untrusted inbound traffic at scale.
- Public `multipeerSession: MCSession` prevents completely removing MultipeerConnectivity without a breaking API change; a source-compatible transition release requires dual backend support.
- `MCBrowserViewController` has no Network framework equivalent.
Expand Down Expand Up @@ -160,23 +162,28 @@ Acceptance criteria:
- Data send/receive works for JSON `PeerMessage` payloads.
- Connection state changes map to existing PeerConnectivity events.

### Phase 4 — Feature parity for data/resource/stream APIs
### Phase 4 — Reliable data parity and unsupported API decision

Objective: preserve current PeerConnectivity capabilities where possible.
Objective: preserve reliable data/message behavior while explicitly bounding the current Network backend.

Tasks:
Decision:

- Implement reliable `Data` and `PeerMessage` send parity.
- Keep `sendDataStream` and `sendResourceAtURL` source-compatible and supported by the MultipeerConnectivity backend.
- Do not implement a custom Network stream or resource-transfer protocol in this migration stack.
- Keep `.receivedStream`, `.startedReceivingResource`, and `.finishedReceivingResource` available for MultipeerConnectivity; the Network backend does not emit them.
- Treat a future Network-native file or streaming protocol as separately scoped work, not as a blocker for the current migration.

1. Implement reliable data send parity.
2. Decide whether unreliable send can be supported or should become best-effort over TCP/TLS.
3. Implement resource transfer protocol with chunking and progress reporting.
4. Evaluate stream API compatibility and document limitations.
5. Add protocol-version negotiation for future compatibility.
Rationale:

Network framework has no one-to-one replacement for these MultipeerConnectivity APIs. Emulation would introduce new framing, flow-control, progress, cancellation, persistence, and protocol-versioning contracts beyond the reliable message transport targeted by this migration.

Acceptance criteria:

- Existing public send APIs either work or have documented migration/deprecation path.
- Resource transfer has tests for success, failure, and progress callbacks.
- Any unsupported MC behavior is explicitly documented.
- Reliable data and typed message APIs work on both backends.
- Network calls to unsupported send APIs fail explicitly with documented behavior.
- Documentation directs stream/resource consumers to remain on `.multipeerConnectivity`.
- Unsupported receive events are documented as MultipeerConnectivity-only.

### Phase 5 — Public API migration and deprecations

Expand All @@ -185,7 +192,7 @@ Objective: guide consumers away from MC-specific API.
Tasks:

1. Add framework-neutral public accessors where needed.
2. Deprecate `multipeerSession: MCSession` if retaining it blocks Network-backed operation.
2. Deprecate `multipeerSession: MCSession` if retaining it blocks Network-backed operation. Do not deprecate stream/resource APIs solely because they are MultipeerConnectivity-only; they remain valid on that backend.
3. Add initializer/configuration to choose `.multipeerConnectivity` vs `.networkFramework` backend for a non-breaking transition release.
4. Decide whether already-deprecated `sendEvent(_:toPeers:)` and related legacy event observation APIs are removed in a major-version migration or retained through adapters.
5. Document deployment target changes and Info.plist requirements.
Expand All @@ -197,22 +204,22 @@ Acceptance criteria:
- MC-specific public API is marked deprecated before removal.
- Migration guide explains breaking changes and fallback behavior.

### Phase 6 — PeerConnectivityUI replacement
### Phase 6 — App-owned browser UI foundation

Objective: replace `MCBrowserViewController` usage.
Objective: support Network peer selection without prematurely standardizing reusable UI behavior.

Tasks:
Decision:

1. Build a custom browser UI backed by framework-neutral discovery events.
2. Rework `PeerConnectionManager+UI.swift` so browser UI no longer requires direct `multipeerSession` access for Network-backed managers.
3. Preserve existing PeerConnectivityUI product structure.
4. Add iOS-only tests where feasible.
5. Deprecate or remove MC browser assistant after replacement exists.
- Use the framework-neutral `PeerBrowserModel` as the supported replacement foundation for Network-backed apps.
- Keep rendering, selection, cancellation, progress, errors, accessibility, and presentation app-owned.
- Preserve the existing `MCBrowserViewController` path for the MultipeerConnectivity backend.
- Defer a reusable SwiftUI or UIKit browser until app integrations establish common requirements.

Acceptance criteria:

- UI package no longer depends on `MCBrowserViewController` for Network backend.
- Existing apps can browse/select peers with Network implementation.
- Network-backed apps can observe discovered peers and connection status, then invite an app-approved peer through `PeerBrowserModel`.
- Documentation includes an app-owned UI example and clearly states that reusable browser UI is deferred.
- No default backend or MultipeerConnectivity browser behavior changes.

## Testing Plan

Expand Down Expand Up @@ -252,23 +259,14 @@ xcodebuild test -workspace PeerConnectivity.xcworkspace \
- Backend selection/deprecation notes.
- Known limitations vs MultipeerConnectivity.

## Open Questions
## Resolved decisions and remaining gates

1. Should Network framework be introduced as an opt-in backend first, or should it replace MC internally once stable?
2. What is the minimum supported OS after migration?
3. Is preserving `multipeerSession: MCSession` required for a transition release?
4. Should unreliable send semantics be preserved, deprecated, or documented as best-effort?
5. Is stream/resource transfer heavily used by consumers, or can those APIs be deprecated?
6. What service type naming convention should be required for Bonjour compatibility?
7. What authentication model should be default: no TLS identity, PSK, certificate identity, or app-provided verifier?
8. When should Network connection policy values become public configuration instead of fixed internal defaults?

## Immediate Next Step

Implement Phase 1's transport seam and mock-backed tests in this branch:

```text
feature/network-framework-migration
```
- Network was introduced as an explicit opt-in; MultipeerConnectivity remains the default.
- Minimum deployment targets are iOS 13 and macOS 10.15.
- `multipeerSession` remains available during dual-backend transition and must be deprecated before MC removal.
- Bare service types map to `_<service>._tcp`; already-qualified TCP Bonjour types are preserved.
- Stream/resource parity is intentionally outside this migration stack; those APIs remain MC-only.
- Connection policy remains fixed/internal until device and load evidence demonstrates a need for public tuning.
- Individual peer authentication remains unresolved and is required before stable/default status.

Keep this first commit behavior-preserving and small so later Network framework work can build on a stable abstraction layer.
The next work is not another unconditional migration phase. Select follow-ups according to [NetworkMigrationReadinessAudit.md](NetworkMigrationReadinessAudit.md): security identity, error observability, resource bounds, and physical-device evidence come before stable status; default switching and MC removal have later, separate gates.
43 changes: 31 additions & 12 deletions NetworkMigrationPRPlan.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@ Acceptance criteria:
- Complete bidirectional reliable data parity for `PeerMessage` use cases.
- Add handshake timeout, idle timeout, connection caps, and discovery caps.
- Keep policy values internal until their defaults are validated across CI and device testing.
- Keep TLS enabled and add app-configurable identity or PSK verification before public Network use.
- Keep TLS enabled. Treat TLS-PSK as group-membership authentication only, and follow [NetworkTrustModelPlan.md](NetworkTrustModelPlan.md) before claiming individual peer identity.
- Add malformed-frame, oversized-frame, timeout, and cap tests.

### PR 6: Public API migration and deprecations

- Add framework-neutral public accessors where MC types currently leak through.
- Deprecate MC-specific APIs that block a complete migration, including `multipeerSession`, stream APIs, resource APIs, and browser-controller APIs where needed.
- Deprecate MC-specific APIs only where they block source-compatible Network-backed operation, such as `multipeerSession` or browser-controller APIs where needed.
- Keep `sendDataStream`, `sendResourceAtURL`, and their receive events available for MultipeerConnectivity consumers; document them as unsupported by the current Network backend rather than deprecating them.
- Document replacement paths and compatibility behavior.

### PR 7: Simplification/refactor pass
Expand All @@ -80,35 +81,53 @@ Acceptance criteria:
- Require a clear justification for any new layer that remains.
- Prefer net LOC reduction unless tests or docs intentionally increase coverage.

### PR 8: SwiftUI browser replacement
### PR 8: App-owned browser UI foundation

- Add `PeerBrowserView` and `PeerBrowserModel` driven by framework-neutral discovery and connection events.
- Use SwiftUI as the primary browser implementation.
- Provide UIKit bridging through `UIHostingController` or representable wrappers where compatibility requires it.
- Retain and deprecate old `MCBrowserViewController`-specific paths as compatibility shims only.
- Add SwiftUI/UI tests for peer listing, selection, cancellation, and connection state updates.
- Use `PeerBrowserModel`, driven by framework-neutral discovery and connection events, as the supported Network browser foundation.
- Document a concise integration pattern for app-owned peer lists and approval flows.
- Defer a reusable `PeerBrowserView` and UIKit bridge until app integrations establish shared requirements.
- Retain the existing `MCBrowserViewController` path for the MultipeerConnectivity backend.
- Do not change the default backend or add transport/trust behavior in this UI decision.

### PR 9: End-to-end automation and UI testing
### PR 9: End-to-end automation and demo testing

- Add a loopback/local integration harness where possible.
- Add XCUITest coverage for the SwiftUI browser and demo app smoke paths.
- Add UI smoke coverage for the demo's app-owned browser flow when stable automation is practical.
- Add CI automation for stable smoke tests.
- Document manual device checks for Bonjour and Local Network privacy prompts.

### PR 10: Docs and release prep

- Update README, migration guide, Info.plist notes, backend-selection docs, and CHANGELOG.
- Document unsupported or deprecated MC-specific APIs.
- Record the current parity boundary: Network supports reliable `Data`/`PeerMessage` transport, while stream/resource send APIs and receive events remain MultipeerConnectivity-only.
- Prepare versioning notes for the deployment-target bump and Network backend opt-in.

### Final planned PR: migration readiness audit

- Reconcile the implemented stack, accepted non-parity, and remaining production evidence.
- Define separate gates for stable opt-in, default-backend selection, and MultipeerConnectivity removal.
- Classify optional follow-ups by the first readiness level that requires them.
- Record release/versioning constraints and a risk register without changing runtime behavior.

The resulting [NetworkMigrationReadinessAudit.md](NetworkMigrationReadinessAudit.md) is authoritative when this historical sequencing plan and the implemented stack differ. It confirms that no optional implementation is needed to merge the experimental opt-in stack, while individual authentication, error observability, resource bounds, and physical-device evidence are required before stable status.

### Future security slice: individual peer identity

- Select one trust mode from [NetworkTrustModelPlan.md](NetworkTrustModelPlan.md) only after focused security and platform review.
- Keep authenticated principal, stable transport identifier, and mutable display name distinct.
- Bind the accepted principal to the connection before connected/data events or duplicate resolution trust that identity.
- Add spoofing, mismatch, replay, revocation, downgrade, and verifier-failure tests in the same implementation PR.
- Do not combine this work with a default-backend change or a general public policy API.

## Required Security Gates

Security review is mandatory for PRs that change:

- Network listener/connection setup.
- TLS identity, PSK, trust evaluation, or handshake payloads.
- Untrusted input parsing, frame decoding, or peer identity validation.
- SwiftUI browser input, peer selection, or invite flows.
- Reusable browser input, peer selection, or invite flows.
- Public backend selection or default backend behavior.

Before the Network backend is publicly selectable, peer authentication must be explicit rather than relying on self-asserted display names or unauthenticated handshakes.
The Network backend is already publicly selectable as an experimental opt-in. Before it is described as production-ready or made the default, individual peer authentication must be explicit rather than relying on a group PSK, self-asserted display names, or unauthenticated handshakes; follow the gates in [NetworkTrustModelPlan.md](NetworkTrustModelPlan.md).
Loading
Loading