RUDPClient/openspec/specs/network-sync-strategy/spec.md

102 lines
8.3 KiB
Markdown

# network-sync-strategy Specification
## Purpose
Define how client and server route high-frequency gameplay synchronization traffic, reject stale updates, reconcile authoritative state, and process clock-sync samples independently of session lifecycle.
## Requirements
### Requirement: Hosts assign delivery policies to synchronization message types
The shared networking core SHALL allow hosts to map business message types to delivery policies. The default shared resolver used by `MessageManager` MUST map `MoveInput` and `PlayerState` to `HighFrequencySync`, while `ShootInput`, `CombatEvent`, and control-plane messages MUST resolve to `ReliableOrdered` unless a host intentionally supplies a different resolver.
#### Scenario: Default resolver sends movement and state traffic to the sync lane
- **WHEN** the runtime uses `DefaultMessageDeliveryPolicyResolver` to send `MoveInput` or `PlayerState`
- **THEN** the resolver returns `HighFrequencySync`
- **THEN** `MessageManager` sends that envelope through the sync transport lane when one is configured
#### Scenario: Default resolver keeps shooting and combat events on the reliable lane
- **WHEN** the runtime uses `DefaultMessageDeliveryPolicyResolver` to send `ShootInput` or `CombatEvent`
- **THEN** the resolver returns `ReliableOrdered`
- **THEN** `MessageManager` sends that envelope through the reliable transport lane
#### Scenario: Default resolver preserves reliable control traffic
- **WHEN** the runtime uses `DefaultMessageDeliveryPolicyResolver` to send login, logout, heartbeat, or other session-management messages
- **THEN** the resolver returns `ReliableOrdered`
- **THEN** those messages continue to use the reliable transport path
### Requirement: Sequenced sync receivers discard stale gameplay updates
The high-frequency sync strategy SHALL tag gameplay synchronization messages with monotonic sequencing information and MUST discard stale `MoveInput` or `PlayerState` updates that arrive older than the last accepted update for the same peer or entity stream. `ShootInput` and `CombatEvent` MUST NOT be discarded by the latest-wins stale filter.
#### Scenario: Older movement input is ignored
- **WHEN** the server receives a `MoveInput` update with a tick or sequence older than the latest accepted input for that player
- **THEN** the server drops that stale movement update
- **THEN** the newer accepted movement input remains authoritative for simulation
#### Scenario: Older player state does not rewind a client
- **WHEN** the client receives a `PlayerState` update with a tick or sequence older than the latest applied authoritative state for that player
- **THEN** the client ignores the stale state update
- **THEN** visible movement continues from the newer authoritative state without rewinding to older data
#### Scenario: Reliable gameplay events bypass stale-drop filtering
- **WHEN** the runtime receives a `ShootInput` or `CombatEvent` message
- **THEN** the latest-wins stale filter does not reject that message solely because of sync-sequence rules
- **THEN** reliable ordered handling remains responsible for preserving event delivery semantics
### Requirement: Authoritative correction prunes acknowledged prediction history
The client sync strategy SHALL reconcile local prediction against authoritative player-state updates by pruning acknowledged movement inputs at or before the authoritative acknowledged movement tick and only reapplying newer pending `MoveInput` messages. For the controlled player, reconciliation MUST classify authoritative error after replay into a bounded-correction path for small cadence-aligned divergence and an immediate snap path for large divergence. When bounded correction is already active, later authoritative snapshots MUST deterministically replace, fold into, or escalate that correction based on the newest residual error instead of stacking unbounded visual offsets.
#### Scenario: Reconciliation removes already acknowledged movement inputs
- **WHEN** the client accepts an authoritative `PlayerState` update that acknowledges movement tick `N`
- **THEN** locally buffered predicted `MoveInput` messages with tick less than or equal to `N` are removed from the replay buffer
- **THEN** only `MoveInput` messages newer than `N` remain eligible for re-simulation
#### Scenario: Small post-replay error uses bounded correction
- **WHEN** the controlled client finishes replay after accepting an authoritative `PlayerState` and the remaining position or rotation error stays within the configured bounded-correction threshold
- **THEN** the client keeps authoritative ownership of the accepted snapshot
- **THEN** local presentation converges through bounded correction instead of an immediate hard snap on that frame
#### Scenario: New small error updates active bounded correction
- **WHEN** the controlled client accepts another authoritative `PlayerState` before the previous bounded correction has finished and the new residual error still stays within bounded-correction limits
- **THEN** the sync strategy updates the active bounded correction state using the newest authoritative residual error
- **THEN** the client does not queue multiple independent correction tails for the same controlled player
#### Scenario: Failed bounded correction escalates to snap
- **WHEN** the controlled client detects that the residual error from consecutive authoritative updates exceeds the snap threshold or remains non-convergent beyond the configured correction budget
- **THEN** the client immediately applies the authoritative transform state
- **THEN** any active bounded correction state is discarded before later prediction continues from the authoritative baseline
### Requirement: Clock synchronization is a separate sync-policy concern
The shared networking core SHALL process server-tick or clock-synchronization samples through a dedicated sync-policy component rather than storing clock-sync ownership inside `SessionManager`.
#### Scenario: Heartbeat response contributes a clock sample without mutating lifecycle
- **WHEN** a heartbeat or gameplay sync message carries a server-tick sample
- **THEN** the runtime forwards that sample to the clock-sync strategy
- **THEN** session lifecycle state remains unchanged except for liveness or RTT bookkeeping
#### Scenario: Hosts can consume smoothed clock data for prediction
- **WHEN** prediction or reconciliation code needs the current server-time estimate
- **THEN** it reads that estimate from the clock-sync strategy or state object
- **THEN** it does not query `SessionManager` for authoritative clock ownership
### Requirement: Integration wiring enforces sync lane selection
The networking stack SHALL route sync-designated traffic through the sync transport when the integration layer provides one, and SHALL fall back to the primary reliable transport when it does not.
#### Scenario: Dedicated sync transport available
- **WHEN** sync-designated traffic is sent from a session whose integration wiring includes a sync transport
- **THEN** the traffic SHALL be dispatched on the sync transport instead of the primary reliable transport
#### Scenario: Dedicated sync transport unavailable
- **WHEN** sync-designated traffic is sent from a session whose integration wiring does not include a sync transport
- **THEN** the traffic SHALL be dispatched on the primary reliable transport without failing session operation
### Requirement: Client gameplay input preserves movement and shooting lane semantics
The client gameplay-input flow SHALL preserve the MVP delivery-lane contract when sending gameplay actions. Explicit zero-vector `MoveInput` updates generated on input release MUST remain valid high-frequency sync traffic, and `ShootInput` generated from local fire intent MUST use the reliable ordered lane.
#### Scenario: Stop movement update remains sync traffic
- **WHEN** the controlled client sends a zero-vector `MoveInput` after releasing movement input
- **THEN** the message is still treated as `MoveInput` for delivery-policy resolution
- **THEN** the networking stack routes it through the high-frequency sync lane when one is configured
#### Scenario: Shoot input remains reliable traffic
- **WHEN** the controlled client sends `ShootInput` from the MVP fire-input path
- **THEN** the networking stack resolves that message to the reliable ordered lane
- **THEN** firing intent does not share the latest-wins sync delivery behavior used for movement updates