# Delta `0.2.7-pre.004` — runtime WebSocket physique + actor JSON-RPC ## 1. Base requise ```text 0.2.7-pre.003 appliquée workspace.package.version = 0.2.7-pre.3 ``` Le checkpoint opérateur reçu avant cette tranche est vert : `cargo fmt --all`, audit Python, `cargo check --workspace`, `cargo clippy --workspace --all-targets`, tests Transport, tests Config et `cargo test --workspace`. ## 2. Signal technique Cette prerelease non-fix modifie dépendances, runtime Rust et tests. Conformément au workflow KSP : ```text livraison = 0.2.7-pre.004 workspace.package.version = 0.2.7-pre.4 commit = v0.2.7-pre.004 ``` Aucun tag prerelease. ## 3. Dépendances WebSocket matérialisées Le réaudit du 22 août 2026 confirme les versions retenues depuis `pre.001` : ```text tokio-tungstenite 0.30.0 futures-util 0.3.34 ``` Le root déclare sans features consumer : ```toml tokio-tungstenite = { version = "^0.30", default-features = false } futures-util = { version = "^0.3", default-features = false } ``` Transport active seulement : ```text tokio-tungstenite : connect + rustls-tls-webpki-roots futures-util : sink + std tokio : macros + rt + sync + time ``` Le fixture serveur local ajoute `tokio/net` côté dev. Aucune dépendance Config, Store, Program, Wallet ou `tracing` direct n'est introduite. ## 4. `WsSession` physique Nouvelle surface publique : ```text WsSession::connect(WsEndpointSettings) WsSession::id() WsSession::state() WsSession::snapshot() ``` Un appel de `connect` crée exactement une connexion physique. Deux appels avec le même endpoint créent deux sockets indépendants ; aucun singleton, pool ou scheduler automatique n'est ajouté. Le caller ne reçoit jamais le socket brut. ## 5. Actor propriétaire du socket Une tâche actor unique possède : ```text WebSocketStream compteur JSON-RPC request id map pending requests bounded command receiver publication WsSessionSnapshot ``` Le handle communique avec l'actor par `tokio::sync::mpsc` borné selon `command_queue_capacity`. Les snapshots sont publiés via `tokio::sync::watch` et conservent seulement les metadata sûres prévues en `pre.002`. ## 6. Handshake et `WebSocketConfig` `WsSession::connect` attend le handshake sous `command_timeout` et configure explicitement : ```text write_buffer_size = 0 max_write_buffer_size = WsSessionSettings.max_write_buffer_size_bytes max_message_size = WsSessionSettings.max_message_size_bytes max_frame_size = WsSessionSettings.max_frame_size_bytes ``` Le `write_buffer_size = 0` évite de rendre la validité de la configuration KSP dépendante du buffer par défaut interne de Tungstenite et garantit que le plafond configuré reste strictement supérieur au target buffer. Les tests oversized et les recalibrages éventuels restent le gate `pre.005`. ## 7. Pending JSON-RPC La primitive interne actor : ```text execute_json_rpc(method, params) ``` reste **`pub(crate)`**. Elle n'est volontairement pas exposée comme API raw provider-extension publique. Comportement : - ID numérique KSP monotone par session ; - sérialisation via `JsonRpcRequest` existant ; - map `BTreeMap` bornée par `max_pending_requests` ; - deadline par request issue de `command_timeout` ; - dispatch des réponses par `id`, y compris si elles arrivent hors ordre ; - erreurs JSON-RPC applicatives renvoyées au caller concerné sans teardown de la connexion ; - ID réponse inconnu/stale ignoré avec diagnostic sûr ; - JSON structurellement invalide classé erreur protocole session. Cette primitive sera consommée par le moteur de subscriptions à partir de `pre.006`. ## 8. Lifecycle limité à la tranche `pre.004` matérialise : ```text Connecting -> Active connection/read/write failure -> Failed last handle dropped -> cleanup best-effort -> Closed ``` Le reconnect/resubscribe reste `pre.007`. Le shutdown async public, les budgets de Close et les fixtures peer hostile restent `pre.005`. Ping reçu est répondu par Pong afin de conserver l'interopérabilité du socket. Aucun heartbeat applicatif périodique n'est ajouté. ## 9. Erreurs Nouveaux codes publics : ```text ws_backpressure_overflow ws_connection_failed ws_protocol_error ws_session_closed ``` Les erreurs de connexion WebSocket ne conservent volontairement pas la source Tungstenite brute : celle-ci pourrait contenir une request/URI ou d'autres détails provider. Les erreurs KSP exposent uniquement `session_id`, endpoint logique, provider et cluster. ## 10. Logging / tracing Toutes les émissions passent exclusivement par `ksp-logging-lib` et réutilisent : ```text crates/ksp-onchain-transport-lib/src/constants.rs TRACING_TARGET = "ksp-onchain-transport-lib" ``` Répartition principale : ```text trace -> ouverture socket, send/dispatch JSON-RPC, Ping/Pong, notification prématurée ignorée debug -> actor start, handshake actif, réponse stale, timeout pending, remote close warn -> handshake/read/write failure, malformed wire, capacité pending épuisée ``` Ne sont jamais loggés : URL complète, credentials, query token, payload JSON-RPC complet ou notification brute. ## 11. Serveur local déterministe Nouveaux tests runtime sans Internet : ```text handshake local + round-trip JSON-RPC deux sessions physiques distinctes sur la même URL deux requests concurrentes + réponses inversées application error sans teardown de session connection error sans fuite URL/credential ``` Le serveur utilise `tokio::net::TcpListener` + `tokio_tungstenite::accept_async`. ## 12. Canaris workspace/public API Le canari workspace dependencies est synchronisé avec les nouvelles dépendances/features et continue de vérifier le firewall Transport. Le canari public API vérifie la disponibilité de `WsSession` et les quatre nouveaux codes d'erreur. ## 13. Documentation synchronisée Mis à jour : ```text crates/ksp-onchain-transport-lib/README.md crates/ksp-onchain-transport-lib/USAGE.md docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md ``` `ROADMAP.md` et `CHANGELOG.md` restent inchangés conformément à la politique de série prerelease. ## 14. Validation de préparation Exécuté dans le sandbox : ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean inspection absence tracing direct OK inspection TRACING_TARGET OK inspection dépendances workspace/member OK inspection Markdown tables OK ``` Cargo n'est pas disponible dans le sandbox de génération ; aucun résultat Cargo local n'est revendiqué. ## 15. Gates opérateur avant commit ```bash cargo fmt --all python3 scripts/audit_rust_workspace_rules.py cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib cargo test --workspace ``` Si le checkpoint est vert : ```text commit = v0.2.7-pre.004 ``` La tranche suivante est `0.2.7-pre.005` : adversarial limits frame/message/request, control frames, cancellation, close/shutdown explicite et peer hostile.