v0.2.7-pre.001
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 191
|
||||
# version: 192
|
||||
|
||||
[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.6"
|
||||
version = "0.2.7-pre.1"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
245
deltas/0.2.7/pre.001.md
Normal file
245
deltas/0.2.7/pre.001.md
Normal file
@@ -0,0 +1,245 @@
|
||||
<!-- file: deltas/0.2.7/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.7-pre.001` — audit WebSocket Solana, threat model, dependencies et sizing
|
||||
|
||||
## Base requise
|
||||
|
||||
Release stable attendue et auditée :
|
||||
|
||||
```text
|
||||
v0.2.6
|
||||
workspace.package.version = 0.2.6 avant ouverture
|
||||
```
|
||||
|
||||
L'archive Gitea fournie contient `deltas/0.2.6/rel.001.md` et annonce `0.2.7 — WebSocket Solana standard` comme prochaine release. Elle est utilisée comme autorité primaire.
|
||||
|
||||
## Type de livraison
|
||||
|
||||
```text
|
||||
ksp-general-0.2.7-pre.001.zip
|
||||
```
|
||||
|
||||
L'archive d'échange est un delta applicable depuis la racine de `v0.2.6` et contient uniquement les fichiers ajoutés/modifiés par cette tranche.
|
||||
|
||||
## Objet
|
||||
|
||||
`pre.001` reste volontairement un gate de lecture/audit/conception. Aucun client WebSocket, session runtime, wrapper subscribe ou dependency réseau nouvelle n'est encore ajouté.
|
||||
|
||||
Le gate :
|
||||
|
||||
- relit les règles, architecture, plans, validations et contrats réels requis ;
|
||||
- vérifie la stabilité `v0.2.6` et l'héritage HTTP/Wallet Desk ;
|
||||
- réaudite `ksp-onchain-transport-lib` et l'adapter Config actuel ;
|
||||
- constate que `std.transport` V1 est strictement HTTP et décide un V2 explicite HTTP+WS avec backward V1 ;
|
||||
- audite l'archive bot3 comme référence historique seulement ;
|
||||
- réaudite la documentation Solana WebSocket officielle du 2026-08-22 et cross-checke Agave `v3.1.8` sur les ambiguïtés ;
|
||||
- documente notamment `accountSubscribe.minContextSlot` comme option partagée mais ignorée en PubSub, et `vote.timestamp` comme `Option<i64>` ;
|
||||
- compte exactement **18 méthodes = 9 subscribe + 9 unsubscribe** ;
|
||||
- classe `block`, `slotsUpdates` et `vote` comme paires unstable ;
|
||||
- crée la matrice compliance initiale `010` ;
|
||||
- audite les crates candidates et retient `tokio-tungstenite 0.30.0` + `futures-util 0.3.34` pour une tranche ultérieure ;
|
||||
- fixe le modèle actor/session, IDs locaux, state machines, reconnect/resubscribe, continuity gaps, backpressure et shutdown ;
|
||||
- fixe les exigences de redaction URL/credentials et de bornes de ressources ;
|
||||
- regranularise la release jusqu'à un forecast nominal `pre.014` sans imposer ce numéro comme deadline.
|
||||
|
||||
## Décisions principales
|
||||
|
||||
### Cardinalité
|
||||
|
||||
```text
|
||||
endpoint -> N sessions physiques explicites -> N subscriptions par session
|
||||
aucun pool/scheduler automatique en 0.2.7
|
||||
```
|
||||
|
||||
### Identités
|
||||
|
||||
```text
|
||||
WsSessionId stable local KSP
|
||||
WsSubscriptionId stable local KSP
|
||||
remote id éphémère et interne, remappé après reconnect
|
||||
```
|
||||
|
||||
### Reconnect / resubscribe
|
||||
|
||||
```text
|
||||
budget fini
|
||||
backoff exponentiel borné
|
||||
pas de jitter en 0.2.7
|
||||
policy Never | ActiveSubscriptions
|
||||
ordre de restore déterministe par ID local
|
||||
continuity gap explicite après toute reconnexion
|
||||
aucune garantie lossless / aucun backfill HTTP Transport
|
||||
```
|
||||
|
||||
### Backpressure
|
||||
|
||||
```text
|
||||
command queue bounded
|
||||
notification queue bounded par subscription
|
||||
overflow -> subscription Failed explicite + best-effort unsubscribe
|
||||
aucun drop silencieux
|
||||
les autres subscriptions restent actives
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```text
|
||||
std.transport V1 reste strict et lisible
|
||||
std.transport V2 = HTTP existant + ws_defaults + profiles[].ws_endpoints
|
||||
Config -> Transport uniquement
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
|
||||
```text
|
||||
tokio-tungstenite ^0.30, default-features=false, connect + rustls-tls-webpki-roots
|
||||
futures-util ^0.3, default-features=false, std + sink
|
||||
```
|
||||
|
||||
Ces dependencies sont **planifiées seulement** ; le graphe n'est pas modifié dans `pre.001`.
|
||||
|
||||
## Prévision souple recalibrée
|
||||
|
||||
```text
|
||||
pre.001 audit + matrice + threat model + dependencies + sizing
|
||||
pre.002 settings/IDs/states/snapshots/redaction
|
||||
pre.003 std.transport V2 + adapter Config
|
||||
pre.004 actor session physique + deps WS + local server
|
||||
pre.005 limits/control/cancellation/shutdown
|
||||
pre.006 registry + generic subscribe/unsubscribe + channels typed
|
||||
pre.007 reconnect/resubscribe/gap/races
|
||||
pre.008 backpressure/limits/leaks adversarial
|
||||
pre.009 account/program/logs
|
||||
pre.010 signature/slot/root
|
||||
pre.011 block/slotsUpdates/vote unstable
|
||||
pre.012 compliance 18/18 + Config composition + HTTP regression
|
||||
pre.013 smoke live + README/USAGE + cargo trees
|
||||
pre.014 workspace final + docs/compliance + prompt 0.2.8
|
||||
rel.001 publication stable
|
||||
```
|
||||
|
||||
Le sizing reste positif : la release n'est pas scindée fonctionnellement, mais le forecast initial `pre.008` est volontairement décompressé.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
|
||||
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
|
||||
deltas/0.2.7/pre.001.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/validation/000-README.md
|
||||
```
|
||||
|
||||
## Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
.env.example
|
||||
config/**
|
||||
crates/**
|
||||
docs/architecture/**
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/USAGE.md
|
||||
```
|
||||
|
||||
`ROADMAP.md` reste global et possède déjà l'entrée `0.2.7`. README/USAGE Transport ne sont pas modifiés avant qu'une surface runtime WebSocket existe réellement.
|
||||
|
||||
## Version technique
|
||||
|
||||
Conformément au workflow non-fix :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.7-pre.1
|
||||
commit = v0.2.7-pre.001
|
||||
aucun tag prerelease
|
||||
```
|
||||
|
||||
## Audit officiel WebSocket
|
||||
|
||||
Index :
|
||||
|
||||
```text
|
||||
https://solana.com/docs/rpc/websocket
|
||||
```
|
||||
|
||||
Inventaire exact au 2026-08-22 :
|
||||
|
||||
```text
|
||||
accountSubscribe/accountUnsubscribe
|
||||
blockSubscribe/blockUnsubscribe unstable pair
|
||||
logsSubscribe/logsUnsubscribe
|
||||
programSubscribe/programUnsubscribe
|
||||
rootSubscribe/rootUnsubscribe
|
||||
signatureSubscribe/signatureUnsubscribe
|
||||
slotSubscribe/slotUnsubscribe
|
||||
slotsUpdatesSubscribe/slotsUpdatesUnsubscribe unstable pair
|
||||
voteSubscribe/voteUnsubscribe unstable pair
|
||||
```
|
||||
|
||||
Aucune méthode de cet index n'est marquée Deprecated.
|
||||
|
||||
## Audit bot3
|
||||
|
||||
Référence inspectée :
|
||||
|
||||
```text
|
||||
ks-onchain-transport/src/standard_ws.rs
|
||||
ks-onchain-transport/src/ws_client.rs
|
||||
ks-onchain-transport/src/ws_pool.rs
|
||||
ks-onchain-transport/src/ws_session.rs
|
||||
```
|
||||
|
||||
Repris comme concepts : session multiplexée, ID local/remote séparé, reconnect/resubscribe borné. Rejetés : Transport -> Config, tracing direct, scheduler/pool, unsubscribe public par remote ID et broadcast data comme contrat principal.
|
||||
|
||||
## Validations exécutées avant modification
|
||||
|
||||
```text
|
||||
archive stable v0.2.6 extraite/auditée OK
|
||||
documents internes obligatoires relus OK
|
||||
inventory Transport + Config OK
|
||||
archive bot3 auditée OK
|
||||
documentation Solana WebSocket actuelle auditée OK
|
||||
dependencies Rust candidates auditée OK
|
||||
python3 scripts/audit_rust_workspace_rules.py OK
|
||||
```
|
||||
|
||||
Sortie audit Python :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
```
|
||||
|
||||
## Validations tentées mais impossibles dans le sandbox
|
||||
|
||||
Le binaire `cargo` n'est pas installé. Tentatives avant modification :
|
||||
|
||||
```text
|
||||
cargo fmt --all code 127
|
||||
cargo check --workspace code 127
|
||||
cargo clippy --workspace --all-targets code 127
|
||||
```
|
||||
|
||||
Aucune de ces commandes n'est déclarée réussie.
|
||||
|
||||
## Validation opérateur requise avant commit
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Aucun test Transport, Config, workspace ou smoke live n'est déclaré vert dans ce sandbox tant qu'il n'a pas été effectivement exécuté par l'opérateur. Aucun build Tauri n'est requis pour `0.2.7-pre.001`.
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 53 -->
|
||||
<!-- version: 54 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -22,6 +22,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
- [`011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) — plan historique clôturé de la release stable `0.2.4`, ouvert par `pre.001`, exécuté jusqu’à `pre.009`, complété par le fix documentaire Wallet `pre.009-fix.001` puis publié par `rel.001`; il couvre les 10 Blocks + 5 Economics et la compliance finale `52/52 + 14/14` sous `KSP-TRANSPORT-007`.
|
||||
- [`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 actif de `0.2.7 — WebSocket Solana standard`, ouvert par `pre.001`; il conserve l'inventaire officiel 18 méthodes, le modèle session/subscription, le threat model, le choix de dependencies et le forecast recalibré.
|
||||
|
||||
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
|
||||
<!-- version: 79 -->
|
||||
<!-- version: 80 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -455,9 +455,13 @@ La tranche historique `pre.014` a traité les défauts visuels/templating observ
|
||||
|
||||
### `0.2.7` — WebSocket Solana standard
|
||||
|
||||
Mission : couvrir la surface WebSocket standard officielle ciblée.
|
||||
Mission : couvrir exhaustivement la surface WebSocket Solana standard officielle ciblée, avec sessions physiques explicites, subscriptions typées, lifecycle borné, reconnexion/resubscribe déterministes et observabilité sûre. Le plan actif est [`014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md`](014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md) et la matrice de compliance initiale est [`../validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md`](../validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md).
|
||||
|
||||
Une URL peut avoir plusieurs sessions physiques ; une session peut avoir plusieurs subscriptions. Un pool automatique de sessions est reporté jusqu'à besoin concret.
|
||||
Le gate `0.2.7-pre.001`, audité le 22 août 2026, inventorie exactement 18 opérations WebSocket documentées : 9 subscribe + 9 unsubscribe. `blockSubscribe`, `slotsUpdatesSubscribe` et `voteSubscribe` sont actuellement marquées unstable ; aucune méthode de l'index officiel courant n'est marquée Deprecated.
|
||||
|
||||
Une URL peut avoir plusieurs sessions physiques explicites ; une session peut avoir plusieurs subscriptions. Un pool/scheduler automatique de sessions reste reporté jusqu'à besoin concret. Les IDs de session/subscription KSP sont locaux et stables ; les IDs serveur restent internes et peuvent être remappés après reconnexion.
|
||||
|
||||
Le forecast initial allant jusqu'à `pre.008` est décompressé par `pre.001` jusqu'à environ `pre.014` afin de conserver des tranches intermédiaires nominales de 15–20 minutes ; ce numéro reste un forecast et non une contrainte de clôture.
|
||||
|
||||
### `0.2.8` — Helius LaserStream WebSocket
|
||||
|
||||
|
||||
791
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
Normal file
791
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
Normal file
@@ -0,0 +1,791 @@
|
||||
<!-- file: docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Plan `0.2.7` — WebSocket Solana standard
|
||||
|
||||
> **Statut : actif, gate `0.2.7-pre.001`.** Cette première tranche fixe l'inventaire normatif, les frontières, le threat model, le modèle session/subscription, la stratégie de dépendances et le sizing. Elle ne matérialise pas encore le client WebSocket runtime.
|
||||
|
||||
## 1. Objet et base vérifiée
|
||||
|
||||
`0.2.7` étend `ksp-onchain-transport-lib` avec le transport WebSocket Solana standard sans créer un second composant on-chain et sans déplacer de logique Config, Store, Program, worker ou métier dans Transport.
|
||||
|
||||
Base opérateur auditée :
|
||||
|
||||
```text
|
||||
archive Gitea fournie : khadhroony-solana-project-v0.2.6-from-gitea.zip
|
||||
workspace.package.version avant ouverture = 0.2.6
|
||||
delta stable présent = deltas/0.2.6/rel.001.md
|
||||
prochaine release annoncée = 0.2.7 — WebSocket Solana standard
|
||||
```
|
||||
|
||||
La clôture `0.2.6` confirme l'héritage : Wallet Desk, `.kspwallet` V1 historique + V2 binaire par défaut, APIs Wallet multi-version, migration V1 -> V2 explicite OWNER-authentifiée, runtime packagé commun aux Desks et transport HTTP Solana stable.
|
||||
|
||||
`0.2.7-pre.001` ouvre techniquement :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.7-pre.1
|
||||
livraison = 0.2.7-pre.001
|
||||
commit = v0.2.7-pre.001
|
||||
```
|
||||
|
||||
Aucune dependency WebSocket n'est ajoutée dans ce gate.
|
||||
|
||||
## 2. Sources internes relues et hiérarchie appliquée
|
||||
|
||||
L'audit a relu, dans l'ordre demandé par le prompt d'ouverture :
|
||||
|
||||
```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/PROMPT_STRUCTURE.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/FILE_CONTRACTS.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/007-V0_2_0_SERIES_PLANNING.md
|
||||
docs/plans/008-V0_2_1_ONCHAIN_HTTP_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
|
||||
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-config-lib/src/transport.rs
|
||||
config/std.transport.json
|
||||
config/schemas/std.transport.schema.json
|
||||
contrats consommés de ksp-core-lib et ksp-logging-lib
|
||||
|
||||
deltas/0.2.6/rel.001.md
|
||||
docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md
|
||||
docs/validation/009-V0_2_6_WALLET_DESK_COMPLIANCE.md
|
||||
```
|
||||
|
||||
`docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` reste l'autorité de numérotation courante. `007-V0_2_0_SERIES_PLANNING.md` est historique.
|
||||
|
||||
## 3. Baseline de démarrage
|
||||
|
||||
Le sandbox d'analyse ne fournit pas le binaire `cargo`.
|
||||
|
||||
Les commandes imposées ont été tentées avant modification :
|
||||
|
||||
```text
|
||||
cargo fmt --all IMPOSSIBLE : cargo absent, code 127
|
||||
python3 scripts/audit_rust_workspace_rules.py OK
|
||||
cargo check --workspace IMPOSSIBLE : cargo absent, code 127
|
||||
cargo clippy --workspace --all-targets IMPOSSIBLE : cargo absent, code 127
|
||||
```
|
||||
|
||||
L'audit Python retourne :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
```
|
||||
|
||||
Aucun gate Cargo n'est déclaré réussi. Une validation opérateur est obligatoire avant commit de `pre.001`.
|
||||
|
||||
## 4. État réel de Transport et Config hérité
|
||||
|
||||
### 4.1 Surface HTTP stable à préserver
|
||||
|
||||
`ksp-onchain-transport-lib` contient actuellement :
|
||||
|
||||
- settings HTTP publics (`HttpEndpointUrl`, provider/cluster/role, retry, limits, endpoint, transport) ;
|
||||
- `HttpEndpointClient` et `HttpTransportPool` ;
|
||||
- 52 wrappers HTTP courants typés et 14 méthodes historiques Deprecated tracées ;
|
||||
- JSON-RPC, retry/no-resend, snapshots et observabilité ;
|
||||
- DTOs wire communs réutilisables, notamment `SolanaCommitment`, `SolanaRpcContext`, `SolanaRpcResponse<T>`, encodings/account DTOs, filters et `SolanaWireField<T>` ;
|
||||
- émissions runtime via `ksp-logging-lib`, sans `tracing` direct.
|
||||
|
||||
La surface WebSocket doit être additive : aucune renormalisation invasive des types `Http*` n'est requise dans `0.2.7`.
|
||||
|
||||
### 4.2 Config actuel est explicitement HTTP V1
|
||||
|
||||
`config/std.transport.json`, son schema et `ksp-config-lib/src/transport.rs` décrivent un document V1 HTTP :
|
||||
|
||||
```text
|
||||
format_version = 1
|
||||
schema title = standard HTTP Transport
|
||||
additionalProperties = false
|
||||
serde(deny_unknown_fields)
|
||||
format_version != 1 rejeté
|
||||
```
|
||||
|
||||
Décision : **ne pas ajouter silencieusement des clés WebSocket au V1**.
|
||||
|
||||
`0.2.7` fera évoluer le même composant standard `std.transport` vers un **format V2 explicitement HTTP + WebSocket**, tout en conservant la lecture du V1 HTTP-only pour compatibilité. Config reste propriétaire du parsing/résolution et adapte ensuite vers les settings publics Transport.
|
||||
|
||||
Shape cible minimale :
|
||||
|
||||
```text
|
||||
format_version = 2
|
||||
retry # HTTP existant, conservé
|
||||
ws_defaults # defaults de session WS KSP, non provider-specific
|
||||
default_profile
|
||||
profiles[]
|
||||
profile_id
|
||||
endpoints[] # HTTP existant, conservé
|
||||
ws_endpoints[] # endpoints WebSocket explicites
|
||||
```
|
||||
|
||||
`ws_endpoints[]` porte seulement les données nécessaires à Transport : nom logique, enabled, provider, cluster, URL et overrides de session éventuellement nécessaires. Les credentials restent résolus par Config comme aujourd'hui ; Transport reçoit un endpoint déjà résolu et doit redacter l'URL dans `Debug`/logs/errors.
|
||||
|
||||
Le V1 chargé sous `0.2.7` produit une configuration HTTP valide et une collection WebSocket vide. Le V2 devient le format livré par les fixtures Config dès la tranche qui matérialise le WebSocket.
|
||||
|
||||
## 5. Audit historique bot3
|
||||
|
||||
Archive auditée uniquement comme référence :
|
||||
|
||||
```text
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
ks-onchain-transport/src/standard_ws.rs
|
||||
ks-onchain-transport/src/ws_client.rs
|
||||
ks-onchain-transport/src/ws_pool.rs
|
||||
ks-onchain-transport/src/ws_session.rs
|
||||
consumers/demo et rapports de validation WebSocket
|
||||
```
|
||||
|
||||
Invariants utiles repris :
|
||||
|
||||
- plusieurs subscriptions sur une session physique ;
|
||||
- plusieurs sessions possibles ;
|
||||
- identifiant local stable distinct de l'identifiant serveur ;
|
||||
- remapping des IDs serveur après reconnect ;
|
||||
- reconnect borné et resubscribe ;
|
||||
- canaris locaux de lifecycle.
|
||||
|
||||
Choix bot3 explicitement **non repris** :
|
||||
|
||||
- `Transport -> Config` ;
|
||||
- `tracing` direct ;
|
||||
- rôles HTTP et `max_subscriptions` mélangés au modèle endpoint générique ;
|
||||
- pool/scheduler de sessions sans besoin démontré ;
|
||||
- API d'unsubscribe publique fondée sur l'ID serveur éphémère ;
|
||||
- broadcast unique comme canal principal de notifications data ;
|
||||
- états lifecycle trop grossiers pour les races reconnect/unsubscribe.
|
||||
|
||||
Le retour historique bot3 sur les flux à fort débit renforce le besoin d'une policy de backpressure explicite et observable ; aucune hypothèse de livraison lossless ne doit reposer sur un canal broadcast qui peut lagger silencieusement.
|
||||
|
||||
## 6. Inventaire WebSocket Solana officiel au 2026-08-22
|
||||
|
||||
Source d'index :
|
||||
|
||||
```text
|
||||
https://solana.com/docs/rpc/websocket
|
||||
```
|
||||
|
||||
L'index courant contient exactement **18 méthodes WebSocket : 9 subscribe + 9 unsubscribe**.
|
||||
|
||||
```text
|
||||
accountSubscribe / accountUnsubscribe
|
||||
blockSubscribe / blockUnsubscribe
|
||||
logsSubscribe / logsUnsubscribe
|
||||
programSubscribe / programUnsubscribe
|
||||
rootSubscribe / rootUnsubscribe
|
||||
signatureSubscribe / signatureUnsubscribe
|
||||
slotSubscribe / slotUnsubscribe
|
||||
slotsUpdatesSubscribe / slotsUpdatesUnsubscribe
|
||||
voteSubscribe / voteUnsubscribe
|
||||
```
|
||||
|
||||
Statut observé :
|
||||
|
||||
```text
|
||||
6 paires sans marque unstable/deprecated dans la documentation actuelle
|
||||
3 paires dont le subscribe est explicitement Unstable :
|
||||
blockSubscribe
|
||||
slotsUpdatesSubscribe
|
||||
voteSubscribe
|
||||
0 méthode WebSocket de cet index marquée Deprecated
|
||||
```
|
||||
|
||||
Pour KSP, le label interne `Stable` signifie ici « documentée et non marquée unstable/deprecated par la source officielle auditée », pas une garantie de standardisation extérieure supplémentaire.
|
||||
|
||||
Règles générales documentées : JSON-RPC 2.0 sur connexion persistante ; résultat subscribe numérique ; notifications avec `params.subscription` numérique ; lorsqu'un contexte est présent `context.slot` est fourni et `context.apiVersion` est omis ; les subscriptions qui acceptent `commitment` utilisent `finalized` par défaut.
|
||||
|
||||
La matrice détaillée initiale est conservée dans `docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md`.
|
||||
|
||||
## 7. Points wire sensibles sous `KSP-TRANSPORT-007`
|
||||
|
||||
### `accountSubscribe`
|
||||
|
||||
Conserver : pubkey ; `commitment` ; encodings `base58|base64|base64+zstd|binary|jsonParsed` ; `dataSlice` ; notification `accountNotification` contextualisée.
|
||||
|
||||
Le type partagé Agave `RpcAccountInfoConfig` contient aussi `min_context_slot`, mais le handler PubSub `v3.1.8` l'ignore explicitement. KSP ne doit donc pas promettre `minContextSlot` comme option WebSocket effective tant que l'upstream ne lui donne pas une sémantique réelle ; cette non-promise doit rester visible dans la compliance pour éviter qu'une option ignorée soit comptée comme supportée.
|
||||
|
||||
### `programSubscribe`
|
||||
|
||||
Conserver : program pubkey ; `commitment` ; `filters` ; mêmes encodings account ; `dataSlice` ; **`withContext` default false**.
|
||||
|
||||
La documentation actuelle expose `withContext`, mais le code Agave `v3.1.8` lié par la page stocke bien `with_context` alors que le chemin générique de notification audité sérialise un `RpcResponse` contexté. KSP ne doit ni ignorer le paramètre, ni convertir cette incohérence amont en hypothèse stricte. Décision : exposer le flag et rendre le décodeur capable d'accepter la forme documentée non-contextée comme la forme contextée observée.
|
||||
|
||||
### `logsSubscribe`
|
||||
|
||||
Conserver les trois filtres : `all`, `allWithVotes`, `{mentions:[pubkey]}`. La forme `mentions` autorise exactement une adresse dans la documentation actuelle. Conserver `commitment`; notification `signature + err + logs` contextualisée.
|
||||
|
||||
### `signatureSubscribe`
|
||||
|
||||
Conserver `commitment` et `enableReceivedNotification`. Le résultat notification est une union wire :
|
||||
|
||||
```text
|
||||
"receivedSignature"
|
||||
OU
|
||||
{ "err": null | transaction error }
|
||||
```
|
||||
|
||||
La subscription se termine après la notification terminale ; elle ne doit donc pas être resubscribed après que le runtime KSP a observé cette terminaison.
|
||||
|
||||
### `slotSubscribe` / `rootSubscribe`
|
||||
|
||||
Aucun paramètre. `slotNotification` conserve `slot`, `parent`, `root`; `rootNotification` conserve le root `u64`.
|
||||
|
||||
### `blockSubscribe` — Unstable
|
||||
|
||||
Conserver : filtre `all` ou `{mentionsAccountOrProgram:<pubkey>}` ; commitment limité à `confirmed|finalized` ; encoding `binary|base58|base64|json|jsonParsed` ; `transactionDetails` `full|accounts|signatures|none` ; `maxSupportedTransactionVersion` ; `showRewards`. La méthode nécessite côté validator les flags documentés ; KSP ne les simule pas.
|
||||
|
||||
La notification conserve `context`, `slot`, `block` nullable et `err` nullable, ainsi que les variantes de block liées à la config.
|
||||
|
||||
### `slotsUpdatesSubscribe` — Unstable
|
||||
|
||||
Conserver les variantes taggées actuelles et leurs champs :
|
||||
|
||||
```text
|
||||
firstShredReceived
|
||||
completed
|
||||
createdBank
|
||||
frozen
|
||||
dead
|
||||
optimisticConfirmation
|
||||
root
|
||||
```
|
||||
|
||||
Le runtime doit prévoir une forme `Unknown`/raw bornée pour qu'une variante ajoutée par une version upstream ne ferme pas la session entière avant réaudit KSP.
|
||||
|
||||
### `voteSubscribe` — Unstable
|
||||
|
||||
Aucun paramètre. La méthode nécessite le flag validator documenté et observe des votes gossip pre-consensus. Conserver `votePubkey`, `slots`, `hash`, `timestamp`, `signature`. Agave `v3.1.8` définit `timestamp` comme `Option<i64>` : le décodeur KSP doit donc préserver cette optionalité et accepter de manière tolérante les formes wire `omitted/null/value`, sans inventer une valeur.
|
||||
|
||||
### `*Unsubscribe`
|
||||
|
||||
Chaque unsubscribe reçoit l'ID serveur et retourne `true` quand la subscription est supprimée ; le handler Agave audité retourne `InvalidParams` pour un ID inconnu. Cette réalité wire ne devient pas l'API publique KSP : le caller utilise l'ID local/handle stable et la session traduit vers l'ID serveur courant.
|
||||
|
||||
Le cross-check Agave `v3.1.8` confirme également que `logsSubscribe` impose exactement une adresse pour `mentions`, que `signatureSubscribe` ne consomme que `commitment` et `enableReceivedNotification`, et que `blockSubscribe` applique bien le jeu d'options documenté avec un commitment au moins `confirmed`. Ces constats renforcent la matrice normative sans ajouter d'options non documentées à KSP.
|
||||
|
||||
## 8. Dépendances WebSocket candidates
|
||||
|
||||
Audit au 2026-08-22 :
|
||||
|
||||
| Candidate | Version auditée | Verdict | Motif |
|
||||
|---------------------|----------------:|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `tokio-tungstenite` | `0.30.0` | **retenue** | mature, Tokio-native, TLS rustls, continuité avec bot3 mais réauditée, contrôle de `WebSocketConfig`, client + serveur local de test |
|
||||
| `futures-util` | `0.3.34` | **retenue comme utilitaire** | `StreamExt`/`SinkExt`; features minimales `std,sink` |
|
||||
| `tokio-websockets` | `0.13.3` | alternative viable, non retenue | strict/minimal et performant, mais exige davantage d'assemblage/features et n'apporte pas de besoin fonctionnel supérieur démontré pour cette foundation |
|
||||
| `fastwebsockets` | `0.10.0` | non retenue | plus bas niveau ; peut déléguer davantage de compliance au caller, inutile pour la première foundation KSP |
|
||||
|
||||
Landing prévu, **pas dans `pre.001`** :
|
||||
|
||||
```toml
|
||||
# root [workspace.dependencies]
|
||||
tokio-tungstenite = { version = "^0.30", default-features = false }
|
||||
futures-util = { version = "^0.3", default-features = false }
|
||||
|
||||
# ksp-onchain-transport-lib
|
||||
tokio-tungstenite = { workspace = true, features = ["connect", "rustls-tls-webpki-roots"] }
|
||||
futures-util = { workspace = true, features = ["std", "sink"] }
|
||||
tokio = { workspace = true, features = ["macros", "rt", "sync", "time"] }
|
||||
```
|
||||
|
||||
Le serveur de test local pourra activer `tokio/net` en dev si KSP utilise directement `TcpListener`.
|
||||
|
||||
`url` n'est pas retenu a priori : l'endpoint KSP peut être validé et passé comme chaîne/request sans ajouter la feature uniquement par habitude bot3. `handshake`/`stream` sont déjà requis transitivement par `connect`/TLS et ne doivent pas être listés sans nécessité directe.
|
||||
|
||||
Les defaults de `tungstenite::WebSocketConfig` ne sont **pas** des limites Solana normatives. KSP configurera explicitement des plafonds finis pour messages, frames et write buffer. Les valeurs numériques KSP seront figées avec les tests adversariaux de la tranche settings/session, et documentées comme policy locale, jamais comme limite protocolaire Solana.
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://docs.rs/crate/tokio-tungstenite/0.30.0
|
||||
https://docs.rs/crate/tokio-tungstenite/0.30.0/features
|
||||
https://docs.rs/crate/futures-util/0.3.34
|
||||
https://docs.rs/crate/tokio-websockets/0.13.3
|
||||
https://docs.rs/crate/fastwebsockets/0.10.0
|
||||
```
|
||||
|
||||
## 9. Modèle public Transport retenu
|
||||
|
||||
### 9.1 Settings
|
||||
|
||||
Noms cibles :
|
||||
|
||||
```text
|
||||
WsEndpointUrl
|
||||
WsProviderName
|
||||
WsClusterName
|
||||
WsReconnectSettings
|
||||
WsResubscribePolicy
|
||||
WsSessionSettings
|
||||
WsEndpointSettings
|
||||
WsTransportSettings
|
||||
```
|
||||
|
||||
Les wrappers `WsProviderName`/`WsClusterName` sont parallèles aux `Http*` pour éviter une migration publique HTTP dans cette release. Une généralisation future n'est justifiée que si un troisième backend démontre un type commun réellement utile.
|
||||
|
||||
`WsEndpointUrl` :
|
||||
|
||||
- accepte seulement `ws://`/`wss://` après validation ;
|
||||
- fournit un accès explicite à la valeur au code de connexion ;
|
||||
- `Debug` et tout diagnostic par défaut sont redacted ;
|
||||
- aucun snapshot public ne contient l'URL complète.
|
||||
|
||||
`WsSessionSettings` porte les bornes runtime nécessaires : command timeout, close timeout, reconnect, resubscribe, capacités de queues, maximum de subscriptions actives, maximum de requests JSON-RPC en vol, maximum de message/frame/write buffer. Pas de rôle HTTP ni de scheduler.
|
||||
|
||||
### 9.2 Cardinalité
|
||||
|
||||
Contrat :
|
||||
|
||||
```text
|
||||
1 WsEndpointSettings
|
||||
-> 0..N WsSession physiques créées explicitement par caller
|
||||
-> 0..N WsSubscription actives
|
||||
```
|
||||
|
||||
Deux appels de création sur le même endpoint ouvrent deux connexions physiques. Transport ne distribue pas automatiquement les subscriptions entre elles.
|
||||
|
||||
### 9.3 Session actor
|
||||
|
||||
Une tâche actor possède exclusivement :
|
||||
|
||||
- le stream WebSocket physique ;
|
||||
- le compteur d'IDs JSON-RPC requests ;
|
||||
- la map des requests en vol ;
|
||||
- le registre local des subscriptions ;
|
||||
- le mapping `remote_subscription_id -> local_subscription_id` ;
|
||||
- le lifecycle reconnect/resubscribe ;
|
||||
- les compteurs/snapshot sûrs.
|
||||
|
||||
Le handle public `WsSession` communique avec cet actor par canal bounded. Aucun caller ne split/manipule directement le socket.
|
||||
|
||||
### 9.4 Identités
|
||||
|
||||
```text
|
||||
WsSessionId # KSP local, stable pour la vie du handle
|
||||
WsSubscriptionId # KSP local, stable malgré reconnect
|
||||
remote id u64 # strictement runtime/interne, remappable
|
||||
```
|
||||
|
||||
Une `WsSubscription<T>` typée contient l'identité locale, la projection de lifecycle et un receiver bounded de notifications typées. L'ID remote ne devient pas un identifiant métier/public de contrôle.
|
||||
|
||||
## 10. State machines retenues
|
||||
|
||||
### 10.1 Session
|
||||
|
||||
```text
|
||||
Disconnected
|
||||
-> Connecting
|
||||
-> Active
|
||||
-> Failed
|
||||
|
||||
Active
|
||||
-> Reconnecting
|
||||
-> Active
|
||||
-> Failed
|
||||
-> Closing
|
||||
-> Closed
|
||||
|
||||
Reconnecting
|
||||
-> Closing
|
||||
-> Closed
|
||||
```
|
||||
|
||||
État public cible :
|
||||
|
||||
```text
|
||||
Disconnected | Connecting | Active | Reconnecting { attempt } | Closing | Closed | Failed
|
||||
```
|
||||
|
||||
### 10.2 Subscription
|
||||
|
||||
```text
|
||||
Requested
|
||||
-> Active
|
||||
-> Failed
|
||||
|
||||
Active
|
||||
-> Resubscribing
|
||||
-> Active
|
||||
-> Failed
|
||||
-> Cancelling
|
||||
-> Closed
|
||||
-> Closed # terminaison serveur connue, ex. signature terminale
|
||||
|
||||
Requested/Resubscribing
|
||||
-> Cancelling
|
||||
-> Closed
|
||||
```
|
||||
|
||||
État public cible :
|
||||
|
||||
```text
|
||||
Requested | Active | Resubscribing | Cancelling | Closed | Failed
|
||||
```
|
||||
|
||||
Le motif terminal est séparé (`Unsubscribed`, `CompletedByServer`, `SessionClosed`, `BackpressureOverflow`, `ProtocolFailure`, etc.) afin de ne pas gonfler l'enum d'états.
|
||||
|
||||
## 11. Reconnect et resubscribe
|
||||
|
||||
### 11.1 Reconnect
|
||||
|
||||
Reconnect uniquement pour perte du canal physique : EOF, close inattendue, erreur I/O/TLS/WebSocket read/write. Une erreur RPC applicative de subscribe/unsubscribe n'entraîne pas une reconnexion automatique de la session.
|
||||
|
||||
Policy :
|
||||
|
||||
- nombre d'essais fini et configurable ;
|
||||
- backoff exponentiel borné par `initial_backoff`/`max_backoff` ;
|
||||
- **pas de jitter dans `0.2.7`** afin d'éviter une dépendance/randomisation supplémentaire et garder les tests déterministes ;
|
||||
- le budget se réinitialise après retour complet à `Active` ;
|
||||
- exhaustion => session `Failed`, subscriptions terminales avec cause explicite ;
|
||||
- shutdown/close annule immédiatement backoff et interdit toute nouvelle tentative.
|
||||
|
||||
Les valeurs numériques par défaut sont une policy KSP et seront figées avec `WsSessionSettings` après tests ; elles ne seront pas attribuées à Solana.
|
||||
|
||||
### 11.2 Resubscribe
|
||||
|
||||
Enum public :
|
||||
|
||||
```text
|
||||
WsResubscribePolicy::Never
|
||||
WsResubscribePolicy::ActiveSubscriptions
|
||||
```
|
||||
|
||||
Default KSP proposé : `ActiveSubscriptions`.
|
||||
|
||||
Après perte de connexion :
|
||||
|
||||
1. tous les remote IDs deviennent invalides et sont retirés du mapping ;
|
||||
2. la session émet/incrémente un signal de **continuity gap** ;
|
||||
3. après reconnect, seules les subscriptions encore désirées actives sont restaurées ;
|
||||
4. ordre déterministe : `WsSubscriptionId` croissant / ordre de création ;
|
||||
5. chaque ack remappe un nouvel ID remote ;
|
||||
6. une erreur de resubscribe marque cette subscription `Failed` mais ne ferme pas les autres si le socket reste sain.
|
||||
|
||||
KSP **ne garantit pas la continuité lossless** entre la déconnexion et la restauration. Aucun backfill HTTP automatique n'est ajouté à Transport. Les consumers workers/jobs pourront réconcilier plus tard avec leur propre checkpoint/persistence.
|
||||
|
||||
### 11.3 Race unsubscribe pendant reconnect
|
||||
|
||||
La cancellation locale gagne toujours :
|
||||
|
||||
- marquer la subscription non restaurable avant de traiter les acks tardifs ;
|
||||
- retirer sa spec de la sélection resubscribe ;
|
||||
- si un subscribe/resubscribe distant tardif réussit malgré tout, envoyer un best-effort unsubscribe de son nouvel ID ;
|
||||
- ne jamais repasser la subscription locale à `Active` après cancellation.
|
||||
|
||||
## 12. Backpressure et bornes de ressources
|
||||
|
||||
### 12.1 Queues
|
||||
|
||||
- canal commands session : bounded ;
|
||||
- notifications : **queue bounded par subscription** ;
|
||||
- lifecycle/snapshot : `watch`/état partagé compact, pas une file data infinie ;
|
||||
- requests JSON-RPC en vol : map bornée + timeout ;
|
||||
- subscriptions actives : plafond configurable par session.
|
||||
|
||||
### 12.2 Overflow notifications
|
||||
|
||||
Aucun drop silencieux.
|
||||
|
||||
Si la queue d'une subscription est pleine :
|
||||
|
||||
1. compteur overflow incrémenté ;
|
||||
2. subscription passe `Failed(BackpressureOverflow)` ;
|
||||
3. best-effort unsubscribe distant si possible ;
|
||||
4. son receiver se termine avec la cause observable via état final ;
|
||||
5. les autres subscriptions de la session restent actives.
|
||||
|
||||
Cette policy isole un consumer lent sans sacrifier toute la connexion et sans prétendre être lossless.
|
||||
|
||||
### 12.3 Frames/messages/JSON
|
||||
|
||||
Configurer des plafonds finis pour :
|
||||
|
||||
```text
|
||||
max_message_size
|
||||
max_frame_size
|
||||
max_write_buffer_size
|
||||
max_pending_requests
|
||||
max_active_subscriptions
|
||||
command_queue_capacity
|
||||
notification_queue_capacity
|
||||
```
|
||||
|
||||
La parse JSON ne reçoit donc jamais un message WebSocket arbitrairement grand. Les payloads raw conservés pour losslessness restent eux aussi sous cette borne.
|
||||
|
||||
## 13. Cancellation, control frames et shutdown
|
||||
|
||||
### 13.1 Control frames
|
||||
|
||||
Le runtime gère proprement Ping/Pong/Close selon la crate WebSocket retenue. Aucun heartbeat applicatif périodique n'est activé par défaut dans `0.2.7` : la documentation Solana actuelle n'impose pas un ping KSP. Un keepalive configurable sera ajouté seulement si un besoin interop réel est démontré.
|
||||
|
||||
### 13.2 Shutdown explicite
|
||||
|
||||
`WsSession::close().await` doit :
|
||||
|
||||
1. passer `Closing` et refuser de nouvelles subscriptions ;
|
||||
2. annuler reconnect/backoff/resubscribe et requests en vol ;
|
||||
3. si connecté, best-effort unsubscribe des actives dans un ordre déterministe sous un budget global ;
|
||||
4. envoyer Close WebSocket ;
|
||||
5. fermer toutes les subscriptions localement avec raison terminale ;
|
||||
6. attendre la fin de l'actor sous `close_timeout` ;
|
||||
7. finir `Closed` même si le peer ne répond pas à temps.
|
||||
|
||||
Si la session est déjà reconnecting, elle ne se reconnecte jamais seulement pour envoyer des unsubscribe.
|
||||
|
||||
`Drop` peut déclencher un signal best-effort, mais ne remplace pas l'API async explicite pour les garanties de lifecycle.
|
||||
|
||||
## 14. Erreurs et anomalies de protocole
|
||||
|
||||
Réutiliser lorsque possible les codes HTTP/JSON-RPC génériques existants :
|
||||
|
||||
```text
|
||||
invalid_settings
|
||||
invalid_rpc_parameters
|
||||
json_encode_failed
|
||||
json_decode_failed
|
||||
json_rpc_protocol_invalid
|
||||
rpc_application_error
|
||||
timeout
|
||||
```
|
||||
|
||||
Codes WS cibles minimaux :
|
||||
|
||||
```text
|
||||
ws_connection_failed
|
||||
ws_protocol_error
|
||||
ws_session_closed
|
||||
ws_subscription_failed
|
||||
ws_backpressure_overflow
|
||||
```
|
||||
|
||||
Policy d'anomalies :
|
||||
|
||||
- JSON/message WebSocket structurellement invalide : erreur protocole session, fermeture/reconnect selon budget ;
|
||||
- notification JSON valide mais payload typed invalide pour une subscription connue : fail de cette subscription, pas de teardown automatique des autres ;
|
||||
- notification valide pour ID remote inconnu/stale : compteur + log safe, drop ;
|
||||
- method notification incompatible avec la subscription connue : fail de cette subscription ;
|
||||
- réponse JSON-RPC d'erreur à subscribe/unsubscribe : `rpc_application_error`, pas reconnect implicite.
|
||||
|
||||
## 15. Observabilité et secrets
|
||||
|
||||
Tous les événements KSP passent par `ksp-logging-lib`.
|
||||
|
||||
Autorisés dans logs/snapshots :
|
||||
|
||||
```text
|
||||
endpoint logical name
|
||||
provider label
|
||||
cluster label
|
||||
WsSessionId
|
||||
WsSubscriptionId
|
||||
subscription kind
|
||||
state transitions
|
||||
active/pending counts
|
||||
reconnect attempt / exhaustion
|
||||
continuity_gap_count
|
||||
overflow_count
|
||||
error code qualifié
|
||||
```
|
||||
|
||||
Interdits :
|
||||
|
||||
```text
|
||||
URL WebSocket complète
|
||||
query token/credential
|
||||
Authorization/header sensible
|
||||
raw notification arbitraire
|
||||
payload massif
|
||||
remote request body complet
|
||||
```
|
||||
|
||||
Snapshot public cible : état session, endpoint name/provider/cluster, counts, reconnect state, continuity gaps, subscription IDs locaux + kinds + states. L'ID serveur peut rester interne ; un booléen `remote_bound` suffit pour diagnostiquer le binding sans faire croire à sa stabilité.
|
||||
|
||||
Tests dédiés : URL `wss://user:pass@host/path?api-key=secret` ne doit apparaître ni dans `Debug`, ni erreurs, ni logs capturés, ni snapshots.
|
||||
|
||||
## 16. DTOs et losslessness
|
||||
|
||||
Réutiliser les DTOs HTTP lorsque leur sémantique wire est réellement identique :
|
||||
|
||||
```text
|
||||
SolanaCommitment
|
||||
SolanaRpcContext
|
||||
SolanaRpcResponse<T>
|
||||
SolanaAccountEncoding
|
||||
SolanaDataSliceConfig
|
||||
SolanaProgramAccountFilter
|
||||
SolanaAccount
|
||||
SolanaKeyedAccount
|
||||
block/transaction DTOs compatibles
|
||||
SolanaWireField<T>
|
||||
```
|
||||
|
||||
Définir des DTOs WS dédiés pour : enveloppes notification, lifecycle, subscription kind/config, logs, signature union, slot/root/slotsUpdates/vote, block update et toute forme où le wire diffère.
|
||||
|
||||
`SolanaRpcContext.api_version` est déjà optionnel ; il peut donc représenter les contexts PubSub où la documentation indique que `apiVersion` est omis.
|
||||
|
||||
Pour unstable/évolutif, préférer des enums avec fallback `Unknown { type_name, raw }` borné plutôt qu'un rejet session-wide d'un variant upstream nouveau.
|
||||
|
||||
## 17. API générique provider-specific
|
||||
|
||||
Le moteur interne doit encoder une spec générique `subscribe_method + unsubscribe_method + params + decoder`, afin que `0.2.8` puisse réutiliser la session.
|
||||
|
||||
**Aucune API publique raw provider-extension n'est promise dans `0.2.7`.** Elle sera décidée après audit Helius de `0.2.8`. Cela évite de figer trop tôt une escape hatch qui deviendrait le contrat principal et contournerait les wrappers typés standards.
|
||||
|
||||
## 18. Tests déterministes attendus
|
||||
|
||||
Le test runtime utilise un serveur WebSocket local déterministe, sans provider externe :
|
||||
|
||||
```text
|
||||
handshake + close
|
||||
subscribe -> notification -> unsubscribe
|
||||
plusieurs subscriptions sur une session
|
||||
deux sessions physiques sur la même URL
|
||||
IDs locaux stables / IDs distants remappés
|
||||
erreur RPC subscribe/unsubscribe
|
||||
JSON/message malformé
|
||||
notification method/payload incompatible
|
||||
unknown/stale remote subscription id
|
||||
message/frame oversized
|
||||
connexion interrompue
|
||||
reconnect borné + exhaustion + reset budget
|
||||
resubscribe déterministe
|
||||
unsubscribe pendant reconnect + ack stale
|
||||
signature terminale => closed, jamais resubscribe
|
||||
shutdown active/pending/reconnecting
|
||||
backpressure : overflow d'une sub n'impacte pas les autres
|
||||
limits active subscriptions/pending requests
|
||||
program notification contexted + non-contexted
|
||||
slotsUpdates unknown variant
|
||||
vote timestamp omitted/null/value
|
||||
URL/credentials absents de Debug/error/log/snapshot
|
||||
warning centralisé pour unstable à la création, pas à chaque notification
|
||||
```
|
||||
|
||||
Le serveur local est un fixture de Transport ; aucune application Tauri n'est modifiée pour tester WebSocket.
|
||||
|
||||
## 19. Smoke live opt-in
|
||||
|
||||
Après stabilisation : un test `#[ignore]` Transport pur sur Devnet, préférentiellement une subscription stable simple (`slotSubscribe`) :
|
||||
|
||||
```text
|
||||
connect
|
||||
slotSubscribe
|
||||
attendre une notification sous timeout
|
||||
unsubscribe
|
||||
close
|
||||
```
|
||||
|
||||
Un endpoint override pourra être fourni par l'environnement Config seulement dans le smoke de composition séparé si celui-ci est réellement utile. Les unstable ne deviennent pas gates live car les validators publics peuvent les désactiver.
|
||||
|
||||
Un rate-limit, refus provider ou indisponibilité externe ne constitue pas automatiquement une régression locale.
|
||||
|
||||
## 20. Threat model synthétique
|
||||
|
||||
| Risque | Défense retenue | Preuves attendues |
|
||||
|--------------------------------------------------|----------------------------------------------------------------------|------------------------------|
|
||||
| URL/token fuit dans diagnostics | type URL redacted + snapshots sans URL + messages d'erreur qualifiés | tests Debug/error/log |
|
||||
| message/frame géant | limites WebSocket explicites avant JSON | tests oversized |
|
||||
| JSON/allocation non bornée | taille message bornée + DTOs ciblés/raw borné | adversarial fixtures |
|
||||
| consumer lent | queue par sub bounded, fail local explicite | overflow isolé |
|
||||
| reconnect infini | budget fini + backoff borné | exhaustion test |
|
||||
| notifications manquées pendant reconnect | continuity gap observable, aucune promesse lossless | lifecycle test/docs |
|
||||
| resubscribe stale après unsubscribe | ID local desired-state, cancellation gagne | race test |
|
||||
| remote ID réutilisé/remappé | mapping éphémère interne | reconnect/remap tests |
|
||||
| subscription orpheline | registry actor + close explicite + cleanup terminal | shutdown tests |
|
||||
| pending request leak | map bornée + timeout + purge reconnect/close | timeout tests |
|
||||
| task leak | actor unique joinable + close timeout | repeated connect/close tests |
|
||||
| shutdown bloqué | budget global + close timeout | hostile peer fixture |
|
||||
| unstable upstream variant casse session | typed enum + Unknown/raw borné | unknown variant fixture |
|
||||
| logique worker/persistence glisse dans Transport | aucun backfill/persistence/checkpoint | dependency/public API audit |
|
||||
|
||||
## 21. Hors périmètre confirmé
|
||||
|
||||
```text
|
||||
Helius LaserStream / provider params -> 0.2.8
|
||||
Yellowstone gRPC -> 0.2.9
|
||||
provider Yellowstone commercial -> plus tard
|
||||
shred/deshred/pre-execution -> plus tard
|
||||
off-chain prices -> 0.2.10
|
||||
Wallet / 2FA / .kspwallet -> hors 0.2.7
|
||||
Store/persistence -> 0.3.x
|
||||
Program decode/materialization -> plus tard
|
||||
frontend réseau direct -> interdit
|
||||
pool/scheduler automatique de sessions -> différé
|
||||
backfill HTTP automatique sur gap WS -> workers/jobs futurs
|
||||
public raw provider-extension API -> gate 0.2.8
|
||||
application heartbeat/ping périodique -> différé sans besoin démontré
|
||||
```
|
||||
|
||||
## 22. Forecast recalibré
|
||||
|
||||
L'inventaire officiel n'impose que 9 familles de subscriptions, mais le lifecycle concurrent est plus coûteux que le forecast initial. Le gate reste **positif sans split de release**, à condition de granulariser les tranches au lieu de compresser le moteur et les wrappers.
|
||||
|
||||
```text
|
||||
pre.001 audit interne/externe + matrice 18 méthodes + bot3 + dependencies + threat model + plan/sizing
|
||||
pre.002 settings WS Transport + URL redaction + IDs/states/snapshots + tests de settings
|
||||
pre.003 std.transport V2 HTTP+WS + backward V1 + schema/fixtures + Config -> WsTransportSettings
|
||||
pre.004 deps tokio-tungstenite/futures-util + actor physique + handshake/read/write + pending JSON-RPC + serveur local
|
||||
pre.005 limites frame/message/request + control frames + cancellation/close/shutdown + adversarial socket tests
|
||||
pre.006 registry subscriptions + IDs locaux + generic subscribe/unsubscribe engine + channels typed bounded
|
||||
pre.007 reconnect borné + resubscribe déterministe + continuity gap + races unsubscribe/reconnect
|
||||
pre.008 backpressure per-sub + overflow/limits + leak/lifecycle adversarial tests
|
||||
pre.009 wrappers stable lot A : account + program + logs, DTOs/options/KSP-TRANSPORT-007
|
||||
pre.010 wrappers stable lot B : signature + slot + root, terminaison signature/KSP-TRANSPORT-007
|
||||
pre.011 unstable : block + slotsUpdates + vote, warnings + fallbacks wire/KSP-TRANSPORT-007
|
||||
pre.012 compliance 18/18 + canaries public API + composition Config + régressions HTTP
|
||||
pre.013 smoke live opt-in + README/USAGE + cargo tree/duplicates + dependency audit final
|
||||
pre.014 validation workspace finale + docs/compliance + prompt 0.2.8
|
||||
rel.001 publication stable stricte
|
||||
```
|
||||
|
||||
Chaque tranche reste scindable si son implémentation réelle dépasse le budget nominal de 15–20 minutes. Le nombre `pre.014` n'est pas une deadline normative.
|
||||
|
||||
## 23. Gates de clôture `0.2.7`
|
||||
|
||||
La release ne peut passer stable que si :
|
||||
|
||||
- l'inventaire officiel est réaudité et reste rapproché par noms exacts ;
|
||||
- 18/18 opérations standard de l'index ciblé ont un statut explicite ;
|
||||
- 9/9 subscribe ont leur wrapper KSP promis et 9/9 unsubscribe sont couverts via handles/registry ;
|
||||
- options et variantes wire sont conservées sous `KSP-TRANSPORT-007` ;
|
||||
- la cardinalité endpoint -> N sessions -> N subscriptions est démontrée ;
|
||||
- reconnect/resubscribe/backpressure/cancellation/shutdown sont bornés et testés ;
|
||||
- continuity gaps sont observables sans promesse lossless ;
|
||||
- secrets/URLs ne fuitent pas ;
|
||||
- Config -> Transport reste l'unique direction d'adaptation ;
|
||||
- aucune dépendance Store/Program/Wallet/Config/tracing direct n'apparaît dans Transport ;
|
||||
- HTTP 52+14 ne régresse pas ;
|
||||
- tests déterministes et workspace sont verts ;
|
||||
- smoke live retenu reste opt-in ;
|
||||
- README/USAGE, matrice finale, graphes Cargo et prompt `0.2.8` sont synchronisés.
|
||||
|
||||
## 24. Validation opérateur requise pour `pre.001`
|
||||
|
||||
Après application de ce gate documentaire/versionné :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
`cargo test --workspace` n'est pas imposé par cette tranche documentaire d'ouverture tant qu'aucun Rust runtime n'est ajouté, mais reste autorisé comme checkpoint opérateur.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/000-README.md -->
|
||||
<!-- version: 17 -->
|
||||
<!-- version: 18 -->
|
||||
|
||||
# Validations KSP
|
||||
|
||||
@@ -18,3 +18,4 @@ Documents :
|
||||
- [`007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) — matrice finale validée de `0.2.4`, inventaire exact 52 current + 14 Deprecated, preuve typed 52/52, audit SIMD final, `KSP-TRANSPORT-007`, workspace complet et deux smokes Devnet passés avant publication stable.
|
||||
- [`008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md`](008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md) — matrice finale validée de la release stable `0.2.5`, threat model V1, canaris adversariaux, reproduction externe des vecteurs, audit de frontières, normalisation Rust/audit structurel, graphes Cargo et checkpoint final `pre.010-fix.003` vert.
|
||||
- [`009-V0_2_6_WALLET_DESK_COMPLIANCE.md`](009-V0_2_6_WALLET_DESK_COMPLIANCE.md) — matrice finale validée de la release stable `0.2.6`, couvrant Wallet Desk, les wires V1/V2, la migration explicite, le runtime Tauri packagé, les frontières sécurité/ownership et le gate opérateur `pre.018-fix.001` avec build final Linux vert.
|
||||
- [`010-V0_2_7_ONCHAIN_WEBSOCKET.md`](010-V0_2_7_ONCHAIN_WEBSOCKET.md) — matrice active de `0.2.7`, ouverte par `pre.001` avec l'inventaire normatif 9 subscribe + 9 unsubscribe, les statuts unstable, le lifecycle, les risques et les preuves à fermer.
|
||||
|
||||
260
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
Normal file
260
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
Normal file
@@ -0,0 +1,260 @@
|
||||
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Validation `0.2.7` — WebSocket Solana standard
|
||||
|
||||
> **Statut : matrice initiale ouverte par `0.2.7-pre.001`.** Les colonnes de preuve seront consolidées au fil des prereleases puis fermées avant `0.2.7-rel.001`.
|
||||
|
||||
## 1. Baseline normative
|
||||
|
||||
Audit officiel effectué le **22 août 2026** contre :
|
||||
|
||||
```text
|
||||
https://solana.com/docs/rpc/websocket
|
||||
```
|
||||
|
||||
Compte exact de l'index courant :
|
||||
|
||||
```text
|
||||
9 subscribe
|
||||
9 unsubscribe
|
||||
18 méthodes WebSocket totales
|
||||
```
|
||||
|
||||
Répartition statut KSP :
|
||||
|
||||
```text
|
||||
12 méthodes appartenant à 6 paires documentées non marquées unstable/deprecated
|
||||
6 méthodes appartenant à 3 paires unstable : block, slotsUpdates, vote
|
||||
0 méthode de l'index courant marquée Deprecated
|
||||
```
|
||||
|
||||
Pour une paire unstable, l'unsubscribe associé est classé `Unstable pair` dans KSP même si sa propre page n'affiche pas nécessairement le bandeau, car il n'existe que pour annuler la subscription unstable correspondante.
|
||||
|
||||
## 2. Matrice exhaustive des 18 opérations
|
||||
|
||||
| # | Méthode | Type | Statut `pre.001` | Paramètres / résultat essentiels | Notification / paire | Stratégie de test | Source officielle | Compliance |
|
||||
|---:|---------------------------|-------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------------|-------------------|
|
||||
| 1 | `accountSubscribe` | subscribe | Stable/documented | pubkey ; config `commitment`, `encoding`, `dataSlice` ; result numeric id ; `minContextSlot` upstream actuellement ignoré, donc non promis | `accountNotification` | fixture encodings/config + subscribe/notify | `https://solana.com/docs/rpc/websocket/accountsubscribe` | Planned `pre.009` |
|
||||
| 2 | `accountUnsubscribe` | unsubscribe | Stable/documented | remote id ; `true` or RPC error unknown id | account pair | handle local -> remote id fixture | `https://solana.com/docs/rpc/websocket/accountunsubscribe` | Planned `pre.009` |
|
||||
| 3 | `blockSubscribe` | subscribe | **Unstable** | `all`/mentions filter ; confirmed/finalized ; encoding ; tx details ; max tx version ; showRewards | `blockNotification` | all options + null block/error + validator capability fixture | `https://solana.com/docs/rpc/websocket/blocksubscribe` | Planned `pre.011` |
|
||||
| 4 | `blockUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | block pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/blockunsubscribe` | Planned `pre.011` |
|
||||
| 5 | `logsSubscribe` | subscribe | Stable/documented | `all`, `allWithVotes`, exactly one `mentions`; commitment | `logsNotification` | 3 filters + invalid multi-mention + notification | `https://solana.com/docs/rpc/websocket/logssubscribe` | Planned `pre.009` |
|
||||
| 6 | `logsUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | logs pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/logsunsubscribe` | Planned `pre.009` |
|
||||
| 7 | `programSubscribe` | subscribe | Stable/documented | program pubkey ; commitment ; filters ; encoding ; dataSlice ; `withContext` | `programNotification` | contexted/non-contexted fixtures + filters | `https://solana.com/docs/rpc/websocket/programsubscribe` | Planned `pre.009` |
|
||||
| 8 | `programUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | program pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/programunsubscribe` | Planned `pre.009` |
|
||||
| 9 | `rootSubscribe` | subscribe | Stable/documented | no params ; numeric id | `rootNotification` => `u64` | exact root fixture | `https://solana.com/docs/rpc/websocket/rootsubscribe` | Planned `pre.010` |
|
||||
| 10 | `rootUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | root pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/rootunsubscribe` | Planned `pre.010` |
|
||||
| 11 | `signatureSubscribe` | subscribe | Stable/documented | first transaction signature ; commitment ; `enableReceivedNotification` | `signatureNotification` early string or terminal error object | early + terminal + auto-close/no-resubscribe | `https://solana.com/docs/rpc/websocket/signaturesubscribe` | Planned `pre.010` |
|
||||
| 12 | `signatureUnsubscribe` | unsubscribe | Stable/documented | remote id before terminal fire ; boolean/error | signature pair | cancel before terminal + stale after terminal | `https://solana.com/docs/rpc/websocket/signatureunsubscribe` | Planned `pre.010` |
|
||||
| 13 | `slotSubscribe` | subscribe | Stable/documented | no params ; numeric id | `slotNotification` `{slot,parent,root}` | exact fixture + live smoke candidate | `https://solana.com/docs/rpc/websocket/slotsubscribe` | Planned `pre.010` |
|
||||
| 14 | `slotUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | slot pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotunsubscribe` | Planned `pre.010` |
|
||||
| 15 | `slotsUpdatesSubscribe` | subscribe | **Unstable** | no params ; numeric id | tagged `slotsUpdatesNotification` | each known variant + unknown fallback | `https://solana.com/docs/rpc/websocket/slotsupdatessubscribe` | Planned `pre.011` |
|
||||
| 16 | `slotsUpdatesUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | slotsUpdates pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotsupdatesunsubscribe` | Planned `pre.011` |
|
||||
| 17 | `voteSubscribe` | subscribe | **Unstable** | no params ; validator flag required | `voteNotification` | fields + timestamp omitted/null/value + warning | `https://solana.com/docs/rpc/websocket/votesubscribe` | Planned `pre.011` |
|
||||
| 18 | `voteUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | vote pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/voteunsubscribe` | Planned `pre.011` |
|
||||
|
||||
## 3. Notification matrix
|
||||
|
||||
| Subscribe | Notification | Shape à préserver | Point lossless / lifecycle |
|
||||
|-------------------------|----------------------------|------------------------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `accountSubscribe` | `accountNotification` | contextual account payload | reuse account DTOs/encodings/dataSlice |
|
||||
| `programSubscribe` | `programNotification` | keyed account, documenté avec contexte | accepter contexted/non-contexted à cause de l'écart docs/source audité ; préserver `withContext` |
|
||||
| `logsSubscribe` | `logsNotification` | context + `{signature, err, logs}` | err nullable ; filtre mentions exactement une adresse |
|
||||
| `signatureSubscribe` | `signatureNotification` | context + `"receivedSignature"` **ou** `{err}` | terminal object clôt la subscription ; early string ne la clôt pas |
|
||||
| `slotSubscribe` | `slotNotification` | `{slot,parent,root}` | non-contextual |
|
||||
| `rootSubscribe` | `rootNotification` | `u64` | non-contextual |
|
||||
| `blockSubscribe` | `blockNotification` | context + `{slot, block, err}` | unstable ; `block`/`err` nullable ; variants block selon config |
|
||||
| `slotsUpdatesSubscribe` | `slotsUpdatesNotification` | tagged union slot lifecycle | unstable ; fallback unknown/raw borné |
|
||||
| `voteSubscribe` | `voteNotification` | `{votePubkey,slots,hash,timestamp,signature}` | unstable/pre-consensus ; timestamp tolerant wire |
|
||||
|
||||
Les contexts WebSocket documentés omettent `apiVersion`. `SolanaRpcContext.api_version: Option<String>` est compatible avec cette omission.
|
||||
|
||||
## 4. Source Agave ciblée pour ambiguïtés
|
||||
|
||||
Les pages officielles WebSocket du 2026-08-22 lient actuellement Agave `v3.1.8` pour les handlers PubSub :
|
||||
|
||||
```text
|
||||
https://github.com/anza-xyz/agave/blob/v3.1.8/rpc/src/rpc_pubsub.rs
|
||||
https://github.com/anza-xyz/agave/blob/v3.1.8/rpc/src/rpc_subscriptions.rs
|
||||
```
|
||||
|
||||
Constats ciblés :
|
||||
|
||||
- `accountSubscribe` : le type partagé `RpcAccountInfoConfig` expose `min_context_slot`, mais le handler PubSub `v3.1.8` le destructure en `_ // ignored`. KSP ne le compte donc pas comme option WebSocket effective ;
|
||||
- `programSubscribe` : `RpcProgramAccountsConfig.with_context` est lu dans `ProgramSubscriptionParams`, le trait exposé dans `rpc_pubsub.rs` utilise `Subscriber<RpcResponse<RpcKeyedAccount>>`, le helper `check_commitment_and_notify` construit un `RpcResponse` avec contexte, et aucune consommation `with_context` n'a été retrouvée dans `rpc_subscriptions.rs` lors de l'audit ;
|
||||
- `logsSubscribe` : le handler accepte `all`, `allWithVotes` ou `mentions` et rejette un filtre `mentions` contenant autre chose qu'exactement une adresse ;
|
||||
- `signatureSubscribe` : le handler utilise la signature, `commitment` et `enable_received_notification`, sans option WebSocket supplémentaire ;
|
||||
- `blockSubscribe` : le handler consomme le jeu d'options documenté et impose un commitment au moins `confirmed` ;
|
||||
- `*Unsubscribe` : un ID serveur inconnu produit `InvalidParams` dans le handler audité ;
|
||||
- `voteSubscribe` : `RpcVote.timestamp` est `Option<i64>`, ce qui justifie de préserver l'optionalité wire sans valeur inventée.
|
||||
|
||||
Décisions compliance : transmettre `programSubscribe.withContext` malgré l'écart observé et accepter les formes contextée/non-contextée ; ne pas promettre `accountSubscribe.minContextSlot` tant qu'il est ignoré upstream ; conserver `vote.timestamp` comme champ optionnel/tolérant.
|
||||
|
||||
## 5. Méthodes unstable
|
||||
|
||||
### `blockSubscribe`
|
||||
|
||||
Conditions officielles :
|
||||
|
||||
```text
|
||||
--rpc-pubsub-enable-block-subscription
|
||||
--enable-rpc-transaction-history
|
||||
```
|
||||
|
||||
KSP : warning centralisé à la création, test fixture toujours disponible, smoke live non requis.
|
||||
|
||||
### `slotsUpdatesSubscribe`
|
||||
|
||||
Le format est explicitement annoncé comme susceptible de changer. Variants actuels :
|
||||
|
||||
```text
|
||||
firstShredReceived slot,timestamp
|
||||
completed slot,timestamp
|
||||
createdBank slot,parent,timestamp
|
||||
frozen slot,timestamp,stats
|
||||
dead slot,timestamp,err
|
||||
optimisticConfirmation slot,timestamp
|
||||
root slot,timestamp
|
||||
```
|
||||
|
||||
`stats` actuel : `numTransactionEntries`, `numSuccessfulTransactions`, `numFailedTransactions`, `maxTransactionsPerEntry`.
|
||||
|
||||
### `voteSubscribe`
|
||||
|
||||
Condition officielle :
|
||||
|
||||
```text
|
||||
--rpc-pubsub-enable-vote-subscription
|
||||
```
|
||||
|
||||
Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans le ledger. Transport les livre comme wire, sans interprétation métier.
|
||||
|
||||
## 6. Lifecycle compliance initiale
|
||||
|
||||
| Contrat | Décision `pre.001` | Gate cible |
|
||||
|---|---|---|
|
||||
| plusieurs sessions / même URL | création physique explicite ; aucun singleton/pool automatique | `pre.004`, `pre.012` |
|
||||
| plusieurs subs / session | registry actor par session | `pre.006` |
|
||||
| ID public subscription | local KSP stable | `pre.006` |
|
||||
| ID serveur | éphémère interne et remappé | `pre.006`/`pre.007` |
|
||||
| session states | Disconnected/Connecting/Active/Reconnecting/Closing/Closed/Failed | `pre.002` |
|
||||
| subscription states | Requested/Active/Resubscribing/Cancelling/Closed/Failed | `pre.002` |
|
||||
| reconnect | physique uniquement, budget/backoff finis | `pre.007` |
|
||||
| resubscribe | policy `Never|ActiveSubscriptions`, ordre local déterministe | `pre.007` |
|
||||
| continuity | gap observable, aucune promesse lossless | `pre.007` |
|
||||
| backpressure | queue par sub bounded ; overflow => fail local explicite | `pre.008` |
|
||||
| shutdown | explicite, bounded, annule reconnect et subscriptions | `pre.005` |
|
||||
| keepalive | pas de ping applicatif périodique sans besoin démontré | `pre.005` |
|
||||
|
||||
## 7. Threat/security compliance initiale
|
||||
|
||||
| Invariant | Preuve attendue | Statut |
|
||||
|---------------------------------------------------|-----------------------------------|---------|
|
||||
| URL/credentials absents de `Debug` | unit tests URL wrapper | Planned |
|
||||
| URL/credentials absents des erreurs | adversarial connection errors | Planned |
|
||||
| URL/credentials absents des logs | writer/capture KSP logging | Planned |
|
||||
| snapshots sans URL/raw payload | public API canary | Planned |
|
||||
| frame/message finis | oversized server fixture | Planned |
|
||||
| JSON borné indirectement par message | oversized + malformed fixture | Planned |
|
||||
| queues notifications bornées | slow consumer fixture | Planned |
|
||||
| pending RPC borné + timeout | no-response fixture | Planned |
|
||||
| reconnect loop bornée | repeated disconnect fixture | Planned |
|
||||
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Planned |
|
||||
| signature terminale ne resubscribe pas | terminal fixture | Planned |
|
||||
| shutdown ne bloque pas | peer hostile/no close ack fixture | Planned |
|
||||
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | Planned |
|
||||
| no direct `tracing` dans Transport | workspace audit/canary | Planned |
|
||||
|
||||
## 8. Dependency compliance initiale
|
||||
|
||||
Candidate retenue au gate :
|
||||
|
||||
```text
|
||||
tokio-tungstenite 0.30.0
|
||||
futures-util 0.3.34
|
||||
```
|
||||
|
||||
Features prévues :
|
||||
|
||||
```text
|
||||
tokio-tungstenite: default-features=false + connect + rustls-tls-webpki-roots
|
||||
futures-util: default-features=false + std + sink
|
||||
```
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://docs.rs/crate/tokio-tungstenite/0.30.0
|
||||
https://docs.rs/crate/tokio-tungstenite/0.30.0/features
|
||||
https://docs.rs/crate/futures-util/0.3.34
|
||||
```
|
||||
|
||||
Alternatives auditées mais non retenues : `tokio-websockets 0.13.3`, `fastwebsockets 0.10.0`.
|
||||
|
||||
Aucune de ces dependencies n'est ajoutée par `pre.001`; le graphe Cargo stable ne change pas dans ce gate hors signal de version workspace.
|
||||
|
||||
## 9. Config compliance initiale
|
||||
|
||||
V1 actuel : HTTP-only strict. Décision :
|
||||
|
||||
```text
|
||||
V1 -> support de lecture conservé, WS vide
|
||||
V2 -> HTTP existant + ws_defaults + profiles[].ws_endpoints
|
||||
Config -> WsTransportSettings
|
||||
Transport -X-> Config
|
||||
```
|
||||
|
||||
La schema V1 n'est pas assouplie. Une schema V2 explicite remplace la fixture standard au moment où l'adapter est matérialisé.
|
||||
|
||||
## 10. Validation du gate `pre.001`
|
||||
|
||||
Exécuté dans le sandbox :
|
||||
|
||||
```text
|
||||
archive stable v0.2.6 vérifiée OK
|
||||
lecture règles/architecture/plans/validation OK
|
||||
inventaire Transport/Config réel OK
|
||||
archive bot3 WebSocket auditée OK
|
||||
audit docs officielles WebSocket OK
|
||||
inventaire exact 18 = 9+9 OK
|
||||
audit dependencies candidates OK
|
||||
state machines / reconnect / resubscribe DECIDED
|
||||
backpressure / cancellation / shutdown / secrets DECIDED
|
||||
shape Config V2 minimal DECIDED
|
||||
plan/sizing OK
|
||||
python3 scripts/audit_rust_workspace_rules.py baseline OK
|
||||
```
|
||||
|
||||
Tenté mais non exécutable dans le sandbox :
|
||||
|
||||
```text
|
||||
cargo fmt --all cargo absent
|
||||
cargo check --workspace cargo absent
|
||||
cargo clippy --workspace --all-targets cargo absent
|
||||
```
|
||||
|
||||
La matrice ne considère donc pas `pre.001` techniquement validé par Cargo tant que l'opérateur n'a pas exécuté ces gates sur son checkout.
|
||||
|
||||
## 11. Critères finaux à transformer en preuves
|
||||
|
||||
Avant `rel.001`, cette matrice doit obtenir :
|
||||
|
||||
```text
|
||||
18/18 méthodes official-index accounted
|
||||
9/9 subscribe wrappers public typed
|
||||
9/9 unsubscribe couverts par handles/registry
|
||||
0 option officielle perdue
|
||||
0 fuite URL/credential
|
||||
N sessions same URL prouvé
|
||||
N subscriptions same session prouvé
|
||||
reconnect/resubscribe/backpressure/shutdown gates verts
|
||||
unstable warnings centralisés
|
||||
HTTP 52+14 non régressé
|
||||
Config V1 backward + V2 WS validés
|
||||
smoke live opt-in documenté
|
||||
cargo tree inspecté
|
||||
cargo test --workspace vert
|
||||
README/USAGE synchronisés
|
||||
prompt 0.2.8 préparé
|
||||
```
|
||||
Reference in New Issue
Block a user