Files
khadhroony-solana-project/deltas/0.2.7/pre.008.md
2026-08-22 21:44:18 +02:00

8.1 KiB

Delta 0.2.7-pre.008 — backpressure par subscription, causes terminales et cleanup borné

Base

Base directe validée par l'opérateur :

0.2.7-pre.007-fix.001
Cargo 0.2.7-pre.7.fix.1

Le checkpoint précédent est entièrement vert sur cargo fmt --all, audit Python KSP, cargo check --workspace, cargo clippy --workspace --all-targets, cargo test -p ksp-onchain-transport-lib avec 283 tests réussis, puis cargo test --workspace avec uniquement les smokes/diagnostics déjà attendus en ignored.

Objectif

Matérialiser la policy de backpressure WebSocket définie par le plan sans avancer sur les wrappers standard publics :

  • queue de notifications réellement bornée par subscription ;
  • aucun drop silencieux quand un consumer ne draine plus assez vite ;
  • overflow isolé à la seule subscription lente ;
  • compteur overflow_count réellement incrémenté et observable sur la session ;
  • cause terminale KSP sûre observable sur WsSubscription<T> ;
  • unsubscribe distant best-effort après overflow ou terminaison locale détectée ;
  • libération de la capacité max_active_subscriptions après terminaison ;
  • cleanup d'un receiver abandonné à la notification suivante ;
  • maintien de la session physique et des subscriptions saines ;
  • conservation des garanties reconnect/resubscribe acquises en pre.007 ;
  • aucune promesse lossless et aucun backfill implicite.

Signal de version

livraison                 0.2.7-pre.008
workspace.package.version 0.2.7-pre.8
commit attendu            v0.2.7-pre.008
Git tag                    aucun

Fichiers modifiés

Cargo.toml
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
crates/ksp-onchain-transport-lib/src/ws_session.rs
crates/ksp-onchain-transport-lib/src/ws_subscription.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/unit_tests/ws_lifecycle.rs
crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md

Fichier ajouté

deltas/0.2.7/pre.008.md

Implémentation

Overflow par subscription

Le dispatcher typed réserve d'abord une place avec try_reserve sur la queue mpsc bornée. Une queue pleine est donc détectée avant décodage et ne bloque jamais l'actor socket :

  1. overflow_count est incrémenté de façon saturante ;
  2. la subscription concernée reçoit la cause terminale ERROR_CODE_WS_BACKPRESSURE_OVERFLOW ;
  3. son état devient Failed ;
  4. son entrée registry et son mapping remote vers local sont retirés ;
  5. un *Unsubscribe distant est envoyé best-effort lorsque le binding existait ;
  6. les autres subscriptions et la session restent actives.

Une notification déjà présente dans la queue avant l'overflow reste lisible. Après drainage de cette valeur, le receiver se ferme parce que le dispatcher actor de la subscription terminale a été libéré.

Causes terminales sûres

WsSubscription<T> expose désormais :

terminal_error_code() -> Option<ErrorCode>

La projection contient uniquement un code KSP stable et sûr. Elle ne transporte ni message RPC distant, ni payload de notification, ni URL, ni credential, ni remote subscription ID.

Les transitions runtime vers Failed publient leur cause avant de terminer le handle : overflow, mismatch protocolaire, decode typed invalide, timeout, erreur RPC applicative, échec de subscribe/resubscribe, policy Never après rupture et exhaustion terminale du reconnect. Une fermeture normale ou un unsubscribe réussi conserve None.

WsSubscriptionSnapshot peut également porter cette cause sûre lorsqu'une entrée terminale reste présente dans un snapshot de session, notamment lors d'une exhaustion globale. Les subscriptions terminales retirées du registry restent observables par leur handle local.

Cleanup et capacité

max_active_subscriptions reste une limite d'admission distincte du compteur d'overflow de notifications. Un rejet de création au plafond utilise le domaine d'erreur de capacité existant mais n'incrémente pas overflow_count.

Une subscription qui est fermée, échoue ou dont le receiver est abandonné puis détecté à la notification suivante libère son entrée locale. Le binding distant est nettoyé best-effort sans attendre son ACK et sans bloquer la session. Une nouvelle subscription peut ensuite réutiliser la capacité locale disponible avec un nouvel ID local monotone.

Le cleanup distant best-effort est également réutilisé pour les mismatchs de méthode, les erreurs de décodage typed et les ACK de resubscribe tardifs déjà traités en pre.007.

Reconnect

Une subscription devenue terminale à cause d'un overflow ou d'une autre erreur locale est retirée du registry et ne peut donc pas être sélectionnée lors d'un reconnect ultérieur. Les subscriptions saines conservent le comportement ActiveSubscriptions ou Never défini en pre.007.

overflow_count est conservé à travers les snapshots et les reconnects. Il reste distinct de continuity_gap_count : le premier décrit une saturation locale d'un consumer, le second une interruption de continuité physique.

Tests déterministes ajoutés ou renforcés

Les fixtures locales couvrent notamment :

  • queue capacité 1 avec deux notifications et consumer lent ;
  • overflow_count == 1 après saturation ;
  • cause terminale ws_backpressure_overflow sur le seul handle lent ;
  • première notification déjà queueée encore lisible puis fermeture du receiver ;
  • subscription saine parallèle toujours Active et recevant sa notification ;
  • session physique toujours Active après overflow isolé ;
  • *Unsubscribe distant best-effort exact après overflow ;
  • plafond max_active_subscriptions sans incrément du compteur d'overflow ;
  • capacité réutilisable après unsubscribe terminal ;
  • receiver abandonné détecté sur notification suivante, cleanup distant et capacité réutilisable ;
  • mismatch de méthode publiant ws_protocol_error sur le handle ;
  • decode typed invalide publiant invalid_response sur le handle ;
  • policy Never publiant ws_connection_failed sur le handle terminal ;
  • erreur RPC applicative de resubscribe publiant rpc_application_error sur le handle concerné.

Les tests HTTP et la surface 52+14 restent inchangés fonctionnellement.

Logging et sécurité

Tous les diagnostics passent par ksp-logging-lib avec le target crate-owned existant.

Les logs d'overflow/cleanup contiennent uniquement des métadonnées sûres : session ID local, subscription ID local, kind, compteur et code KSP. Ils ne contiennent jamais l'URL, le remote subscription ID ni le payload de notification.

Validation exécutée dans le sandbox

Le sandbox ne fournit pas cargo, rustc ni rustfmt. Aucune validation Cargo de cette tranche n'est revendiquée ici.

Les contrôles statiques KSP et l'overlay exact sont exécutés avant publication de l'archive.

Validation opérateur requise

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

Décisions

  • overflow_count compte uniquement les saturations des queues de notifications ; un rejet d'admission par max_active_subscriptions ne l'incrémente pas.
  • Une queue pleine fait échouer la subscription au lieu de bloquer l'actor ou de dropper silencieusement des notifications.
  • La cause terminale publique reste un ErrorCode KSP sans contenu distant arbitraire.
  • Le cleanup distant est best-effort et non bloquant ; la terminaison locale reste prioritaire.
  • Une subscription terminale libère sa capacité locale et n'est jamais resubscribe automatiquement.
  • Les wrappers WebSocket Solana standard publics restent réservés à pre.009+.

Questions ouvertes

Aucune question bloquante pour ce checkpoint. La tranche suivante peut ouvrir le premier lot de wrappers standard stables : account, program et logs.