# Plan `0.2.10` — OrbitFlare Yellowstone gRPC **Statut courant : `0.2.10-pre.002-fix.001` corrige l’hypothèse d’auth de `pre.002`. Le live sans metadata a atteint OrbitFlare puis `SubscribeOpen` a été rejeté `Unauthenticated`. Le Dashboard opérateur et la référence Yellowstone OrbitFlare établissent désormais que la License Key `ORBIT-*` du produit Solana Free doit être envoyée comme metadata secrète `x-token`. Config V3 et le smoke sont corrigés sans aucune modification N1/N2 ; le rerun authentifié `Slot + Ping` reste le gate live.** ## 1. Base et autorité Base stable autoritaire : ```text v0.2.9 ``` État vérifié dans l'archive Gitea fournie : ```text workspace.package.version = 0.2.9 deltas/0.2.9/rel.001.md présent prompts/015-V0_2_10_START_PROMPT.md présent plan 016 Yellowstone présent validation 012 Yellowstone présente Config Transport V3 présente PublicNode Mainnet + Testnet présents ``` Ordre d'autorité pendant `0.2.10` : ```text règles normatives KSP archive stable v0.2.9 et code réellement livré décisions du présent plan et validation 013 deltas immuables de 0.2.10 prompt 015 pour les contraintes non supersédées sources provider/upstream actuelles pour les faits externes ``` Le présent gate supersède une hypothèse du prompt : une divergence lifecycle OrbitFlare ne doit jamais être résolue par modification du moteur N1. Si elle ne peut pas être proprement composée au-dessus du moteur, elle devient un blocker/split explicite. ## 2. Mission opérationnelle réelle L'objectif prioritaire de `0.2.10` est de disposer d'au moins un provider Yellowstone **gratuit et durable sur Solana Devnet** pour les validations futures de KSP. PublicNode/Allnodes a déjà validé le standard KSP sur : ```text Mainnet Testnet ``` OrbitFlare complète cette couverture avec : ```text Devnet ``` Le pricing OrbitFlare observé le 2026-08-25 confirme : ```text plan Free 0 USD/mois RPC 10 RPS transactions 1 TPS gRPC Devnet only credit limits unlimited carte bancaire non requise selon la page d'accueil ``` Sources principales : ```text https://orbitflare.com/pricing https://orbitflare.com/products/rpc-nodes https://docs.orbitflare.com/cli ``` Mainnet OrbitFlare payant n'est pas un gate de cette release. Le résultat minimal utile est un smoke Yellowstone standard KSP sur l'endpoint Devnet gratuit. ## 3. Invariant architectural renforcé ### 3.1 N1 gRPC immuable Les modules qui constituent le moteur Yellowstone livré par `0.2.9` ne doivent pas être modifiés pour OrbitFlare : ```text src/grpc_settings.rs src/grpc_channel.rs src/grpc_unary.rs src/grpc_subscribe.rs src/grpc_stream.rs ``` Le même principe vaut durablement pour les moteurs physiques : ```text moteur HTTP provider-neutral moteur WebSocket provider-neutral moteur gRPC provider-neutral ``` Une release provider peut modifier : ```text provider facade provider policy provider capability projection Config provider profile provider smoke/compliance provider-specific tests ``` Elle ne modifie pas le moteur pour faire rentrer une différence fournisseur. ### 3.2 N2 standard Yellowstone immuable La surface Solana Yellowstone standard publiée par `0.2.9` reste la seule surface wire de référence : ```text Subscribe SubscribeReplayInfo Ping GetLatestBlockhash GetBlockHeight GetSlot IsBlockhashValid GetVersion accounts slots transactions transactions_status blocks blocks_meta entry commitment accounts_data_slice ping from_slot 9 variantes SubscribeUpdate ``` OrbitFlare ne redéfinit aucun DTO, filtre, unary, request ou update standard. ### 3.3 N3 provider uniquement si divergence démontrée Architecture cible : ```text OrbitFlare N3 -> standard Yellowstone N2 inchangé -> moteur gRPC N1 inchangé ``` Une façade OrbitFlare publique n'est créée que si un consumer KSP doit réellement voir une restriction ou une extension provider. Un simple endpoint, un `provider = orbitflare`, une policy Config ou un smoke ne suffisent pas à justifier une nouvelle API publique. ## 4. Baseline opérateur `v0.2.9` Preuves fournies le 2026-08-25 : | Gate | Résultat | |-------------------------------------------|------------------------------------------| | `cargo fmt --all` | PASS | | audit Rust workspace | PASS, 0 candidate export | | audit Markdown tables | PASS, 97 tables et 233 files sur `pre.1` | | `cargo check --workspace` | PASS | | `cargo clippy --workspace --all-targets` | PASS | | `cargo test --workspace` | PASS | | Transport unit | 383 sur 383 PASS | | Transport public API | 49 sur 49 PASS | | Transport release completeness | 43 sur 43 PASS | | Config unit | 113 sur 113 PASS | | PublicNode Yellowstone live | ignored opt-in comme attendu | | `cargo tree --duplicates` Transport | fourni et inspecté | | `cargo tree -p ksp-onchain-transport-lib` | fourni sur `0.2.10-pre.1` | Versions visibles dans le graphe fourni : ```text yellowstone-grpc-proto 12.6.0 tonic 0.14.6 tonic-prost 0.14.6 prost 0.14.4 tokio 1.53.1 http 1.5.0 reqwest 0.13.4 ``` Aucune seconde génération Tonic/Prost/Yellowstone incompatible n'est observée. Les doublons restants ne justifient aucun changement pour `0.2.10`. ## 5. Réaudit Yellowstone upstream du 2026-08-25 État courant observé : ```text release GitHub courante v15.1.2+solana.4.2.0 publication 2026-08-18 yellowstone-grpc-proto publié 12.6.0 stack proto prost 0.14 / tonic 0.14 ``` Sources : ```text https://github.com/rpcpool/yellowstone-grpc/releases https://github.com/rpcpool/yellowstone-grpc/blob/master/README.md https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto https://crates.io/crates/yellowstone-grpc-proto ``` Aucune évolution matérielle n'impose de changer le contrat KSP de `0.2.9`. Il n'y a donc aucun bump de dependency Yellowstone/Tonic/Prost prévu dans `0.2.10`. ## 6. Endpoint et network OrbitFlare Les sources actuelles distinguent plusieurs formes de service. | Élément | Observation actuelle | Décision KSP | |------------------------|-----------------------------------------------|---------------------------------------------| | Devnet gRPC | `http://devnet.rpc.orbitflare.com:10000` | premier endpoint live à tester | | endpoint régional | `http://{region}.rpc.orbitflare.com:10000` | descriptif, pas de fallback inventé | | endpoint licence/dédié | `https://your-endpoint.grpc.orbitflare.com` | utiliser uniquement si Dashboard le fournit | | `http` | HTTP/2 plaintext | ne jamais présenter comme TLS | | `https` | HTTP/2 TLS | conserver tel quel | | Mainnet | disponible selon plan/service | non requis pour le gate gratuit | | Devnet | explicitement documenté | **IN** | | Testnet | CLI accepte le label mais endpoint non prouvé | non requis, ne rien inventer | Sources : ```text https://docs.orbitflare.com/cli https://docs.orbitflare.com/sdk/go-grpc https://docs.orbitflare.com/data-streaming/yellowstone-quickstart ``` L'endpoint Dashboard opérateur reste autoritaire lorsqu'il existe. KSP ne transforme jamais automatiquement une URL `http` en `https`, ne change pas de région et ne construit pas un hostname provider non documenté. ## 7. Auth OrbitFlare : classification live corrigée Le live `pre.002` et les sources OrbitFlare permettent désormais de séparer les credentials sans supposition. | Credential ou mécanisme | Usage observé | Classification après `pre.002` | |-------------------------|---------------------------|------------------------------------------------------| | `X-ORBIT-KEY` | Customer API | control-plane, interdit sur Yellowstone | | Bearer Device Flow | Customer API v2 | control-plane | | `api_key` RPC | Solana HTTP RPC | data-plane HTTP | | License Key `ORBIT-*` | produit Solana Free | data-plane provider | | metadata `x-token` | Yellowstone gRPC | transport prouvé de la License Key | | aucune metadata | premier smoke KSP | rejetée `Unauthenticated` au `SubscribeOpen` | | IP whitelist | autre mode d’auth produit | non retenu pour le service opérateur en API Key Mode | La référence Yellowstone OrbitFlare donne explicitement le modèle suivant : ```text ORBITFLARE_LICENSE_KEY -> metadata gRPC x-token -> Yellowstone ``` Le Dashboard opérateur confirme parallèlement que le produit `Solana Free` est en `API Key Mode Active`, donc utilisable depuis toute IP avec la License Key. Le `X-ORBIT-KEY` et le Bearer issus du Device Flow restent réservés au Customer API. Le CLI OrbitFlare courant ne constitue pas un canari gRPC d’auth fiable : son `ping` ouvre le canal sans injecter la License Key et reçoit `invalid x-token: api key not found`. Ce défaut du CLI ne modifie pas le contrat provider documenté. Décision : ```text ne jamais versionner la License Key réelle ne jamais injecter X-ORBIT-KEY dans Yellowstone représenter la License Key par secret_metadata x-token dans Config V3 faire lire le secret du smoke par stdin, jamais par argument CLI ne modifier ni N1 ni N2 pour cette auth provider ``` ## 8. Heartbeat : réconciliation KSP / Yellowstone / OrbitFlare ### 8.1 Faits upstream Yellowstone upstream documente que : ```text les load balancers peuvent fermer un stream si le client reste silencieux le serveur Yellowstone envoie un SubscribeUpdate::Ping périodique le client peut répondre par un SubscribeRequest::Ping le serveur répond alors par SubscribeUpdate::Pong ``` Source : ```text https://github.com/rpcpool/yellowstone-grpc/blob/master/README.md ``` ### 8.2 Faits OrbitFlare OrbitFlare documente : ```text idle timeout partagé environ 10 minutes client ping recommandé toutes les 30 secondes produit gRPC recommandation 15 à 30 secondes SDK Go PingInterval default 10 secondes SDK Go MaxMissedPongs 3 ``` Sources : ```text https://docs.orbitflare.com/data-streaming/yellowstone https://docs.orbitflare.com/authentication https://docs.orbitflare.com/sdk/go-grpc https://orbitflare.com/products/solana-grpc ``` ### 8.3 Couverture KSP déjà présente Le moteur `0.2.9` possède déjà exactement la réponse standard : ```text SubscribeUpdate::Ping reçu -> send_automatic_ping(...) -> SubscribeRequest::Ping envoyé sur le stream existant -> request de subscription mémorisée inchangée ``` Cette propriété est testée déterministiquement par le moteur N1. ### 8.4 Décision `pre.001` **Aucun heartbeat OrbitFlare supplémentaire n'est retenu à ce stade.** Le premier smoke Devnet doit vérifier que l'endpoint OrbitFlare émet bien le `SubscribeUpdate::Ping` standard. Si ce Ping live est observé, la combinaison suivante suffit : ```text OrbitFlare server Ping live + KSP N1 automatic Ping reply deterministic test = client-side activity périodique sans code provider supplémentaire ``` Il est interdit d'ajouter un timer dans `grpc_stream.rs` ou `YellowstoneGrpcSessionSettings` pour OrbitFlare. Si le live montre qu'OrbitFlare ne produit pas le Ping standard ou exige réellement un heartbeat proactif indépendant, cela ouvre un **gate provider spécifique séparé**. La solution doit alors être composée au-dessus de N1 sans modifier le moteur et sans corrompre la requête de reconnect mémorisée. Point de sécurité important : appeler naïvement la mutation standard avec un request `ping` seul n'est pas acceptable, car le moteur mémorise la dernière mutation complète pour le replay/reconnect. Une éventuelle façade provider doit préserver cette sémantique au lieu de contourner N1. ## 9. Capabilities OrbitFlare ### 9.1 Streaming documenté OrbitFlare documente actuellement : ```text accounts transactions slots blocks blocks_meta entry commitment accounts_data_slice ping ``` Le CLI/SDK montre également les filtres account/transaction/slot/block standard nécessaires aux canaris principaux. ### 9.2 Surface non encore prouvée provider Ces capacités existent dans N2 KSP mais ne sont pas déclarées supportées sur OrbitFlare sans preuve supplémentaire : ```text SubscribeReplayInfo Ping unary GetLatestBlockhash GetBlockHeight GetSlot IsBlockhashValid GetVersion from_slot et retention réelle transactions_status complet champs récents compressed/cuckoo/token expansion selon endpoint déployé ``` L'absence de documentation n'est pas une preuve d'absence. Le live provider doit distinguer : ```text standard KSP disponible provider support prouvé provider entitlement éventuel unknown non testé ``` Aucune capacité N2 n'est supprimée du standard global à cause d'une restriction OrbitFlare. ## 10. Limits et quotas utiles La documentation actuelle des services partagés indique : | Limite | Valeur observée | Traitement KSP | |-----------------------------|------------------------------------------|---------------------------------------------| | connexions gRPC simultanées | 50 par IP | information provider, pas borne N1 | | portée du cap | globale par IP et régions gRPC partagées | éviter les reconnect storms | | subscriptions par connexion | unlimited | ne pas convertir en garantie universelle | | idle timeout | environ 10 minutes | gate heartbeat live | | dépassement | gRPC `RESOURCE_EXHAUSTED` | status distant safe existant | | reconnect conseillé | exponential backoff | KSP N1 possède déjà un budget/backoff borné | Ces valeurs commerciales/opérationnelles ne deviennent pas des constantes du standard KSP. ## 11. Config V3 Le schéma V3 existant représente directement le contrat live corrigé : ```text provider = orbitflare cluster = devnet protocol = solana_yellowstone url = http://devnet.rpc.orbitflare.com:10000 metadata = [] secret_metadata = x-token <- ${KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN} ``` La variable porte la License Key `ORBIT-*` du produit Solana Free. Elle ne porte jamais `X-ORBIT-KEY`. Décision : ```text pas de format_version 4 pas de champ region si l’URL suffit pas de heartbeat dans grpc_defaults secret provider géré par Config V3 existante redaction KSP obligatoire dans safe/debug projections ``` Le profil `orbitflare_devnet` conserve les companions HTTP/WS Solana Devnet standards et ajoute exactement un endpoint gRPC authentifié par secret metadata `x-token`. ## 12. Stratégie live Devnet ### 12.1 Résultat du premier canari `pre.002` Le smoke initial utilisait le standard N2 directement, sans Config et sans metadata. Le canal physique a atteint le service OrbitFlare, puis l’ouverture du Subscribe a retourné : ```text grpc_operation = SubscribeOpen grpc_status = Unauthenticated grpc_code = The request does not have valid authentication credentials ``` Cette preuve ferme l’hypothèse « Devnet Free sans metadata ». ### 12.2 Canari corrigé `pre.002-fix.001` Le même test reste provider-neutral et ne dépend toujours pas de Config. Il lit une seule License Key sur stdin puis construit la metadata secrète standard : ```text endpoint = http://devnet.rpc.orbitflare.com:10000 provider = orbitflare cluster = devnet protocol = solana_yellowstone auth = x-token <- License Key lue sur stdin request = Subscribe slots à commitment confirmed preuve = au moins un Slot non nul close = borné ``` La valeur secrète ne doit apparaître ni dans Debug ni dans la ligne de commande. ### 12.3 Preuve heartbeat Le smoke corrigé attend encore suffisamment pour observer : ```text SubscribeUpdate::Ping ``` Un `Ping` serveur live, combiné au test déterministe N1 qui prouve la réponse automatique, ferme le besoin heartbeat sans code OrbitFlare. Si aucun Ping serveur n’est observé après authentification, cette divergence est traitée dans une tranche provider dédiée au-dessus de N1/N2. Le smoke final durable peut rester court après cette caractérisation ; il n’a pas besoin de patienter 10 minutes à chaque workspace run. ### 12.4 Unary et replay Après le canari Subscribe authentifié : ```text probe 7 unary N2 probe SubscribeReplayInfo probe from_slot si support observable ``` Les probes provider ne doivent pas rendre indisponible le smoke minimal `Subscribe -> Slot` si le plan gratuit restreint certaines unary. ## 13. Threat model recalibré Le gate retient : ```text Customer API key injectée sur le mauvais plan gRPC token confondu avec X-ORBIT-KEY secret metadata leak endpoint Dashboard sensible plaintext http présenté comme TLS IP/network entitlement mal classifié heartbeat ajouté au moteur global par erreur ping provider écrasant le last accepted full request ping flood missed pong surinterprété RESOURCE_EXHAUSTED et reconnect storm 50 connections par IP consommées par des smokes mal fermés region failover changeant de node/fork from_slot hors retention provider unary unavailable remote Status arbitraire SDK OrbitFlare introduit sans nécessité ``` ## 14. Surface de code autorisée et interdite ### 14.1 Interdit par défaut ```text modification grpc_stream.rs modification grpc_channel.rs pour une policy OrbitFlare modification grpc_settings.rs pour un heartbeat OrbitFlare modification des DTOs grpc_subscribe.rs second raw Tonic client orbitflare-sdk-rs dependency provider-specific proto Transport -> Config/env ``` ### 14.2 Autorisé si nécessaire ```text profil Config V3 orbitflare_devnet smoke provider utilisant les APIs N2 existantes provider capability descriptor sans wire nouveau petite façade OrbitFlare au-dessus de N2 seulement si divergence live prouvée provider-specific tests/compliance README/USAGE dans la tranche documentaire finale ``` ## 15. Forecast recalibré Le fix d’auth ne change pas l’ordre des couloirs finaux. ```text pre.001 audit actuel + architecture immuable N1/N2 + auth/endpoints + free Devnet + heartbeat + sizing preuve : plan 017 + validation 013 + delta + baseline pre.002 profil Config V3 OrbitFlare Devnet + smoke de caractérisation standard N2 hypothèse initiale sans metadata ; live classifie Unauthenticated au SubscribeOpen pre.002-fix.001 corrige l’auth par License Key -> secret x-token adapte .env.example, Config test et smoke stdin live : Subscribe -> Slot + observation Ping serveur ; aucune modification moteur gRPC pre.003 soit gate technique/live final si le rerun authentifié reste 100 pourcent standard, soit tranche provider-specific minimale uniquement si le live démontre une divergence heartbeat réelle pre.004 gate technique/live final si pre.003 a porté une divergence ; sinon réconciliation documentaire finale pre.005 publication minimale si pre.004 est documentaire ; sinon réconciliation documentaire finale pre.006 publication minimale uniquement si la divergence a décalé les couloirs précédents rel.001 publication stable stricte ``` Chemins effectifs : ```text standard pre.001 -> pre.002 -> pre.002-fix.001 -> pre.003 technique -> pre.004 docs -> pre.005 publication -> rel.001 divergence pre.001 -> pre.002 -> pre.002-fix.001 -> pre.003 provider -> pre.004 technique -> pre.005 docs -> pre.006 publication -> rel.001 ``` Le numéro n’est jamais le critère de clôture ; l’ordre technique, documentaire, publication reste obligatoire. ## 16. Critères de split Ouvrir une tranche provider dédiée avant le gate final si et seulement si le live démontre l'un de ces cas : ```text OrbitFlare n'émet pas le Ping standard et exige un Ping client proactif l’auth x-token fonctionne mais révèle une exigence provider supplémentaire non composable au-dessus de N1/N2 le service requiert un mécanisme TLS/channel absent du moteur stable un method/filter standard est remplacé par une extension wire OrbitFlare le replay/from_slot exige une policy provider visible au consumer un failover provider impose une sémantique que N1 ne peut pas composer sans modification ``` Dans le dernier cas, ne pas modifier N1 dans `0.2.10` : qualifier le blocker et replanifier l'architecture. ## 17. Critères de clôture `0.2.10` est stable seulement si : ```text Devnet OrbitFlare Free réellement atteint par KSP ou bloc externe qualifié N1 gRPC inchangé N2 Yellowstone inchangé aucun SDK OrbitFlare runtime provider/auth correctement classifiés aucune Customer API key sur le data-plane Yellowstone heartbeat live classifié Config V3 cohérente sans nouveau format inutile smoke provider architecture-safe PublicNode non régressé Yellowstone standard non régressé HTTP 52+14 non régressé WebSocket standard 18/18 non régressé Helius WebSocket non régressé workspace complet vert graphes Cargo inspectés réconciliation documentaire séparée publication minimale séparée ``` ## 18. Release suivante La release suivante reste : ```text 0.2.11 — Helius LaserStream gRPC ``` Elle doit appliquer le même invariant : le moteur gRPC `0.2.9` est une fondation stable ; Helius ne peut ajouter que des fonctionnalités provider au-dessus.