v0.2.9-pre.010
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<!-- file: docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md -->
|
||||
<!-- version: 20 -->
|
||||
<!-- version: 21 -->
|
||||
|
||||
# Validation `0.2.9` — moteur Yellowstone + standard Solana + PublicNode
|
||||
|
||||
> **Statut : `pre.009` est fonctionnellement verte : Transport 379 unit + 48 public API + 42 completeness + 4 doctests et workspace PASS. Clippy signale deux warnings d’hygiène ; `pre.009-fix.001` est candidate pour les supprimer sans changement de protocole/lifecycle.**
|
||||
> **Statut : `pre.009-fix.001` est fermé : fmt/audit/check/Clippy sans warning, Transport 379 unit + 48 public API + 42 completeness + 4 doctests, dependency canary et workspace PASS. `pre.010` est candidate reconnect/replay avec observabilité prudente des gaps/duplicates.**
|
||||
|
||||
## 1. Autorités du gate
|
||||
|
||||
@@ -287,25 +287,25 @@ DONE pre.003 source/tests channel/client Debug sans URL, metadata value ni raw
|
||||
|
||||
## 11. Lifecycle / backpressure / replay
|
||||
|
||||
| Cas | Attendu | État |
|
||||
|--------------------------------------------|------------------------------------------|-----------------------------------|
|
||||
| stream open | session bornée | CANDIDATE pre.009 |
|
||||
| request mutation | ordre déterministe | CANDIDATE pre.009 |
|
||||
| server Ping -> client request ping -> Pong | explicite | CANDIDATE pre.009 |
|
||||
| server half-close | terminal normal avant reconnect | CANDIDATE pre.009 |
|
||||
| client close | half-close + cleanup borné | CANDIDATE pre.009 |
|
||||
| receiver drop | Drop session => cleanup best-effort | CANDIDATE pre.009 |
|
||||
| slow subscription | pas de queue infinie | CANDIDATE pre.009 |
|
||||
| inbound oversized | limite Tonic avant payload KSP | CANDIDATE pre.009 |
|
||||
| outbound oversized | encoded_len avant queue/write | CANDIDATE pre.009 |
|
||||
| reconnect budget | borné | TODO |
|
||||
| resubscribe order | déterministe | TODO |
|
||||
| `from_slot` | utilisé sans promesse lossless | TODO |
|
||||
| ReplayInfo | informatif | DONE unary ; usage reconnect TODO |
|
||||
| duplicates | observables | TODO |
|
||||
| gaps | observables | TODO |
|
||||
| divergent node history | couverture documentée | TODO |
|
||||
| shutdown during reconnect | aucune nouvelle connexion après shutdown | TODO |
|
||||
| Cas | Attendu | État |
|
||||
|--------------------------------------------|-----------------------------------------------------------------|----------------------------------------|
|
||||
| stream open | session bornée | DONE pre.009 / gate fix.001 PASS |
|
||||
| request mutation | ordre déterministe | DONE pre.009 |
|
||||
| server Ping -> client request ping -> Pong | explicite | DONE pre.009 |
|
||||
| server half-close | reconnect si budget > 0 ; terminal normal sinon | CANDIDATE pre.010 |
|
||||
| client close | half-close + cleanup borné | DONE pre.009 |
|
||||
| receiver drop | Drop session => cleanup best-effort | DONE pre.009 |
|
||||
| slow subscription | pas de queue infinie | DONE pre.009 |
|
||||
| inbound oversized | limite Tonic avant payload KSP | DONE pre.009 |
|
||||
| outbound oversized | encoded_len avant queue/write | DONE pre.009 |
|
||||
| reconnect budget | borné | CANDIDATE pre.010 |
|
||||
| resubscribe order | dernier request complet accepté | CANDIDATE pre.010 |
|
||||
| `from_slot` | max(explicite, highest observed), sans promesse lossless | CANDIDATE pre.010 |
|
||||
| ReplayInfo | informatif ; clamp seulement si gap de couverture replay prouvé | DONE unary + CANDIDATE usage reconnect |
|
||||
| duplicates | identités bornées observables, jamais supprimées | CANDIDATE pre.010 |
|
||||
| gaps | seulement si `first_available > requested_from_slot` | CANDIDATE pre.010 |
|
||||
| divergent node history | Block/BlockMeta hash-aware ; pas de claim global | CANDIDATE couverture documentée |
|
||||
| shutdown during reconnect | aucune nouvelle connexion après shutdown | CANDIDATE pre.010 |
|
||||
|
||||
Claims interdits sans nouvelle preuve :
|
||||
|
||||
@@ -411,8 +411,8 @@ pre.005 DONE standard: accounts + slots 15
|
||||
pre.006 DONE structure: namespace privé HTTP `http_*` 15–20 min ; gate PASS
|
||||
pre.007 DONE standard: transactions + transaction_status 15–20 min ; gate PASS
|
||||
pre.008 DONE standard: blocks + block_meta + entry 15–20 min ; gate final fix.001 PASS sans warning
|
||||
pre.009 FIX.001 CANDIDATE moteur: bidi/backpressure/half-close/shutdown 15–20 min ; gate fonctionnel vert, 2 warnings Clippy
|
||||
pre.010 TODO moteur: reconnect/replay/gap/duplicate 15–20 min
|
||||
pre.009 DONE moteur: bidi/backpressure/half-close/shutdown 15–20 min ; gate final fix.001 PASS sans warning, 379/48/42/4
|
||||
pre.010 CANDIDATE moteur: reconnect/replay/gap/duplicate 15–20 min ; source/fixture candidate, gate opérateur à exécuter
|
||||
pre.011 TODO Config V3 + protocol/provider + profils PublicNode 15–20 min
|
||||
pre.012 TODO PublicNode live + compliance + docs/prompt 0.2.10 15–20 min
|
||||
rel.001 TODO stable
|
||||
@@ -918,7 +918,7 @@ Le flux sortant utilise la même `mpsc` bornée que celle fournie à `tonic::cli
|
||||
|
||||
`pre.009` ne tente aucun reconnect. Un half-close serveur est terminal normal ; `Status`, decode invalide et overflow sont terminaux en erreur. Le budget de reconnect, l'ordre de resubscribe, `from_slot`/ReplayInfo, gaps, duplicates et node divergence restent exclusivement `pre.010`.
|
||||
|
||||
**Verdict `pre.009` :** contrat fonctionnel validé ; fix Clippy-only requis avant fermeture.
|
||||
**Verdict `pre.009` :** fermé après `pre.009-fix.001`, gate opérateur final intégralement vert et sans warning.
|
||||
|
||||
## 28. Gate `pre.009-fix.001` — taille de l’enum update + canari `Send`
|
||||
|
||||
@@ -937,6 +937,45 @@ Le flux sortant utilise la même `mpsc` bornée que celle fournie à `tonic::cli
|
||||
| `large_enum_variant` | Transaction ~664 B, Block ~280 B | `Transaction(Box<YellowstoneTransactionUpdate>)` |
|
||||
| `extra_unused_type_parameters` | helper `assert_send<T>()` n’utilise pas T | `PhantomData<T>` matérialise l’usage compile-time |
|
||||
|
||||
Le boxing ne modifie ni le protobuf ni `YellowstoneTransactionUpdate` : il réduit uniquement la taille du discriminant public transporté dans la queue bidi. Le canari `Send` conserve la même contrainte et ne construit aucune session réseau. Aucun `allow` Clippy n’est ajouté.
|
||||
Le boxing ne modifie ni le protobuf ni `YellowstoneTransactionUpdate` : il réduit uniquement la taille du discriminant public transporté dans la queue bidi. Le canari `Send` conserve la même contrainte et ne construit aucune session réseau. Aucun `allow` Clippy n’est ajouté. Le gate opérateur final du `2026-08-24` repasse intégralement vert, Clippy sans warning, avec les compteurs 379/48/42/4 inchangés.
|
||||
|
||||
**Verdict fix candidate :** correction minimale prête ; fermeture de `pre.009` après gate opérateur sans warning.
|
||||
|
||||
|
||||
## 29. Candidate `pre.010` — reconnect/replay et continuité observable
|
||||
|
||||
Réaduit upstream au `2026-08-24` :
|
||||
|
||||
```text
|
||||
SubscribeRequest.from_slot toujours présent
|
||||
SubscribeReplayInfoResponse.first_available? toujours présent
|
||||
changelog 2026-07-22 fix replay Blocks/state gap
|
||||
changelog 2026-06-15 upstream autoreconnect traite l'equivocation par quarantaine/blockhash
|
||||
```
|
||||
|
||||
KSP conserve sa stratégie B : aucune importation de la sémantique `yellowstone-grpc-client` autoreconnect. Le stream KSP rouvre lui-même `/geyser.Geyser/Subscribe` sur le channel N1 existant.
|
||||
|
||||
| Preuve source `pre.010` | État |
|
||||
|-------------------------------------------------------------|--------------------|
|
||||
| état public `Reconnecting` | SOURCE |
|
||||
| snapshot reconnect/replay/gap/duplicate | SOURCE |
|
||||
| budget `max_retries` | SOURCE |
|
||||
| backoff exponentiel initial/max | SOURCE |
|
||||
| dernier request complet resoumis | SOURCE |
|
||||
| resume `max(explicit, last_observed)` | SOURCE |
|
||||
| ReplayInfo consulté avant replay | SOURCE |
|
||||
| `first_available > requested` => replay non couvert + clamp | SOURCE+TEST |
|
||||
| duplicate identité bornée, update livrée | SOURCE+TEST |
|
||||
| mutation refusée pendant `Reconnecting` | SOURCE+TEST |
|
||||
| shutdown interrompt le backoff | SOURCE+TEST |
|
||||
| épuisement budget => terminal sûr | SOURCE+TEST |
|
||||
| cache identité borné à 512 | SOURCE |
|
||||
| exactement-once/lossless | EXPLICIT NON-CLAIM |
|
||||
| Config V3 / PublicNode | OUT pre.010 |
|
||||
| `SubscribeDeshred` | OUT 0.2.9 |
|
||||
|
||||
La détection de gap n'utilise pas les sauts entre slots d'updates filtrés : un filtre peut légitimement ne produire aucun message pendant plusieurs slots. Le seul gap compté par cette tranche est une plage de replay objectivement devenue indisponible d'après `SubscribeReplayInfo.first_available` ; cela ne prouve pas qu'un update correspondant aux filtres existait ou a été perdu.
|
||||
|
||||
Le cache de duplicates retient des identités minimales Account/Slot/Transaction/TransactionStatus/Block/BlockMeta/Entry. Il ne retient pas les payloads complets et ne supprime jamais un update. Pour Block/BlockMeta, le blockhash fait partie de l'identité afin de ne pas classer deux histoires divergentes de même slot comme un simple duplicate ; aucune détection globale d'equivocation n'est prétendue.
|
||||
|
||||
**Gate candidate attendu :** audit statique clean ; après exécution opérateur, Transport attendu autour de 383 unit / 49 public API / 43 release-completeness / 4 doctests. Aucune dépendance/feature changée, donc pas de `cargo tree` supplémentaire.
|
||||
|
||||
Reference in New Issue
Block a user