# Delta `0.2.2-pre.003` — cinq wrappers HTTP Accounts typés ## Base requise Livraison précédente corrigée et validée localement par l'opérateur : ```text 0.2.2-pre.002-fix.002 workspace.package.version = "0.2.2-pre.2.fix.2" ``` La validation opérateur du 2026-08-18 a confirmé : ```text cargo fmt --all OK cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test -p ksp-onchain-transport-lib OK ``` Résultats Transport de cette base : ```text 85 unit tests 9 public API tests 2 release completeness tests 0 warning signalé par check/clippy ``` Le plan canonique reste `docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md` version 3. ## Objectif Clôturer la famille Accounts attribuée à `0.2.2` avec cinq wrappers publics typés : ```text getAccountInfo getLargestAccounts getMinimumBalanceForRentExemption getMultipleAccounts getProgramAccounts ``` Tous passent par la foundation HTTP `0.2.1` : ```text wrapper typé -> descriptor audité -> execute_standard_rpc -> pool/admission/retry/deadline -> reqwest HTTP -> JSON-RPC validation -> décodage DTO KSP ``` Aucun wrapper ne contacte `reqwest` directement. ## Version Cargo Conformément à `VER-ID-009` : ```text 0.2.2-pre.2.fix.2 -> 0.2.2-pre.3 ``` Aucune dépendance ni feature Cargo n'est ajoutée. ## Surface typée Accounts ### `getAccountInfo` Signature publique conceptuelle : ```text role + Pubkey + Option -> SolanaRpcResponse> ``` Le wrapper : - sérialise `encoding`, `dataSlice`, `commitment` et `minContextSlot` ; - omet l'objet config lorsqu'il est vide ; - conserve l'absence du compte sous `None` ; - conserve les formes Account data legacy, tuple encodé et `jsonParsed` ; - convertit l'owner en `ksp_core_lib::Pubkey` sans recopier une valeur invalide dans le diagnostic. ### `getLargestAccounts` Signature publique conceptuelle : ```text role + Option -> SolanaRpcResponse> ``` Le wrapper conserve l'ordre du wire et sérialise les champs KSP déjà audités dans `pre.002`, y compris `filter` et `sortResults` lorsqu'ils sont explicitement renseignés. ### `getMinimumBalanceForRentExemption` Signature publique conceptuelle : ```text role + usize data_len + Option -> u64 lamports ``` Le wrapper encode la longueur de données sans valeur sentinelle et conserve les erreurs JSON-RPC applicatives comme telles. ### `getMultipleAccounts` Signature publique conceptuelle : ```text role + &[Pubkey] + Option -> SolanaRpcResponse>> ``` Le wrapper : - refuse localement plus de 100 public keys ; - sérialise les adresses dans l'ordre fourni ; - conserve les `null` individuels ; - vérifie que le nombre d'éléments retournés correspond au nombre d'adresses demandées, afin de ne pas fabriquer silencieusement un mapping positionnel incohérent. ### `getProgramAccounts` Signature publique conceptuelle : ```text role + program Pubkey + Option -> SolanaProgramAccountsResult ``` Le résultat préserve les deux formes wire : ```text Accounts(Vec) Context(SolanaRpcResponse>) ``` Le wrapper sérialise `dataSize`, `memcmp`, `tokenAccountState`, `withContext`, `sortResults` et la config Account commune. ## Validation locale des paramètres Nouveau code d'erreur public Transport : ```text ERROR_CODE_INVALID_RPC_PARAMETERS onchain_transport.invalid_rpc_parameters ``` Il distingue une requête KSP localement invalide d'une erreur JSON-RPC distante ou d'une réponse invalide. Les invariants appliqués avant I/O sont : ```text getMultipleAccounts : <= 100 public keys getProgramAccounts : <= 4 filters memcmp raw bytes : <= 128 bytes ``` Pour `memcmp` encodé sous forme base58/base64, KSP ne décode toujours pas localement la chaîne : la limite des 128 octets décodés reste donc contrôlée par le serveur. Cette décision évite d'ajouter `bs58` ou `base64` uniquement pour une validation anticipée. ## Wire Account activé en production Les helpers privés préparés par `pre.002` et réellement nécessaires à ces wrappers deviennent production-live : - sérialisation des configs Account/Largest/Program ; - conversion des encodings Account ; - décodage `SolanaAccountData` ; - décodage Account/KeyedAccount/AccountBalance ; - conversion `Pubkey` wire ; - construction interne de `SolanaRpcResponse`. Les helpers Cluster/Token préparatoires restent inchangés et ne deviennent pas production-live avant leurs tranches respectives. ## Fixtures HTTP déterministes ajoutées ```text crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.null.json crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.invalid_owner.json crates/ksp-onchain-transport-lib/fixtures/http/get_largest_accounts.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_largest_accounts.invalid_address.json crates/ksp-onchain-transport-lib/fixtures/http/get_minimum_balance_for_rent_exemption.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_minimum_balance_for_rent_exemption.error.json crates/ksp-onchain-transport-lib/fixtures/http/get_multiple_accounts.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_program_accounts.bare.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_program_accounts.context.success.json ``` Les tests locaux utilisent un serveur HTTP loopback et n'accèdent pas à Internet. ## Couverture de tests ajoutée Les tests Accounts couvrent : - request exacte pour chaque méthode ; - config et omission de config vide ; - succès typé ; - account absent ; - `null` dans `getMultipleAccounts` ; - ordre de `getMultipleAccounts` ; - résultat bare et contextualisé de `getProgramAccounts` ; - invalid owner/address ; - erreur JSON-RPC applicative ; - limite des 100 comptes ; - limite des 4 filtres ; - limite raw `memcmp` de 128 octets ; - mismatch cardinalité request/result de `getMultipleAccounts`. Le test public compile explicitement les cinq méthodes sur `HttpTransportPool` et vérifie le nouveau code d'erreur. Un canari release supplémentaire fige l'ensemble Accounts `0.2.2` exact : ```text getAccountInfo getLargestAccounts getMinimumBalanceForRentExemption getMultipleAccounts getProgramAccounts ``` Il vérifie aussi que ces descriptors restent `Read + RetrySafe`. Aucune famille Tokens/Cluster n'est déclarée typed-complete par cette tranche. Après application, la cible Transport attendue devient : ```text 98 unit tests 10 public API tests 3 release completeness tests ``` ## Fichiers ajoutés ```text crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.null.json crates/ksp-onchain-transport-lib/fixtures/http/get_account_info.invalid_owner.json crates/ksp-onchain-transport-lib/fixtures/http/get_largest_accounts.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_largest_accounts.invalid_address.json crates/ksp-onchain-transport-lib/fixtures/http/get_minimum_balance_for_rent_exemption.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_minimum_balance_for_rent_exemption.error.json crates/ksp-onchain-transport-lib/fixtures/http/get_multiple_accounts.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_program_accounts.bare.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_program_accounts.context.success.json deltas/0.2.2/pre.003.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/error.rs crates/ksp-onchain-transport-lib/src/lib.rs crates/ksp-onchain-transport-lib/src/rpc_accounts.rs crates/ksp-onchain-transport-lib/src/rpc_common.rs crates/ksp-onchain-transport-lib/unit_tests/rpc_accounts.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs ``` ## Fichiers supprimés Aucun. ## Fichiers volontairement inchangés ```text CHANGELOG.md ROADMAP.md docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/src/executor.rs crates/ksp-onchain-transport-lib/src/rpc_method.rs crates/ksp-onchain-transport-lib/src/rpc_tokens.rs crates/ksp-onchain-transport-lib/src/rpc_cluster.rs crates/ksp-config-lib/** config/** ``` La tranche suivante reste `pre.004 — cinq wrappers Tokens`. ## Validations exécutées - prise en compte de la validation opérateur propre de `pre.002-fix.002` comme base ; - relecture des règles `VERSION_WORKFLOW.md` et `RULES_RUST.md` applicables ; - revérification de la documentation HTTP Solana actuelle pour les cinq méthodes Accounts ; - recoupement des signatures/limites avec la source Agave `v4.2.1` auditée par le plan ; - validation JSON syntaxique des dix nouvelles fixtures ; - contrôle statique de l'absence de `unwrap`, `expect`, `panic!` et `#[allow(dead_code)]` dans le code de production modifié ; - contrôle statique que les cinq wrappers utilisent `execute_standard_rpc` et aucun appel `reqwest` direct ; - contrôle statique de l'absence de nouvelle dépendance/feature ; - contrôle exact des fichiers inclus dans l'archive d'échange. ## Validations non exécutées Le sandbox d'échange ne fournit pas `cargo`, `rustc` ou `rustfmt`. Les commandes suivantes doivent être exécutées sur le checkout opérateur avant commit : ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` `cargo test --workspace` reste réservé au checkpoint de clôture/session conformément au workflow KSP. Aucun `cargo tree` n'est requis par cette tranche puisqu'aucune dépendance ni feature n'a changé. ## Décisions prises - utiliser les DTOs `pre.002` sans créer de seconde couche RPC ; - conserver `execute_standard_rpc()` comme unique entrée d'exécution HTTP standard ; - introduire un code d'erreur dédié aux paramètres typed invalides plutôt que détourner `invalid_settings` ; - vérifier localement les limites dont KSP peut connaître la violation sans dépendance de décodage supplémentaire ; - préserver les `null`, l'ordre et la dualité bare/context au lieu de normaliser artificiellement les réponses ; - ne pas modifier Config ; - ne pas ajouter de logging spécifique par méthode. ## Questions ouvertes Aucune question bloquante pour `pre.004`. ## Suite `0.2.2-pre.004` : implémenter les cinq wrappers Tokens (`getTokenAccountBalance`, `getTokenAccountsByDelegate`, `getTokenAccountsByOwner`, `getTokenLargestAccounts`, `getTokenSupply`) avec les DTOs préparés, selector `Mint | ProgramId`, fixtures HTTP déterministes et conservation de `uiAmount: null`.