32 lines
4.8 KiB
Markdown
32 lines
4.8 KiB
Markdown
# Command contract v1
|
|
|
|
Source of truth: `Packages/WristivoKit/Sources/RemoteCore`. The integration owner maintains these types. This document defines production adapter behavior in addition to the foundation types; the scaffold does not yet implement the relay/session handshake.
|
|
|
|
## 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.
|
|
|
|
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. Proposed control-plane operations: `beginSession` returns v1, sessionID, televisionID and expiry policy; `endSession` invalidates that exact session; a new phone process, TV switch, re-pair, bridge deactivation or app stop invalidates old authorization. Add typed control-plane DTOs under integration ownership before transport implementation. Starting a session must never issue a TV key.
|
|
|
|
Sequence starts at 0 or 1 and strictly increases within a session; all senders in a given session must share one counter. At UInt64 exhaustion start a new session rather than wrapping. The receiver rejects wrong target/session/version, invalid/non-finite times, future timestamps beyond 250 ms, messages over one second old, expiry in the past, expiry preceding issue, or a declared lifetime longer than one second. No arbitrary clock-skew widening: report need to resync/start a new session. Test actual paired-device skew. Adapter also maintains a receiver-local monotonic deadline so wall-clock changes cannot extend pending work.
|
|
|
|
Validate decoded values at every trust boundary; Codable construction alone does not validate invariants. The bridge performs structural validation only and delegates to one authoritative phone command actor. Only that actor consumes CommandAdmission state and owns the authorized session; duplicate checks must not advance a second gate in the bridge. Admit each ID once with bounded storage and monotonic sequence. Consume admission before sending; on ambiguous transport failure do not retry the same action. Check expiry/session again immediately before the live WebSocket send; reject pending work on disconnect, never reconnect-and-flush.
|
|
|
|
## Receipt semantics
|
|
|
|
`CommandReceipt` correlates the envelope ID. Status is sentToTransport, rejected, expired, duplicate or unavailable. A successful send only means the adapter completed the socket write; Samsung may provide no per-key execution acknowledgement. Never display "TV confirmed" based only on that receipt. Timeout after possible delivery is uncertain; ask the user to issue a new action if needed rather than replaying.
|
|
|
|
Planned bridge container: `["schemaVersion": 1, "kind": "command", "payload": Data]` with bounded JSON payload (4 KiB maximum), delivered using sendMessage/replyHandler. Validate container types and payload size before decoding. Reply uses the same versioned container with kind `receipt`. Exactly one reply per incoming request, including errors. No passwords/tokens/raw motion in these messages. Test Codable round trips, invalid payloads, schema mismatches and restart cases.
|
|
|
|
## Adapter interfaces
|
|
|
|
Existing `RemoteTransport.send(_ envelope: CommandEnvelope) async -> CommandReceipt` is the command sink. The sender has no implicit retry guarantee. Platform agents propose small lifecycle protocols for connection, session acquisition, token repository and motion source through the integrator; do not hide setup inside `send` or start pairing in response to a gesture.
|
|
|
|
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.
|
|
|
|
## 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.
|