# Plan `0.2.3` — HTTP Transactions ## Statut Ce plan, ouvert par `0.2.3-pre.001` sur la base stable `v0.2.2`, est désormais **clôturé par `0.2.3-rel.001`**. `pre.009` a constitué la candidate finale validée avant publication stable. `0.2.1` a stabilisé la foundation HTTP Solana et quatre wrappers typés canari. `0.2.2` a ajouté les 22 wrappers Accounts/Tokens/Cluster, les DTOs wire communs, le smoke Devnet Transport pur et les canaries exactes de complétude. La release `0.2.3` complète uniquement les **11 méthodes Transactions** déjà affectées à `HttpRpcCoverageRelease::V0_2_3`. Elle ne crée ni client HTTP parallèle, ni executor métier de transaction, ni dépendance Transport -> Config/Store/Program. ## Sources normatives réauditées le 2026-08-18 Sources documentaires principales : ```text https://solana.com/docs/rpc/http https://solana.com/docs/rpc/json-structures ``` Pages Transaction réauditées : ```text https://solana.com/docs/rpc/http/getfeeformessage https://solana.com/docs/rpc/http/getlatestblockhash https://solana.com/docs/rpc/http/getrecentprioritizationfees https://solana.com/docs/rpc/http/getsignaturesforaddress https://solana.com/docs/rpc/http/getsignaturestatuses https://solana.com/docs/rpc/http/gettransaction https://solana.com/docs/rpc/http/gettransactioncount https://solana.com/docs/rpc/http/isblockhashvalid https://solana.com/docs/rpc/http/requestairdrop https://solana.com/docs/rpc/http/sendtransaction https://solana.com/docs/rpc/http/simulatetransaction ``` Sources primaires Agave utilisées pour lever les ambiguïtés du wire et des limites runtime : ```text https://github.com/anza-xyz/agave/blob/v4.2.1/rpc/src/rpc.rs https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/config.rs https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/request.rs https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/response.rs https://github.com/anza-xyz/agave/blob/v4.2.1/transaction-status-client-types/src/lib.rs ``` Les liens `Source` du site RPC Solana consultés pointent encore vers Agave `v3.1.8` et les exemples affichent encore `apiVersion: 3.1.8`. Comme pour la clôture `0.2.2`, KSP recoupe donc la documentation publique avec Agave `v4.2.1`, dont le workspace déclare la version `4.2.1`, sans prendre de dépendance sur ses crates RPC/client. ## Audit global et périmètre confirmé L'index HTTP Solana courant contient toujours **52 méthodes** et sa catégorie Transactions contient exactement : ```text getFeeForMessage getLatestBlockhash getRecentPrioritizationFees getSignaturesForAddress getSignatureStatuses getTransaction getTransactionCount isBlockhashValid requestAirdrop sendTransaction simulateTransaction ``` La navigation Deprecated officielle conserve les **14 méthodes historiques** déjà enregistrées dans KSP : ```text confirmTransaction getConfirmedBlock getConfirmedBlocks getConfirmedBlocksWithLimit getConfirmedSignaturesForAddress2 getConfirmedTransaction getFeeCalculatorForBlockhash getFeeRateGovernor getFees getRecentBlockhash getSignatureConfirmation getSignatureStatus getSnapshotSlot getStakeActivation ``` Aucune méthode Transaction n'est ajoutée, supprimée ou déplacée par rapport à la partition KSP stable `0.2.2` : ```text 0.2.1 exact = 4 0.2.2 exact = 22 0.2.3 exact = 11 0.2.4 reste = 15 ``` Les onze pages courantes ciblées restent des méthodes HTTP courantes. `getTransaction` conserve une **forme de requête moderne** par objet de configuration et une **forme legacy de compatibilité** où le second paramètre est directement la chaîne d'encoding ; la documentation actuelle marque explicitement cette forme bare comme dépréciée et recommande l'objet. ## Gate de sizing obligatoire Question : ```text Les 11 wrappers Transactions, leurs DTOs/wires, les règles write/simulation, les tests et la documentation peuvent-ils être clôturés proprement dans cette session ? ``` Réponse : ```text OUI. ``` Le périmètre est plus petit que `0.2.2`, mais les méthodes sont plus hétérogènes. Le sizing reste acceptable en isolant les trois zones coûteuses : 1. `getTransaction` et son wire encoding/version/meta ; 2. `requestAirdrop` + `sendTransaction` et les preuves de no-resend après dispatch ambigu ; 3. `simulateTransaction` et son résultat riche. Aucun split de release n'est donc nécessaire à `pre.001`. Si une tranche réelle dépasse 15–20 minutes, une prerelease supplémentaire est ajoutée dans `0.2.3` sans déplacer silencieusement une méthode vers `0.2.4`. ## Classification de sécurité confirmée La metadata KSP existante reste correcte après réaudit : ```text 8 Read / RetrySafe 2 WriteSubmission / NeverAfterDispatch : requestAirdrop, sendTransaction 1 Simulation / RetrySafe : simulateTransaction ``` La règle centrale reste normative : > une `WriteSubmission` ne doit jamais être resoumise automatiquement lorsque KSP ne peut pas prouver que la tentative précédente n'a pas été dispatchée. Un timeout après envoi, un HTTP temporaire reçu après dispatch, un rate-limit reçu après dispatch ou une rupture dont l'état de dispatch est ambigu arrêtent donc la boucle de retry Transport pour `requestAirdrop` et `sendTransaction`. Une erreur explicitement classée `NotDispatched` peut encore suivre la policy centrale existante ; aucun wrapper write ne possède sa propre boucle. Le champ RPC `sendTransaction.maxRetries` est **distinct** : il configure les retransmissions du noeud RPC après acceptation de la requête et ne constitue jamais une autorisation de retry HTTP côté KSP. `simulateTransaction` n'émet pas la transaction sur le réseau et reste `Simulation / RetrySafe` dans la metadata Transport. ## Flux architectural obligatoire Tous les wrappers de cette release suivent le flux unique : ```text wrapper typed -> descriptor central -> execute_standard_rpc -> pool/admission -> executor HTTP -> validation JSON-RPC -> decode typed ``` Restent interdits : ```text wrapper -> reqwest direct wrapper -> nouveau client HTTP wrapper -> retry/deadline/admission bypass Transport -> Config Transport -> Store Transport -> Program Transport -> tracing direct ``` Les wrappers réutilisent `SolanaCommitment`, `SolanaContextConfig`, `SolanaRpcContext`, `SolanaRpcResponse` et les erreurs KSP existantes lorsque leur contrat s'applique. ## Décision dépendances et payloads sérialisés ### Décision `pre.001` Aucune nouvelle dépendance n'est ajoutée : ```text base64 NON bs58 NON wincode NON solana-client NON crate RPC SDK NON ``` Motif : les trois entrées sérialisées de cette release peuvent être transportées comme **chaînes encodées opaques** accompagnées d'un encoding typé. KSP n'a pas besoin de désérialiser un message ou une transaction pour construire la requête, appliquer la policy de retry, préserver le wire ou décoder la réponse. Agave réalise des contrôles de décodage, de désérialisation, de sanitization et de taille de transaction. Les reproduire complètement côté KSP impliquerait davantage que `base64`/`bs58` : cela rapprocherait Transport d'un codec transactionnel et d'un SDK wire complet sans besoin fonctionnel établi. `pre.001` ne crée donc pas cette responsabilité. KSP applique en revanche avant I/O les invariants qui ne nécessitent aucun décodage du payload : cardinalités documentées/runtime, encodings acceptés par l'opération, formes de config, incompatibilités de flags et paramètres structuraux. Cette décision peut être réouverte dans une future tranche si un besoin concret exige une validation locale des bytes sérialisés. L'ajout devra alors être borné, déclaré dans `[workspace.dependencies]` et justifié par un test qui démontre la valeur de la validation locale. ### Encodings à distinguer Pour les **entrées** `sendTransaction` et `simulateTransaction`, la source Agave actuelle accepte les encodings binaires `base58` et `base64` ; les encodings JSON ne sont pas des formats d'entrée valides pour ces deux opérations. `getFeeForMessage` reçoit une chaîne base64. La page publique documente les messages legacy et v0. KSP ne parse pas la version du message et ne fige donc pas artificiellement le type public sur une liste de versions sérialisées que le runtime pourrait faire évoluer. Pour la **sortie** `getTransaction`, le wire doit rester plus large : `base58`, `base64`, `json`, `jsonParsed`, ainsi que les formes legacy encore acceptées/auditées. Les formes encodées et JSON ne doivent pas être écrasées dans un seul `String` ambigu. ## Règle de complétude des wrappers RPC À partir de `pre.005`, la règle générale `KSP-TRANSPORT-007` explicite un principe déjà recherché par les releases HTTP précédentes : un wrapper KSP n'est pas considéré complet s'il ne couvre qu'un sous-ensemble de convenance de la méthode RPC. Il doit exposer toute la surface sémantique auditée : ```text paramètres obligatoires et optionnels champs de configuration variantes/overloads courants formes legacy encore supportées contraintes déterministes connues variantes/null/omissions significatives des réponses ``` Cette exigence ne signifie pas recopier `solana-rpc-client` ou tout `solana-transaction-status-client-types`. Une structure riche peut rester un `serde_json::Value` à une frontière explicitement lossless lorsque KSP n'a pas encore besoin de son modèle métier, à condition qu'aucune possibilité RPC ni information wire ne soit supprimée. Les syntaxes strictement équivalentes peuvent être canonicalisées. Pour `getTransaction`, `pre.005` couvre donc les deux formes de requête auditée : objet moderne et bare encoding legacy déprécié. La documentation publique courante expose `base58`, `base64`, `json` et `jsonParsed` pour l'objet moderne ; Agave `v4.2.1` accepte aussi l'alias rétrocompatible `binary` via le même enum wire, que KSP conserve donc sans le présenter comme choix moderne recommandé. La config complète `commitment/encoding/maxSupportedTransactionVersion` est exposée, avec rejet local de `processed` car la méthode documente `confirmed|finalized`. Le résultat `null`, les transactions chaîne/tuple/objet, les versions `legacy`/numériques, `meta` lossless et `transactionIndex` optionnel courant sont préservés. ## Matrice exacte des 11 méthodes | Méthode | Paramètres ordonnés / config | Résultat à préserver | Validation / particularités | |-------------------------------|-------------------------------------------------------|--------------------------------------------------|--------------------------------------------------------------------------------| | `getFeeForMessage` | `messageBase64`, `SolanaContextConfig?` | `SolanaRpcResponse>` | message base64 opaque ; `null` préservé | | `getLatestBlockhash` | `SolanaContextConfig?` | contexte + `{ blockhash, lastValidBlockHeight }` | blockhash wire non vide ; contexte conservé | | `getRecentPrioritizationFees` | `Vec?` | `Vec<{ slot, prioritizationFee }>` | maximum 128 adresses ; ordre serveur conservé | | `getSignaturesForAddress` | `Pubkey`, config pagination | `Vec` | `limit` `1..=1000`; newest -> oldest; nulls préservés | | `getSignatureStatuses` | `Vec`, config history? | contexte + `Vec>` | maximum 256; positions/nulls conservés; tableau vide accepté par Agave courant | | `getTransaction` | signature, config moderne **ou** encoding bare legacy | `Option` | transaction absente = `null`; encoding/version/meta lossless | | `getTransactionCount` | `SolanaContextConfig?` | `u64` | forme simple, config contextuelle | | `isBlockhashValid` | blockhash, `SolanaContextConfig?` | `SolanaRpcResponse` | blockhash passé tel quel au runtime sauf invariant KSP non ambigu | | `requestAirdrop` | `Pubkey`, lamports, config? | signature | `WriteSubmission`; aucun resend après dispatch ambigu | | `sendTransaction` | transaction encodée, config? | première signature | `base58/base64`; `maxRetries` est node-side; no-resend KSP | | `simulateTransaction` | transaction encodée, config? | contexte + résultat simulation | `base58/base64`; `sigVerify` incompatible avec `replaceRecentBlockhash` | ## DTOs et wires communs prévus Les noms Rust exacts restent ajustables à `pre.002`, mais les responsabilités suivantes sont figées. ### Blockhash et latest blockhash Le résultat de `getLatestBlockhash` conserve : ```text blockhash String/newtype wire KSP lastValidBlockHeight u64 ``` Le même petit objet `{ blockhash, lastValidBlockHeight }` peut être réutilisé lorsque `simulateTransaction` retourne un `replacementBlockhash`. Aucune primitive cryptographique supplémentaire n'est nécessaire pour le transporter. ### Signature information `getSignaturesForAddress` conserve au minimum : ```text signature String/newtype KSP slot u64 err JSON transaction error nullable memo Option blockTime Option confirmationStatus Option transactionIndex Option ``` La page HTTP actuelle ne liste pas `transactionIndex`, mais Agave `v4.2.1` l'expose comme champ optionnel avec `serde(default)` et omission lorsque absent. KSP doit donc l'accepter sans le rendre obligatoire, afin de ne pas perdre une donnée runtime actuelle ni casser les providers qui ne l'émettent pas encore. `err` reste un contrat transaction-error wire et ne devient pas un modèle Program. Une représentation `serde_json::Value` bornée à cette frontière est acceptable tant que KSP ne possède pas encore le codec générique des erreurs de transaction. ### Signature status `getSignatureStatuses` préserve l'ordre exact du tableau d'entrée. Chaque position de sortie est : ```text Option ``` Un statut présent conserve : ```text slot u64 confirmations Option err transaction error nullable status forme legacy de résultat, encore présente sur le wire confirmationStatus Option ``` La forme `status` historique à l'intérieur de l'objet courant n'est pas confondue avec les anciennes **méthodes RPC** Deprecated du registre. KSP peut la préserver de manière lossless sans la recommander comme nouvelle API métier. ### Transaction encoding/config Le contrat moderne `getTransaction` doit disposer d'un objet de config contenant : ```text commitment Option encoding Option maxSupportedTransactionVersion Option ``` La compatibilité auditée garde en plus une forme legacy explicite : ```text getTransaction(signature, "") ``` Cette API legacy doit être nommée/annotée de manière à ne pas sembler être la voie recommandée. Le descriptor existant `StableWithDeprecatedLegacy` reste correct. Le résultat confirmé garde un top-level typé : ```text slot u64 blockTime Option transaction EncodedTransaction meta absent | null | transaction-meta wire version absent | null | legacy | number transactionIndex absent | null | u32 ``` Le recoupement d'implémentation `pre.002` avec `transaction-status-client-types` Agave `v4.2.1` a confirmé que `EncodedConfirmedTransactionWithStatusMeta` expose également `transactionIndex: Option` au top-level de `getTransaction`. Cette extension optionnelle est donc préservée comme celle de `getSignaturesForAddress`, sans être rendue obligatoire pour les providers plus anciens. `EncodedTransaction` doit préserver les différentes formes réellement sérialisées : ```text objet JSON/jsonParsed chaîne legacy binaire [string, "base58" | "base64"] ``` KSP ne doit pas dupliquer tout `solana-transaction-status-client-types` pour obtenir cette union. Les sous-structures transaction/message/meta qui sont riches, évolutives ou dépendantes de `jsonParsed` peuvent rester lossless via des DTOs étroits + `serde_json::Value` aux frontières prévues. Le meta doit au minimum respecter la distinction **absent/null/présent** imposée par le wire et ne jamais inventer des listes ou zéros lorsque le provider omet une donnée optionnelle. `pre.002` matérialise cette distinction avec une primitive générique `SolanaWireField` limitée au wire Transport : `Omitted`, `Null`, `Value(T)`. Elle est utilisée pour les champs Transaction/Simulation où l'omission et `null` doivent rester distinguables ; elle ne transforme pas ce mécanisme en modèle métier et ne remplace pas `Option` lorsque les deux états ont le même sens contractuel. ### `getRecentPrioritizationFees` Le paramètre optionnel est un tableau d'adresses. La documentation actuelle fixe un maximum de **128** et précise que, lorsqu'il est fourni, les samples correspondent aux transactions ayant verrouillé toutes ces adresses en writable. La cache d'un noeud conserve actuellement jusqu'à 150 blocs de données de prioritization fees ; ce nombre décrit le runtime/cache et n'est pas une cardinalité de réponse à imposer côté client. Le résultat conserve simplement : ```text slot u64 prioritizationFee u64 ``` ### Pagination `getSignaturesForAddress` La config prévue conserve : ```text commitment Option minContextSlot Option limit Option before Option until Option ``` Agave `v4.2.1` applique `1000` par défaut et refuse `limit == 0` ou `limit > 1000`. KSP peut donc rejeter cette cardinalité avant I/O sans dépendance supplémentaire. ### `getSignatureStatuses` La requête conserve : ```text signatures Vec searchTransactionHistory Option ``` La documentation et Agave bornent le tableau à **256** signatures. La source actuelle refuse uniquement `> 256`; un tableau vide reste donc une forme valide à ne pas interdire arbitrairement. Quand `searchTransactionHistory` est absent/faux, le noeud recherche seulement son cache récent. KSP transporte l'option sans transformer silencieusement l'appel en recherche historique coûteuse. ## Write submissions ### `requestAirdrop` La config courante conserve : ```text commitment Option recentBlockhash Option ``` Le résultat est une signature de transaction. L'appel déclenche la création/soumission d'une transaction de faucet : il reste donc `WriteSubmission / NeverAfterDispatch` même si la réponse n'est qu'une signature. Aucun retry ad hoc n'est autorisé dans le wrapper. Un résultat ambigu après dispatch remonte au caller. ### `sendTransaction` Transport reçoit une transaction **déjà construite et signée**. Il ne devient ni builder, ni signer, ni executor métier. La config courante conserve : ```text encoding Option skipPreflight Option/default false preflightCommitment Option maxRetries Option minContextSlot Option ``` Le runtime RPC vérifie normalement les signatures et simule la transaction avant relay lorsque `skipPreflight` est faux. Une réponse réussie ne constitue pas une confirmation on-chain ; le résultat est la première signature embarquée dans la transaction. La distinction de retry doit rester explicite : ```text sendTransaction.maxRetries = retry/retransmission du noeud RPC KSP HttpRetrySettings = retry de la requête HTTP ``` La première peut être configurée par l'appel. La seconde reste bloquée après tout dispatch ambigu grâce au descriptor central. ## `simulateTransaction` La simulation conserve les options Agave actuelles : ```text commitment Option encoding Option replaceRecentBlockhash bool/default false sigVerify bool/default false minContextSlot Option innerInstructions bool/default false accounts Option ``` L'invariant runtime courant : ```text sigVerify == true && replaceRecentBlockhash == true -> invalid params ``` KSP doit le rejeter avant I/O, car il est déterministe et ne nécessite aucun décodage de la transaction. La sous-config `accounts` conserve l'encoding Account compatible et un tableau d'adresses. Agave rejette actuellement les encodings Account `binary/base58` pour ce retour et borne dynamiquement le nombre demandé au nombre de comptes de la transaction. Comme KSP ne décode pas la transaction en `0.2.3`, cette limite dynamique reste une validation runtime/provider et n'est pas réimplémentée avec une dépendance transactionnelle. Le résultat de simulation Agave `v4.2.1` contient notamment, sous forme optionnelle lorsque pertinente : ```text err logs accounts unitsConsumed loadedAccountsDataSize returnData innerInstructions replacementBlockhash fee preBalances postBalances preTokenBalances postTokenBalances loadedAddresses ``` Transport doit préserver ces champs et leurs `null`/absences sans décoder les instructions ou retours Program en modèles métier. ## Erreurs et validations avant I/O Les wrappers réutilisent le domaine d'erreur KSP. Les contrôles locaux ciblés comprennent au minimum : ```text getRecentPrioritizationFees : <= 128 adresses getSignaturesForAddress : limit 1..=1000 quand fourni getSignatureStatuses : <= 256 signatures sendTransaction : encoding d'entrée binaire supporté simulateTransaction : encoding d'entrée binaire supporté simulateTransaction : sigVerify XOR replaceRecentBlockhash pour le couple interdit ``` Les validations nécessitant de décoder/sanitizer les bytes de message/transaction restent côté RPC pour cette release. Les erreurs JSON-RPC significatives — invalid params, min-context non atteint, transaction non trouvée sous forme `null`, preflight failure, transaction history indisponible, unsupported transaction version — doivent être couvertes par fixtures lorsque la méthode correspondante peut les produire. KSP ne convertit pas une erreur RPC applicative en retry de transport. ## Stratégie de tests Chaque wrapper possède des fixtures HTTP locales déterministes qui vérifient selon son contrat : - méthode et tableau `params` exacts, dans l'ordre exact ; - omission correcte du paramètre config lorsqu'il est absent ; - success typed ; - `null` / champ optionnel / champ omis ; - erreur JSON-RPC ; - cardinalité rejetée avant I/O lorsque KSP la connaît sans décodage ; - forme legacy `getTransaction` séparée de la forme moderne ; - `maxSupportedTransactionVersion` ; - encodings transaction ; - positions `null` de `getSignatureStatuses` ; - ordre newest-first de `getSignaturesForAddress` ; - champs de simulation riches et optionnels. ### Tests write/no-resend Les tests `requestAirdrop` et `sendTransaction` ne doivent pas se contenter de tester la fonction pure `evaluate_transport_retry` déjà existante. Ils doivent exercer le chemin wrapper -> executor avec un serveur fixture capable de compter les requêtes et démontrer au minimum : ```text connection failure prouvée NotDispatched -> policy centrale applicable HTTP 429 après dispatch -> une seule soumission write HTTP 5xx temporaire après dispatch -> une seule soumission write timeout/issue ambiguë après dispatch -> aucune seconde soumission automatique ``` L'objectif n'est pas de créer une policy parallèle dans les wrappers, mais de prouver que les descriptors write utilisent réellement la policy centrale dans l'exécution standard. ### Simulation `simulateTransaction` reste retry-safe. Les fixtures doivent donc vérifier la config, l'incompatibilité `sigVerify/replaceRecentBlockhash`, les résultats partiels/nullables et au moins un scénario de retry transport sûr déjà supporté par l'executor commun. ## Canaries de complétude à conserver À toute la release : ```text current == 52 historical == 14 0.2.1 exact == 4 0.2.2 exact == 22 0.2.3 exact == 11 0.2.4 exact == 15 ``` Aucun wrapper `0.2.4` n'est déclaré typed-complete avant sa release. La canarie `0.2.3 exact == 11` ne devient réellement verte qu'une fois les onze wrappers publics et leurs tests de surface en place. Le registry peut déjà contenir leurs descriptors sans que cela ne compte comme couverture typée. ## Smokes live Les fixtures locales restent normatives pour la correctness des wrappers. Les smokes live sont opt-in et ne les remplacent pas. La décision finale de smoke est réservée à la prerelease de clôture. Toute extension doit respecter l'ownership déjà stabilisée : - un smoke **Transport pur** qui construit ses settings programmatiquement peut rester sous `ksp-onchain-transport-lib` ; - un nouveau smoke cross-crates `Config + Transport + ...` ne doit pas être ajouté sous Config comme destination générale ; - `requestAirdrop` et `sendTransaction` ne seront pas exercés live sans justification forte, car un smoke de lecture/simulation suffit à valider la route Transaction sans introduire d'effet de bord ou de dépendance faucet/provider. Un candidat raisonnable pour la clôture est un smoke Transport pur combinant `getLatestBlockhash` et une lecture Transaction déterministe ; une simulation live n'est retenue que si une fixture transactionnelle stable peut être fournie sans déplacer la construction/signature métier dans Transport. ## Audit rétroactif `KSP-TRANSPORT-007` planifié La règle `KSP-TRANSPORT-007` formalise en `pre.005` un principe déjà appliqué dans les audits de `0.2.1` et `0.2.2`, mais elle n'était pas encore un critère de clôture nommé lors de ces releases. Un contrôle rétroactif dédié est donc ajouté avant la clôture documentaire. L'audit `pre.008` couvrira au minimum : ```text 4 wrappers foundation de 0.2.1 22 wrappers Accounts/Tokens/Cluster de 0.2.2 11 wrappers Transactions de 0.2.3 ``` Il comparera la surface publique KSP aux paramètres/configs/overloads et formes de réponse des sources normatives courantes retenues. Les syntaxes strictement équivalentes peuvent rester canonicalisées conformément à la règle. Toute possibilité supportée manquante sera corrigée dans cette tranche ; si aucun manque n'est trouvé, la tranche fournira la preuve/canarie d'audit sans modification fonctionnelle artificielle. Un contrôle ciblé effectué pendant `pre.006` confirme déjà que les configs structurantes de `0.2.2` (`RpcAccountInfoConfig`, `RpcProgramAccountsConfig`, `RpcLargestAccountsConfig`, `RpcLeaderScheduleConfig`, `RpcGetVoteAccountsConfig`) correspondent aux champs Agave `v4.2.1` exposés par les DTOs KSP. Ce contrôle ne remplace pas l'audit exhaustif `pre.008`. ## Prévision souple des prereleases ```text pre.001 audit officiel/Agave + matrice + sécurité + wire/deps + sizing pre.002 primitives/configs/results Transactions partagés + fixtures communes pre.003 getFeeForMessage + getLatestBlockhash + getTransactionCount + isBlockhashValid pre.004 getRecentPrioritizationFees + getSignaturesForAddress + getSignatureStatuses pre.005 getTransaction moderne + compatibilité legacy + transaction/meta/version wire pre.006 requestAirdrop + sendTransaction + preuves end-to-end no-resend pre.007 simulateTransaction + résultat riche + invariants de config pre.008 audit rétroactif KSP-TRANSPORT-007 sur 0.2.1 -> 0.2.3 + remédiations éventuelles pre.009 réaudit final + canaries + smoke opt-in si pertinent + README/USAGE + validation + prompt 0.2.4 ``` Une prerelease intermédiaire peut être ajoutée si le volume réel d'une tranche dépasse le budget. Après formalisation de `KSP-TRANSPORT-007` en `pre.005`, `pre.008` est désormais réservée à un audit rétroactif explicite des wrappers HTTP déjà livrés depuis `0.2.1`, afin de ne pas transformer la tranche de clôture en remédiation fonctionnelle tardive. La dernière prerelease reste une tranche de clôture documentaire/validation et ne doit pas devenir une implémentation massive tardive. ## Résultat de `pre.008` — réaudit rétroactif `KSP-TRANSPORT-007` Le réaudit rétroactif a été exécuté sur les **37 wrappers HTTP typés courants** livrés par `0.2.1`, `0.2.2` et `0.2.3-pre.007` : 4 foundation, 22 Accounts/Tokens/Cluster et 11 Transactions. La matrice durable est conservée dans `docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`. Le contrôle croise la documentation HTTP Solana courante avec Agave `v4.2.1`, génération recommandée pour adoption générale Mainnet-beta le 10 août 2026 et dont les activations Mainnet-beta ont commencé le 17 août 2026. `master` est déjà en `4.3.0-alpha`, mais n'est pas retenu comme contrat stable de cette release. Verdict : **aucune possibilité RPC supportée n'est manquante dans les 37 wrappers audités**. Les extensions runtime déjà prises en charge par KSP (`binary`, `sortResults`, `tokenAccountState`, `clientId`, `inflationRewardsCommissionBps`, `recentBlockhash`, champs riches de simulation, `transactionIndex`, etc.) sont conservées même lorsqu'elles ne sont pas toutes détaillées dans la page publique Solana. Les syntaxes strictement équivalentes peuvent rester canonicalisées conformément à `KSP-TRANSPORT-007`. Aucune remédiation fonctionnelle artificielle n'est donc introduite en `pre.008`. La tranche ajoute une preuve durable et une canarie nommée couvrant exactement les 37 descriptors courants de `0.2.1` à `0.2.3`, tout en préservant la forme legacy dépréciée de `getTransaction`. La clôture reste déplacée à `pre.009`. ## Résultat de `pre.009` — candidate de clôture Le réaudit final du 18 août 2026 confirme que l'index HTTP Solana courant contient toujours **52 méthodes** et que la navigation Deprecated conserve les **14 méthodes historiques** déjà enregistrées. La partition KSP reste donc inchangée : 4 foundation + 22 Accounts/Tokens/Cluster + 11 Transactions déjà typées, puis 15 Blocks/Economics réservées à `0.2.4`. La candidate `pre.009` ne modifie aucun wrapper fonctionnel. Elle : - synchronise README/USAGE, inventaire composant, séquence fonctionnelle et index documentaires avec la surface réelle de 37 wrappers typés ; - conserve la matrice `KSP-TRANSPORT-007` corrigée par l'opérateur comme preuve rétroactive durable ; - ajoute `docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md` comme matrice de clôture de la release ; - étend le smoke Transport pur avec trois reads Transactions sans effet de bord : `getLatestBlockhash`, `isBlockhashValid` et `getTransactionCount` ; - prépare `prompts/009-V0_2_4_START_PROMPT.md` pour les 10 Blocks + 5 Economics restants ; - maintient `CHANGELOG.md` inchangé jusqu'à `rel.001`. La publication stable reste strictement publicationnelle : version Cargo finale, ROADMAP `[X]`, CHANGELOG, clôture des preuves opérateur et tag stable après validation. ## Résultat de `rel.001` — publication stable La candidate `0.2.3-pre.009` a été validée par l'opérateur le **18 août 2026** avec la matrice de clôture complète : formatage, check et clippy workspace, tests ciblés Transport/Config/Core/Config Desk, `cargo test --workspace`, graphes Cargo Transport/Config et les deux smokes Devnet opt-in. Preuves principales : ```text Transport : 182 unit + 19 public API + 14 release completeness, 0 échec Config : 95 unit + 5 ownership + 13 public API, 0 échec Core : 14 unit + 3 public API + 2 workspace dependencies + 1 workspace logging, 0 échec Config Desk : 63 unit + 2 desktop contract + 2 desktop security + 1 public API, 0 échec cargo test --workspace : OK smoke Transport Devnet : 1 passed smoke Config -> Transport Devnet : 1 passed ``` Les graphes confirment la frontière attendue `Config -> Transport`, sans dépendance inverse Transport -> Config/Store/Program ni `tracing` direct. Les doublons observés restent transitifs/proc-macro, notamment `syn` 2.x/3.x, sans seconde stack HTTP KSP. `rel.001` ne modifie aucun wrapper, DTO, comportement runtime, dépendance ou feature. Il publie uniquement la version Cargo stable `0.2.3`, clôt le ROADMAP/CHANGELOG et transforme cette matrice candidate en historique stable. Le point d'entrée suivant est `prompts/009-V0_2_4_START_PROMPT.md`. ## Critères de clôture de `0.2.3` Les critères de clôture suivants sont satisfaits par la candidate validée `pre.009` : - les 11 wrappers sont publics et passent tous par `execute_standard_rpc` ; - chaque wrapper couvre tous les paramètres/options/overloads normatifs ou runtime supportés retenus par l'audit, selon `KSP-TRANSPORT-007` ; - les trois classes de sécurité restent exactes `8 Read / 2 WriteSubmission / 1 Simulation` ; - `requestAirdrop` et `sendTransaction` prouvent l'absence de resend automatique après dispatch ambigu ; - `getTransaction` préserve la forme moderne et la compatibilité legacy explicitement dépréciée ; - `maxSupportedTransactionVersion` est préservé ; - les cardinalités 128 / 1000 / 256 sont testées selon leur contrat exact ; - les tableaux et `null` positionnels sont préservés ; - `simulateTransaction` préserve son config/result sans décodage Program ; - les canaries 52/14/4/22/11/15 passent ; - aucune dépendance Transport -> Config/Store/Program/tracing direct n'est introduite ; - README/USAGE, plan, matrice de validation et prompt `0.2.4` sont synchronisés ; - les validations Cargo de clôture et graphes de dépendances ont une preuve opérateur ou une exécution réelle ; - `CHANGELOG.md` est renseigné uniquement par `0.2.3-rel.001` ; - la release stable finale reste strictement publicationnelle. ## Validations prévues pendant le développement ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` ## Validations prévues à la clôture ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib cargo test -p ksp-config-lib cargo test -p ksp-core-lib cargo test -p ksp-app-config-desk cargo test --workspace cargo tree -p ksp-onchain-transport-lib cargo tree -p ksp-onchain-transport-lib -d cargo tree -p ksp-onchain-transport-lib -e features cargo tree -p ksp-onchain-transport-lib -e normal ``` Aucune commande n'est déclarée réussie sans exécution réelle ou preuve opérateur. ## Résultat de `pre.001` `pre.001` s'arrête volontairement avant toute source Rust fonctionnelle : - périmètre 11/11 confirmé ; - classification sécurité confirmée ; - architecture commune confirmée ; - wire/config/result audités ; - limites locales/runtime distinguées ; - aucune nouvelle dépendance justifiée ; - gate de sizing positif ; - découpage `pre.002`–`pre.008` défini. La tranche suivante peut commencer par les primitives wire communes sans réouvrir le scope de release. ## Résultat de `pre.002` `pre.002` installe les primitives/configurations/résultats partagés sans déclarer un wrapper Transaction comme terminé : - encodings Transaction séparés entre entrées binaires `base58/base64` et surface `getTransaction` incluant les formes JSON/legacy ; - configs modernes de `getTransaction`, pagination signatures, statuses, airdrop, send et simulation ; - DTOs `latestBlockhash`, prioritization fee, signature info/status, transaction encodée/versionnée et résultat de simulation ; - primitive `SolanaWireField` pour préserver explicitement `omitted/null/value` ; - `transactionIndex` préservé sur `getSignaturesForAddress` et sur le top-level `getTransaction` courant ; - transaction/meta/return data/inner instructions/token balances riches conservés losslessly aux frontières prévues sans décodage Program ; - fixtures communes déterministes pour les variantes legacy/binary/JSON, version/meta/index et simulation riche ; - aucune nouvelle dépendance Cargo et aucun wrapper `0.2.3` activé prématurément. La tranche suivante reste `pre.003` : `getFeeForMessage`, `getLatestBlockhash`, `getTransactionCount` et `isBlockhashValid`. ## Résultat de `pre.006` `pre.006` active les deux écritures Transaction sans introduire de chemin de soumission parallèle : - `requestAirdrop` expose `Pubkey`, lamports, `commitment` et le `recentBlockhash` encore supporté par Agave `v4.2.1` ; - `sendTransaction` transporte une transaction déjà signée/encodée et expose `base58/base64`, `skipPreflight`, `preflightCommitment`, `maxRetries` et `minContextSlot` ; - `sendTransaction.maxRetries` reste explicitement node-side et ne modifie jamais `HttpRetrySettings` ; - les deux wrappers passent par leur descriptor central `WriteSubmission / NeverAfterDispatch` puis `execute_standard_rpc` ; - les fixtures end-to-end comptent les requêtes et prouvent une seule soumission après HTTP 429, HTTP 503 et timeout après dispatch ; - une connexion refusée classée `NotDispatched` peut encore utiliser la policy centrale de retry/fallback, démontrée pour les deux wrappers ; - les erreurs RPC applicatives, dont un échec de preflight `sendTransaction`, restent des erreurs applicatives sans retry transport ; - aucune dépendance transactionnelle/codec supplémentaire n'est ajoutée ; - `simulateTransaction` reste la seule méthode `0.2.3` non encore activée. La prévision est ajustée : `pre.008` devient l'audit rétroactif `KSP-TRANSPORT-007` et la clôture finale est déplacée à `pre.009`. ## Résultat de `pre.007` `pre.007` active la dernière méthode Transaction, `simulateTransaction`, et porte donc la couverture typée `0.2.3` à **11/11** : - transaction d'entrée conservée comme chaîne opaque, sans dépendance codec/SDK ; - encodings d'entrée `base58` et `base64` couverts ; - config complète conservée : `commitment`, `encoding`, `replaceRecentBlockhash`, `sigVerify`, `minContextSlot`, `innerInstructions`, `accounts` ; - sous-config `accounts` capable d'émettre `base64`, `base64+zstd` et `jsonParsed`, avec rejet local de `binary/base58` conformément à Agave `v4.2.1` ; - incompatibilité déterministe `sigVerify=true` + `replaceRecentBlockhash=true` rejetée avant I/O ; - limite dynamique du nombre d'adresses `accounts` laissée au runtime puisque KSP ne décode pas la transaction ; - résultat riche préservé losslessly, y compris les champs Agave `v4.2.1` au-delà du résumé documentaire public : `fee`, balances, token balances et loaded addresses ; - `omitted/null/value` conservés pour les champs optionnels avec `SolanaWireField` ; - accounts de simulation décodés via le wire Account KSP existant, avec `null` positionnels conservés ; - erreur RPC applicative conservée sans transformation en erreur transport ; - descriptor central `Simulation / RetrySafe` exercé end-to-end par un scénario HTTP 503 puis succès, démontrant que la simulation peut être retentée ; - canarie release exacte `8 Read / 2 WriteSubmission / 1 Simulation`, soit les 11 méthodes `V0_2_3`. Aucune dépendance n'est ajoutée. Le travail fonctionnel initialement planifié pour les 11 Transactions est désormais implémenté ; `pre.008` reste volontairement réservée au réaudit rétroactif `KSP-TRANSPORT-007` des wrappers HTTP `0.2.1` -> `0.2.3`, puis `pre.009` à la clôture.