# Validation `0.2.9` — Yellowstone gRPC standard + PublicNode > **Statut courant : `pre.010-fix.001` est fermée sans warning. `pre.011` est candidate et doit prouver Config Transport V3, le mapping Config -> Yellowstone gRPC, la séparation protocol/provider et le profil PublicNode Mainnet. Ce document a été restructuré : les logs détaillés historiques vivent dans `deltas/0.2.9/`; cette matrice porte les exigences et le verdict courant.** ## 1. Autorités et baseline courante Autorités : ```text RULES.md + docs/rules/* plan 016 courant code réel Transport/Config prompts/014-V0_2_9_START_PROMPT.md pour les contraintes non supersédées deltas/0.2.9/* pour l'historique immuable et les décisions postérieures au prompt upstream Yellowstone primaire ``` Baseline opérateur immédiatement avant `pre.011` (`0.2.9-pre.010-fix.001`) : | Gate | Résultat | |------------------------------------------|--------------------------| | `cargo fmt --all` | PASS | | audit Rust workspace | PASS, 0 candidate export | | `cargo check --workspace` | PASS | | `cargo clippy --workspace --all-targets` | PASS sans warning | | Transport unit | 383/383 PASS | | Transport public API | 49/49 PASS | | Transport release completeness | 43/43 PASS | | Transport doctests | 4/4 PASS | | workspace dependency canary | 3/3 PASS | | `cargo test --workspace` | PASS | Cette baseline est le seuil de non-régression de `pre.011` pour Transport. ## 2. Gate dépendances et licence | Exigence | Décision / preuve | État | |--------------------------------|------------------------------------------|-------------------| | proto officiel sans vendoring | `yellowstone-grpc-proto ^12.6` | **PASS** | | pas de client upstream runtime | `yellowstone-grpc-client` absent | **PASS** | | runtime Tonic KSP-owned | `tonic ^0.14` + `tonic-prost ^0.14` | **PASS** | | proto subtree compatible | Apache-2.0 selon `LICENSING.md` upstream | **PASS** | | source AGPL copiée | aucune | **PASS** | | raw client Tonic public | aucun | **PASS** | | graph final | réinspection `pre.012` | **PENDING FINAL** | Le graphe n'est pas modifié par `pre.011`; aucune nouvelle dépendance Cargo n'est introduite dans cette tranche. ## 3. Matrice service `Geyser` | RPC | Classification | Cible | Preuve | Verdict | |-----------------------|--------------------------------|-------|---------------------------------|----------| | `Subscribe` | standard | oui | stream bidi local + lifecycle | **PASS** | | `SubscribeDeshred` | extension/pré-exécution Triton | non | exclusion documentée | **OUT** | | `SubscribeReplayInfo` | standard unary | oui | fixture unary + reconnect tests | **PASS** | | `Ping` | standard unary | oui | fixture exact echo | **PASS** | | `GetLatestBlockhash` | standard unary | oui | fixture typed | **PASS** | | `GetBlockHeight` | standard unary | oui | fixture typed | **PASS** | | `GetSlot` | standard unary | oui | fixture typed | **PASS** | | `IsBlockhashValid` | standard unary | oui | fixture typed + invalid input | **PASS** | | `GetVersion` | standard unary | oui | fixture typed | **PASS** | ## 4. `SubscribeRequest` — coverage normative ### 4.1 Top-level | Champ | Verdict | Preuve minimale | |-----------------------|----------|----------------------------------| | `accounts` | **PASS** | maps typed + wire exact | | `slots` | **PASS** | maps typed + wire exact | | `transactions` | **PASS** | maps typed + wire exact | | `transactions_status` | **PASS** | same filter family, separate map | | `blocks` | **PASS** | maps typed + wire exact | | `blocks_meta` | **PASS** | named empty marker preserved | | `entry` | **PASS** | named empty marker preserved | | `commitment` | **PASS** | optional wire semantics | | `accounts_data_slice` | **PASS** | order + bounds | | `ping` | **PASS** | optional id | | `from_slot` | **PASS** | optional + replay mutation | ### 4.2 Accounts ```text account[] owner[] filters[] nonempty_txn_signature? cuckoo_accounts_filter? memcmp bytes/base58/base64 datasize token_account_state lamports eq/ne/lt/gt ``` Verdict : **PASS** — wire complet retenu, bounds déterministes, payload Debug redacted, malformed fixed-width rejeté. ### 4.3 Slots ```text filter_by_commitment? interslot_updates? processed confirmed finalized first_shred_received completed created_bank dead + dead_error? ``` Verdict : **PASS**. ### 4.4 Transactions et transaction_status ```text vote? failed? signature? account_include[] account_exclude[] account_required[] cuckoo_account_include? token_accounts? = ALL | BALANCE_CHANGED ``` Verdict : **PASS** — request wire, transaction storage/meta, status error et malformed signature couverts. ### 4.5 Blocks, block_meta, entry ```text account_include[] include_transactions? include_accounts? include_entries? cuckoo_account_include? blocks_meta marker entry marker ``` Verdict : **PASS** — block complet, metadata, entries et champs optional/legacy couverts. ## 5. `SubscribeUpdate` — coverage normative | Variante | Verdict | |--------------------------------------|----------| | account | **PASS** | | slot | **PASS** | | transaction | **PASS** | | transaction_status | **PASS** | | block | **PASS** | | ping | **PASS** | | pong | **PASS** | | block_meta | **PASS** | | entry | **PASS** | | top-level `filters[]` / `created_at` | **PASS** | Les raw protobufs ne sortent pas de la façade publique. Les décodeurs rejettent les formes structurellement invalides sans copier des payloads arbitraires dans les erreurs. ## 6. Settings, bounds et redaction | Contrôle | État | |-----------------------------------------------|--------------------| | URL `http/https` seulement et longueur bornée | **PASS** | | URL Debug redacted | **PASS** | | metadata key/value/count bornés | **PASS** | | metadata secret/public distincte | **PASS** Transport | | timeouts non nuls et bornés | **PASS** | | reconnect bounds cohérents | **PASS** | | inbound/outbound message sizes | **PASS** | | request/update queue capacities | **PASS** | | filter group/name bounds | **PASS** | | account/owner/memcmp/data slice bounds | **PASS** | | transaction/block selectors bounds | **PASS** | | remote `Status` message/details non recopiés | **PASS** | | Transport -> env/config | absent ou **PASS** | ## 7. Lifecycle, backpressure et replay | Exigence | Verdict | Preuve | |------------------------------|-----------------|------------------------------------------------| | stream bidi unique | **PASS** | round-trip fixture | | mutation request | **PASS** | same request channel | | server Ping / client reply | **PASS** | actor test | | Pong decode | **PASS** | update decode | | server half-close | **PASS** | state terminal observable | | explicit client close | **PASS** | half-close avant deadline | | hostile server shutdown | **PASS** | close timeout borné | | slow receiver | **PASS** | overflow terminal observable | | oversized inbound | **PASS** | Tonic decoder bound | | oversized outbound | **PASS** | reject avant queue dispatch | | reconnect backoff | **PASS** | budget borné | | shutdown pendant backoff | **PASS** | interruption sans nouvelle connexion | | resubscribe déterministe | **PASS** | last accepted full request | | reprise `from_slot` | **PASS** | dernier slot observé + demande explicite | | ReplayInfo `first_available` | **PASS** | clamp/gap seulement si prouvé | | duplicate observability | **PASS** | compteur borné, pas de suppression silencieuse | | exactly-once/lossless | **NON GARANTI** | contrat explicite | Snapshot public requis et présent : ```text reconnect_count replay_attempt_count continuity_gap_count duplicate_update_count last_requested_from_slot last_observed_slot state/error code safe ``` ## 8. Gate Config V3 — `pre.011` ### 8.1 Schema et backward compatibility Exigences candidate : | Exigence | Preuve source actuelle | Verdict avant gate opérateur | |------------------------------------------|------------------------------------------|------------------------------| | schema `$id` V3 | `urn:ksp:schema:std.transport:v3` | **SOURCE OK** | | branches V1/V2 conservées | `documentV1`, `documentV2`, `documentV3` | **SOURCE OK** | | V1 HTTP-only | fixture historique | **PENDING TEST** | | V2 HTTP+WS | fixture historique | **PENDING TEST** | | V3 HTTP+WS+gRPC | fixture V3 + config committée | **PENDING TEST** | | `grpc_endpoints` optionnel par profil V3 | profiles génériques sans gRPC | **PENDING TEST** | | no `additionalProperties` relaxation | branches strictes | **SOURCE OK** | ### 8.2 Mapping runtime V3 doit mapper : ```text grpc_defaults -> YellowstoneGrpcSessionSettings grpc_endpoints[].url -> YellowstoneGrpcEndpointUrl provider -> YellowstoneGrpcProviderName cluster -> YellowstoneGrpcClusterName protocol = solana_yellowstone -> gate Config explicite metadata -> YellowstoneGrpcMetadataEntry::public secret_metadata -> YellowstoneGrpcMetadataEntry::secret session overrides -> merge avec grpc_defaults ``` API : | Surface | Exigence | Statut source | |---------------------------------|-------------------------------------|---------------| | `http_settings()` | inchangée | **OK** | | `ws_settings()` | V1 None, V2/V3 selon profil | **OK** | | `grpc_settings()` | V1/V2 None, V3 optionnel | **ADDED** | | `into_transport_settings()` | tuple historique HTTP + WS inchangé | **PRESERVED** | | `into_all_transport_settings()` | nouveau tuple HTTP + WS + gRPC | **ADDED** | ### 8.3 Provenance et secrets Règles candidate : ```text metadata publique + provenance KSP_SECRET_* -> reject secret_metadata sans provenance secret -> reject secret_metadata + variable KSP_PUBLIC_/KSP_* -> reject secret_metadata + KSP_SECRET_/KSPB_SECRET_ -> accept segments littéraux autour du secret -> accept safe_value -> secret segment ******** Transport Debug -> URL/metadata secret absents ``` Le test V3 doit démontrer le cas valide et les deux croisements invalides sans exposer les canaris. ### 8.4 PublicNode Mainnet Profil committé attendu : ```text profile_id = publicnode_mainnet provider = publicnode cluster = mainnet-beta protocol = solana_yellowstone url = https://solana-yellowstone-grpc.publicnode.com:443 # provider affiche host:port ; KSP ajoute le scheme TLS requis metadata = aucune ``` Le mapping doit produire un endpoint TLS Yellowstone standard et `Debug` ne doit pas exposer l'URL. ### 8.5 PublicNode Testnet Verdict `pre.011` : **DEFERRED, NOT GUESSED**. La page publique réauditée le 2026-08-24 expose une capacité Solana Testnet gRPC, mais l'hostname exact n'a pas été obtenu depuis une source suffisamment autoritative/indexable. Aucun profil Testnet n'est committé avant confirmation. `pre.012` doit soit : ```text confirmer hostname + réussir le smoke -> PASS ou documenter l'impossibilité externe -> EXTERNAL BLOCK, sans endpoint inventé ``` ## 9. Provider-neutrality | Point | Verdict | |-----------------------------------------------|----------------------| | type public `PublicNodeGrpc*` sans divergence | absent, **PASS** | | protocol standard encodé comme provider | non, **PASS** | | provider descriptif séparé | oui, **PASS source** | | auth PublicNode hardcodée dans Transport | non, **PASS** | | Helius/OrbitFlare runtime gRPC dans `0.2.9` | non, **PASS** | | provider extensions dans N2 | aucune, **PASS** | ## 10. Non-régressions obligatoires Le gate final doit préserver : ```text HTTP current typed 52/52 HTTP historical 14/14 Deprecated/Removed KSP-TRANSPORT-007 vert Standard WebSocket 9 familles / 18 opérations Helius LaserStream WebSocket 7 familles standard + transaction + slotsUpdates, heartbeat provider-owned Transport -> Config interdit Transport -> std::env KSP_* interdit tracing direct Transport interdit ``` `pre.011` ne modifie pas Transport runtime ; son seuil est donc au minimum la baseline `pre.010-fix.001`. ## 11. Historique des gates fermé Les détails de commandes, warnings corrigés et fichiers exacts restent dans leurs deltas immuables. | Tranche | Gate consolidé | |-----------------------------------|--------------------------------------| | `pre.001` + `fix.001` + `fix.002` | audit/sizing/providers/licence fermé | | `pre.002` + `fix.001` + `fix.002` | moteur/settings/channel fermé | | `pre.003` + `fix.001` | TLS/metadata/unary fermé | | `pre.004` + `fix.001` | Subscribe common fermé | | `pre.005` + `fix.001` | Accounts/Slots fermé | | `pre.006` | namespace HTTP fermé | | `pre.007` | Transactions fermé | | `pre.008` + `fix.001` | Blocks fermé | | `pre.009` + `fix.001` | bidi/backpressure fermé | | `pre.010` + `fix.001` | reconnect/replay fermé sans warning | Cette table remplace les anciens appendices numérotés successivement `19.x`, `20`, `21`, etc. qui rendaient le document ambigu. ## 12. Gate opérateur `pre.011` Commandes requises : ```bash cargo fmt --all python3 scripts/audit_rust_workspace_rules.py cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-config-lib cargo test -p ksp-config-lib --test public_api cargo test -p ksp-config-lib --test ownership cargo test -p ksp-onchain-transport-lib cargo test -p ksp-core-lib --test workspace_dependencies cargo test --workspace ``` Résultats attendus si aucun fix n'est requis : ```text audit Rust clean / 0 export candidate check/clippy PASS sans warning Config unit baseline 110 + 3 nouveaux tests V3 = 113 attendus Config public API 15 attendus, canari enrichi Config ownership 5 attendus Transport unit >= 383 sans régression Transport public API >= 49 sans régression Transport completeness >= 43 sans régression Transport doctests 4 sans régression workspace dependencies 3 sans régression cargo test --workspace PASS ``` Ces nombres sont des attentes de candidate, pas un résultat déclaré avant exécution opérateur. ## 13. Gate `pre.012` et clôture stable ### 13.1 Live PublicNode Mainnet minimal : ```text opt-in seulement settings Transport programmatic aucun secret connexion TLS unary simple et/ou Subscribe borné selon smoke retenu close borné aucune dépendance Config ajoutée au test Transport pur ``` Testnet seulement après endpoint exact confirmé. ### 13.2 Compliance finale ```text réaudit upstream release/proto cargo tree Transport cargo tree Transport --duplicates cargo tree --duplicates HTTP 52 + 14 Standard WS 18/18 Helius WS public API crate-root release completeness Config V1/V2/V3 security/redaction README/USAGE prompt release suivante workspace complet ``` ### 13.3 Verdict stable `0.2.9` peut devenir stable seulement si tous les éléments suivants sont vrais : ```text standard vs extension explicitement classifié SubscribeDeshred OUT documenté 7 unary verts Subscribe + 9 updates verts resource/backpressure/lifecycle verts reconnect/replay sans promesse lossless Config V3 backward V1/V2 provider/protocol distincts PublicNode Mainnet validé ou incident externe précisément documenté Testnet jamais inventé HTTP/WS/Helius non régressés dependency firewall vert cargo graphs inspectés workspace final vert ```