# Delta `0.2.8-pre.007` — heartbeat Helius WebSocket + idle lifecycle ## 1. Base et objet Base appliquée : ```text 0.2.8-pre.6 ``` Le checkpoint opérateur de `pre.006` est intégralement vert et sans warning : ```text cargo fmt --all OK python3 scripts/audit_rust_workspace_rules.py clean cargo check --workspace OK cargo clippy --workspace --all-targets OK Transport unit 325/325 Transport public API 40/40 Transport release completeness 28/28 Transport doctests compile-fail 4/4 cargo test --workspace OK ``` Cette tranche ajoute uniquement la policy de heartbeat Helius LaserStream WebSocket dans l'actor physique commun. Elle ne rouvre pas le lifecycle transaction validé par `pre.006`. ## 2. Version technique ```text workspace.package.version = 0.2.8-pre.7 commit attendu = v0.2.8-pre.007 Git tag = aucun tag prerelease ``` Le header root `Cargo.toml` passe en version `227`. ## 3. Policy heartbeat provider-owned La décision d'architecture de `pre.001` est matérialisée sans nouveau réglage public : ```text protocol WsProtocolKind::HeliusLaserStream uniquement intervalle nominal 60 s frame WebSocket Ping control frame vide état actor Active uniquement succès réarmement à now + 60 s reconnect réussi réarmement depuis la connexion de remplacement write timeout/failure WsActorIoOutcome::Failed close/shutdown timer abandonné ; shutdown prioritaire SolanaStandard aucun heartbeat provider ``` Le heartbeat n'est pas un appel JSON-RPC `ping`. KSP utilise la frame de contrôle WebSocket `Ping`, déjà compatible avec le traitement `Pong` de l'actor. Aucun champ `heartbeat_*` n'est ajouté à : ```text WsSessionSettings WsEndpointSettings Config .env.example schema Transport ``` La cadence est donc une policy Helius WebSocket interne, pas une option de configuration générique. ## 4. Intégration dans l'actor unique `run_ws_session_actor` possède le deadline heartbeat avec les mêmes priorités de shutdown que le reste du moteur : ```text shutdown command socket input Helius heartbeat deadline pending JSON-RPC timeout ``` Le branch heartbeat est désactivé pour `SolanaStandard`. Sur succès du Ping, le prochain deadline est recalculé à partir de `Instant::now()`. Pendant reconnect, aucun heartbeat n'est émis ; lorsque `recover_websocket_session` rend une connexion de remplacement active, le deadline est réarmé à 60 s. Le helper d'écriture sélectionne de façon bornée entre : ```text shutdown signal websocket.send(Ping) command_timeout ``` Une erreur d'écriture ou un timeout retourne le même `WsActorIoOutcome::Failed` que les autres erreurs de connexion. Le chemin de reconnect, son budget, son backoff, les remaps et le shutdown restent donc uniques. ## 5. Timers déterministes de test La cadence runtime ne doit pas être raccourcie pour rendre les tests rapides. La crate active donc uniquement côté dev/test la feature Tokio : ```text test-util ``` avec `io-util` nécessaire au canari de socket cassé en mémoire. Il ne s'agit pas d'une nouvelle dépendance ; aucune feature runtime de production n'est ajoutée au contrat KSP. Les tests utilisent `tokio::time::pause()` / `advance()` pour vérifier la vraie constante de 60 s. ## 6. Canaris ajoutés Six tests unitaires Transport sont ajoutés : ```text Helius-only + constante 60 s premier Ping à 60 s + second Ping après réarmement absence totale de heartbeat provider sur SolanaStandard close à 30 s sans Ping échec d'écriture Ping -> WsActorIoOutcome::Failed / ERROR_CODE_WS_CONNECTION_FAILED reconnect avant heartbeat -> nouveau deadline 60 s depuis la connexion de remplacement ``` Le test hérité `websocket_shutdown_interrupts_reconnect_backoff_without_new_connection` continue de couvrir l'interruption du backoff par shutdown, tandis que le nouveau branch heartbeat place également le signal shutdown en première priorité. Le canari release-completeness vérifie que : - la policy reste dans `ws_session.rs` ; - le Ping est une frame WebSocket ; - `WsSessionSettings` ne gagne aucun champ de heartbeat ; - la façade Helius ne possède aucun timer séparé. Comptages attendus : ```text Transport unit 331 Transport public API 40 release completeness 29 doctests compile-fail 4 ``` ## 7. Non-régressions Cette tranche ne modifie pas : ```text surface Helius standard 6 familles transactionSubscribe request/filter/options transactionNotification Full/Signature/Unknown WsSubscriptionKind::HeliusTransaction remote/local ID remapping late notification handling backpressure logical subscription standard Solana WebSocket 18/18 HTTP 52 current / 14 historical Config Helius mainnet/devnet dependency firewall ``` Aucune promesse de replay WebSocket ou de livraison lossless n'est introduite. ## 8. Documentation Le plan `015` : - ferme `pre.006` sur preuve opérateur ; - marque `pre.007` PREPARED ; - matérialise la policy Helius-only 60 s et ses canaris. La validation `011` : - transforme les critères lifecycle `pre.006` en preuves acquises ; - ouvre la gate `pre.007` ; - conserve les tests adversariaux élargis pour `pre.008`. ## 9. Hors scope Restent hors de `pre.007` : ```text provider adversarial lifecycle élargi pre.008 payload/security/redaction adversarial pre.008 compliance Helius + standard + HTTP pre.009 smoke Helius WebSocket live opt-in pre.010 LaserStream gRPC future backend distinct ``` ## 10. Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/src/ws_session.rs crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md deltas/0.2.8/pre.007.md ``` ## 11. Gate opérateur ```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 ``` Critère de fermeture : zéro warning nouveau, audit Rust clean, **331 unit / 40 public API / 29 completeness / 4 doctests** et workspace vert.