Integrate live phone and watch remote prototype with guarded motion control
This commit is contained in:
+10
-3
@@ -1,12 +1,12 @@
|
||||
# Command contract v1
|
||||
|
||||
Source of truth: `Packages/WristivoKit/Sources/RemoteCore`, including `WatchSession.swift`. The integration owner maintains these types. The v1 control-plane DTOs, codec and actor protocol are now defined. WCSession delivery and the production phone actor are still to be implemented; protocol definitions are not a functioning handshake.
|
||||
Source of truth: `Packages/WristivoKit/Sources/RemoteCore`, including `WatchSession.swift`. The integration owner maintains these types. The v1 control-plane DTOs, codec and actor protocol are now defined. WCSession delivery and the production phone actor are integrated. Handshake behavior is covered by fake-session tests; real paired-device delivery is pending.
|
||||
|
||||
## Commands and envelope
|
||||
|
||||
`RemoteCommand`: up, down, left, right, select, back, home, playPause, volumeUp, volumeDown, mute. Wire values are the enum's raw strings. Unknown values fail decoding. No raw arbitrary Samsung keys from UI or watch.
|
||||
|
||||
`CommandEnvelope`: `schemaVersion` (1), `id` (UUID), `sessionID` (UUID), `televisionID` (UUID), `sequence` (UInt64), `issuedAt` (Date), `expiresAt` (Date), `command`. UUIDs identify local opaque records, not TV serial numbers or network addresses. Date encoding on the future bridge is explicitly JSON milliseconds since Unix epoch; both encoders/decoders must set the same strategy. Package round-trip tests alone are not sufficient to validate that adapter.
|
||||
`CommandEnvelope`: `schemaVersion` (1), `id` (UUID), `sessionID` (UUID), `televisionID` (UUID), `sequence` (UInt64), `issuedAt` (Date), `expiresAt` (Date), `command`. UUIDs identify local opaque records, not TV serial numbers or network addresses. Date encoding on the bridge is explicitly JSON milliseconds since Unix epoch; both encoders/decoders must set the same strategy. Package round-trip tests alone are not sufficient to validate that adapter.
|
||||
|
||||
A session is issued by the phone for one selected paired TV, bound to the currently activated paired WCSession. The watch cannot select an arbitrary target by manufacturing an envelope. `BeginRemoteSessionRequest` returns `RemoteSessionGrant` with v1, sessionID, televisionID, issuedAt and maximumCommandLifetimeMilliseconds (1...1000); `EndRemoteSessionRequest` ends that exact session and returns `RemoteSessionEnded`. Errors use `RelayFailure`, which conforms to Error for Result return values. A new phone process, TV switch, re-pair, bridge deactivation or app stop invalidates old authorization. Starting a session must never issue a TV key.
|
||||
|
||||
@@ -30,8 +30,15 @@ Existing `RemoteTransport.send(_ envelope: CommandEnvelope) async -> CommandRece
|
||||
|
||||
The local `WatchPeerGeneration` is a fresh UUID per phone-side bridge activation. It is not Codable and must not cross the wire, persist, identify watch hardware, or come from the remote message. B serializes lifecycle delivery, awaits activation before forwarding requests, and passes the captured generation on every call. The phone actor rejects requests from non-current peers and ignores delayed deactivation for old peers. Repeated activation of the same peer is idempotent; activating a new peer invalidates previous grants. Repeated begin requests create fresh sessions and invalidate the previous session; B must serialize starts and ignore delayed replies after a lifecycle or local request-generation change. Stale end requests return sessionInvalidated and never end a newer session. After every suspension, the actor rechecks generation/session/target/deadline before sending. A protocol cannot enforce these semantics; A's tests must prove them.
|
||||
|
||||
GestureCore receives normalized inputs from the future MotionCapture adapter. Its thresholds are algorithm fixtures, not physically calibrated degrees or validated human-motion confidence. Sensor coordinate transforms and physical traces are required before claiming wrist-swipe recognition. Watch and phone UI depend on domain contracts, never Samsung frame strings.
|
||||
GestureCore receives normalized rotation-rate inputs from the MotionCapture adapter. Its thresholds are algorithm fixtures, not physically calibrated degrees or validated human-motion confidence. Sensor coordinate transforms and physical traces are required before claiming wrist-swipe recognition. Watch and phone UI depend on domain contracts, never Samsung frame strings.
|
||||
|
||||
## Compatibility change policy
|
||||
|
||||
An additive optional field may remain v1 only if existing behavior stays safe. New command semantics, changed time units or altered authorization require a new schema version and explicit negotiation. Unsupported versions fail closed. Mixed-version phone/watch installations must show update guidance and preserve accessible phone control.
|
||||
|
||||
|
||||
## Integration decision — 2026-09-18
|
||||
|
||||
PhoneControl composes one TVConnectionActor with KeychainTVAuthorizationStore. `sendPhoneCommand` creates a local envelope; watch envelopes enter through `submitWatchCommand`. Separate local/watch session counters feed a single actor-owned drain, with exactly one admission consumption per command. Phone actions do not replace the watch grant. Peer replacement or grant rotation during an active write closes the ambiguous socket; reconnect is explicit and never replays.
|
||||
|
||||
Configuration context now includes `isConnectionReady: Bool` (default false when absent) alongside the optional opaque ID/name. It never contains hostnames, certificates, tokens or commands. Old receivers that reject this additive key fail closed; deploy matching prototype phone/watch builds. A context snapshot is advisory, not authority: the phone actor still issues and validates every grant.
|
||||
|
||||
Reference in New Issue
Block a user