v0.2.8-pre.001

This commit is contained in:
2026-08-23 12:36:54 +02:00
parent 4d77b607ea
commit f0865d5137
8 changed files with 1241 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 56 -->
<!-- version: 57 -->
# Plans KSP
@@ -23,6 +23,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
- [`012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](012-V0_2_5_WALLET_FOUNDATION_PLAN.md) — plan historique clôturé de la release stable `0.2.5 — Wallet foundation`, ouvert par `pre.001`, livré jusquà `pre.010`, renforcé par `pre.010-fix.001``fix.003` pour Dalek 3 et la normalisation Rust/audit structurel, puis publié par `rel.001`; il couvre `.kspwallet` V1, VIEW/OWNER, crypto, persistence, administration, transfer et compliance.
- [`013-V0_2_6_WALLET_DESK_PLAN.md`](013-V0_2_6_WALLET_DESK_PLAN.md) — plan historique clôturé de la release stable `0.2.6 — Wallet Desk`, ouvert par `pre.001`, étendu en `pre.015``pre.017` au wire binaire `.kspwallet` V2, aux APIs multi-version et à la migration V1 -> V2, puis fermé par `pre.018`/`fix.001` avec le runtime Tauri packagé et le build final vert avant publication `rel.001`.
- [`014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md`](014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md) — plan historique clôturé de la release stable `0.2.7 — WebSocket Solana standard`, ouvert par `pre.001`, exécuté jusquà `pre.014`, corrigé documentairement par `pre.014-fix.001` puis publié par `rel.001`; il conserve linventaire officiel 18 méthodes, le modèle session/subscription, le threat model, les preuves de compliance/smoke/dépendances et la préparation de `0.2.8`.
- [`015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md`](015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md) — plan actif de `0.2.8 — Helius LaserStream WebSocket`, ouvert par `pre.001`; il conserve laudit Helius du 23 août 2026, la matrice provider, le choix `HeliusLaserStream`, la stratégie transaction/heartbeat/Config/secrets et le forecast souple recalibré.
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
<!-- version: 82 -->
<!-- version: 83 -->
# Séquence des releases fonctionnelles KSP
@@ -465,7 +465,11 @@ La candidate atteint `pre.014` après matérialisation des 9 familles standard,
### `0.2.8` — Helius LaserStream WebSocket
Mission : étendre le moteur WebSocket standard avec les opérations/filtres/capabilities Helius ciblés sans copier le client.
Mission active : étendre le moteur WebSocket standard avec la surface Helius LaserStream WebSocket actuelle sans copier le client/session actor. Le gate `pre.001` est conservé dans [`015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md`](015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md) et la matrice active dans [`../validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md`](../validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md).
L'audit Helius du 23 août 2026 retient `helius_laserstream` comme nouveau protocol kind : les six familles standard `account/logs/program/root/signature/slot` réutilisent les wrappers publiés, tandis que `block/slotsUpdates/vote` sont rejetées avant I/O sur Helius selon l'index provider exhaustif. `transactionSubscribe`/`transactionUnsubscribe` et `tokenAccounts` constituent la nouvelle surface typed principale. `notifyOn`, désormais deprecated et no-op depuis Agave 4.2, n'est pas exposé. Un heartbeat Helius-only est planifié dans l'actor existant pour le timeout d'inactivité provider.
Le forecast souple est recalibré jusqu'à `pre.010` avant `rel.001`; le numéro final reste non contractuel. Aucun SDK Helius, aucune dépendance gRPC et aucun replay historique WebSocket ne sont introduits.
### `0.2.9` — Yellowstone gRPC standard

View File

@@ -0,0 +1,739 @@
<!-- file: docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md -->
<!-- version: 2 -->
# Plan `0.2.8` — Helius LaserStream WebSocket
> **Statut : gate `0.2.8-pre.001` préparé, publication conditionnée aux graphes Cargo opérateur.** L'audit normatif Helius du 23 août 2026, l'inventaire du runtime `v0.2.7`, le threat model provider et le sizing sont fermés. Aucun runtime Helius, aucun changement Config provider et aucune nouvelle dépendance ne sont introduits dans `pre.001`.
## 1. Objet et base vérifiée
`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 client/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
```
La combinaison archive stable fournie + version Cargo stable + delta `rel.001` + prompt actif satisfait la base documentaire exigée par le prompt. Les souvenirs, prereleases et anciennes copies ne sont pas utilisés comme autorité.
`0.2.8-pre.001` ouvre techniquement :
```text
workspace.package.version = 0.2.8-pre.1
livraison = 0.2.8-pre.001
commit attendu = v0.2.8-pre.001
aucun tag prerelease
```
## 2. 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` est audit + brainstorming + sizing ;
- une prerelease non-fix synchronise toujours Cargo ;
- une tranche vise nominalement environ 1520 minutes de travail effectif ;
- le forecast est souple et doit être recalibré, jamais traité comme une deadline ;
- `ROADMAP.md` reste global ; les détails des prereleases vivent dans le plan, la validation et les deltas ;
- `CHANGELOG.md` reste réservé principalement à la publication stable.
## 3. Baseline de démarrage
### 3.1 Preuve opérateur fournie sur `v0.2.7`
Le log opérateur joint à la session enregistre, avant ouverture de `0.2.8` :
```text
cargo fmt --all OK
python3 scripts/audit_rust_workspace_rules.py OK
General Rust rule audit clean
Rust export completeness audit 0 candidate(s)
KSP workspace Rust rule audit 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.
### 3.2 Baseline du sandbox de préparation
Le sandbox de préparation ne fournit pas `cargo`. Avant modification :
```text
python3 scripts/audit_rust_workspace_rules.py OK
cargo fmt/check/clippy/tree IMPOSSIBLE : cargo absent
```
L'archive ne contient pas `.git`; `git status`/validation du tag n'est donc pas disponible dans ce sandbox.
Aucun `cargo tree` de `v0.2.7` n'a été fourni dans le log opérateur de cette session. Les deux graphes imposés par le prompt restent donc un **gate opérateur avant commit** de `pre.001` :
```bash
cargo tree -p ksp-onchain-transport-lib
cargo tree -p ksp-onchain-transport-lib --duplicates
```
## 4. État réel hérité de `v0.2.7`
### 4.1 HTTP à ne pas régresser
Le contrat stable reste :
```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
```
### 4.2 WebSocket standard publié
Le runtime stable expose neuf familles :
```text
Account
Block
Logs
Program
Root
Signature
Slot
SlotsUpdates
Vote
```
avec les paires exactes subscribe/unsubscribe et la 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é.
### 4.3 Contrats publics utiles
`WsProtocolKind` est `#[non_exhaustive]` mais ne contient que :
```text
SolanaStandard -> "solana_standard"
```
`WsEndpointSettings` possède déjà le conteneur commun nécessaire :
```text
name
enabled
provider
cluster
protocol kind
WsEndpointUrl redacted
WsSessionSettings
```
`WsSubscriptionKind` est lui aussi non exhaustif et centralise pour les neuf familles les triplets :
```text
subscribe method
unsubscribe method
notification method
```
`WsSession::subscribe_typed` est interne à la crate et constitue le point naturel de contrôle de capability avant émission JSON-RPC.
### 4.4 Config V2
Le document stable conserve :
```text
format_version = 2
retry
ws_defaults
default_profile
profiles[].endpoints[]
profiles[].ws_endpoints[].kind
```
Le schema et l'adapter n'acceptent aujourd'hui que :
```text
solana_standard
```
La structure a été volontairement rendue extensible en `0.2.7`; il n'est pas nécessaire de créer un nouveau conteneur provider.
## 5. Audit Helius officiel du 2026-08-23
### 5.1 Sources primaires utilisées
Sources Helius relues :
```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 de rapprochement. 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 au lieu d'être résolue silencieusement.
### 5.2 Terminologie et endpoints
Décisions normatives :
```text
nom produit courant = LaserStream WebSocket
ancien nom = Enhanced WebSockets, désormais 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
```
La FAQ Helius confirme que les anciens chemins Enhanced WebSockets redirigent vers la famille LaserStream WebSocket et que les méthodes standard/Helius passent par les mêmes endpoints par réseau.
### 5.3 Inventaire provider retenu
La page exhaustive **LaserStream WebSocket Methods** distingue :
```text
standard supporté : account, logs, program, root, signature, slot
Helius extension : transactionSubscribe
non supporté : block, slotsUpdates, vote
```
`transactionUnsubscribe` n'est pas listé comme entrée séparée dans l'index des méthodes, mais la référence `transactionSubscribe` le documente explicitement avec :
```text
method = transactionUnsubscribe
params = [remoteSubscriptionId]
result = true
```
et précise que quelques notifications in-flight peuvent encore arriver après l'unsubscribe.
### 5.4 Divergence `slotsUpdatesSubscribe`
Les sources Helius se contredisent :
- la page exhaustive `websocket-methods` classe explicitement `slotsUpdatesSubscribe`/`slotsUpdatesUnsubscribe` dans **Unstable Methods (Not Supported)** ;
- la page individuelle dit que la méthode est unstable et « may not always be supported » ;
- le fichier `websocket/llms.txt` la place paradoxalement dans une section « Stable, Helius-supported » avant d'introduire une section de méthodes unstable non supportées.
Décision KSP du gate :
```text
HeliusLaserStream + SlotsUpdates -> capability Unsupported, rejet avant I/O
```
Raison : la page exhaustive courante énonce le support provider le plus explicitement. Un futur réaudit peut changer cette décision si Helius harmonise sa documentation ou si une preuve live sûre l'infirme.
### 5.5 `transactionSubscribe`
Filtre documenté courant :
```text
vote Option<bool>
failed Option<bool>
signature Option<string>
accountInclude Option<string[]> max 50_000
accountExclude Option<string[]> max 50_000
accountRequired Option<string[]> max 50_000
tokenAccounts none | balanceChanged | all
```
`tokenAccounts` étend la correspondance owner/ATA pour les adresses d'`accountInclude`; `none` équivaut à l'absence. Une valeur invalide reçoit actuellement `-32602` côté provider. KSP doit rendre les trois valeurs représentables par type et ne pas exposer une string arbitraire.
Options documentées :
```text
commitment processed | confirmed | finalized
encoding base58 | base64 | jsonParsed
transactionDetails full | signatures | accounts | none
showRewards bool
maxSupportedTransactionVersion integer
```
La référence impose `maxSupportedTransactionVersion` lorsque `transactionDetails` vaut `accounts` ou `full`.
Notification :
```text
method = transactionNotification
```
La forme `full` illustrée contient :
```text
transaction.transaction
transaction.meta
signature
slot
transactionIndex
```
La documentation officielle ne détaille pas avec la même précision la forme de résultat de chacun des quatre modes `transactionDetails`. **KSP ne doit pas inventer ces formes.** Le plan retient un contrat typé capable de représenter les formes prouvées et un fallback `Unknown` borné pour les formes/futures variantes non suffisamment documentées, sur le modèle déjà utilisé pour les variantes standard évolutives.
### 5.6 `accountSubscribe` / `programSubscribe` et `notifyOn`
Les références courantes de `accountSubscribe` et `programSubscribe` documentent `notifyOn` mais le marquent :
```text
deprecated
no-op depuis Agave 4.2
suppression future annoncée
```
Décision : **ne pas ajouter `notifyOn` aux DTOs KSP**.
La FAQ et les indexes continuent d'employer l'expression « enhanced/filtered accountSubscribe », mais la page API courante et le guide `accountSubscribe` ne publient pas de wire provider-specific supplémentaire précis au-delà du contrat standard et du champ `notifyOn` devenu no-op.
Décision :
```text
Account/Program sur HeliusLaserStream -> wrappers standard KSP réutilisés tels quels
nouveau DTO provider account/program -> non
notifyOn -> non exposé
extension account provider non spécifiée exactement -> reportée explicitement
```
Le report n'est pas un oubli : une surface provider ne sera ajoutée que lorsqu'une référence courante fournit un contrat wire exact et testable.
## 6. Matrice normative Helius WebSocket
| Famille | Paire | Classe | Support Helius retenu | Paramètres/options utiles | Notification | Idle/credential | Stratégie KSP/test |
|---------------------|-----------------------------------------------------|------------------|------------------------------------------------|----------------------------------------------------------|--------------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|
| `account` | `accountSubscribe` / `accountUnsubscribe` | Solana standard | Oui | contrat standard ; `notifyOn` deprecated/no-op donc omis | `accountNotification` | ping provider ; api-key query | wrapper 0.2.7 inchangé + fixture capability |
| `block` | `blockSubscribe` / `blockUnsubscribe` | Solana unstable | **Non** | aucune émission provider | `blockNotification` théorique | api-key query | rejet capability avant I/O |
| `logs` | `logsSubscribe` / `logsUnsubscribe` | Solana standard | Oui | contrat standard | `logsNotification` | ping provider ; api-key query | wrapper 0.2.7 inchangé |
| `program` | `programSubscribe` / `programUnsubscribe` | Solana standard | Oui | contrat standard ; `notifyOn` deprecated/no-op donc omis | `programNotification` | ping provider ; api-key query | wrapper 0.2.7 inchangé + filtres existants |
| `root` | `rootSubscribe` / `rootUnsubscribe` | Solana standard | Oui | aucun paramètre | `rootNotification` | ping provider ; api-key query | wrapper 0.2.7 inchangé |
| `signature` | `signatureSubscribe` / `signatureUnsubscribe` | Solana standard | Oui | contrat standard ; one-shot conservé | `signatureNotification` | ping provider ; api-key query | wrapper 0.2.7 + fermeture terminale inchangée |
| `slot` | `slotSubscribe` / `slotUnsubscribe` | Solana standard | Oui | aucun paramètre | `slotNotification` | ping provider ; api-key query | wrapper 0.2.7 inchangé |
| `slotsUpdates` | `slotsUpdatesSubscribe` / `slotsUpdatesUnsubscribe` | Solana unstable | **Non** par page exhaustive ; docs divergentes | aucune émission provider | `slotsUpdatesNotification` théorique | api-key query | rejet avant I/O + canari divergence |
| `vote` | `voteSubscribe` / `voteUnsubscribe` | Solana unstable | **Non** | aucune émission provider | `voteNotification` théorique | api-key query | rejet capability avant I/O |
| `heliusTransaction` | `transactionSubscribe` / `transactionUnsubscribe` | Helius extension | Oui | filtres + `tokenAccounts`; options complètes ci-dessus | `transactionNotification` | ping provider ; api-key query ; extension Developer+ d'après index | nouveaux DTOs typed + fixtures exactes + actor existant |
Statut provider de la surface standard :
```text
6 paires standard supportées
3 paires standard explicitement non supportées
1 paire Helius transaction ajoutée
```
La compliance standard globale KSP reste toutefois **18/18** : les 18 opérations continuent d'exister et de fonctionner pour `WsProtocolKind::SolanaStandard`; le protocol Helius applique une capability matrix différente.
## 7. Décisions d'architecture du gate
### 7.1 Nouveau protocol kind
Retenir :
```text
WsProtocolKind::HeliusLaserStream
as_str() = "helius_laserstream"
provider metadata attendu = "helius"
```
Pourquoi ne pas utiliser `SolanaStandard + provider=helius` : les capabilities et le heartbeat provider changent le comportement de session et l'ensemble de méthodes admissibles. Le discriminateur de protocole est précisément le contrat extensible préparé par `0.2.7`.
`provider` reste une metadata ouverte et sûre ; il ne devient pas un second discriminateur implicite.
### 7.2 Pas de nouveau moteur
Le chemin reste :
```text
WsEndpointSettings
-> WsSession::connect
-> actor existant
-> subscribe_typed / registry
-> local WsSubscriptionId
-> remote id interne/remappable
```
Aucun `HeliusWsClient`, aucun second actor et aucun SDK Helius ne sont prévus.
### 7.3 Extension du registry de subscription
Retenir une nouvelle famille logique provider :
```text
WsSubscriptionKind::HeliusTransaction
subscribe = transactionSubscribe
unsubscribe = transactionUnsubscribe
notification = transactionNotification
```
Le nom public exact pourra rester provider-explicite pour ne pas faire passer `transactionSubscribe` pour une méthode Solana standard.
### 7.4 Capability validation avant I/O
Ajouter une matrice déterministe `protocol kind x subscription kind` avant construction/envoi du RPC :
```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
```
Le rejet doit produire un code d'erreur sûr et stable sans URL/api-key/payload. Une erreur RPC provider reste possible pour des paramètres/quotas/plan runtime non déterministes et ne doit pas tuer la session physique sans raison.
### 7.5 DTOs transaction provider-specific
Créer des types dédiés, sans polluer les DTOs standard :
```text
HeliusTransactionSubscribeFilter
HeliusTokenAccountsMode
HeliusTransactionEncoding
HeliusTransactionSubscribeOptions
HeliusTransactionNotification / variantes prouvées
```
Réutilisations possibles après vérification d'égalité sémantique :
```text
SolanaCommitment
SolanaTransactionDetails
SolanaEncodedTransaction / types transaction wire communs compatibles
SolanaWireField<T>
```
`HeliusTransactionEncoding` doit rester restreint aux valeurs documentées Helius (`base58`, `base64`, `jsonParsed`) plutôt que de réexporter automatiquement toutes les valeurs d'un enum HTTP plus large.
Validation locale prouvable :
```text
accountInclude.len() <= 50_000
accountExclude.len() <= 50_000
accountRequired.len() <= 50_000
accounts/full -> maxSupportedTransactionVersion requis
```
Ne pas inventer de limite agrégée, de minimum ou d'interaction non documentée.
### 7.6 Heartbeat/idle ownership
Helius annonce un timeout d'inactivité de 10 minutes et recommande des pings périodiques, généralement toutes les 3060 secondes / chaque minute.
Décision : **heartbeat provider-owned dans l'actor existant**, activé automatiquement pour `HeliusLaserStream`, sans devenir un champ public générique de `WsSessionSettings` dans cette release.
Politique cible :
```text
intervalle nominal = 60 s
frame = WebSocket Ping control frame
actif uniquement quand la session est Active
annulé pendant close / terminal failure
réarmé après reconnect réussi
échec d'écriture -> chemin disconnect/reconnect existant
aucune boucle de reconnect infinie : budget 0.2.7 conservé
aucun secret/payload dans logs
```
Raison du choix : ce heartbeat est une exigence opérationnelle provider, pas une politique générique démontrée pour tous les protocoles. Une cadence configurable ne sera ajoutée que si un besoin réel apparaît.
Les réponses automatiques aux Ping entrants déjà acquises en `0.2.7` restent distinctes de ce Ping sortant périodique.
### 7.7 Config V2
Évolution retenue :
```text
profiles[].ws_endpoints[].kind:
solana_standard
helius_laserstream
```
Aucun nouveau conteneur Config et aucun champ heartbeat n'est requis au gate.
Les filtres/options de `transactionSubscribe` sont des paramètres de subscription runtime ; ils n'appartiennent pas au profil endpoint Config.
### 7.8 Credentials
L'api-key Helius reste uniquement contenue dans l'URL résolue :
```text
wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY}
```
Le nom exact de secret sera matérialisé en `pre.003`, sous le namespace secret KSP et avec `.env.example` sans vraie valeur. Transport ne lit jamais `std::env`; il reçoit seulement `WsEndpointUrl`, déjà redacted dans `Debug` et erreurs.
Aucun champ `api_key` n'est ajouté à `WsEndpointSettings`.
## 8. Threat model provider
### 8.1 Secret dans query URL
Risque : URL complète copiée dans `Debug`, erreur de handshake, logs tungstenite ou contexte `KspError`.
Mesures : conserver `WsEndpointUrl` opaque/redacted, erreurs mappées vers metadata sûre, canaris avec valeur secret reconnaissable et interdiction de l'observer dans `Debug`/Display/log context.
### 8.2 Heartbeat concurrent avec reconnect/close
Risque : timer continue après close, écrit sur ancien socket, déclenche reconnect parasite ou bloque l'actor.
Mesures : timer détenu par l'actor, sélectionné dans la boucle Active, reset/cancel avec le lifecycle, test temps raccourci déterministe par hook interne/test-only.
### 8.3 Late notifications et IDs distants
Helius documente des messages in-flight après `transactionUnsubscribe`. Le contrat KSP 0.2.7 est compatible : local unsubscribe gagne, remote id devient non routable et une notification tardive ne réactive pas la subscription.
### 8.4 Payload transaction volumineux
`transactionDetails=full`, rewards et metadata transaction peuvent produire des notifications nettement plus grosses que les familles standard légères.
Mesures : conserver `max_message_size_bytes`/`max_frame_size_bytes`, reject/reconnect borné sur frame oversized, notification queue par subscription et overflow isolé. Aucun payload brut dans snapshots/logs.
### 8.5 Filtres 50k
Trois listes indépendantes peuvent contenir jusqu'à 50 000 adresses chacune. Risques : mémoire de construction, clone inutile, sérialisation lourde et logs accidentels.
Mesures : validation de cardinalité avant I/O, pas de Debug affichant les listes, éviter les copies superflues et ne jamais projeter les adresses comme metadata de session.
### 8.6 Capability mismatch
Risque : envoyer `block/slotsUpdates/vote` à Helius puis interpréter `Method not found` comme panne session.
Mesure : capability validation locale déterministe. Les erreurs provider dynamiques restent des erreurs de subscription/request, pas une faillite du socket par défaut.
### 8.7 Continuité
LaserStream WebSocket ne reçoit aucune promesse KSP de replay historique. Après reconnect :
```text
resubscribe oui
continuity_gap_count oui
backfill non
historical replay non
lossless non
```
Les capacités de replay de LaserStream gRPC sont hors scope.
## 9. Audit dépendances
Dépendances directes déjà présentes et versions stables observées au 2026-08-23 :
```text
futures-util 0.3.34
tokio 1.53.1
tokio-tungstenite 0.30.0
reqwest 0.13.4
```
Les contraintes workspace (`^0.3`, `^1.53`, `^0.30`, `^0.13`) restent compatibles avec ces versions. Aucun changement de manifest n'est justifié dans `pre.001`.
Verdict : **aucune nouvelle dépendance**.
Le moteur actuel sait déjà : WebSocket TLS, control Ping/Pong, timers Tokio, futures sink/stream, JSON serde. Un SDK Helius dupliquerait le moteur, introduirait des choix de lifecycle non KSP et n'est pas requis pour modéliser le wire.
Le graphe résolu/doublons doit encore être observé par les commandes opérateur `cargo tree` avant commit de cette prerelease.
## 10. Stratégie de tests
### 10.1 Gate principal : déterministe local
Prévoir des fixtures/local peers couvrant :
```text
protocol capability matrix
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
public API canaries
Config -> Transport mapping
standard WS 18/18 non régressé
HTTP 52 + 14 non régressé
```
### 10.2 Smoke live Helius
Le live est opt-in et ne constitue pas la preuve principale de wire.
Stratégie retenue : composition Config -> Transport avec secret résolu par Config. Transport ne doit jamais faire `std::env` pour récupérer l'api-key.
Le smoke ne sera matérialisé qu'après le contrat Config de `pre.003`. En absence de credential opérateur sûr, la release peut rester déterministiquement conforme et documenter le smoke opérateur plutôt que de violer les frontières.
## 11. Questions explicitement reportées
```text
forme provider-specific exacte de « enhanced/filtered accountSubscribe » non publiée clairement
modes transactionNotification non suffisamment documentés pour inventer leurs DTOs
Gatekeeper beta
provider metering/billing
LaserStream gRPC / replay
Yellowstone gRPC
pool/scheduler automatique de sessions
configuration publique arbitraire du heartbeat
```
Le premier point doit être réaudité à la compliance finale. Si Helius publie un wire exact pendant `0.2.8`, le forecast peut ajouter une tranche dédiée ; il ne doit pas être injecté silencieusement dans un DTO standard.
## 12. Sizing et forecast recalibré
L'audit réduit le scope par rapport au forecast initial : `notifyOn` ne doit pas être implémenté et aucune extension account/program exacte supplémentaire n'est actuellement spécifiable. La difficulté se concentre sur `transactionSubscribe`, capability validation et heartbeat provider.
Prévision souple recalibrée :
```text
pre.001 audit actuel + matrice + architecture + threat model + dependencies + sizing
preuves : ce plan + validation/011 + delta ; graphes Cargo opérateur requis ; aucun runtime Helius
pre.002 WsProtocolKind::HeliusLaserStream + WsSubscriptionKind::HeliusTransaction
+ capability matrix + erreurs/redaction/public canaries
preuves : aucun second client ; 6 standard Helius admis, 3 standard Helius rejetés avant I/O
pre.003 Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport
+ stratégie de secret Helius
preuves : V1/V2 backward, unknown kind rejeté, URL secret redacted, aucune dépendance inverse
pre.004 transactionSubscribe request typed + filters/options/tokenAccounts + transactionUnsubscribe
preuves : wire exact, bounds 50k, max version conditionnel, ack/error fixtures, aucune string raw publique
pre.005 transactionNotification typed + actor integration + reconnect/resubscribe/unsubscribe races
preuves : formes officielles prouvées, fallback borné, remote/local remap, late notification ignorée
pre.006 heartbeat Helius 60s + interaction control frames/reconnect/shutdown
preuves : tests temporels locaux déterministes, cancellation bornée, échec Ping -> lifecycle existant
pre.007 provider adversarial lifecycle + payload/backpressure + security
preuves : provider RPC error isolée, oversized, queue overflow, secret canaries, mismatch capability
pre.008 compliance Helius + non-régression standard 18/18 + HTTP 52/14 + Config/API canaries
preuves : matrice rapprochée source par source, account/program standard inchangés, aucun scope silencieux
pre.009 smoke Helius opt-in si credential/config sûrs + README/USAGE + audit dependencies/duplicates
preuves : smoke sans secret versionné si réalisable ; cargo tree direct + duplicates ; docs version-neutral
pre.010 validation workspace finale + fermeture plan/matrice/indexes + prompt 0.2.9
preuves : workspace complet vert, docs cohérentes, dépendances finales auditées, prompt suivant autonome
rel.001 publication stable stricte
```
Budget nominal : chaque tranche vise environ **1520 minutes** de travail effectif.
Critères de split/addition :
- une tranche dépasse réellement ~20 minutes parce que notification decoding ou lifecycle cache plusieurs problèmes indépendants ;
- Helius publie une nouvelle surface provider WebSocket normative avant le gate final ;
- la forme exacte de plusieurs modes `transactionDetails` nécessite une investigation distincte ;
- la stratégie live impose une surface d'intégration qui n'existe pas encore ;
- un défaut du moteur standard doit être corrigé séparément plutôt que masqué dans une tranche provider.
`pre.010` n'est pas une deadline. Des `pre.011+` ou fixes seront ajoutés si nécessaire.
## 13. Verdict du gate `pre.001`
### Décisions fermées
```text
base stable autoritaire confirmé
surface officielle Helius actuelle auditée
terminologie LaserStream WebSocket clarifiée
protocol kind HeliusLaserStream / helius_laserstream
moteur WsSession actor existant réutilisé
standard Helius 6 paires supportées / 3 rejetées
transaction pair transactionSubscribe / transactionUnsubscribe
transaction notification transactionNotification
transaction filters/options inventoriés, tokenAccounts inclus
notifyOn deprecated no-op, non exposé
account/program provider extras report explicite faute de wire exact courant
capability validation avant I/O
heartbeat actor provider-owned, 60s cible
Config V2 kind addition, pas de nouveau conteneur
credential URL Secret résolue par Config, jamais env direct Transport
new dependency aucune
historical/lossless replay aucune promesse
forecast recalibré pre.001 -> pre.010
```
### Point restant avant commit
Le gate n'est **pas déclaré entièrement positif dans ce sandbox** tant que les deux graphes Cargo obligatoires n'ont pas été exécutés par l'opérateur :
```bash
cargo tree -p ksp-onchain-transport-lib
cargo tree -p ksp-onchain-transport-lib --duplicates
```
Aucun code provider ne doit commencer avant cette preuve. Si les graphes ne révèlent pas de dérive incompatible, `pre.001` peut être validé/commité et `pre.002` ouvrir le runtime provider.