From 3b64d1e0ec386804406757cb7efe001e57f79a2c Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sun, 23 Aug 2026 16:11:44 +0200 Subject: [PATCH] v0.2.8-pre.007-fix.001 --- Cargo.toml | 4 +- .../unit_tests/ws_session.rs | 8 +- deltas/0.2.8/pre.007-fix.001.md | 111 ++++++++++++++++++ ...0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md | 55 ++++++++- ...011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md | 56 ++++++++- 5 files changed, 221 insertions(+), 13 deletions(-) create mode 100644 deltas/0.2.8/pre.007-fix.001.md diff --git a/Cargo.toml b/Cargo.toml index 3948502..1fd1302 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 227 +# version: 228 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.2.8-pre.7" +version = "0.2.8-pre.7.fix.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs b/crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs index c1b4f97..104e6e3 100644 --- a/crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs +++ b/crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs @@ -1,5 +1,5 @@ // file: crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs -// version: 8 +// version: 9 use futures_util::SinkExt; // rust-rules: trait-import use futures_util::StreamExt; // rust-rules: trait-import @@ -186,6 +186,7 @@ async fn yield_runtime_steps() { for _ in 0..16 { tokio::task::yield_now().await; } + return; } #[tokio::test(flavor = "current_thread")] @@ -451,6 +452,7 @@ async fn helius_heartbeat_sends_ping_at_sixty_seconds_and_rearms() { }); let session = crate::HeliusLaserStreamWsSession::connect(helius_local_endpoint(url.as_str())).await.expect("Helius fixture session must connect"); tokio::time::pause(); + yield_runtime_steps().await; tokio::time::advance(std::time::Duration::from_secs(59)).await; yield_runtime_steps().await; assert!(matches!(ping_rx.try_recv(), std::result::Result::Err(tokio::sync::mpsc::error::TryRecvError::Empty))); @@ -520,11 +522,13 @@ async fn helius_explicit_close_cancels_heartbeat_before_deadline() { }); let session = crate::HeliusLaserStreamWsSession::connect(helius_local_endpoint(url.as_str())).await.expect("Helius close fixture session must connect"); tokio::time::pause(); + yield_runtime_steps().await; tokio::time::advance(std::time::Duration::from_secs(30)).await; yield_runtime_steps().await; + assert!(matches!(ping_rx.try_recv(), std::result::Result::Err(tokio::sync::mpsc::error::TryRecvError::Empty))); session.close().await.expect("Helius close fixture session must close before heartbeat deadline"); yield_runtime_steps().await; - assert!(matches!(ping_rx.try_recv(), std::result::Result::Err(tokio::sync::mpsc::error::TryRecvError::Empty))); + assert!(!matches!(ping_rx.try_recv(), std::result::Result::Ok(()))); tokio::time::resume(); server.await.expect("Helius close fixture server must complete"); } diff --git a/deltas/0.2.8/pre.007-fix.001.md b/deltas/0.2.8/pre.007-fix.001.md new file mode 100644 index 0000000..b135cca --- /dev/null +++ b/deltas/0.2.8/pre.007-fix.001.md @@ -0,0 +1,111 @@ + + + +# Delta `0.2.8-pre.007-fix.001` — déterminisme canaris heartbeat Tokio + +## 1. Base et défaut corrigé + +Base appliquée : + +```text +0.2.8-pre.7 +``` + +Le checkpoint opérateur confirme que `fmt`, audit Rust et `cargo check --workspace` sont propres. Le gate reste toutefois bloqué par : + +```text +cargo clippy --workspace --all-targets + 1 erreur clippy::implicit_return dans le helper test yield_runtime_steps + +cargo test -p ksp-onchain-transport-lib + 329/331 unit passent + 2 échecs heartbeat test-only +``` + +Les autres canaris heartbeat, notamment policy Helius-only, absence sur standard, write failure/reconnect et réarmement après reconnexion, passent déjà. Aucun défaut runtime heartbeat n'est démontré. + +## 2. Version technique + +```text +workspace.package.version = 0.2.8-pre.7.fix.1 +commit attendu = v0.2.8-pre.007-fix.001 +Git tag = aucun tag prerelease +``` + +Le header root `Cargo.toml` passe en version `228`. + +## 3. Correction `implicit_return` + +Le helper privé test-only : + +```rust +async fn yield_runtime_steps() +``` + +termine désormais par un `return;` explicite après sa boucle de yields. Aucun `allow` Clippy n'est introduit. + +## 4. Armement déterministe du timer Tokio + +Dans le canari 60 s, `tokio::time::pause()` était suivi immédiatement de `advance(59 s)`. Rien ne garantissait alors que la tâche actor ait déjà été pollée et ait enregistré son `sleep_until(heartbeat_deadline)` sous l'horloge pausée. + +Le fix insère un passage de stabilisation par `yield_runtime_steps().await` immédiatement après `pause()` et avant toute avance. Le canari vérifie ensuite toujours la vraie cadence runtime : + +```text +t=59 s aucun Ping +t=60 s un Ping +t=119 s aucun second Ping +t=120 s second Ping +``` + +Aucune cadence spéciale de test n'est créée. + +## 5. Sémantique du canari close + +Le canari close est renforcé en deux étapes : + +```text +t=30 s avant close -> observation channel obligatoirement Empty +après close -> aucun Ping `Ok(())` accepté +``` + +Après réception de la frame Close, le serveur fixture termine et détruit naturellement son sender. Le receiver peut donc rendre `Disconnected`, ce qui prouve toujours qu'aucun heartbeat n'a été émis après fermeture. Exiger uniquement `Empty` après close était une hypothèse incorrecte du test. + +## 6. Runtime explicitement inchangé + +Ce fix ne modifie pas : + +```text +crates/ksp-onchain-transport-lib/src/ws_session.rs +HELIUS_WS_HEARTBEAT_INTERVAL = 60 s +WebSocket Ping control frame +WsProtocolKind +WsSessionSettings +Config / schema / env +transactionSubscribe / transactionNotification lifecycle +reconnect / remap / backpressure +``` + +Il ne rajoute aucune dépendance ni feature. + +## 7. Fichiers modifiés + +```text +Cargo.toml +crates/ksp-onchain-transport-lib/unit_tests/ws_session.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-fix.001.md +``` + +## 8. 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, audit clean, **331 unit / 40 public API / 29 completeness / 4 doctests** et workspace vert. `pre.008` reste bloqué jusque-là. diff --git a/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md b/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md index ae7a390..d1efb21 100644 --- a/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md +++ b/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md @@ -1,9 +1,9 @@ - + # Plan `0.2.8` — Helius LaserStream WebSocket -> **Statut : `0.2.8-pre.006` est validé intégralement. `0.2.8-pre.007` prépare maintenant le heartbeat Helius LaserStream WebSocket provider-owned dans l'actor physique unique : Ping control frame à 60 s, timer uniquement en `Active`, réarmement après reconnect et arrêt immédiat au shutdown.** +> **Statut : `0.2.8-pre.007` est fonctionnellement implémenté mais son gate opérateur révèle un défaut de canaris Tokio pausés et un lint `implicit_return`. `0.2.8-pre.007-fix.001` corrige uniquement le protocole de test ; le runtime heartbeat Helius 60 s reste inchangé.** ## 1. Objet, base et état courant @@ -34,10 +34,11 @@ pre.005 contrat typed transactionSubscribe/unsubscribe validé pre.005-fix.001 correction types de canaris + visibilité/tests/règles validée pre.005-fix.002 suppression warnings dead_code via cfg(test) validée pre.006 transactionNotification + lifecycle actor validé -pre.007 heartbeat Helius WebSocket / idle préparé +pre.007 heartbeat Helius WebSocket / idle — checkpoint gate à corriger +pre.007-fix.001 déterminisme canaris Tokio + lint test — préparé -workspace.package.version courant = 0.2.8-pre.7 -commit attendu = v0.2.8-pre.007 +workspace.package.version courant = 0.2.8-pre.7.fix.1 +commit attendu = v0.2.8-pre.007-fix.001 aucun tag prerelease ``` @@ -67,7 +68,9 @@ pre.005 DONE — transactionSubscribe request typed + filters/options/tokenAcco fix.002 DONE — helpers wire non consommés en production bornés à #[cfg(test)] ; zéro warning dead_code pre.006 DONE — transactionNotification + handle live + actor registry/reconnect/resubscribe/unsubscribe races + late notifications + backpressure ciblée, sans second actor/socket -pre.007 PREPARED — heartbeat Helius WebSocket/idle + timers + interaction reconnect/control frames/shutdown +pre.007 CHECKPOINT — heartbeat Helius WebSocket/idle + timers + interaction reconnect/control frames/shutdown + fix.001 PREPARED — actor armé avant avance de l'horloge Tokio + close accepte canal d'observation fermé + + `return;` explicite du helper de yield pour `clippy::implicit_return` pre.008 provider adversarial lifecycle + capability guards + payload/backpressure + security/redaction pre.009 compliance Helius WebSocket + non-régressions Solana standard 18/18 + HTTP 52/14 + Config/API/dependency-firewall canaries @@ -1138,3 +1141,43 @@ doctests compile-fail 4 Le heartbeat Helius reste un mécanisme de maintien de connexion ; il n'introduit aucune promesse de replay WebSocket ni de livraison lossless. +## 16. Checkpoint `pre.007` et préparation `pre.007-fix.001` + +Checkpoint opérateur `0.2.8-pre.007` reçu le 2026-08-23 : + +```text +[x] cargo fmt --all +[x] python3 scripts/audit_rust_workspace_rules.py = clean +[x] cargo check --workspace = sans warning +[!] cargo clippy --workspace --all-targets + unit_tests/ws_session.rs: yield_runtime_steps() termine sans `return;` explicite +[!] cargo test -p ksp-onchain-transport-lib + 329/331 unit passent ; 2 canaris heartbeat échouent +[ ] cargo test --workspace — non retenu tant que le gate Transport n'est pas vert +``` + +Les quatre autres preuves heartbeat importantes passent déjà : policy Helius-only/60 s, absence de heartbeat standard, erreur d'écriture mappée vers le reconnect existant, et réarmement après reconnexion. Le défaut observé est donc borné au harness de test, pas au chemin runtime `ws_session.rs`. + +Cause exacte des deux canaris : + +```text +helius_heartbeat_sends_ping_at_sixty_seconds_and_rearms + l'horloge pausée est avancée avant d'avoir garanti un premier poll de l'actor ; + le sleep_until heartbeat peut donc être armé seulement après l'avance. + +helius_explicit_close_cancels_heartbeat_before_deadline + après close, le serveur fixture termine et le sender d'observation est détruit ; + try_recv() peut légitimement rendre Disconnected au lieu de Empty. +``` + +`fix.001` ne touche pas le runtime heartbeat. Il modifie uniquement le canari : + +```text +- `yield_runtime_steps()` termine par `return;` explicite ; +- après `tokio::time::pause()`, l'actor reçoit plusieurs yields avant la première avance ; +- le test close prouve d'abord `Empty` à t=30 s avant close ; +- après close, il exige seulement qu'aucun `Ok(())` Ping n'ait été observé, donc `Empty` et `Disconnected` sont tous deux acceptables. +``` + +La constante 60 s, la frame Ping, le branch actor, le reconnect, Config et `WsSessionSettings` restent byte-for-byte hors du fix. `pre.008` reste bloqué jusqu'au replay vert de `pre.007-fix.001`. + diff --git a/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md b/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md index 99f1ce4..9c80b3e 100644 --- a/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md +++ b/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md @@ -1,9 +1,9 @@ - + # Validation `0.2.8` — Helius LaserStream WebSocket -> **Statut : `pre.006` est validé intégralement. `pre.007` est préparé pour le heartbeat Helius LaserStream WebSocket provider-owned : Ping control frame à 60 s uniquement en `Active`, réarmé après reconnect et interrompu par close/shutdown.** +> **Statut : `pre.007` est implémenté mais son gate est bloqué par un lint de helper test et deux canaris Tokio pausés. `pre.007-fix.001` est préparé comme correction test-only, sans changement runtime heartbeat.** ## 1. Références @@ -24,6 +24,8 @@ pre.005 deltas/0.2.8/pre.005.md pre.005 visibility/test fix deltas/0.2.8/pre.005-fix.001.md pre.005 dead-code fix deltas/0.2.8/pre.005-fix.002.md pre.006 actor transaction deltas/0.2.8/pre.006.md +pre.007 heartbeat Helius deltas/0.2.8/pre.007.md +pre.007 test determinism fix deltas/0.2.8/pre.007-fix.001.md validation standard WS docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md HTTP compliance docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md KSP-TRANSPORT-007 docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md @@ -342,7 +344,6 @@ Constats `pre.002-fix.001` : Aucun split en fichiers supplémentaires n'est retenu : les plans historiques `0.2.5`–`0.2.7` sont de taille comparable ou supérieure, et le contenu du plan `015` reste entièrement centré sur une seule release. Le problème identifié était **l'ordre interne et la duplication de responsabilités**, pas la nécessité d'un nouveau type de document. - ## 12. Gates opérateur `pre.004` / `fix.001` / `fix.002` Premier passage `pre.004` reçu le 2026-08-23 : @@ -629,3 +630,52 @@ Le `test-util` Tokio ajouté côté dev sert uniquement à avancer l'horloge des Verdict courant : **`pre.006` DONE ; `pre.007` PREPARED.** +## 18. Gate `pre.007` et `pre.007-fix.001` + +Résultat opérateur reçu pour `0.2.8-pre.007` : + +```text +[x] cargo fmt --all +[x] audit Rust workspace = clean / 0 candidate +[x] cargo check --workspace = vert, sans warning +[!] cargo clippy --workspace --all-targets = 1 erreur `implicit_return` dans `yield_runtime_steps` +[!] cargo test -p ksp-onchain-transport-lib = 329 passed / 2 failed sur 331 unit +``` + +Tests heartbeat déjà verts dans ce même run : + +```text +[x] helius_heartbeat_policy_is_provider_owned_and_fixed_to_sixty_seconds +[x] standard_session_never_emits_helius_provider_heartbeat +[x] helius_heartbeat_write_failure_maps_to_existing_reconnect_failure_outcome +[x] helius_heartbeat_is_rearmed_from_successful_reconnect +``` + +Échecs bornés : + +```text +[!] helius_heartbeat_sends_ping_at_sixty_seconds_and_rearms + actor non garanti pollé/armé avant la première `advance()` Tokio + +[!] helius_explicit_close_cancels_heartbeat_before_deadline + assertion trop stricte : après fermeture de la fixture, `try_recv()` peut être `Disconnected` +``` + +Critères `pre.007-fix.001` : + +```text +[ ] aucune modification de `src/ws_session.rs` +[ ] aucune modification de la constante heartbeat 60 s +[ ] aucun champ Config/WsSessionSettings ajouté +[ ] helper `yield_runtime_steps` satisfait `clippy::implicit_return` +[ ] actor laissé se stabiliser après `pause()` avant la première avance +[ ] test close prouve aucun Ping à t=30 s avant close +[ ] après close, aucun `Ok(())` Ping n'est accepté ; Empty/Disconnected sont valides +[ ] cargo check sans warning +[ ] cargo clippy sans warning +[ ] Transport = 331 unit + 40 public API + 29 completeness + 4 doctests +[ ] cargo test --workspace = vert +``` + +Verdict courant : **`pre.007` FIX REQUIRED ; `pre.007-fix.001` PREPARED ; `pre.008` bloqué.** +