v0.2.7-pre.008
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Plan `0.2.7` — WebSocket Solana standard
|
||||
|
||||
@@ -627,11 +627,15 @@ 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 ;
|
||||
4. son receiver se termine après drainage des valeurs déjà queueées et la cause reste observable via le handle ;
|
||||
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.
|
||||
|
||||
`pre.008` matérialise cette policy dans l'actor : une réservation de capacité non bloquante sur la queue typed ne bloque jamais le socket, `overflow_count` est incrémenté de façon saturante, le handle conserve `ERROR_CODE_WS_BACKPRESSURE_OVERFLOW` comme cause terminale sûre et le binding distant est nettoyé best-effort. Un receiver abandonné est détecté à la notification suivante et libère lui aussi le registry local. `max_active_subscriptions` reste une borne d'admission distincte et sa capacité redevient disponible après toute terminaison locale.
|
||||
|
||||
Les autres transitions runtime vers `Failed` publient également leur `ErrorCode` KSP sûr sur le handle local. Les fermetures normales conservent une cause terminale absente. Aucun payload, URL ou remote subscription ID n'entre dans cette projection.
|
||||
|
||||
### 12.3 Frames/messages/JSON
|
||||
|
||||
Configurer des plafonds finis pour :
|
||||
@@ -738,7 +742,7 @@ 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é.
|
||||
Snapshot public cible : état session, endpoint name/provider/cluster, counts, reconnect state, continuity gaps, subscription IDs locaux + kinds + states. L'ID serveur reste interne ; un booléen `remote_bound` suffit pour diagnostiquer le binding sans faire croire à sa stabilité. Depuis `pre.008`, les causes terminales sont exposées uniquement sous forme d'`ErrorCode` KSP sûr et `overflow_count` distingue explicitement les saturations de queues de notifications.
|
||||
|
||||
`pre.002` matérialise `WsSessionSnapshot` et `WsSubscriptionSnapshot`. Leurs constructeurs restent crate-internal : les consumers ne peuvent pas fabriquer une fausse projection runtime. Aucun des deux types ne contient URL, credential, request body, raw notification ou remote subscription id.
|
||||
|
||||
@@ -882,7 +886,7 @@ pre.004 DONE — deps tokio-tungstenite/futures-util + actor physique + handsha
|
||||
pre.005 DONE — limites frame/message/request + control frames + cancellation/close/shutdown + adversarial socket tests
|
||||
pre.006 DONE — registry subscriptions + IDs locaux + generic subscribe/unsubscribe engine + channels typed bounded
|
||||
pre.007 DONE — reconnect borné + resubscribe déterministe + continuity gap + races unsubscribe/reconnect
|
||||
pre.008 backpressure per-sub + overflow/limits + leak/lifecycle adversarial tests
|
||||
pre.008 DONE — backpressure per-sub + overflow/limits + causes terminales sûres + 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Validation `0.2.7` — WebSocket Solana standard
|
||||
|
||||
@@ -192,17 +192,17 @@ Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans l
|
||||
| Contrat | Décision `pre.001` | Gate cible |
|
||||
|-------------------------------|-------------------------------------------------------------------|--------------------------------------------|
|
||||
| plusieurs sessions / même URL | création physique explicite ; aucun singleton/pool automatique | **Done `pre.004`**, canary final `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` |
|
||||
| plusieurs subs / session | registry actor par session | **Done `pre.006`** |
|
||||
| ID public subscription | local KSP stable | **Done `pre.006`** |
|
||||
| ID serveur | éphémère interne et remappé | **Done `pre.006` puis `pre.007`** |
|
||||
| session states | Disconnected/Connecting/Active/Reconnecting/Closing/Closed/Failed | **Done `pre.002`** |
|
||||
| subscription states | Requested/Active/Resubscribing/Cancelling/Closed/Failed | **Done `pre.002`** |
|
||||
| reconnect | physique uniquement, budget/backoff finis | `pre.007` |
|
||||
| resubscribe | policy `Never` ou `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` |
|
||||
| reconnect | physique uniquement, budget/backoff finis | **Done `pre.007`** |
|
||||
| resubscribe | policy `Never` ou `ActiveSubscriptions`, ordre local déterministe | **Done `pre.007`** |
|
||||
| continuity | gap observable, aucune promesse lossless | **Done `pre.007`** |
|
||||
| backpressure | queue par sub bounded ; overflow => fail local explicite | **Done `pre.008`** |
|
||||
| shutdown | explicite, bounded, annule reconnect et subscriptions | **Done `pre.005`** |
|
||||
| keepalive | pas de ping applicatif périodique sans besoin démontré | **Done `pre.005`** |
|
||||
|
||||
## 7. Threat/security compliance initiale
|
||||
|
||||
@@ -212,14 +212,14 @@ Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans l
|
||||
| URL/credentials absents des erreurs | validation URL + connection errors safe | **Done through `pre.004`** |
|
||||
| URL/credentials absents des logs | actor logs only safe endpoint metadata | Partial `pre.004`, capture finale future |
|
||||
| snapshots sans URL/raw payload | unit shape + public contract | **Done `pre.002`** |
|
||||
| frame/message finis | settings bornés + `WebSocketConfig` raccordé | Partial `pre.004`, adversarial `pre.005` |
|
||||
| JSON borné indirectement par message | oversized + malformed fixture | Planned |
|
||||
| queues notifications bornées | capacité settings, channel futur | Partial `pre.002` |
|
||||
| frame/message finis | settings bornés + `WebSocketConfig` raccordé | **Done `pre.005`** |
|
||||
| JSON borné indirectement par message | oversized + malformed fixture | **Done `pre.005`** |
|
||||
| queues notifications bornées | queue typed bornée + overflow isolé | **Done `pre.008`** |
|
||||
| pending RPC borné + timeout | map actor bornée + timeout request | **Done `pre.004`** |
|
||||
| reconnect loop bornée | repeated disconnect fixture | Done `pre.007` |
|
||||
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Done `pre.007` |
|
||||
| signature terminale ne resubscribe pas | terminal fixture | Planned |
|
||||
| shutdown ne bloque pas | peer hostile/no close ack fixture | Planned |
|
||||
| shutdown ne bloque pas | peer hostile/no close ack fixture | **Done `pre.005`** |
|
||||
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | Planned |
|
||||
| no direct `tracing` dans Transport | workspace audit + source audit | **Done `pre.002`** |
|
||||
|
||||
@@ -365,7 +365,7 @@ Gates déterministes ajoutés :
|
||||
```text
|
||||
max_pending_requests saturé -> seule la request excédentaire est rejetée
|
||||
outbound JSON-RPC > borne message/frame -> rejet avant socket write, session Active
|
||||
inbound frame/message oversized -> rejet Tungstenite avant parse JSON, session Failed
|
||||
inbound frame/message oversized -> rejet Tungstenite avant parse JSON ; depuis pre.007, reconnect borné
|
||||
pending request silencieuse -> timeout + purge de capacité, session Active
|
||||
Ping distant -> Pong automatique flushé, session Active
|
||||
Close distant propre -> checkpoint `pre.005` Closed ; à partir de `pre.007`, perte physique reprise par reconnect borné
|
||||
@@ -391,7 +391,7 @@ subscribe generic crate-private, wrappers publics futurs
|
||||
unsubscribe handle public, bool Solana préservé
|
||||
notification queue typed + bounded
|
||||
reconnect/resubscribe non à ce checkpoint ; matérialisé en pre.007
|
||||
backpressure adversarial complet non, pre.008
|
||||
backpressure adversarial complet oui, pre.008
|
||||
```
|
||||
|
||||
Gates déterministes ajoutés :
|
||||
@@ -447,6 +447,40 @@ continuity_gap_count -> 1 puis 2 sur deux pertes distinctes
|
||||
|
||||
Les requests applicatives en vol au moment d'une perte physique échouent ; Transport ne les rejoue pas implicitement. La restauration ne promet aucune continuité lossless et n'effectue aucun backfill HTTP. Les remote subscription IDs restent strictement internes et sont remplacés à chaque ACK de resubscribe.
|
||||
|
||||
## 9.6 Checkpoint backpressure/lifecycle `pre.008`
|
||||
|
||||
Surface matérialisée :
|
||||
|
||||
```text
|
||||
notification_queue_capacity borne effective par WsSubscription<T>
|
||||
overflow_count compteur session saturating, réellement incrémenté
|
||||
terminal_error_code ErrorCode KSP sûr sur le handle Failed
|
||||
queue pleine fail local uniquement, aucun drop silencieux
|
||||
remote cleanup *Unsubscribe best-effort après overflow/receiver drop/erreur locale
|
||||
max_active_subscriptions admission bornée, capacité réutilisable après terminaison
|
||||
receiver abandonné détecté sur notification suivante, registry libéré
|
||||
reconnect après overflow subscription Failed absente de toute restauration future
|
||||
```
|
||||
|
||||
Gates déterministes ajoutés :
|
||||
|
||||
```text
|
||||
queue capacité 1 + 2 notifications -> overflow_count 1 + ws_backpressure_overflow
|
||||
subscription lente en overflow -> Failed, première notification déjà queueée reste lisible puis channel fermé
|
||||
subscription saine parallèle -> notification livrée et état Active
|
||||
session après overflow isolé -> Active
|
||||
binding distant overflow -> *Unsubscribe best-effort exact
|
||||
max_active_subscriptions atteint -> création excédentaire rejetée sans incrémenter overflow_count
|
||||
unsubscribe terminal -> capacité locale libérée puis nouvelle subscription acceptée
|
||||
receiver droppé -> notification suivante déclenche cleanup distant et libère la capacité
|
||||
method mismatch -> ws_protocol_error terminal sur le handle, session Active
|
||||
decode typed invalide -> code invalid_response terminal sur le handle, session Active
|
||||
policy Never après perte physique -> ws_connection_failed terminal sur le handle
|
||||
resubscribe RPC application error -> rpc_application_error terminal sur le handle
|
||||
```
|
||||
|
||||
`overflow_count` et `continuity_gap_count` sont deux signaux distincts : le premier mesure les saturations locales de consumers, le second les ruptures de continuité physique. Aucun des deux ne déclenche de replay ou de backfill automatique. Les causes terminales n'exposent qu'un `ErrorCode` KSP, jamais le payload distant, le remote subscription ID ou l'URL.
|
||||
|
||||
## 10. Validation du gate `pre.001`
|
||||
|
||||
Exécuté dans le sandbox :
|
||||
|
||||
Reference in New Issue
Block a user