# Plan `0.2.8` — Helius LaserStream WebSocket > **Statut : `0.2.8-pre.002` matérialise le socle protocolaire décidé par le gate `pre.001`.** Le moteur physique `WsSession` de `0.2.7` reste unique et partagé ; `SolanaStandardWsSession` devient la façade standard explicite et `HeliusLaserStreamWsSession` ouvre le lifecycle Helius LaserStream WebSocket sans encore exposer ses subscriptions. Le constructeur historique `WsSession::connect` reste standard-only et les six wrappers Helius communs restent réservés à `pre.003`. ## 1. Objet, base et état du gate `0.2.8` étend le moteur WebSocket publié par `0.2.7` avec la surface Helius LaserStream WebSocket réellement documentée, sans créer un second moteur/session actor et sans confondre WebSocket avec LaserStream gRPC. Base autoritaire auditée : ```text archive fournie : khadhroony-solana-project-v0.2.7-full-from-gitea.zip workspace.package.version avant ouverture = 0.2.7 delta stable présent = deltas/0.2.7/rel.001.md prompt actif présent = prompts/013-V0_2_8_START_PROMPT.md Git metadata dans l'archive = absente ; le tag n'est donc pas revalidable localement avec git ``` `0.2.8-pre.001` a ouvert techniquement : ```text workspace.package.version = 0.2.8-pre.1 livraison = 0.2.8-pre.001 ``` Correctifs documentaires appliqués à `pre.001` : ```text 0.2.8-pre.001-fix.001 séparation des façades protocolaires + fermeture du gate Cargo 0.2.8-pre.001-fix.002 normalisation du forecast + clarification LaserStream WebSocket/gRPC livraison précédente = 0.2.8-pre.001-fix.002 livraison courante = 0.2.8-pre.002 workspace.package.version = 0.2.8-pre.2 commit attendu = v0.2.8-pre.002 aucun tag prerelease ``` Les deux graphes Cargo manquants lors de la préparation initiale ont été fournis par l'opérateur le 2026-08-23 : ```text cargo tree -p ksp-onchain-transport-lib exécuté cargo tree -p ksp-onchain-transport-lib --duplicates exécuté ``` Constat : aucune dépendance Helius/SDK ajoutée ; les doublons visibles sont transitifs (`syn` 2/3 et `webpki-roots` 0.26/1.0) et ne constituent pas une anomalie bloquante de `pre.001`. **Verdict courant : gate `pre.001` positif ; socle `pre.002` implémenté dans la présente livraison.** Les validations compilées restent à exécuter par l'opérateur avant commit. ## 2. Décisions structurantes de `pre.001-fix.001` / `fix.002` — séparer les surfaces, qualifier le protocole La première version du plan prévoyait un unique `WsSession` public exposant toutes les méthodes standard et une matrice de capabilities rejetant à l'exécution les méthodes incompatibles avec Helius. Cette approche est remplacée par une séparation plus forte : **les méthodes impossibles pour un protocole doivent être absentes de sa façade publique**. Architecture cible : ```text moteur physique commun WsSession actor/socket/reconnect/queues pending/remapping/backpressure/close │ ┌───────────────┴────────────────┐ │ │ ▼ ▼ SolanaStandardWsSession HeliusLaserStreamWsSession façade protocole standard façade protocole Helius │ │ 9 familles standard 6 familles communes + transaction + policy heartbeat ``` Principe : ```text ce qui est dupliqué/séparé : façade publique de protocole méthodes disponibles policy/capabilities du protocole DTOs provider-specific lorsque le wire diverge heartbeat/provider behavior ce qui reste partagé : socket physique actor unique command queue / pending JSON-RPC WsSubscription local/remote IDs et remapping reconnect/resubscribe machinery backpressure shutdown snapshots/redaction DTOs wire réellement identiques ``` Aucun `HeliusWsClient`, aucun second actor et aucune copie du lifecycle physique ne sont autorisés. ### 2.1 Surface `SolanaStandardWsSession` La façade standard expose exactement les neuf familles acquises en `0.2.7` : ```text account block logs program root signature slot slotsUpdates vote ``` Les 18 opérations standard restent donc présentes et testées : 9 subscribe + 9 unsubscribe. ### 2.2 Surface cible `HeliusLaserStreamWsSession` À partir de `pre.003`, la façade Helius doit exposer uniquement les familles de subscription suivantes : ```text account logs program root signature slot transaction ``` Même après `pre.003`, elle **n'expose pas** : ```text block slotsUpdates vote ``` L'objectif est qu'un appel du genre : ```text helius.block_subscribe(...) ``` soit absent de l'API Helius et donc impossible à écrire contre la façade Helius, plutôt que simplement rejeté après construction d'une requête. La validation runtime avant I/O reste conservée en défense en profondeur pour les constructeurs, descriptors internes et chemins de compatibilité. ### 2.3 Compatibilité de `WsSession` publié en `0.2.7` `WsSession` est déjà public et ses wrappers standard sont déjà stabilisés. `0.2.8` ne les supprime pas et ne casse pas les consommateurs existants. Décision cible : ```text WsSession reste le handle/moteur physique partagé conserve la compatibilité publique standard publiée en 0.2.7 ne devient pas l'entrée publique Helius générique SolanaStandardWsSession nouvelle façade explicite/recommandée pour le protocole standard délègue au même WsSession HeliusLaserStreamWsSession nouvelle façade Helius contient/délègue à un WsSession privé n'expose aucun getter/into_inner permettant de contourner sa surface en 0.2.8 ``` Le chemin public historique `WsSession::connect` doit rester compatible avec `SolanaStandard`. Lors de l'introduction de `HeliusLaserStream`, il ne doit pas permettre d'obtenir un `WsSession` générique Helius puis d'appeler une méthode standard non supportée. Le socle de `pre.002` doit donc extraire/réutiliser un chemin de connexion physique interne partageable, tout en gardant un garde protocolaire sur les constructeurs publics. ### 2.4 DTOs communs versus DTOs Helius Les six familles communes réutilisent les DTOs standard lorsque le wire et la sémantique sont réellement identiques : ```text account logs program root signature slot ``` Ne pas créer artificiellement `HeliusAccountNotification`, `HeliusLogsNotification`, etc. si ces types seraient des copies strictes des types standard. Créer des types Helius distincts dès que le contrat diverge ou n'existe pas en standard : ```text HeliusTransactionSubscribeFilter HeliusTokenAccountsMode HeliusTransactionEncoding HeliusTransactionSubscribeOptions HeliusTransactionNotification / formes prouvées ``` Une option provider-specific ne doit jamais être injectée dans un DTO Solana standard pour éviter une duplication de façade. ### 2.5 Kind de subscription et registry interne `WsSubscriptionKind` appartient au lifecycle/snapshot commun et non à la capacité d'invocation publique. Il peut être étendu de manière `#[non_exhaustive]` avec une variante provider-explicite pour `transaction` si cela minimise la rupture du snapshot existant. Le point obligatoire n'est pas de dupliquer cet enum à tout prix ; le point obligatoire est que : ```text la façade Helius ne puisse pas invoquer Block/SlotsUpdates/Vote la façade standard ne puisse pas invoquer HeliusTransaction le registry/actor interne reste unique et provider-neutral ``` Si `pre.002` montre qu'un descriptor interne distinct rend le snapshot plus propre sans rupture publique, cette forme peut être retenue. Aucun refactor ne doit toutefois remplacer une séparation de façade simple par une hiérarchie générique lourde. ### 2.6 Réalisation de `pre.002` Le socle concret retient une séparation minimale sans dupliquer les wrappers wire ni l'actor : ```text WsSession::connect(endpoint) -> accepte uniquement WsProtocolKind::SolanaStandard -> compatibilité publique 0.2.7 conservée SolanaStandardWsSession::connect(endpoint) -> guard SolanaStandard -> WsSession::connect_for_protocol(...) interne -> même connect_physical / même run_ws_session_actor -> délègue les 9 wrappers standard existants HeliusLaserStreamWsSession::connect(endpoint) -> guard HeliusLaserStream -> WsSession::connect_for_protocol(...) interne -> même connect_physical / même run_ws_session_actor -> lifecycle seulement en pre.002 -> aucune subscription Helius exposée avant pre.003 ``` `WsProtocolKind` possède désormais : ```text SolanaStandard -> solana_standard HeliusLaserStream -> helius_laserstream ``` Les mismatches de constructeur sont rejetés avec `ERROR_CODE_INVALID_SETTINGS` et des contextes sûrs `expected_protocol` / `actual_protocol`, avant toute tentative réseau. Aucune URL ni credential n'entre dans cette erreur. La façade Helius conserve son `WsSession` interne privé et ne fournit ni `inner()` ni `into_inner()`. Des canaries `compile_fail` verrouillent l'absence de `block_subscribe` et de l'escape hatch à ce stade. Une canary source confirme aussi que le module de façade ne contient ni second `tokio::spawn`, ni `tokio_tungstenite`, ni `WsSessionCommand`. La façade standard délègue déjà les neuf familles existantes sans recopier leurs encoders/decoders : ```text account block logs program root signature slot slotsUpdates vote ``` La façade Helius ne recevra les six délégations communes qu'en `pre.003`, afin de garder la tranche actuelle limitée au socle protocolaire et aux guards. ## 3. Forecast souple recalibré Le forecast suit le format historique des plans KSP `0.2.5` et `0.2.7` : un bloc compact, directement révisable, qui porte aussi l'état courant des tranches. Les `fix.*` sont rattachés à leur prerelease d'origine au lieu d'être présentés comme des tranches planifiées autonomes. ```text pre.001 DONE — audit Helius actuel + matrice + architecture + threat model + dependencies + sizing fix.001 DONE — séparation des façades standard/Helius + moteur unique + gate Cargo fermé fix.002 DONE — forecast normalisé + namespace LaserStream WebSocket/gRPC clarifié pre.002 PREPARED — socle protocolaire : WsProtocolKind::HeliusLaserStream + façades standard/Helius + connexion physique partagée + guards, sans duplication de l'actor pre.003 surface Helius standard supportée : account/logs/program/root/signature/slot + absence typée de block/slotsUpdates/vote sur Helius + non-régression standard 9/9 pre.004 Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport + stratégie de secret Helius et redaction URL pre.005 transactionSubscribe request typed + filters/options/tokenAccounts + transactionUnsubscribe + bounds 50k + maxSupportedTransactionVersion conditionnel pre.006 transactionNotification + actor integration + reconnect/resubscribe/unsubscribe races + late notifications + backpressure ciblée pre.007 heartbeat Helius WebSocket/idle + timers + interaction reconnect/control frames/shutdown 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 pre.010 smoke Helius WebSocket live opt-in si stratégie sûre + README/USAGE + cargo tree direct/duplicates final pre.011 validation workspace finale + fermeture plan/matrice/indexes + prompt 0.2.9 rel.001 publication stable stricte ``` Règles de lecture et de recalibrage : - une ligne `pre.NNN` représente une tranche de travail planifiée ; ses `fix.MMM` éventuels sont regroupés dessous et n'augmentent pas artificiellement le forecast initial ; - l'état (`DONE`, puis si utile un état intermédiaire explicite) peut être mis à jour directement dans ce bloc lorsque la tranche évolue ; - chaque nouvelle prerelease vise nominalement environ **15–20 minutes** de travail effectif ; - un `fix` reste insérable après n'importe quelle prerelease ; - une tranche qui cache plusieurs problèmes indépendants ou dépasse réellement le budget est scindée ; - une nouvelle ambiguïté normative peut ajouter une prerelease ; - `pre.011` n'est ni une deadline ni un critère de clôture : `pre.012+` reste autorisé ; - les détails d'exécution restent dans les deltas ; ce bloc sert de forecast courant et de vue d'état, pas de changelog détaillé. Critères de split déjà identifiés : notification decoding multiforme non documenté, refactor générique du lifecycle nécessaire, évolution Helius normative en cours de release, ou stratégie live nécessitant une surface d'intégration séparée. ## 4. Sources internes relues et hiérarchie appliquée Les sources internes obligatoires du prompt ont été relues depuis la base stable, notamment : ```text RULES.md docs/000-README.md docs/rules/RULES_GENERAL.md docs/rules/RULES_KSP.md docs/rules/RULES_RUST.md docs/rules/RULES_DEPENDENCIES.md docs/rules/RULES_DOCUMENTATION.md docs/rules/FILE_CONTRACTS.md docs/rules/VERSION_WORKFLOW.md docs/rules/PROMPT_STRUCTURE.md docs/architecture/000-README.md docs/architecture/002-LAYERS_AND_DEPENDENCIES.md docs/architecture/003-COMPONENT_CONTRACTS.md docs/architecture/004-COMPONENT_INVENTORY.md docs/architecture/005-DEPENDENCY_GRAPH.md docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md docs/validation/003-V0_2_1_ONCHAIN_HTTP.md docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md deltas/0.2.7/rel.001.md docs/IDEAS.md crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/README.md crates/ksp-onchain-transport-lib/USAGE.md crates/ksp-onchain-transport-lib/src/** crates/ksp-onchain-transport-lib/tests/** crates/ksp-config-lib/Cargo.toml crates/ksp-config-lib/src/transport.rs crates/ksp-config-lib/unit_tests/transport.rs config/std.transport.json config/schemas/std.transport.schema.json .env.example ``` Décisions de workflow conservées : - `pre.001` reste audit + brainstorming + sizing ; - ce fix corrige uniquement le design prévu par cette tranche ; - une prerelease non-fix synchronise toujours Cargo ; - un fix documentaire conserve la version Cargo de sa base ; - `ROADMAP.md` reste global ; les détails vivent dans plan/validation/deltas ; - `CHANGELOG.md` reste principalement réservé à la publication stable. ## 5. Baseline de démarrage et graphes Cargo ### 5.1 Baseline opérateur sur `v0.2.7` Le log opérateur fourni avant ouverture de `0.2.8` enregistre : ```text cargo fmt --all OK python3 scripts/audit_rust_workspace_rules.py OK / clean cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test --workspace OK ``` Les tests live/bench explicitement opt-in restent ignorés par défaut, conformément à leurs contrats. ### 5.2 Graphes fournis après application de `pre.001` État observé : ```text ksp-onchain-transport-lib = 0.2.8-pre.1 futures-util = 0.3.34 tokio = 1.53.1 tokio-tungstenite = 0.30.0 reqwest = 0.13.4 new Helius dependency = aucune ``` `cargo tree --duplicates` ciblé montre uniquement des doublons transitifs attendus dans le graphe courant : ```text syn 2.0.119 / 3.0.3 webpki-roots 0.26.11 / 1.0.9 ``` Aucun doublon direct introduit par `0.2.8-pre.001`, aucun SDK Helius et aucune inversion de dépendance KSP ne sont observés. ## 6. État réel hérité de `v0.2.7` ### 6.1 HTTP à ne pas régresser ```text 52/52 méthodes HTTP courantes typées 14/14 méthodes historiques Deprecated/Removed conservées KSP-TRANSPORT-007 appliqué write submissions sans resend après dispatch ambigu ``` ### 6.2 WebSocket standard publié Le runtime stable expose neuf familles : ```text Account Block Logs Program Root Signature Slot SlotsUpdates Vote ``` Partition : ```text stable : Account, Logs, Program, Root, Signature, Slot unstable : Block, SlotsUpdates, Vote ``` Le moteur possède déjà : actor unique propriétaire du socket, pending JSON-RPC borné, queues bornées, local IDs stables, remote IDs internes/remappables, reconnect fini, resubscribe déterministe, cleanup late ACK, backpressure isolée, `continuity_gap_count`, one-shot Signature et `close().await` borné. ### 6.3 Contrats publics utiles `WsProtocolKind` est `#[non_exhaustive]` et ne contient en `v0.2.7` que : ```text SolanaStandard -> "solana_standard" ``` `WsEndpointSettings` fournit déjà : ```text name enabled provider cluster protocol kind WsEndpointUrl redacted WsSessionSettings ``` `WsSession` est un handle `Clone` vers un actor unique et les wrappers standard sont implémentés directement sur ce type. Cette réalité explique la correction de `pre.001-fix.001` : la façade Helius ne doit pas être le même type public surchargé de méthodes incompatibles. ### 6.4 Config V2 ```text format_version = 2 retry ws_defaults default_profile profiles[].endpoints[] profiles[].ws_endpoints[].kind ``` Le schema et l'adapter n'acceptent actuellement que : ```text solana_standard ``` ## 7. Audit Helius officiel du 2026-08-23 ### 7.1 Sources primaires utilisées ```text https://www.helius.dev/docs/rpc/websocket https://www.helius.dev/docs/api-reference/rpc/websocket-methods https://www.helius.dev/docs/api-reference/rpc/websocket/transactionsubscribe https://www.helius.dev/docs/rpc/websocket/transaction-subscribe https://www.helius.dev/docs/rpc/websocket/token-account-filtering https://www.helius.dev/docs/api-reference/rpc/websocket/accountsubscribe https://www.helius.dev/docs/rpc/websocket/account-subscribe https://www.helius.dev/docs/api-reference/rpc/websocket/programsubscribe https://www.helius.dev/docs/api-reference/rpc/websocket/slotsupdatessubscribe https://www.helius.dev/docs/faqs/websockets https://www.helius.dev/docs/api-reference/rpc/websocket/llms.txt https://www.helius.dev/docs/llms.txt ``` Les documents `llms.txt` servent d'index et de source secondaire. Lorsqu'ils divergent d'une page de référence dédiée ou de la page exhaustive des méthodes, la divergence est enregistrée. ### 7.2 Terminologie et endpoints ```text nom produit courant = LaserStream WebSocket ancien nom = Enhanced WebSockets, intégré à LaserStream WebSocket mainnet = wss://mainnet.helius-rpc.com/?api-key=... devnet = wss://devnet.helius-rpc.com/?api-key=... credential = api-key en query URL, Secret Gatekeeper beta = hors 0.2.8 LaserStream gRPC = distinct, hors 0.2.8 ``` ### 7.3 Inventaire provider retenu ```text standard supporté : account, logs, program, root, signature, slot Helius extension : transactionSubscribe / transactionUnsubscribe non supporté : block, slotsUpdates, vote ``` `transactionUnsubscribe` est documenté dans la référence `transactionSubscribe` avec : ```text method = transactionUnsubscribe params = [remoteSubscriptionId] result = true ``` La référence précise que quelques notifications in-flight peuvent encore arriver après l'unsubscribe. ### 7.4 Divergence `slotsUpdatesSubscribe` Les sources Helius se contredisent : - `websocket-methods` classe `slotsUpdatesSubscribe`/`slotsUpdatesUnsubscribe` parmi les méthodes unstable non supportées ; - la page individuelle indique que la méthode est unstable et peut ne pas être supportée ; - `websocket/llms.txt` la place aussi dans une section « Stable, Helius-supported ». Décision KSP : ```text HeliusLaserStreamWsSession n'expose pas SlotsUpdates ``` Une validation interne garde aussi un rejet avant I/O si un descriptor incompatible atteint le moteur par un chemin interne ou de compatibilité. ### 7.5 `transactionSubscribe` Filtre courant : ```text vote Option failed Option signature Option accountInclude Option max 50_000 accountExclude Option max 50_000 accountRequired Option max 50_000 tokenAccounts none | balanceChanged | all ``` Options : ```text commitment processed | confirmed | finalized encoding base58 | base64 | jsonParsed transactionDetails full | signatures | accounts | none showRewards bool maxSupportedTransactionVersion integer ``` `maxSupportedTransactionVersion` est requis lorsque `transactionDetails` vaut `accounts` ou `full`. Notification : ```text method = transactionNotification ``` La documentation ne détaille pas avec la même précision chacun des quatre modes de `transactionDetails`. KSP ne doit pas inventer ces formes : types précis pour les formes prouvées et fallback borné uniquement si nécessaire. ### 7.6 `accountSubscribe` / `programSubscribe` et `notifyOn` `notifyOn` est documenté mais marqué : ```text deprecated no-op depuis Agave 4.2 suppression future annoncée ``` Décision : ne pas l'ajouter aux DTOs KSP. Les pages continuent à employer « enhanced/filtered accountSubscribe » sans publier un wire provider-specific supplémentaire assez précis pour une API typed. Ce point reste reporté explicitement. ## 8. Matrice normative Helius WebSocket | Famille | Paire | Classe | Support Helius retenu | Surface publique Helius | Paramètres/options utiles | Notification | Stratégie KSP/test | |---------------------|-----------------------------------------------------|------------------|-----------------------|-------------------------|------------------------------------|---------------------------|----------------------------------------------------| | `account` | `accountSubscribe` / `accountUnsubscribe` | Solana standard | Oui | présente | contrat standard ; `notifyOn` omis | `accountNotification` | DTO/wire standard partagé | | `block` | `blockSubscribe` / `blockUnsubscribe` | Solana unstable | **Non** | **absente** | aucune émission provider | théorique | façade Helius sans méthode + guard interne | | `logs` | `logsSubscribe` / `logsUnsubscribe` | Solana standard | Oui | présente | contrat standard | `logsNotification` | DTO/wire standard partagé | | `program` | `programSubscribe` / `programUnsubscribe` | Solana standard | Oui | présente | contrat standard ; `notifyOn` omis | `programNotification` | DTO/wire standard partagé | | `root` | `rootSubscribe` / `rootUnsubscribe` | Solana standard | Oui | présente | aucun paramètre | `rootNotification` | wrapper partagé | | `signature` | `signatureSubscribe` / `signatureUnsubscribe` | Solana standard | Oui | présente | one-shot conservé | `signatureNotification` | wrapper partagé + terminal close | | `slot` | `slotSubscribe` / `slotUnsubscribe` | Solana standard | Oui | présente | aucun paramètre | `slotNotification` | wrapper partagé | | `slotsUpdates` | `slotsUpdatesSubscribe` / `slotsUpdatesUnsubscribe` | Solana unstable | **Non** | **absente** | aucune émission provider | théorique | façade Helius sans méthode + divergence documentée | | `vote` | `voteSubscribe` / `voteUnsubscribe` | Solana unstable | **Non** | **absente** | aucune émission provider | théorique | façade Helius sans méthode + guard interne | | `heliusTransaction` | `transactionSubscribe` / `transactionUnsubscribe` | Helius extension | Oui | présente | filtres/options/`tokenAccounts` | `transactionNotification` | DTOs Helius + actor partagé | Statut : ```text SolanaStandardWsSession : 9 familles / 18 opérations standard HeliusLaserStreamWsSession : 6 familles standard supportées + 1 famille Helius ``` La compliance standard KSP reste **18/18** pour `SolanaStandard`. ## 9. Décisions d'architecture détaillées ### 9.1 Protocol kind et namespace LaserStream Retenir pour **WebSocket uniquement** : ```text WsProtocolKind::HeliusLaserStream as_str() = "helius_laserstream" provider metadata attendu = "helius" Config owner = profiles[].ws_endpoints[].kind façade publique = HeliusLaserStreamWsSession ``` `helius_laserstream` n'est donc pas un nom de transport générique Helius : il est possédé par le namespace WebSocket (`WsProtocolKind` / `ws_endpoints`). Dans toute prose, log safe metadata, documentation ou API où ce contexte n'est pas déjà évident, employer **Helius LaserStream WebSocket** et non le raccourci ambigu « Helius LaserStream ». Le futur **Helius LaserStream gRPC** reste un backend/provider distinct, hors `0.2.8`. Il ne doit jamais être représenté par `WsProtocolKind`, `WsEndpointSettings`, `HeliusLaserStreamWsSession` ni `ws_endpoints`. Son éventuel protocol kind, discriminateur Config et façade seront décidés par l'audit de la release gRPC concernée ; ils devront porter un ownership gRPC explicite et ne pourront pas réutiliser le contrat WebSocket par simple alias de nom produit. Cette règle permet de conserver le code court `helius_laserstream` dans son conteneur WS sans créer d'ambiguïté future entre les deux produits portant le nom LaserStream. ### 9.2 Connexion et propriété du moteur Cible de `pre.002` : ```text un seul code de création/spawn de l'actor physique un seul type de socket physique un seul registry pending/subscriptions un seul lifecycle reconnect/backpressure/shutdown ``` Les façades délèguent à ce moteur commun. Le mécanisme précis d'extraction du chemin physique est choisi en `pre.002` à partir du code réel, avec les invariants suivants : ```text pas de clone du run_ws_session_actor pas de second WsSessionCommand pas de second snapshot model pas de public escape hatch Helius -> raw standard WsSession ``` ### 9.3 Capability validation defense-in-depth La séparation de façade est la première barrière. Une matrice interne reste utile : ```text SolanaStandard: Account Block Logs Program Root Signature Slot SlotsUpdates Vote -> allowed HeliusTransaction -> rejected HeliusLaserStream: Account Logs Program Root Signature Slot HeliusTransaction -> allowed Block SlotsUpdates Vote -> rejected ``` Cette matrice sert aux guards de constructor/descriptor, aux canaries et à la protection interne ; elle ne remplace plus la séparation de l'API publique. ### 9.4 Heartbeat/idle ownership Helius annonce un timeout d'inactivité de 10 minutes et recommande des pings périodiques. Décision : heartbeat provider-owned dans l'actor existant, activé pour `WsProtocolKind::HeliusLaserStream` (LaserStream **WebSocket**), sans champ public générique ajouté à `WsSessionSettings` dans cette release. Politique cible : ```text intervalle nominal = 60 s frame = WebSocket Ping control frame actif = session Active seulement close/failure = timer annulé reconnect réussi = timer réarmé write failure = chemin disconnect/reconnect existant budget reconnect = fini, inchangé ``` ### 9.5 Config V2 Évolution : ```text profiles[].ws_endpoints[].kind: solana_standard helius_laserstream ``` Les paramètres de `transactionSubscribe` restent runtime et n'appartiennent pas au profil endpoint Config. ### 9.6 Credentials L'api-key reste uniquement dans l'URL résolue : ```text wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY} ``` Le nom final du secret est matérialisé avec Config. Transport ne lit jamais `std::env` et reçoit un `WsEndpointUrl` redacted. ## 10. Threat model provider ### 10.1 Secret dans query URL Risque : fuite par `Debug`, handshake error, logs tungstenite ou contexte d'erreur. Mesures : `WsEndpointUrl` opaque/redacted, mapping vers metadata sûre, canaris avec secret reconnaissable. ### 10.2 Contournement de façade Risque nouveau identifié par le fix : obtenir un handle générique Helius puis appeler une méthode standard non supportée. Mesures : ```text HeliusLaserStreamWsSession possède son inner privé aucun inner()/into_inner() public en 0.2.8 constructeur générique historique gardé standard-only validation protocolaire interne avant I/O ``` ### 10.3 Heartbeat concurrent avec reconnect/close Timer détenu par l'actor, actif seulement en `Active`, reset/cancel avec lifecycle, test déterministe par cadence raccourcie interne/test-only. ### 10.4 Late notifications et IDs distants Après `transactionUnsubscribe`, les messages in-flight sont possibles. L'unsubscribe local gagne ; un remote ID tardif ne réactive pas la subscription. ### 10.5 Payload transaction volumineux Conserver `max_message_size_bytes`, `max_frame_size_bytes`, queue bornée par subscription et absence de payload brut dans les logs/snapshots. ### 10.6 Filtres 50k Valider chaque liste avant I/O, ne pas logguer les valeurs et éviter les clones inutiles. ### 10.7 Continuité ```text reconnect oui resubscribe oui continuity_gap_count oui backfill non historical replay non lossless WebSocket non ``` ## 11. Audit dépendances Versions observées dans le graphe opérateur : ```text futures-util 0.3.34 tokio 1.53.1 tokio-tungstenite 0.30.0 reqwest 0.13.4 ``` Verdict : **aucune nouvelle dépendance**. Le moteur courant sait déjà gérer TLS WebSocket, Ping/Pong, timers Tokio, futures sink/stream et JSON serde. Un SDK Helius dupliquerait des choix de lifecycle que KSP possède déjà. ## 12. Stratégie de tests ### 12.1 Architecture/façades Prévoir : ```text public API canary SolanaStandardWsSession public API canary HeliusLaserStreamWsSession Helius facade sans block/slotsUpdates/vote Solana facade sans transactionSubscribe Helius facade sans escape hatch vers WsSession générique WsSession historique standard toujours disponible un seul actor/socket implementation path constructeur protocolaire invalide rejeté avant I/O ``` L'absence d'une méthode peut être couverte par compile-fail doctest/canary sans ajouter de dépendance de test si cette forme reste compatible avec les règles Rust KSP. ### 12.2 Helius transaction/lifecycle ```text transactionSubscribe serialization exacte transactionUnsubscribe exact transactionNotification method exact ack/error RPC 50k/50k/50k bounds maxSupportedTransactionVersion requirement tokenAccounts exact enum late notifications après unsubscribe remote id remapping reconnect/resubscribe provider RPC error sans session failure heartbeat timer + cancellation shutdown pendant heartbeat/reconnect oversized frame/message queue overflow isolé URL/api-key redaction ``` ### 12.3 Non-régressions ```text standard WS 18/18 pour SolanaStandard partition unstable 3/9 inchangée signature one-shot inchangée HTTP 52 current + 14 historical KSP-TRANSPORT-007 Config V1 HTTP-only backward readable Config V2 solana_standard backward readable no Transport -> Config/Wallet/Store/Program/tracing direct ``` ## 13. Smoke live Helius Le live reste opt-in et secondaire par rapport aux fixtures déterministes. Stratégie : Config résout le secret et construit l'endpoint Helius ; Transport ne lit jamais l'environnement. Si aucune surface d'intégration sûre n'est disponible, le smoke opérateur peut rester documenté plutôt que d'introduire une dépendance inverse. ## 14. Questions explicitement reportées ```text wire exact d'un éventuel enhanced/filtered accountSubscribe provider-specific modes transactionNotification non suffisamment documentés Gatekeeper beta provider metering/billing LaserStream gRPC / replay Yellowstone gRPC pool/scheduler automatique de sessions configuration publique arbitraire du heartbeat refonte générique WsSession

