mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-07 11:19:58 +02:00
docs(design): specify delivery when the recipient is not running
Sender-held offers with a bounded foreground pull instead of push infrastructure. Records that APNs is out of scope and that mobile-to-mobile with both apps closed is unsupported.
This commit is contained in:
@@ -25,8 +25,9 @@ Local network discovery was considered and deliberately dropped. See
|
|||||||
### Non-goals
|
### Non-goals
|
||||||
|
|
||||||
- No automatic acceptance of transfers, under any configuration.
|
- No automatic acceptance of transfers, under any configuration.
|
||||||
- No store-and-forward: an offer to an unreachable device fails; nothing is
|
- No server-side store-and-forward and no push infrastructure. An offer to an
|
||||||
queued and nothing is uploaded anywhere.
|
unreachable device is held **on the sender's own device** or fails; nothing is
|
||||||
|
uploaded anywhere. See §11 for what this means in practice.
|
||||||
- No presence or "who is online" indicator. Knowing it requires probing, and
|
- No presence or "who is online" indicator. Knowing it requires probing, and
|
||||||
probing tells every contact when you opened your list. Reachability is
|
probing tells every contact when you opened your list. Reachability is
|
||||||
resolved lazily, at send time.
|
resolved lazily, at send time.
|
||||||
@@ -237,7 +238,8 @@ plainly rather than presenting an opaque failure. Local-only users in particular
|
|||||||
should be told that contacts depend on a cached address.
|
should be told that contacts depend on a cached address.
|
||||||
|
|
||||||
Reachability is never polled in the background. It is determined when the user
|
Reachability is never polled in the background. It is determined when the user
|
||||||
actually sends.
|
actually sends — and, for incoming offers, when the app next comes to the
|
||||||
|
foreground (§11).
|
||||||
|
|
||||||
### 5.1 Identity lifetime
|
### 5.1 Identity lifetime
|
||||||
|
|
||||||
@@ -329,6 +331,9 @@ No new OS permissions, entitlements, or platform bridges are required.
|
|||||||
cleanly and reports an actionable error, rather than hanging.
|
cleanly and reports an actionable error, rather than hanging.
|
||||||
- **Persistence:** grants and contacts survive a core shutdown and reopen of the
|
- **Persistence:** grants and contacts survive a core shutdown and reopen of the
|
||||||
same data dir, following the existing recovery-test pattern.
|
same data dir, following the existing recovery-test pattern.
|
||||||
|
- **Sender-held offers (§11):** an offer to an unreachable contact is retained,
|
||||||
|
is cancellable, is collected on the receiver's next pull, and is not
|
||||||
|
double-delivered if the receiver pulls twice.
|
||||||
- Per `AGENTS.md`, any bug found gets a regression test at the lowest layer.
|
- Per `AGENTS.md`, any bug found gets a regression test at the lowest layer.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -352,6 +357,67 @@ with their rationale so the reasoning is not lost.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 11. Delivery when the recipient is not running
|
||||||
|
|
||||||
|
An offer is a live connection to a running app. This section states plainly what
|
||||||
|
that costs and how far it is mitigated.
|
||||||
|
|
||||||
|
### 11.1 The constraint
|
||||||
|
|
||||||
|
Notifying the user is not the problem — `LocalNotificationService` and the
|
||||||
|
existing `ApprovalCoordinator` already turn an incoming approval request into a
|
||||||
|
user-visible prompt, and an incoming offer reuses that path unchanged.
|
||||||
|
|
||||||
|
*Receiving* the request is the problem. `BackgroundActivityController` holds an
|
||||||
|
iOS background assertion only while there is active work and releases it as soon
|
||||||
|
as that drains, so a suspended app has no listening socket: the sender's dial
|
||||||
|
fails and there is nothing to notify about.
|
||||||
|
|
||||||
|
Waking a suspended iOS app from the network requires a remote push through APNs,
|
||||||
|
which means a server holding device tokens and observing who contacts whom. That
|
||||||
|
is infrastructure plus a metadata leak, both of which contradict the product's
|
||||||
|
no-cloud posture. **APNs is out of scope.** (This is also why AirDrop can do it
|
||||||
|
and a third-party app cannot: AirDrop is an OS daemon, not an app.)
|
||||||
|
|
||||||
|
### 11.2 Sender-held offers with a foreground pull
|
||||||
|
|
||||||
|
When the target is unreachable, the sender holds the offer **locally** — the
|
||||||
|
share stays on the sender's disk exactly as today, with no copy anywhere else —
|
||||||
|
and the receiver collects it when its app next comes to the foreground, raising
|
||||||
|
a local notification at that point.
|
||||||
|
|
||||||
|
Resulting coverage:
|
||||||
|
|
||||||
|
| Scenario | Result |
|
||||||
|
|---|---|
|
||||||
|
| Phone → always-on desktop | Immediate; the desktop is listening |
|
||||||
|
| Desktop → phone, app closed | Delivered on the phone's next launch |
|
||||||
|
| Phone → phone, both apps closed | **Not supported** |
|
||||||
|
|
||||||
|
Desktop platforms are unaffected by any of this and are always reachable while
|
||||||
|
the app runs.
|
||||||
|
|
||||||
|
### 11.3 The presence cost of pulling
|
||||||
|
|
||||||
|
Dialing contacts on launch tells them when the app was opened and reveals the
|
||||||
|
device's address to them — precisely the leak §1 avoids by refusing background
|
||||||
|
presence polling. The pull is therefore bounded rather than automatic:
|
||||||
|
|
||||||
|
- It runs only for contacts the user has explicitly marked as allowed to be
|
||||||
|
checked, or on an explicit "check for incoming" action.
|
||||||
|
- It never runs in the background, only on an actual foreground transition.
|
||||||
|
- It is rate-limited per contact, so repeated app switching does not turn into a
|
||||||
|
presence beacon.
|
||||||
|
|
||||||
|
### 11.4 Scope statement for the UI
|
||||||
|
|
||||||
|
Mobile-to-mobile transfer with both apps closed is not supported and must not be
|
||||||
|
implied. The contact list distinguishes "reachable now" from "will be delivered
|
||||||
|
when they next open VniDrop", and an offer awaiting pickup is visible and
|
||||||
|
cancellable on the sender's side.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Appendix A — Deferred: local network discovery
|
## Appendix A — Deferred: local network discovery
|
||||||
|
|
||||||
An earlier draft specified AirDrop-style discovery: three visibility tiers
|
An earlier draft specified AirDrop-style discovery: three visibility tiers
|
||||||
|
|||||||
Reference in New Issue
Block a user