v0.2.7-pre.007

This commit is contained in:
2026-08-22 20:42:06 +02:00
parent 435126f67a
commit b67fa89f44
11 changed files with 1352 additions and 112 deletions

View File

@@ -1,9 +1,9 @@
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# Validation `0.2.7` — WebSocket Solana standard
> **Statut : matrice active, `0.2.7-pre.005`.** Settings/lifecycle `pre.002`, Config V2 `pre.003`, session physique `pre.004` et durcissement limits/control/shutdown `pre.005` sont matérialisés. Registry subscriptions, reconnect et wrappers typed restent ouverts.
> **Statut : matrice active, `0.2.7-pre.007`.** Settings/lifecycle `pre.002`, Config V2 `pre.003`, session physique `pre.004`, durcissement `pre.005`, registry `pre.006` et reconnect/resubscribe `pre.007` sont matérialisés. Backpressure per-sub et wrappers typed restent ouverts.
## 1. Baseline normative
@@ -216,8 +216,8 @@ Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans l
| JSON borné indirectement par message | oversized + malformed fixture | Planned |
| queues notifications bornées | capacité settings, channel futur | Partial `pre.002` |
| pending RPC borné + timeout | map actor bornée + timeout request | **Done `pre.004`** |
| reconnect loop bornée | repeated disconnect fixture | Planned |
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Planned |
| 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 |
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | Planned |
@@ -368,7 +368,7 @@ outbound JSON-RPC > borne message/frame -> rejet avant socket write, session Act
inbound frame/message oversized -> rejet Tungstenite avant parse JSON, session Failed
pending request silencieuse -> timeout + purge de capacité, session Active
Ping distant -> Pong automatique flushé, session Active
Close distant propre -> Closed et non Failed
Close distant propre -> checkpoint `pre.005` Closed ; à partir de `pre.007`, perte physique reprise par reconnect borné
WsSession::close() -> Closing -> Closed
close() annule les pending requests avec ws_session_closed
peer hostile qui ne répond pas au Close -> shutdown borné
@@ -390,7 +390,7 @@ remote -> local mapping actor-owned
subscribe generic crate-private, wrappers publics futurs
unsubscribe handle public, bool Solana préservé
notification queue typed + bounded
reconnect/resubscribe non, pre.007
reconnect/resubscribe non à ce checkpoint ; matérialisé en pre.007
backpressure adversarial complet non, pre.008
```
@@ -410,6 +410,43 @@ snapshot -> local IDs + remote_bound uniquement
Le registry est détenu par le même actor que le socket et la pending map JSON-RPC. Aucun caller ne manipule le socket ni le remote ID. Les wrappers publics `accountSubscribe`, `programSubscribe`, etc. restent volontairement différés aux lots `pre.009+` afin de ne pas exposer une API raw provider-extension intermédiaire.
## 9.5 Checkpoint reconnect/resubscribe `pre.007`
Surface matérialisée :
```text
reconnect triggers EOF, Close distant inattendu, I/O/TLS/WebSocket/protocole structurel
reconnect budget fini, configurable
backoff exponentiel borné, sans jitter
shutdown pendant reconnect prioritaire, annule backoff/handshake
continuity_gap_count incrémenté une fois par perte de continuité logique
remote IDs après perte invalidés immédiatement
ActiveSubscriptions resubscribe local-ID croissant
Never aucune restauration automatique
budget reset seulement après retour complet à Active
unsubscribe pendant reconnect cancellation locale gagnante
ACK resubscribe tardif cleanup distant best-effort, aucune réactivation locale
backfill HTTP aucun
lossless guarantee aucune
```
Gates déterministes ajoutés :
```text
remote Close + budget insuffisant -> Reconnecting puis Failed, jamais boucle infinie
2 subscriptions -> resubscribe dans l'ordre WsSubscriptionId 1 puis 2
remote IDs 101/202 -> remappés 301/302 sans changer les IDs locaux
params de subscribe -> conservés et rejoués à l'identique
unsubscribe pendant backoff -> sub Closed et absente de la sélection resubscribe
unsubscribe après émission resubscribe -> ACK tardif nettoyé par *Unsubscribe best-effort
policy Never -> session reconnectée Active, subscription terminale Failed
2 pertes séparées avec max_retries=1 -> deux recoveries possibles, budget réinitialisé après Active
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.
## 10. Validation du gate `pre.001`
Exécuté dans le sandbox :