: non nécessaire en 0.2.8 ``` Une nouvelle preuve normative peut rouvrir un point et insérer une tranche ; aucun report ne doit disparaître silencieusement. ## 15. Critères de split et de clôture Créer une tranche/fix supplémentaire si : - l'extraction du chemin physique de `WsSession` révèle un problème générique indépendant ; - une des six familles Helius dites communes diverge réellement du standard ; - plusieurs formes de notification transaction demandent des contrats séparés ; - Helius modifie sa surface normative pendant la release ; - le smoke live impose une intégration non disponible ; - un gate final reste rouge après `pre.011`. La release ne passe stable que si : ```text surface Helius rapprochée source par source façades protocolaires séparées moteur WsSession/actor unique unsupported Helius absent de la façade publique transaction extension sans pollution des DTOs standard standard WS 18/18 non régressé HTTP 52/14 non régressé Config -> Transport uniquement credentials redacted heartbeat borné/testé si implémenté reconnect/resubscribe/backpressure/shutdown bornés aucune promesse replay/lossless WebSocket aucune nouvelle dépendance injustifiée workspace complet vert README/USAGE synchronisés validation finale fermée prompt 0.2.9 prêt ``` ## 16. Verdict après `pre.002` Décisions fermées : ```text base stable autoritaire confirmé surface Helius actuelle auditée Cargo graph audité, non bloquant protocol kind HeliusLaserStream / helius_laserstream namespace WebSocket-owned ; gRPC explicitement distinct/hors 0.2.8 moteur physique WsSession actor unique, partagé façade standard SolanaStandardWsSession façade Helius HeliusLaserStreamWsSession Helius standard exposé Account Logs Program Root Signature Slot Helius standard absent Block SlotsUpdates Vote Helius extension Transaction DTOs communs réutilisés si wire identique DTOs provider dédiés uniquement si divergence capability guard defense-in-depth avant I/O heartbeat actor provider-owned, 60s cible Config V2 kind addition, même conteneur credential URL Secret résolue par Config new dependency aucune historical/lossless replay aucune promesse forecast format compact KSP, fixes groupés, pre.001 -> pre.011 pre.002 protocol kind matérialisé : SolanaStandard + HeliusLaserStream pre.002 standard facade 9 wrappers existants délégués, aucun wire dupliqué pre.002 Helius facade lifecycle seulement, inner privé pre.002 generic WsSession constructeur public standard-only pre.002 physical connection chemin unique partagé, aucun second actor pre.002 Config/transaction/heartbeat non commencés conformément au forecast ``` **`pre.002` est préparé ; après validations opérateur vertes, la prochaine tranche est `0.2.8-pre.003` — six familles standard supportées sur la façade Helius et absence typée durable des trois familles non supportées.**