Files
khadhroony-solana-project/deltas/0.2.9/pre.010.md
2026-08-24 18:39:19 +02:00

95 lines
4.1 KiB
Markdown

<!-- file: deltas/0.2.9/pre.010.md -->
<!-- version: 1 -->
# Delta `0.2.9-pre.010` — reconnect borné + replay prudent + continuité observable
## Base
```text
0.2.9-pre.009-fix.001
gate opérateur final : fmt/audit/check/Clippy/workspace PASS sans warning
Transport : 379 unit + 48 public API + 42 release-completeness + 4 doctests
```
## Changements runtime
- ajoute l'état public `YellowstoneGrpcSubscribeState::Reconnecting` ;
- ajoute `YellowstoneGrpcSubscribeSnapshot` avec compteurs sûrs de reconnect/replay/continuité ;
- active le `YellowstoneGrpcReconnectSettings` déjà introduit en `pre.002` pour le stream `Subscribe` ;
- rouvre le stream avec un backoff exponentiel borné et un nombre d'essais borné ;
- conserve le dernier `YellowstoneSubscribeRequest` complet accepté ;
- après perte du stream, resoumet ce request déterministement avec un `from_slot` au moins égal au plus haut slot déjà observé ;
- consulte `SubscribeReplayInfo` avant les tentatives de replay lorsque `from_slot` est disponible ;
- si `first_available > from_slot`, incrémente `continuity_gap_count` et clamp le replay à `first_available` ;
- maintient un cache borné de 512 identités d'updates pour observer les duplicates autour d'un replay ;
- les duplicates restent livrés : aucun contrat exactly-once n'est inventé ;
- rejette les mutations request pendant `Reconnecting` pour éviter une application ambiguë entre deux streams physiques ;
- un shutdown pendant le backoff interrompt immédiatement la boucle et interdit une nouvelle ouverture ;
- un épuisement du budget devient terminal avec un code KSP sûr `grpc_channel_failed`.
## Sémantique de continuité
```text
from_slot de reconnect = max(from_slot explicite du dernier request, last_observed_slot)
ReplayInfo = information de rétention ; pas preuve de replay complet
continuity gap = couverture de replay indisponible, comptée seulement si first_available > slot demandé
slot manquant entre deux updates filtrés = jamais assimilé automatiquement à un gap
duplicate = identité KSP bornée déjà observée ; update toujours livrée
exactly-once = non garanti
lossless = non garanti
ordre global sans gap = non garanti
```
Identités retenues pour l'observation bornée :
```text
Account slot + pubkey + write_version
Slot slot + status
Transaction slot + signature
TransactionStatus slot + signature
Block slot + blockhash
BlockMeta slot + blockhash
Entry slot + index + hash
Ping/Pong hors déduplication
```
La couverture d'une éventuelle divergence de node reste volontairement limitée : deux Block/BlockMeta de même slot mais de blockhash différent ne sont pas classés duplicate. KSP ne généralise pas cette preuve aux familles qui ne transportent pas de blockhash.
## Fixture locale
| Cas | Preuve |
|------------------------------------------------|-------------|
| reconnect après server half-close | PASS source |
| `from_slot = last_observed_slot` | PASS source |
| ReplayInfo disponible | PASS source |
| replay duplicate observable | PASS source |
| couverture replay indisponible prouvée + clamp | PASS source |
| budget reconnect épuisé | PASS source |
| mutation pendant reconnect rejetée | PASS source |
| shutdown pendant backoff | PASS source |
| endpoint/Status secret non réémis | PASS source |
| anciens gates bidi avec reconnect `0` | PASS source |
## Frontières
```text
OUT pre.010 : Config V3 / PublicNode / provider facade
OUT 0.2.9 : SubscribeDeshred
aucune nouvelle dépendance / feature Cargo
aucun yellowstone-grpc-client runtime
```
## Validation candidate
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
cargo test -p ksp-core-lib --test workspace_dependencies
cargo test --workspace
```
Le `cargo tree` n'est pas requis : aucune dépendance ni feature n'a changé.