12 Commits

Author SHA1 Message Date
f7acac3fc8 v0.2.3-rel.001 2026-08-18 17:42:12 +02:00
039b93cfb3 v0.2.3-pre.009 2026-08-18 17:33:46 +02:00
c9a0f7fd37 v0.2.3-pre.008 2026-08-18 16:47:54 +02:00
704110d509 v0.2.3-pre.007 2026-08-18 16:12:07 +02:00
fb32ed03f8 v0.2.3-pre.006-fix.001 2026-08-18 12:40:24 +02:00
4439589f0d v0.2.3-pre.006 2026-08-18 12:35:29 +02:00
1e1bc0d421 v0.2.3-pre.005 2026-08-18 12:33:16 +02:00
bd26d4f636 v0.2.3-pre.004 2026-08-18 12:14:59 +02:00
2a7f3e8f40 v0.2.3-pre.003 2026-08-18 11:35:51 +02:00
1d37f04d63 v0.2.3-pre.002-fix.001 2026-08-18 11:27:24 +02:00
1ccf11bcc1 v0.2.3-pre.002 2026-08-18 11:13:04 +02:00
d06284fca2 v0.2.3-pre.001 2026-08-18 10:47:19 +02:00
70 changed files with 8507 additions and 37 deletions

View File

@@ -1,10 +1,14 @@
<!-- file: CHANGELOG.md --> <!-- file: CHANGELOG.md -->
<!-- version: 6 --> <!-- version: 7 -->
# Changelog KSP # Changelog KSP
Ce changelog résume uniquement les releases KSP considérées comme stables, dans l'ordre chronologique décroissant. Les détails de chaque livraison restent dans `deltas/`. Ce changelog résume uniquement les releases KSP considérées comme stables, dans l'ordre chronologique décroissant. Les détails de chaque livraison restent dans `deltas/`.
## 0.2.3 — HTTP Transactions — 2026-08-18
`0.2.3` complète la famille HTTP Transactions de `ksp-onchain-transport-lib` avec 11 wrappers typés, portant la surface HTTP typée courante à 37 méthodes : 4 foundation, 22 Accounts/Tokens/Cluster et 11 Transactions. La release stabilise la classification exacte `8 Read / RetrySafe`, `2 WriteSubmission / NeverAfterDispatch` (`requestAirdrop`, `sendTransaction`) et `1 Simulation / RetrySafe` (`simulateTransaction`), avec preuves end-to-end qu'une write submission n'est jamais resoumise après dispatch ambigu mais peut retenter lorsqu'un échec est prouvé `NotDispatched`. `getTransaction` couvre la config moderne complète et la forme bare encoding legacy dépréciée ; les variantes de transaction, metadata, version et `transactionIndex` restent préservées losslessly. `simulateTransaction` couvre sa config complète, ses invariants déterministes et son résultat riche sans introduire de client RPC Solana haut niveau ni de décodage transactionnel dans Transport. La release formalise `KSP-TRANSPORT-007` et réaudite rétroactivement les 37 wrappers courants sans remédiation fonctionnelle. Les canaries conservent 52 méthodes HTTP courantes, 14 historiques Deprecated/Removed et 15 Blocks/Economics réservées à `0.2.4`. Les graphes Cargo et les deux smokes Devnet — Transport pur read-only et composition Config -> Transport transitoire — ont été validés avant publication. Le prompt `prompts/009-V0_2_4_START_PROMPT.md` ouvre `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale`.
## 0.2.2 — HTTP Accounts + Tokens + Cluster — 2026-08-18 ## 0.2.2 — HTTP Accounts + Tokens + Cluster — 2026-08-18
`0.2.2` complète la surface HTTP typée de `ksp-onchain-transport-lib` avec 22 wrappers supplémentaires : 5 Accounts, 5 Tokens et 12 Cluster, portant la couverture typée totale à 26 méthodes avec les quatre canaris foundation de `0.2.1`. La release stabilise les DTOs/configs wire communs, préserve les formes Account encodées/`jsonParsed`, les `null` et champs optionnels, les selectors Token exclusifs, les contextes RPC, les structures Cluster/leader/vote et les limites locales auditées (`getMultipleAccounts <= 100`, `getProgramAccounts <= 4` filtres, `memcmp` raw <= 128 octets, `getSlotLeaders` entre 1 et 5000). Les 22 descriptors restent `Read / RetrySafe` et passent exclusivement par le flux central `descriptor -> execute_standard_rpc -> pool/admission -> executor HTTP`. La release n'ajoute aucune dépendance externe, ne crée aucun client HTTP parallèle et conserve le firewall Transport -> Config/Store/Program. Elle ajoute un smoke Devnet pur à Transport avec settings programmatiques couvrant Accounts/Tokens/Cluster, conserve séparément le smoke historique Config -> Transport comme exception transitoire, et valide les deux explicitement avant publication. Les canaries figent toujours 52 méthodes HTTP courantes, 14 historiques Deprecated/Removed et la partition typed `4 / 22 / 11 / 15`. Le prompt `prompts/008-V0_2_3_START_PROMPT.md` ouvre `0.2.3 — HTTP Transactions`. `0.2.2` complète la surface HTTP typée de `ksp-onchain-transport-lib` avec 22 wrappers supplémentaires : 5 Accounts, 5 Tokens et 12 Cluster, portant la couverture typée totale à 26 méthodes avec les quatre canaris foundation de `0.2.1`. La release stabilise les DTOs/configs wire communs, préserve les formes Account encodées/`jsonParsed`, les `null` et champs optionnels, les selectors Token exclusifs, les contextes RPC, les structures Cluster/leader/vote et les limites locales auditées (`getMultipleAccounts <= 100`, `getProgramAccounts <= 4` filtres, `memcmp` raw <= 128 octets, `getSlotLeaders` entre 1 et 5000). Les 22 descriptors restent `Read / RetrySafe` et passent exclusivement par le flux central `descriptor -> execute_standard_rpc -> pool/admission -> executor HTTP`. La release n'ajoute aucune dépendance externe, ne crée aucun client HTTP parallèle et conserve le firewall Transport -> Config/Store/Program. Elle ajoute un smoke Devnet pur à Transport avec settings programmatiques couvrant Accounts/Tokens/Cluster, conserve séparément le smoke historique Config -> Transport comme exception transitoire, et valide les deux explicitement avant publication. Les canaries figent toujours 52 méthodes HTTP courantes, 14 historiques Deprecated/Removed et la partition typed `4 / 22 / 11 / 15`. Le prompt `prompts/008-V0_2_3_START_PROMPT.md` ouvre `0.2.3 — HTTP Transactions`.

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 119 # version: 131
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"] members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"]
[workspace.package] [workspace.package]
version = "0.2.2" version = "0.2.3"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md --> <!-- file: ROADMAP.md -->
<!-- version: 37 --> <!-- version: 40 -->
# Roadmap KSP # Roadmap KSP
@@ -47,7 +47,7 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
- [X] `0.2.1`**HTTP transport foundation réduite par le gate `pre.001`** : crate/settings/JSON-RPC/registry 52 current + 14 deprecated historiques, pool/rôles/limites/retry, Config adapter, documentation et 4 méthodes typées canari (`getBalance`, `getGenesisHash`, `getHealth`, `getVersion`) publiés stables. - [X] `0.2.1`**HTTP transport foundation réduite par le gate `pre.001`** : crate/settings/JSON-RPC/registry 52 current + 14 deprecated historiques, pool/rôles/limites/retry, Config adapter, documentation et 4 méthodes typées canari (`getBalance`, `getGenesisHash`, `getHealth`, `getVersion`) publiés stables.
- [X] `0.2.2` — HTTP Accounts + Tokens + Cluster : 22 wrappers typés (5 Accounts + 5 Tokens + 12 Cluster), canaries de complétude 52+14, smoke Devnet Transport pur et smoke historique Config -> Transport validés, documentation durable et prompt `0.2.3` publiés stables. - [X] `0.2.2` — HTTP Accounts + Tokens + Cluster : 22 wrappers typés (5 Accounts + 5 Tokens + 12 Cluster), canaries de complétude 52+14, smoke Devnet Transport pur et smoke historique Config -> Transport validés, documentation durable et prompt `0.2.3` publiés stables.
- [ ] `0.2.3`Compléter les 11 méthodes HTTP Transactions, y compris write/submission technique avec politique no-resend ambigu. - [X] `0.2.3`HTTP Transactions stable : 11/11 wrappers typés publiés, classification `8 Read / 2 WriteSubmission / 1 Simulation`, no-resend ambigu prouvé pour les write submissions, `KSP-TRANSPORT-007` réaudité conforme sur les 37 wrappers HTTP courants, graphes Cargo et deux smokes Devnet validés ; `0.2.4` reprend les 15 Blocks/Economics restants.
- [ ] `0.2.4` — Compléter les 10 méthodes HTTP Blocks + 5 Economics et exécuter la compliance finale de toute la surface HTTP 52 current + 14 deprecated historiques. - [ ] `0.2.4` — Compléter les 10 méthodes HTTP Blocks + 5 Economics et exécuter la compliance finale de toute la surface HTTP 52 current + 14 deprecated historiques.
- [ ] `0.2.5` — Introduire `ksp-wallet-lib`, le format `.kspwallet`, la gestion sûre des secrets et une architecture d'import/export extensible ; exclure `WalletPolicy`. - [ ] `0.2.5` — Introduire `ksp-wallet-lib`, le format `.kspwallet`, la gestion sûre des secrets et une architecture d'import/export extensible ; exclure `WalletPolicy`.
- [ ] `0.2.6` — Introduire `ksp-app-wallet-desk` utilisant Config composite + Wallet + transport HTTP, notamment pour afficher l'identité et le solde d'un wallet. - [ ] `0.2.6` — Introduire `ksp-app-wallet-desk` utilisant Config composite + Wallet + transport HTTP, notamment pour afficher l'identité et le solde d'un wallet.

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-onchain-transport-lib/README.md --> <!-- file: crates/ksp-onchain-transport-lib/README.md -->
<!-- version: 5 --> <!-- version: 7 -->
# `ksp-onchain-transport-lib` # `ksp-onchain-transport-lib`
@@ -69,16 +69,21 @@ Le registre porte notamment :
- remplacement historique éventuel ; - remplacement historique éventuel ;
- release de couverture typée KSP. - release de couverture typée KSP.
La surface typée stable après `0.2.2` contient **26 méthodes** : La release stable `0.2.3` porte la surface typée à **37 méthodes courantes** :
```text ```text
0.2.1 foundation : 4 0.2.1 foundation : 4
0.2.2 Accounts : 5 0.2.2 Accounts : 5
0.2.2 Tokens : 5 0.2.2 Tokens : 5
0.2.2 Cluster : 12 0.2.2 Cluster : 12
0.2.3 Transactions : 11
``` ```
Les quatre canaris foundation restent `getBalance`, `getGenesisHash`, `getHealth` et `getVersion`. `0.2.2` ajoute les 22 wrappers Accounts/Tokens/Cluster affectés à `HttpRpcCoverageRelease::V0_2_2`. Les 26 méthodes Transactions/Blocks/Economics encore affectées à `0.2.3``0.2.4` peuvent déjà passer par l'exécuteur JSON-RPC standard générique lorsqu'un consumer fournit explicitement descriptor et paramètres JSON, mais cette surface raw/générique **ne vaut pas couverture typée**. Les quatre canaris foundation restent `getBalance`, `getGenesisHash`, `getHealth` et `getVersion`. `0.2.2` ajoute les 22 wrappers Accounts/Tokens/Cluster. `0.2.3` ajoute les 11 wrappers Transactions, dont `requestAirdrop` et `sendTransaction` en `WriteSubmission / NeverAfterDispatch` et `simulateTransaction` en `Simulation / RetrySafe`.
Les **15 méthodes Blocks/Economics** encore affectées à `0.2.4` peuvent déjà passer par l'exécuteur JSON-RPC standard générique lorsqu'un consumer fournit explicitement descriptor et paramètres JSON, mais cette surface raw/générique **ne vaut pas couverture typée**.
`KSP-TRANSPORT-007` impose qu'un wrapper typé couvre toutes les possibilités RPC supportées retenues par l'audit : paramètres/options, overloads et formes legacy encore supportées, contraintes déterministes utiles et variantes de réponse pertinentes sans perte. Le réaudit `0.2.3-pre.008` confirme cette complétude sur les 37 wrappers courants.
Les 14 méthodes historiques restent découvrables pour la compliance mais sont `Removed` et ne sont pas simulées comme appelables. Les 14 méthodes historiques restent découvrables pour la compliance mais sont `Removed` et ne sont pas simulées comme appelables.
@@ -122,7 +127,8 @@ Deux smokes Devnet opt-in sont séparés par responsabilité :
```text ```text
Transport pur : settings programmatiques -> HttpTransportPool Transport pur : settings programmatiques -> HttpTransportPool
-> getAccountInfo/getTokenAccountsByOwner/getEpochInfo/getVoteAccounts -> Accounts/Tokens/Cluster représentatifs
-> getLatestBlockhash/isBlockhashValid/getTransactionCount
Composition historique : Config -> std.transport/devnet_public -> HttpTransportPool Composition historique : Config -> std.transport/devnet_public -> HttpTransportPool
-> getHealth/getGenesisHash/getVersion/getBalance -> getHealth/getGenesisHash/getVersion/getBalance
@@ -138,4 +144,6 @@ Les deux sont `ignored` par défaut. Le smoke Transport appartient durablement
- [`../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md) — foundation HTTP stable ; - [`../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](../../docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md) — foundation HTTP stable ;
- [`../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — extension typed Accounts/Tokens/Cluster ; - [`../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](../../docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — extension typed Accounts/Tokens/Cluster ;
- [`../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée `0.2.2` ; - [`../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](../../docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée `0.2.2` ;
- [`../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](../../docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) — plan historique clôturé de `0.2.3` ;
- [`../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée `0.2.3` ;
- [`../../config/std.transport.json`](../../config/std.transport.json) — configuration standard HTTP. - [`../../config/std.transport.json`](../../config/std.transport.json) — configuration standard HTTP.

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-onchain-transport-lib/USAGE.md --> <!-- file: crates/ksp-onchain-transport-lib/USAGE.md -->
<!-- version: 5 --> <!-- version: 7 -->
# Utilisation de `ksp-onchain-transport-lib` # Utilisation de `ksp-onchain-transport-lib`
@@ -96,7 +96,24 @@ let epoch = pool.get_epoch_info(&role, None).await;
let vote_accounts = pool.get_vote_accounts(&role, None).await; let vote_accounts = pool.get_vote_accounts(&role, None).await;
``` ```
La surface stable `0.2.2` contient 26 wrappers typés au total : 4 foundation + 5 Accounts + 5 Tokens + 12 Cluster. Les DTOs Transport conservent les `null`, options et formes wire : données Account encodées/`jsonParsed`, `TokenAmount.uiAmount`, contexte RPC, nodes, epoch, leader schedule et vote accounts. Aucun décodage Program/SPL métier n'est effectué ici. La release stable `0.2.3` contient 37 wrappers typés : 4 foundation + 5 Accounts + 5 Tokens + 12 Cluster + 11 Transactions. Les DTOs Transport conservent les `null`, options et formes wire sans décodage Program/SPL métier.
Exemples Transaction représentatifs :
```rust
let context = ksp_onchain_transport_lib::SolanaContextConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized),
std::option::Option::None,
);
let latest = pool
.get_latest_blockhash(&role, std::option::Option::Some(&context))
.await;
let transaction_count = pool
.get_transaction_count(&role, std::option::Option::Some(&context))
.await;
```
`getTransaction` expose la config moderne complète et une forme bare-encoding legacy séparée et deprecated. `requestAirdrop` et `sendTransaction` sont des write submissions : elles utilisent la protection centrale `NeverAfterDispatch`. `simulateTransaction` reste une simulation retry-safe et conserve son résultat riche sans introduire de décodage Program.
## 4. Exécution JSON-RPC standard générique ## 4. Exécution JSON-RPC standard générique
@@ -155,13 +172,13 @@ La configuration standard route les événements `info` de Transport vers un fic
## 9. Smokes Devnet opt-in ## 9. Smokes Devnet opt-in
Le smoke **Transport pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif de `0.2.2` : Le smoke **Transport pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif de `0.2.2` puis trois reads Transactions de `0.2.3` :
```bash ```bash
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
``` ```
Il appelle `getAccountInfo`, `getTokenAccountsByOwner`, `getEpochInfo` et `getVoteAccounts`. La branche Token suit la forme Devnet documentée : owner Pubkey ordinaire de l'exemple officiel, selector `programId` avec l'ID canonique du programme SPL Token, puis config explicite `commitment: finalized` + `encoding: jsonParsed`. Une réponse vide reste acceptable : le smoke valide ainsi la route Token sans dépendre de la persistance d'un mint ou d'un token account Devnet particulier. Il appelle `getAccountInfo`, `getTokenAccountsByOwner`, `getEpochInfo`, `getVoteAccounts`, puis `getLatestBlockhash`, `isBlockhashValid` et `getTransactionCount`. La branche Token suit la forme Devnet documentée : owner Pubkey ordinaire de l'exemple officiel, selector `programId` avec l'ID canonique du programme SPL Token, puis config explicite `commitment: finalized` + `encoding: jsonParsed`. Une réponse vide reste acceptable. La branche Transaction reste read-only : elle ne déclenche ni airdrop ni soumission de transaction et ne remplace pas les fixtures déterministes couvrant les 11 wrappers.
Le smoke historique de **composition Config -> Transport** reste également disponible : Le smoke historique de **composition Config -> Transport** reste également disponible :

View File

@@ -0,0 +1,36 @@
[
{
"slot": 430000123,
"blockTime": 1787000000,
"transaction": ["AQIDBAUGBwg=", "base64"],
"meta": {
"err": null,
"status": {"Ok": null},
"fee": 5000,
"preBalances": [10000],
"postBalances": [5000]
},
"version": 0,
"transactionIndex": 7
},
{
"slot": 430000100,
"blockTime": null,
"transaction": "3Bxs4NN8M2Yn4TLb",
"meta": null,
"version": "legacy",
"transactionIndex": null
},
{
"slot": 430000050,
"blockTime": null,
"transaction": {
"signatures": [],
"message": {
"accountKeys": [],
"recentBlockhash": "11111111111111111111111111111111",
"instructions": []
}
}
}
]

View File

@@ -0,0 +1,12 @@
[
"3Bxs4NN8M2Yn4TLb",
["AQIDBAUGBwg=", "base64"],
{
"signatures": ["5h6xBEauJ3PK6SWQkgLxHcQpWyRZyG7c4pUpK9fd2B2B7hRQ1S6F9J7BqvQPEmxQxK4DThfYF5f5f5f5f5f5f5f5"],
"message": {
"accountKeys": [],
"recentBlockhash": "11111111111111111111111111111111",
"instructions": []
}
}
]

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid param: unable to decode message"},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000002},"value":null},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000001},"value":5000},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000004},"value":{"blockhash":"","lastValidBlockHeight":431123456}},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000003},"value":{"blockhash":"11111111111111111111111111111111","lastValidBlockHeight":431123456}},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":[{"slot":431000030,"prioritizationFee":1200},{"slot":431000029,"prioritizationFee":0}],"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000052},"value":[null]},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000051},"value":[]},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000053},"value":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000050},"value":[null,{"slot":431000049,"confirmations":null,"status":{"Ok":null},"err":null,"confirmationStatus":"finalized"},{"slot":431000048,"confirmations":2,"status":{"Err":{"InstructionError":[0,"Custom"]}},"err":{"InstructionError":[0,"Custom"]},"confirmationStatus":"confirmed"}]},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","error":{"code":-32015,"message":"Transaction history is not available from this node"},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":[{"signature":"newest-signature","slot":431000040,"err":null,"memo":"memo-newest","blockTime":1787000100,"confirmationStatus":"finalized","transactionIndex":9},{"signature":"older-signature","slot":431000039,"err":{"InstructionError":[0,"Custom"]},"memo":null,"blockTime":null,"confirmationStatus":"confirmed"}],"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"slot":431000061,"blockTime":1787000201,"transaction":["3Bxs4NN8M2Yn4TLb","base58"],"meta":null,"version":"legacy","transactionIndex":0},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"slot":431000062,"blockTime":1787000202,"transaction":["AQIDBAUGBwg=","base64"],"meta":null,"version":0,"transactionIndex":1},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"slot":431000060,"blockTime":null,"transaction":"3Bxs4NN8M2Yn4TLb","meta":null,"version":"legacy"},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","error":{"code":-32015,"message":"Transaction version (1) is not supported by the requesting client. Please try the request again with the following configuration parameter: \"maxSupportedTransactionVersion\": 1"},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"slot":431000063,"blockTime":1787000203,"transaction":{"signatures":["fixture-signature"],"message":{"header":{"numRequiredSignatures":1,"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":1},"accountKeys":["11111111111111111111111111111111","SysvarRent111111111111111111111111111111111"],"recentBlockhash":"11111111111111111111111111111111","instructions":[{"programIdIndex":0,"accounts":[0,1],"data":"3Bxs4NN8","stackHeight":1}],"addressTableLookups":null}},"meta":{"err":null,"status":{"Ok":null},"fee":5000,"preBalances":[100000,1],"postBalances":[95000,1],"innerInstructions":[],"logMessages":["Program 11111111111111111111111111111111 invoke [1]","Program 11111111111111111111111111111111 success"],"preTokenBalances":[],"postTokenBalances":[],"rewards":null,"loadedAddresses":{"writable":[],"readonly":[]},"returnData":{"programId":"11111111111111111111111111111111","data":["AQID","base64"]},"computeUnitsConsumed":150,"costUnits":190},"version":0,"transactionIndex":7},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"slot":431000064,"blockTime":1787000204,"transaction":{"signatures":["fixture-signature-parsed"],"message":{"accountKeys":[{"pubkey":"11111111111111111111111111111111","signer":true,"writable":true,"source":"transaction"},{"pubkey":"SysvarRent111111111111111111111111111111111","signer":false,"writable":false,"source":"transaction"}],"recentBlockhash":"11111111111111111111111111111111","instructions":[{"program":"system","programId":"11111111111111111111111111111111","stackHeight":1,"parsed":{"type":"transfer","info":{"lamports":1,"source":"11111111111111111111111111111111","destination":"SysvarRent111111111111111111111111111111111"}}}]}},"meta":{"err":null,"status":{"Ok":null},"fee":5000,"preBalances":[100000,1],"postBalances":[95000,1],"innerInstructions":null,"logMessages":null,"preTokenBalances":[],"postTokenBalances":[],"rewards":null,"returnData":null,"computeUnitsConsumed":150,"costUnits":190},"version":"legacy","transactionIndex":null},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":null,"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":987654321,"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":{"context":{"apiVersion":"4.2.1","slot":431000005},"value":true},"id":1}

View File

@@ -0,0 +1,4 @@
{
"blockhash": "11111111111111111111111111111111",
"lastValidBlockHeight": 430123456
}

View File

@@ -0,0 +1,4 @@
[
{"slot": 430000123, "prioritizationFee": 1000},
{"slot": 430000122, "prioritizationFee": 0}
]

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid param: supplied blockhash is not valid"},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":"airdrop-fixture-signature-111111111111111111111111111111111111111111111111","id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Error processing Instruction 0","data":{"err":{"InstructionError":[0,"Custom"]},"logs":["Program log: fixture preflight failure"],"unitsConsumed":123}},"id":1}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","result":"send-fixture-signature-22222222222222222222222222222222222222222222222222","id":1}

View File

@@ -0,0 +1,19 @@
[
{
"signature": "5h6xBEauJ3PK6SWQkgLxHcQpWyRZyG7c4pUpK9fd2B2B7hRQ1S6F9J7BqvQPEmxQxK4DThfYF5f5f5f5f5f5f5f5",
"slot": 430000123,
"err": null,
"memo": "fixture memo",
"blockTime": 1787000000,
"confirmationStatus": "finalized",
"transactionIndex": 7
},
{
"signature": "4Nd1mC5QfVhNq8xqP7z8d7K6a5m4n3b2v1c9x8z7y6w5u4t3s2r1q9p8o7n6m5L4K3J2H1G9F8E7D6C5B4A3",
"slot": 430000100,
"err": {"InstructionError": [0, "Custom"]},
"memo": null,
"blockTime": null,
"confirmationStatus": "confirmed"
}
]

View File

@@ -0,0 +1,17 @@
[
null,
{
"slot": 430000123,
"confirmations": null,
"status": {"Ok": null},
"err": null,
"confirmationStatus": "finalized"
},
{
"slot": 430000120,
"confirmations": 3,
"status": {"Err": {"InstructionError": [0, "Custom"]}},
"err": {"InstructionError": [0, "Custom"]},
"confirmationStatus": "confirmed"
}
]

View File

@@ -0,0 +1,8 @@
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "invalid transaction: failed to sanitize accounts offsets correctly"
},
"id": 1
}

View File

@@ -0,0 +1,18 @@
{
"jsonrpc": "2.0",
"result": {
"context": {
"slot": 431000031,
"apiVersion": "4.2.1"
},
"value": {
"err": null,
"logs": null,
"accounts": null,
"unitsConsumed": 99,
"returnData": null,
"replacementBlockhash": null
}
},
"id": 1
}

View File

@@ -0,0 +1,60 @@
{
"jsonrpc": "2.0",
"result": {
"context": {
"slot": 431000030,
"apiVersion": "4.2.1"
},
"value": {
"err": null,
"logs": [
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success"
],
"accounts": [
{
"lamports": 1000,
"data": [
"",
"base64"
],
"owner": "11111111111111111111111111111111",
"executable": false,
"rentEpoch": 0,
"space": 0
},
null
],
"unitsConsumed": 150,
"loadedAccountsDataSize": 64,
"returnData": {
"programId": "11111111111111111111111111111111",
"data": [
"AQI=",
"base64"
]
},
"innerInstructions": [],
"replacementBlockhash": {
"blockhash": "ComputeBudget111111111111111111111111111111",
"lastValidBlockHeight": 430123999
},
"fee": 5000,
"preBalances": [
10000,
0
],
"postBalances": [
5000,
5000
],
"preTokenBalances": [],
"postTokenBalances": [],
"loadedAddresses": {
"writable": [],
"readonly": []
}
}
},
"id": 1
}

View File

@@ -0,0 +1,35 @@
{
"err": null,
"logs": ["Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success"],
"accounts": [
{
"lamports": 1000,
"data": ["", "base64"],
"owner": "11111111111111111111111111111111",
"executable": false,
"rentEpoch": 0,
"space": 0
},
null
],
"unitsConsumed": 150,
"loadedAccountsDataSize": 64,
"returnData": {
"programId": "11111111111111111111111111111111",
"data": ["AQI=", "base64"]
},
"innerInstructions": [],
"replacementBlockhash": {
"blockhash": "ComputeBudget111111111111111111111111111111",
"lastValidBlockHeight": 430123999
},
"fee": 5000,
"preBalances": [10000, 0],
"postBalances": [5000, 5000],
"preTokenBalances": [],
"postTokenBalances": [],
"loadedAddresses": {
"writable": [],
"readonly": []
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/src/lib.rs // file: crates/ksp-onchain-transport-lib/src/lib.rs
// version: 11 // version: 16
#![warn(missing_docs)] #![warn(missing_docs)]
#![deny(unreachable_pub)] #![deny(unreachable_pub)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
@@ -10,7 +10,9 @@
//! independent from `ksp-config-lib`, Store and Program layers. `ksp-config-lib` now constructs these public settings through its one-way Config -> //! independent from `ksp-config-lib`, Store and Program layers. `ksp-config-lib` now constructs these public settings through its one-way Config ->
//! Transport adapter without creating a reverse dependency. Logical endpoint clients, priority-aware pools, bounded admission limits and retry/no-resend policy //! Transport adapter without creating a reverse dependency. Logical endpoint clients, priority-aware pools, bounded admission limits and retry/no-resend policy
//! are available. The four typed Solana HTTP foundation canaries plus all 22 typed `0.2.2` Accounts, Tokens and Cluster wrappers execute real JSON-RPC //! are available. The four typed Solana HTTP foundation canaries plus all 22 typed `0.2.2` Accounts, Tokens and Cluster wrappers execute real JSON-RPC
//! requests through the shared transport path while the `0.2.3` and `0.2.4` audited families remain staged. //! requests through the shared transport path. `0.2.3` exposes its shared Transaction wire/config primitives and all eleven Transaction wrappers through
//! `pre.007`: eight reads, two write submissions with centralized no-resend protection, and retry-safe `simulateTransaction`, including complete
//! modern/legacy `getTransaction` coverage. The `0.2.4` family remains staged.
mod client; mod client;
mod constants; mod constants;
@@ -25,6 +27,7 @@ mod rpc_cluster;
mod rpc_common; mod rpc_common;
mod rpc_method; mod rpc_method;
mod rpc_tokens; mod rpc_tokens;
mod rpc_transactions;
mod settings; mod settings;
pub(crate) use self::constants::TRACING_TARGET; pub(crate) use self::constants::TRACING_TARGET;
@@ -197,6 +200,44 @@ pub use self::rpc_tokens::SolanaTokenAccountBalance;
pub use self::rpc_tokens::SolanaTokenAccountSelector; pub use self::rpc_tokens::SolanaTokenAccountSelector;
/// Token amount returned by Solana HTTP token RPC methods. /// Token amount returned by Solana HTTP token RPC methods.
pub use self::rpc_tokens::SolanaTokenAmount; pub use self::rpc_tokens::SolanaTokenAmount;
/// Confirmed transaction result returned by `getTransaction` when the RPC result is non-null.
pub use self::rpc_transactions::SolanaConfirmedTransaction;
/// Wire-preserving transaction payload returned by `getTransaction`.
pub use self::rpc_transactions::SolanaEncodedTransaction;
/// Modern configuration object accepted by `getTransaction`.
pub use self::rpc_transactions::SolanaGetTransactionConfig;
/// Blockhash information returned by `getLatestBlockhash` and optionally by simulation.
pub use self::rpc_transactions::SolanaLatestBlockhash;
/// One recent prioritization-fee sample returned by `getRecentPrioritizationFees`.
pub use self::rpc_transactions::SolanaPrioritizationFee;
/// Configuration accepted by `requestAirdrop`.
pub use self::rpc_transactions::SolanaRequestAirdropConfig;
/// Configuration accepted by `sendTransaction` without changing KSP transport retry semantics.
pub use self::rpc_transactions::SolanaSendTransactionConfig;
/// One ordered signature record returned by `getSignaturesForAddress`.
pub use self::rpc_transactions::SolanaSignatureInfo;
/// One non-null position returned by `getSignatureStatuses`.
pub use self::rpc_transactions::SolanaSignatureStatus;
/// Optional historical-search configuration accepted by `getSignatureStatuses`.
pub use self::rpc_transactions::SolanaSignatureStatusesConfig;
/// Pagination and context configuration accepted by `getSignaturesForAddress`.
pub use self::rpc_transactions::SolanaSignaturesForAddressConfig;
/// Configuration accepted by `simulateTransaction`.
pub use self::rpc_transactions::SolanaSimulateTransactionConfig;
/// Rich result payload returned inside the contextual `simulateTransaction` response.
pub use self::rpc_transactions::SolanaSimulateTransactionResult;
/// Account-return configuration nested under `simulateTransaction`.
pub use self::rpc_transactions::SolanaSimulationAccountsConfig;
/// Binary encoding accepted for serialized transaction input payloads.
pub use self::rpc_transactions::SolanaTransactionBinaryEncoding;
/// Confirmation state reported for a signature or transaction status.
pub use self::rpc_transactions::SolanaTransactionConfirmationStatus;
/// Encoding accepted by `getTransaction`, including its retained legacy `binary` alias.
pub use self::rpc_transactions::SolanaTransactionEncoding;
/// Transaction version reported by `getTransaction` when the version field is present.
pub use self::rpc_transactions::SolanaTransactionVersion;
/// Three-state wire field used when Solana distinguishes omission from an explicit JSON `null`.
pub use self::rpc_transactions::SolanaWireField;
/// Open cluster or network descriptor used by HTTP endpoint settings. /// Open cluster or network descriptor used by HTTP endpoint settings.
pub use self::settings::HttpClusterName; pub use self::settings::HttpClusterName;
/// Runtime settings for one role declared by an HTTP endpoint. /// Runtime settings for one role declared by an HTTP endpoint.

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/tests/public_api.rs // file: crates/ksp-onchain-transport-lib/tests/public_api.rs
// version: 9 // version: 15
//! Integration tests for the public `ksp-onchain-transport-lib` consumer contract. //! Integration tests for the public `ksp-onchain-transport-lib` consumer contract.
@@ -243,3 +243,107 @@ fn public_pre_006_remaining_cluster_wrappers_are_available_from_crate_root() {
let request = ksp_onchain_transport_lib::SolanaLeaderScheduleRequest::default(); let request = ksp_onchain_transport_lib::SolanaLeaderScheduleRequest::default();
assert!(matches!(request, ksp_onchain_transport_lib::SolanaLeaderScheduleRequest::CurrentEpoch(std::option::Option::None))); assert!(matches!(request, ksp_onchain_transport_lib::SolanaLeaderScheduleRequest::CurrentEpoch(std::option::Option::None)));
} }
#[test]
fn public_transaction_pre_002_shared_types_are_constructible_from_crate_root() {
let get_transaction = ksp_onchain_transport_lib::SolanaGetTransactionConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::JsonParsed),
std::option::Option::Some(0),
);
assert_eq!(get_transaction.max_supported_transaction_version(), std::option::Option::Some(0));
let send = ksp_onchain_transport_lib::SolanaSendTransactionConfig::new(
std::option::Option::Some(false),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64),
std::option::Option::Some(3),
std::option::Option::None,
);
assert_eq!(send.max_retries(), std::option::Option::Some(3));
let pagination = ksp_onchain_transport_lib::SolanaSignaturesForAddressConfig::new(
std::option::Option::Some("before".to_owned()),
std::option::Option::None,
std::option::Option::Some(10),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized),
std::option::Option::None,
);
assert_eq!(pagination.limit(), std::option::Option::Some(10));
assert!(ksp_onchain_transport_lib::SolanaWireField::<u64>::Omitted.is_omitted());
}
#[test]
fn public_transaction_pre_003_read_wrappers_are_available_from_crate_root() {
let _get_fee_for_message = ksp_onchain_transport_lib::HttpTransportPool::get_fee_for_message;
let _get_latest_blockhash = ksp_onchain_transport_lib::HttpTransportPool::get_latest_blockhash;
let _get_transaction_count = ksp_onchain_transport_lib::HttpTransportPool::get_transaction_count;
let _is_blockhash_valid = ksp_onchain_transport_lib::HttpTransportPool::is_blockhash_valid;
}
#[test]
fn public_transaction_pre_004_additional_read_wrappers_are_available_from_crate_root() {
let _get_recent_prioritization_fees = ksp_onchain_transport_lib::HttpTransportPool::get_recent_prioritization_fees;
let _get_signatures_for_address = ksp_onchain_transport_lib::HttpTransportPool::get_signatures_for_address;
let _get_signature_statuses = ksp_onchain_transport_lib::HttpTransportPool::get_signature_statuses;
}
#[allow(deprecated)]
#[test]
fn public_transaction_pre_005_get_transaction_complete_request_forms_are_available_from_crate_root() {
let _get_transaction = ksp_onchain_transport_lib::HttpTransportPool::get_transaction;
let _get_transaction_legacy = ksp_onchain_transport_lib::HttpTransportPool::get_transaction_legacy;
let config = ksp_onchain_transport_lib::SolanaGetTransactionConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::JsonParsed),
std::option::Option::Some(0),
);
assert_eq!(config.commitment(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed));
assert_eq!(config.encoding(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::JsonParsed));
assert_eq!(config.max_supported_transaction_version(), std::option::Option::Some(0));
}
#[test]
fn public_transaction_pre_006_write_wrappers_and_complete_configs_are_available_from_crate_root() {
let _request_airdrop = ksp_onchain_transport_lib::HttpTransportPool::request_airdrop;
let _send_transaction = ksp_onchain_transport_lib::HttpTransportPool::send_transaction;
let airdrop = ksp_onchain_transport_lib::SolanaRequestAirdropConfig::new(
std::option::Option::Some("recent-blockhash".to_owned()),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed),
);
assert_eq!(airdrop.recent_blockhash(), std::option::Option::Some("recent-blockhash"));
let send = ksp_onchain_transport_lib::SolanaSendTransactionConfig::new(
std::option::Option::Some(false),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64),
std::option::Option::Some(5),
std::option::Option::Some(431_000_000),
);
assert_eq!(send.encoding(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64));
assert_eq!(send.max_retries(), std::option::Option::Some(5));
assert_eq!(send.min_context_slot(), std::option::Option::Some(431_000_000));
}
#[test]
fn public_transaction_pre_007_simulation_wrapper_and_complete_config_are_available_from_crate_root() {
let _simulate_transaction = ksp_onchain_transport_lib::HttpTransportPool::simulate_transaction;
let address = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
let accounts = ksp_onchain_transport_lib::SolanaSimulationAccountsConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaAccountEncoding::Base64Zstd),
std::vec![address],
);
let config = ksp_onchain_transport_lib::SolanaSimulateTransactionConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64),
std::option::Option::Some(false),
std::option::Option::Some(true),
std::option::Option::Some(431_000_000),
std::option::Option::Some(true),
std::option::Option::Some(accounts),
);
assert_eq!(config.commitment(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed));
assert_eq!(config.encoding(), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64));
assert_eq!(config.sig_verify(), std::option::Option::Some(true));
assert_eq!(
config.accounts().and_then(ksp_onchain_transport_lib::SolanaSimulationAccountsConfig::encoding),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaAccountEncoding::Base64Zstd),
);
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs // file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
// version: 6 // version: 13
//! Release-level completeness canaries for the `0.2.1` HTTP foundation contract. //! Release-level completeness canaries for the `0.2.1` HTTP foundation contract.
@@ -194,3 +194,239 @@ fn release_pre_007_v0_2_2_exact_set_is_complete_without_advancing_future_release
assert_eq!(future_transactions, 11); assert_eq!(future_transactions, 11);
assert_eq!(future_blocks_economics, 15); assert_eq!(future_blocks_economics, 15);
} }
#[test]
fn release_v0_2_3_descriptor_set_and_safety_classes_are_exact() {
let mut expected = std::vec![
"getFeeForMessage",
"getLatestBlockhash",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getTransaction",
"getTransactionCount",
"isBlockhashValid",
"requestAirdrop",
"sendTransaction",
"simulateTransaction",
];
let mut actual = std::vec::Vec::new();
let mut reads = 0_usize;
let mut writes = 0_usize;
let mut simulations = 0_usize;
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 {
continue;
}
actual.push(descriptor.method());
match descriptor.operation_kind() {
ksp_onchain_transport_lib::RpcOperationKind::Read => {
reads += 1;
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
},
ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => {
writes += 1;
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
},
ksp_onchain_transport_lib::RpcOperationKind::Simulation => {
simulations += 1;
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
},
}
}
actual.sort_unstable();
expected.sort_unstable();
assert_eq!(actual, expected);
assert_eq!(reads, 8);
assert_eq!(writes, 2);
assert_eq!(simulations, 1);
}
#[test]
fn release_pre_003_transaction_read_subset_is_exact_and_retry_safe() {
let mut expected = std::vec!["getFeeForMessage", "getLatestBlockhash", "getTransactionCount", "isBlockhashValid"];
let mut actual = std::vec::Vec::new();
for method_name in &expected {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.003 Transaction descriptor must exist");
actual.push(descriptor.method());
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
actual.sort_unstable();
expected.sort_unstable();
assert_eq!(actual, expected);
assert_eq!(actual.len(), 4);
}
#[test]
fn release_pre_004_transaction_read_subset_is_exact_and_retry_safe() {
let mut expected = std::vec![
"getFeeForMessage",
"getLatestBlockhash",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getTransactionCount",
"isBlockhashValid",
];
let deferred = std::vec!["getTransaction", "requestAirdrop", "sendTransaction", "simulateTransaction"];
let mut actual = std::vec::Vec::new();
for method_name in &expected {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.004 Transaction descriptor must exist");
actual.push(descriptor.method());
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
for method_name in &deferred {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered");
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
}
actual.sort_unstable();
expected.sort_unstable();
assert_eq!(actual, expected);
assert_eq!(actual.len(), 7);
assert_eq!(deferred.len(), 4);
}
#[test]
fn release_pre_005_transaction_read_subset_adds_complete_get_transaction_without_advancing_writes_or_simulation() {
let mut expected = std::vec![
"getFeeForMessage",
"getLatestBlockhash",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getTransaction",
"getTransactionCount",
"isBlockhashValid",
];
let deferred = std::vec!["requestAirdrop", "sendTransaction", "simulateTransaction"];
let mut actual = std::vec::Vec::new();
for method_name in &expected {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 Transaction descriptor must exist");
actual.push(descriptor.method());
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist");
assert!(get_transaction.request_form_status().has_deprecated_legacy());
for method_name in &deferred {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered");
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
}
actual.sort_unstable();
expected.sort_unstable();
assert_eq!(actual, expected);
assert_eq!(actual.len(), 8);
assert_eq!(deferred.len(), 3);
}
#[test]
fn release_pre_006_transaction_subset_adds_both_write_submissions_without_advancing_simulation() {
let reads = std::vec![
"getFeeForMessage",
"getLatestBlockhash",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getTransaction",
"getTransactionCount",
"isBlockhashValid",
];
let writes = std::vec!["requestAirdrop", "sendTransaction"];
for method_name in &reads {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 read descriptor must exist");
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
for method_name in &writes {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 write descriptor must exist");
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
}
let simulation = ksp_onchain_transport_lib::find_http_rpc_method("simulateTransaction").expect("simulation descriptor must remain registered");
assert_eq!(simulation.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation);
assert_eq!(reads.len(), 8);
assert_eq!(writes.len(), 2);
}
#[test]
fn release_pre_007_completes_all_v0_2_3_transaction_wrappers_with_exact_safety_classes() {
let reads = std::vec![
"getFeeForMessage",
"getLatestBlockhash",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getTransaction",
"getTransactionCount",
"isBlockhashValid",
];
let writes = std::vec!["requestAirdrop", "sendTransaction"];
let simulations = std::vec!["simulateTransaction"];
for method_name in &reads {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 read descriptor must exist");
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
for method_name in &writes {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 write descriptor must exist");
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
}
for method_name in &simulations {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 simulation descriptor must exist");
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation);
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
}
assert_eq!(reads.len(), 8);
assert_eq!(writes.len(), 2);
assert_eq!(simulations.len(), 1);
assert_eq!(reads.len() + writes.len() + simulations.len(), 11);
}
#[test]
fn release_pre_008_ksp_transport_007_retro_audit_covers_all_typed_current_methods() {
let mut audited = std::vec::Vec::<&str>::new();
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
if matches!(
descriptor.coverage_release(),
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1
| ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2
| ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3
) {
audited.push(descriptor.method());
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported);
match descriptor.operation_kind() {
ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => {
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
},
ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => {
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
},
}
}
}
audited.sort_unstable();
assert_eq!(audited.len(), 37);
assert_eq!(audited.first(), std::option::Option::Some(&"getAccountInfo"));
assert_eq!(audited.last(), std::option::Option::Some(&"simulateTransaction"));
let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist");
assert!(get_transaction.request_form_status().has_deprecated_legacy());
}

View File

@@ -1,7 +1,7 @@
// file: crates/ksp-onchain-transport-lib/tests/transport_devnet_smoke.rs // file: crates/ksp-onchain-transport-lib/tests/transport_devnet_smoke.rs
// version: 3 // version: 4
//! Opt-in live Devnet smoke for the pure Transport Accounts/Tokens/Cluster path. //! Opt-in live Devnet smoke for representative pure Transport Accounts/Tokens/Cluster/Transactions reads.
fn devnet_pool() -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpTransportPool> { fn devnet_pool() -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpTransportPool> {
let role = ksp_onchain_transport_lib::HttpRoleName::new("default"); let role = ksp_onchain_transport_lib::HttpRoleName::new("default");
@@ -42,7 +42,7 @@ fn devnet_pool() -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpTranspor
#[tokio::test(flavor = "current_thread")] #[tokio::test(flavor = "current_thread")]
#[ignore = "opt-in live Solana Devnet smoke; performs external network requests"] #[ignore = "opt-in live Solana Devnet smoke; performs external network requests"]
async fn programmatic_devnet_transport_reaches_accounts_tokens_and_cluster_wrappers() { async fn programmatic_devnet_transport_reaches_accounts_tokens_cluster_and_transaction_read_wrappers() {
let pool = devnet_pool().expect("programmatic Devnet Transport settings must construct a pool"); let pool = devnet_pool().expect("programmatic Devnet Transport settings must construct a pool");
let role = ksp_onchain_transport_lib::HttpRoleName::new("default"); let role = ksp_onchain_transport_lib::HttpRoleName::new("default");
@@ -94,4 +94,27 @@ async fn programmatic_devnet_transport_reaches_accounts_tokens_and_cluster_wrapp
let vote_accounts = pool.get_vote_accounts(&role, std::option::Option::None).await.expect("Devnet getVoteAccounts smoke must succeed"); let vote_accounts = pool.get_vote_accounts(&role, std::option::Option::None).await.expect("Devnet getVoteAccounts smoke must succeed");
assert!(!vote_accounts.current().is_empty() || !vote_accounts.delinquent().is_empty()); assert!(!vote_accounts.current().is_empty() || !vote_accounts.delinquent().is_empty());
let transaction_context = ksp_onchain_transport_lib::SolanaContextConfig::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized),
std::option::Option::None,
);
let latest_blockhash = pool
.get_latest_blockhash(&role, std::option::Option::Some(&transaction_context))
.await
.expect("Devnet getLatestBlockhash smoke must succeed");
assert!(!latest_blockhash.value().blockhash().is_empty());
assert!(latest_blockhash.value().last_valid_block_height() > 0);
let blockhash_valid = pool
.is_blockhash_valid(&role, latest_blockhash.value().blockhash(), std::option::Option::Some(&transaction_context))
.await
.expect("Devnet isBlockhashValid smoke must succeed");
assert_eq!(blockhash_valid.value(), &true);
let transaction_count = pool
.get_transaction_count(&role, std::option::Option::Some(&transaction_context))
.await
.expect("Devnet getTransactionCount smoke must succeed");
assert!(transaction_count > 0);
} }

File diff suppressed because it is too large Load Diff

205
deltas/0.2.3/pre.001.md Normal file
View File

@@ -0,0 +1,205 @@
<!-- file: deltas/0.2.3/pre.001.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.001` — réaudit HTTP Transactions, sécurité et sizing
## Base requise
Release stable attendue :
```text
v0.2.2
```
L'archive KSP fournie porte `workspace.package.version = "0.2.2"`. Elle ne contient pas `.git`; le tag `v0.2.2` n'est donc pas revérifiable
localement depuis le zip.
## Objectif
Exécuter la première tranche obligatoire de `0.2.3` sans implémentation fonctionnelle lourde : relire les contrats KSP, réauditer la surface
HTTP Solana officielle actuelle, confirmer la matrice des 11 méthodes Transactions, vérifier les règles de sécurité Read/WriteSubmission/Simulation,
cadrer les DTOs et formes wire, réévaluer les dépendances d'encodage et trancher le gate de sizing.
## Version Cargo
Conformément à `VER-ID-009`, la prerelease non-fix synchronise le signal technique :
```text
0.2.2 -> 0.2.3-pre.1
```
Aucune source Rust, dépendance Cargo ou configuration runtime n'est modifiée dans cette tranche.
## Résultats principaux
- index HTTP Solana courant réaudité : **52 méthodes courantes** ;
- navigation Deprecated officielle : **14 méthodes historiques**, inchangées ;
- les 11 méthodes affectées à `HttpRpcCoverageRelease::V0_2_3` restent exactement :
`getFeeForMessage`, `getLatestBlockhash`, `getRecentPrioritizationFees`, `getSignaturesForAddress`, `getSignatureStatuses`, `getTransaction`,
`getTransactionCount`, `isBlockhashValid`, `requestAirdrop`, `sendTransaction`, `simulateTransaction` ;
- la partition KSP reste donc `0.2.1 = 4`, `0.2.2 = 22`, `0.2.3 = 11`, `0.2.4 = 15` sans avancement prématuré ;
- la classification centrale reste correcte : **8 Read / RetrySafe**, **2 WriteSubmission / NeverAfterDispatch** (`requestAirdrop`, `sendTransaction`),
**1 Simulation / RetrySafe** (`simulateTransaction`) ;
- `sendTransaction.maxRetries` reste une option RPC de retry côté nœud et ne doit jamais être confondue avec la retry policy HTTP KSP ;
- un résultat ambigu après dispatch d'une WriteSubmission (`timeout`, rupture après envoi, HTTP temporaire après dispatch ou équivalent) interdit toute
resoumission automatique par KSP ;
- `getFeeForMessage` transporte un message encodé en base64 et retourne un `RpcResponse` dont la valeur fee est nullable ;
- `getLatestBlockhash` conserve `blockhash` + `lastValidBlockHeight` sous contexte ;
- `getRecentPrioritizationFees` conserve un tableau optionnel d'adresses, borné à **128** par la documentation/runtime courant, et un résultat ordonné
de couples `slot/prioritizationFee` ;
- `getSignaturesForAddress` conserve `before/until/limit`, `minContextSlot`, l'ordre newest-to-oldest et une limite runtime **1..=1000** ;
- la source Agave courante expose aussi `transactionIndex` comme champ optionnel de la structure de signature ; le wire KSP ne doit pas le perdre ;
- `getSignatureStatuses` conserve une cardinalité maximale de **256**, `searchTransactionHistory`, l'ordre positionnel des résultats et les `null`
documentés ; la source Agave courante n'interdit pas un tableau d'entrée vide ;
- `getTransaction` conserve l'objet de config moderne (`commitment`, `encoding`, `maxSupportedTransactionVersion`) et la forme legacy du second paramètre
`encoding` uniquement pour compatibilité, explicitement non recommandée ; son résultat reste nullable et doit préserver les formes transaction/meta/version
sans imposer un modèle Program métier ;
- `requestAirdrop` reste une soumission malgré son rôle de faucet : une signature retournée ou une issue réseau ambiguë n'autorise aucun resend aveugle ;
- `sendTransaction` ne construit ni ne signe la transaction : Transport transmet une transaction déjà construite/signée et préserve les options RPC ;
- `simulateTransaction` reste retry-safe, accepte `base58`/`base64` côté runtime courant, et `sigVerify=true` est incompatible avec
`replaceRecentBlockhash=true` ;
- le résultat courant de simulation comporte de nombreux champs optionnels (`logs`, `accounts`, unités consommées, return data, inner instructions,
replacement blockhash, fee, balances, token balances, loaded addresses) qui doivent être préservés sans décodage Program.
## Gate de sizing
Question obligatoire :
```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.
```
Aucun split de release n'est nécessaire. Le volume est inférieur à `0.2.2`, mais trois fils restent volontairement isolés : `getTransaction`, les
WriteSubmission/no-resend et `simulateTransaction`. Si une tranche réelle dépasse le budget KSP d'environ 1520 minutes, une prerelease
supplémentaire sera créée dans `0.2.3` sans déplacer silencieusement une méthode vers `0.2.4`.
## Décision dépendances et encodages
Aucune nouvelle dépendance n'est ajoutée à `pre.001` :
```text
base64 NON
bs58 NON
wincode NON
solana-client NON
crate RPC/SDK Solana haut niveau NON
```
Transport peut préserver les messages/transactions sérialisés sous forme de chaînes accompagnées d'un enum d'encodage typé. Les validations locales
retenues sont celles qui n'exigent pas de désérialiser la transaction : cardinalités, limites fixes, variantes d'encodage/config autorisées et
incompatibilités de paramètres.
Ajouter uniquement `base64`/`bs58` ne suffirait pas à reproduire correctement les validations runtime actuelles, qui comprennent aussi limites de taille,
désérialisation de message/transaction, versioning et sanitization. Tant qu'aucun besoin KSP concret n'exige ce décodage local, ces contrôles restent la
responsabilité du runtime RPC. Toute future dépendance d'encodage devra être justifiée par un invariant KSP précis et testable.
## Prévision de travail
```text
pre.001 audit officiel + matrice + sécurité + DTOs/wire + dépendances + sizing
pre.002 primitives/configs/results Transactions partagés + fixtures communes
pre.003 reads contextuels : fee/message, latest blockhash, transaction count, blockhash validity
pre.004 prioritization fees + signatures for address + signature statuses
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 réaudit final + canaries + smoke opt-in pertinent + README/USAGE + validation + prompt 0.2.4
```
Une prerelease supplémentaire reste autorisée si le budget réel d'une tranche l'exige.
## Fichiers ajoutés
```text
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
deltas/0.2.3/pre.001.md
```
## Fichiers modifiés
```text
Cargo.toml
ROADMAP.md
docs/000-README.md
docs/plans/000-README.md
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
```
`docs/000-README.md` synchronise aussi son arbre de validation avec le fichier `docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md` déjà
présent dans la release stable mais omis de cet index.
## Fichiers supprimés
Aucun.
## Fichiers volontairement inchangés
```text
CHANGELOG.md
docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md
docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md
docs/validation/003-V0_2_1_ONCHAIN_HTTP.md
docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/**
crates/ksp-onchain-transport-lib/unit_tests/**
crates/ksp-onchain-transport-lib/tests/**
```
Les anciens deltas restent historiques et ne sont pas réécrits.
## Validations exécutées
- relecture des sources KSP obligatoires du prompt `0.2.3` ;
- inspection de l'archive stable KSP fournie et de la surface Transport `0.2.2` ;
- confirmation locale que le registry expose toujours `52 current / 14 historical` et partitionne les releases `4 / 22 / 11 / 15` ;
- confirmation locale que les 11 descriptors `V0_2_3` se répartissent `8 Read/RetrySafe + 2 WriteSubmission/NeverAfterDispatch + 1 Simulation/RetrySafe` ;
- inspection de `execute_standard_rpc`, du mapping de dispatch et de la retry policy centrale pour confirmer l'arrêt après dispatch ambigu d'une
WriteSubmission ;
- consultation de l'index HTTP Solana officiel courant, de `Solana RPC JSON Structures` et des 11 pages Transactions ;
- consultation de la navigation Deprecated officielle courante ;
- consultation des sources primaires Agave liées par la documentation HTTP et cross-audit du tag `v4.2.1` pour configs, cardinalités, unions wire,
champs optionnels, simulation et validations runtime ;
- confirmation du maintien de la compatibilité legacy `getTransaction` sans la présenter comme forme recommandée ;
- contrôle de l'absence de nouvelle dépendance d'encodage/RPC dans `Cargo.toml` et dans le manifest Transport ;
- contrôle que `pre.001` ne modifie aucune source/test Rust ni `CHANGELOG.md`.
## Validations non exécutées
Le sandbox courant ne fournit pas le binaire `cargo` (`command -v cargo` ne retourne aucun chemin). Les validations Cargo suivantes n'ont donc pas
été exécutées ici et doivent être rejouées sur le checkout de développement avant commit :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Aucun `cargo tree` n'est nécessaire dans cette tranche car aucune dépendance ni feature n'a changé. Les quatre vues `cargo tree` du prompt restent
obligatoires à la clôture de `0.2.3` et lors de toute prerelease qui modifierait une dépendance/feature.
L'archive KSP fournie ne contient pas `.git`; le commit attendu après application et validations suit `VER-GIT-001` :
```text
v0.2.3-pre.001
```
## Questions ouvertes
Aucune question bloquante pour `pre.002`.
Les noms Rust définitifs des DTOs restent ajustables pendant l'implémentation, mais les invariants wire, cardinalités, compatibilités et frontières de
sécurité fixés par le plan `010` ne doivent pas être relâchés pour simplifier artificiellement les wrappers.
## Suite
`0.2.3-pre.002` : introduire les primitives/configs/results Transactions partagés et les fixtures déterministes communes avant les premiers wrappers
Transactions.

View File

@@ -0,0 +1,201 @@
<!-- file: deltas/0.2.3/pre.002-fix.001.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.002-fix.001` — Clippy et helpers wire préparatoires
## Base requise
Ce correctif s'applique après :
```text
0.2.3-pre.002
workspace.package.version = "0.2.3-pre.2"
```
Le commit de livraison attendu pour la base est :
```text
v0.2.3-pre.002
```
## Motif du fix
Les validations opérateur du 2026-08-18 ont établi :
```text
cargo fmt --all OK
cargo check --workspace OK avec warnings dead_code
cargo clippy --workspace --all-targets ÉCHEC
cargo test -p ksp-onchain-transport-lib OK
```
Le test Transport a confirmé :
```text
145 unit tests OK
14 public API tests OK
8 release completeness OK
1 smoke Devnet ignored / opt-in
0 échec
```
Le défaut bloquant est `clippy::implicit-return` dans la sérialisation des adresses de `SolanaSimulationAccountsConfig` :
```text
.map(|address| address.to_string())
```
La policy Clippy du workspace exige un `return` explicite y compris dans cette closure.
La même validation a aussi révélé 28 warnings `dead_code` sur les helpers `pub(crate)` / privés préparés par `pre.002` pour les futurs wrappers Transactions. Ces helpers sont exercés par les tests unitaires de `pre.002`, mais n'ont volontairement encore aucun caller dans la bibliothèque non-test puisque les wrappers ne commencent qu'en `pre.003`.
Le fix traite les deux problèmes avant d'ouvrir `pre.003`.
## Version technique
Ce correctif modifie une source Rust de production et une source Rust de test. Conformément au signal technique KSP :
```text
0.2.3-pre.2 -> 0.2.3-pre.2.fix.1
```
Le header du `Cargo.toml` passe de `version: 121` à `version: 122`.
Le commit de livraison attendu est :
```text
v0.2.3-pre.002-fix.001
```
## Correction `clippy::implicit-return`
La conversion des adresses de simulation n'utilise plus une closure `map` dont la dernière expression constitue un retour implicite.
La construction devient volontairement explicite :
```rust
let mut addresses = std::vec::Vec::with_capacity(self.addresses.len());
for address in &self.addresses {
addresses.push(serde_json::Value::String(address.to_string()));
}
```
Le wire produit reste strictement identique : tableau JSON de pubkeys en chaînes, dans l'ordre fourni par le caller.
## Helpers préparatoires et `dead_code`
`pre.002` doit installer les contrats partagés et prouver les formes wire avant que les wrappers ne soient activés. Il ne doit cependant pas injecter dans la build normale une collection de fonctions privées sans caller pendant plusieurs prereleases.
Les helpers strictement internes suivants sont donc compilés uniquement sous `#[cfg(test)]` tant qu'un wrapper réel ne les consomme pas :
- parsing interne `SolanaTransactionBinaryEncoding::from_wire` ;
- `is_empty` / `to_json_value` des configs Transaction ;
- `decode_wire` des résultats partagés ;
- helpers privés de décodage Transaction ;
- DTOs `Wire*` privés utilisés par ces décodeurs.
Cette décision ne retire **aucun type public**, getter public, enum public ou contrat public installé par `pre.002`.
Elle n'ajoute pas non plus de `#[allow(dead_code)]` : le lint reste actif et continue donc de détecter une vraie régression de code inutilisé.
À partir de `pre.003`, chaque tranche rendra disponible hors `#[cfg(test)]` uniquement le sous-ensemble de helpers effectivement utilisé par les wrappers introduits dans cette tranche. Les helpers des méthodes plus tardives restent test-only jusqu'à leur intégration effective.
## Couverture complémentaire des configs
Les deux helpers `is_empty` qui restaient inutilisés même dans la build de tests sont désormais couverts explicitement :
```text
SolanaSignatureStatusesConfig::is_empty
SolanaRequestAirdropConfig::is_empty
```
Les tests vérifient les états non vides et `Default` vide, sans modifier les contrats ni les fixtures.
## Contrats inchangés
Le correctif ne change pas :
- les 19 types publics Transactions installés par `pre.002` ;
- leurs constructeurs/getters publics ;
- `SolanaWireField<T>` et la distinction `Omitted / Null / Value` ;
- les encodings Transaction ;
- les 7 fixtures JSON ;
- le plan `010` version 3 ;
- la partition des 11 méthodes `0.2.3` ;
- les classes de sécurité `8 Read / 2 WriteSubmission / 1 Simulation` ;
- les descriptors centraux ;
- la policy no-resend ;
- les dépendances ;
- la frontière Transport -> Config/Store/Program/tracing ;
- l'absence de wrapper Transaction typed-complete avant `pre.003`.
Aucun fichier historique `pre.002.md` n'est réécrit.
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
```
Headers Rust :
```text
rpc_transactions.rs version 1 -> 2
unit_tests/rpc_transactions.rs version 1 -> 2
```
## Fichier ajouté
```text
deltas/0.2.3/pre.002-fix.001.md
```
## Dépendances
Aucune dépendance ajoutée, supprimée ou modifiée.
La décision `pre.001` reste inchangée :
```text
base64 NON
bs58 NON
wincode NON
solana-client NON
crate RPC SDK NON
```
## Validations à rejouer
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Résultat attendu :
```text
cargo check : aucun warning dead_code issu de rpc_transactions.rs
cargo clippy : 0 erreur et aucun warning dead_code/implicit-return issu de rpc_transactions.rs
Transport : 145 unit tests + 14 public API + 8 release completeness, 0 échec
smoke Devnet : toujours ignored sauf opt-in explicite
```
Aucune validation du fix lui-même n'est déclarée réussie sans exécution réelle sur le dépôt opérateur.
## Suite
Après validation et commit de `v0.2.3-pre.002-fix.001`, reprendre la tranche planifiée :
```text
0.2.3-pre.003
getFeeForMessage
getLatestBlockhash
getTransactionCount
isBlockhashValid
```
`pre.003` devra sortir de `#[cfg(test)]` uniquement les sérialiseurs/décodeurs réellement nécessaires à ces quatre wrappers.

271
deltas/0.2.3/pre.002.md Normal file
View File

@@ -0,0 +1,271 @@
<!-- file: deltas/0.2.3/pre.002.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.002` — primitives Transaction et wire partagé
## Base requise
Livraison précédente :
```text
0.2.3-pre.001
workspace.package.version = "0.2.3-pre.1"
```
Le plan canonique de départ est `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` version 2, avec l'alignement Markdown corrigé par
l'opérateur avant cette tranche.
## Objectif
Installer les primitives, configurations et résultats partagés nécessaires aux 11 wrappers Transactions `0.2.3`, ainsi que des fixtures wire
locales déterministes, sans encore implémenter les quatre premiers wrappers Read prévus pour `pre.003` et sans déclarer la couverture typed
`0.2.3` complète.
Cette tranche doit préserver les unions/nullable/omissions du wire Transaction tout en restant une couche Transport : aucun décodage Program,
aucune construction/signature de transaction et aucun client RPC Solana parallèle ne sont introduits.
## Version Cargo
Conformément à `VER-ID-009`, la nouvelle prerelease synchronise le signal technique :
```text
0.2.3-pre.1 -> 0.2.3-pre.2
```
Aucune dépendance ou feature Cargo n'est ajoutée.
## Implémentation
### Encodings et champs wire
Le nouveau module `rpc_transactions` ajoute :
```text
SolanaTransactionBinaryEncoding
SolanaTransactionEncoding
SolanaWireField<T>
```
`SolanaTransactionBinaryEncoding` borne les entrées sérialisées `sendTransaction`/`simulateTransaction` à `base58 | base64` sans décoder les
bytes. `SolanaTransactionEncoding` conserve la surface plus large de `getTransaction` : `binary` legacy, `base58`, `base64`, `json` et
`jsonParsed`.
`SolanaWireField<T>` matérialise explicitement les trois états qui comptent sur les réponses Transaction évolutives :
```text
Omitted
Null
Value(T)
```
Cette primitive évite de fusionner un champ absent avec un champ explicitement `null`, notamment pour `getTransaction` et
`simulateTransaction`.
### Configurations partagées
Les configurations suivantes sont ajoutées :
```text
SolanaGetTransactionConfig
SolanaSignaturesForAddressConfig
SolanaSignatureStatusesConfig
SolanaRequestAirdropConfig
SolanaSendTransactionConfig
SolanaSimulationAccountsConfig
SolanaSimulateTransactionConfig
```
Elles sérialisent uniquement les options explicitement fournies. `SolanaSendTransactionConfig::max_retries` reste nommé et documenté comme une
limite de retransmission **côté noeud RPC** et ne modifie jamais la retry policy HTTP KSP.
Les validations propres aux wrappers restent volontairement dans leurs tranches d'exécution : limites `128 / 1000 / 256`, encodings Account
interdits pour le retour de simulation et incompatibilité `sigVerify + replaceRecentBlockhash` ne sont pas transformés ici en une seconde policy
parallèle.
### Résultats et DTOs Transaction
Les résultats communs suivants sont ajoutés :
```text
SolanaLatestBlockhash
SolanaPrioritizationFee
SolanaTransactionConfirmationStatus
SolanaSignatureInfo
SolanaSignatureStatus
SolanaEncodedTransaction
SolanaTransactionVersion
SolanaConfirmedTransaction
SolanaSimulateTransactionResult
```
`SolanaEncodedTransaction` conserve séparément :
```text
chaîne binaire legacy
[data, "base58" | "base64"]
objet JSON / jsonParsed
```
Aucun `base64`, `bs58` ou `wincode` n'est donc requis. Les objets Transaction/message riches restent lossless via `serde_json::Value` aux
frontières où Transport ne possède pas de modèle métier.
`SolanaConfirmedTransaction` conserve `meta`, `version` et `transactionIndex` avec la sémantique `Omitted | Null | Value`. Pendant
l'implémentation de cette tranche, le recoupement direct avec Agave `v4.2.1` a confirmé que `EncodedConfirmedTransactionWithStatusMeta` expose
également `transactionIndex: Option<u32>` au top-level de `getTransaction`. Le plan `010` passe donc en version 3 pour enregistrer cette précision
wire additive ; il ne s'agit pas d'un changement de périmètre.
`SolanaSimulateTransactionResult` conserve les champs Agave courants utiles, y compris les comptes positionnels nullable, unités consommées,
loaded account data size, return data, inner instructions, replacement blockhash, fee, balances, token balances et loaded addresses. Les
sous-structures Program/transaction riches restent volontairement opaques lorsqu'un modèle Transport étroit n'apporte pas de valeur.
### Validation de wire locale
Les décodeurs partagés :
- utilisent le domaine d'erreur Transport existant pour les shapes invalides ;
- rejettent un `getLatestBlockhash.blockhash` vide sans tenter de le décoder ;
- rejettent les labels de confirmation inconnus ;
- rejettent les tuples transaction binaires mal formés ou utilisant un encoding non binaire ;
- bornent le champ `version` de `getTransaction` à `legacy | u8` conformément au wire actuel ;
- préservent les `null` positionnels des comptes de simulation.
Ils ne désérialisent ni message ni transaction Solana.
## Fixtures déterministes ajoutées
```text
crates/ksp-onchain-transport-lib/fixtures/http/latest_blockhash.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/prioritization_fee.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/signature_info.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/signature_status.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/encoded_transaction.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_transaction.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction_result.v4_2_1.json
```
Elles couvrent notamment :
- latest blockhash ;
- ordre de samples de prioritization fees ;
- `transactionIndex` présent et absent sur les signatures ;
- `null` positionnel pour les statuses ;
- status legacy encore présent ;
- transaction legacy, tuple base64 et JSON ;
- `meta/version/transactionIndex` présents, `null` ou omis ;
- résultat de simulation riche avec compte positionnel `null` et champs optionnels actuels.
## Tests ajoutés
`unit_tests/rpc_transactions.rs` ajoute **18 tests déterministes** pour les enums/configs/décodeurs/fixtures de cette tranche.
Les tests de surface ajoutent aussi :
- un test public de construction/réexport des primitives Transaction depuis la racine de crate ;
- une canarie de registre qui confirme l'ensemble exact des 11 descriptors `0.2.3` et leur répartition `8 Read / 2 WriteSubmission / 1 Simulation`
sans prétendre que les 11 wrappers typed existent déjà.
La canarie typed-complete `0.2.3 exact == 11` reste donc volontairement fermée jusqu'aux tranches de wrappers.
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
crates/ksp-onchain-transport-lib/fixtures/http/latest_blockhash.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/prioritization_fee.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/signature_info.v4_2_1.json
crates/ksp-onchain-transport-lib/fixtures/http/signature_status.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/encoded_transaction.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/confirmed_transaction.variants.json
crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction_result.v4_2_1.json
deltas/0.2.3/pre.002.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
```
## Fichiers supprimés
Aucun.
## Fichiers volontairement inchangés
```text
CHANGELOG.md
ROADMAP.md
crates/ksp-onchain-transport-lib/Cargo.toml
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/executor.rs
crates/ksp-onchain-transport-lib/src/rpc_method.rs
crates/ksp-config-lib/**
config/**
```
Aucun ancien delta n'est réécrit. Aucun wrapper `0.2.4` n'est avancé.
## Validations exécutées
- reconstruction de la base `0.2.3-pre.001` puis remplacement du plan `010` par la version 2 corrigée fournie par l'opérateur ;
- contrôle différentiel de la tranche contre cette base corrigée ;
- recoupement ciblé des unions/configs/résultats avec les sources primaires Agave `v4.2.1` déjà normatives pour le plan ;
- confirmation additive de `getTransaction.transactionIndex: Option<u32>` dans `EncodedConfirmedTransactionWithStatusMeta` ;
- parse JSON local des sept nouvelles fixtures ;
- contrôle statique des réexports crate-root des nouveaux types publics ;
- contrôle statique de l'absence de nouveau client HTTP, de `reqwest` direct dans le module Transaction, de boucle de retry locale et de wrapper
Transaction exécuté prématurément ;
- contrôle statique de l'absence de nouvelle dépendance/feature Cargo ;
- contrôle statique de l'absence de `unwrap`, `expect`, `panic!` et `?` dans la nouvelle source de production ;
- contrôle statique des lignes Rust modifiées à `<= 160` colonnes ;
- contrôle que `CHANGELOG.md` reste inchangé.
## Validations non exécutées
Le sandbox ne fournit pas `cargo` ni `rustfmt`. Les commandes suivantes ne sont donc pas déclarées comme réussies et doivent être exécutées sur
le checkout de développement avant commit :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Aucun `cargo tree` supplémentaire n'est requis par cette tranche puisqu'aucune dépendance ni feature n'a changé. Les vues de dépendances du prompt
restent obligatoires à la clôture de `0.2.3`.
Le commit attendu après application et validations suit `VER-GIT-001` :
```text
v0.2.3-pre.002
```
## Décisions prises
- conserver les payloads message/transaction sérialisés comme chaînes opaques tant qu'aucun invariant KSP n'exige leur décodage ;
- distinguer l'encoding binaire d'entrée de la surface d'encoding plus large de `getTransaction` ;
- représenter explicitement `absent / null / présent` lorsque le wire courant le nécessite ;
- conserver `serde_json::Value` seulement aux frontières Transaction/Program riches et évolutives, plutôt que dupliquer tout
`solana-transaction-status-client-types` ;
- réutiliser `SolanaContextConfig`, `SolanaAccountEncoding`, `SolanaAccount` et les erreurs Transport existantes ;
- ne pas ajouter les validations de wrapper avant leur tranche propriétaire ;
- ajouter `getTransaction.transactionIndex` au plan et au DTO après confirmation Agave `v4.2.1`.
## Questions ouvertes
Aucune question bloquante pour `pre.003`.
Le formatage canonique final doit être produit par `cargo fmt --all`/`rustfmt` lors de l'application locale, puisque ces binaires ne sont pas
disponibles dans le sandbox d'échange.
## Suite
`0.2.3-pre.003` : implémenter `getFeeForMessage`, `getLatestBlockhash`, `getTransactionCount` et `isBlockhashValid` via le chemin
`descriptor -> execute_standard_rpc`, avec requêtes exactes, résultats contextuels/nullables, erreurs RPC et fixtures HTTP locales.

311
deltas/0.2.3/pre.003.md Normal file
View File

@@ -0,0 +1,311 @@
<!-- file: deltas/0.2.3/pre.003.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.003` — quatre premiers wrappers HTTP Transactions Read
## Base requise
Livraison précédente corrigée et validée localement par l'opérateur :
```text
0.2.3-pre.002-fix.001
workspace.package.version = "0.2.3-pre.2.fix.1"
```
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
145 unit tests
14 public API tests
8 release completeness tests
0 warning signalé par check/clippy
```
Le plan canonique reste `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` version 3.
## Objectif
Implémenter les quatre premiers wrappers Transaction `Read / RetrySafe` prévus par le plan :
```text
getFeeForMessage
getLatestBlockhash
getTransactionCount
isBlockhashValid
```
Tous passent par le chemin HTTP commun :
```text
wrapper typé
-> descriptor Transaction audité
-> execute_standard_rpc
-> pool/admission/retry/deadline
-> executor HTTP
-> validation JSON-RPC
-> décodage DTO KSP
```
Aucun wrapper n'appelle `reqwest` directement et aucune boucle de retry locale n'est ajoutée.
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.3-pre.2.fix.1 -> 0.2.3-pre.3
```
Aucune dépendance ni feature Cargo n'est ajoutée.
## Surface typée ajoutée
### `getFeeForMessage`
Signature publique conceptuelle :
```text
role + message base64 opaque + Option<SolanaContextConfig>
-> SolanaRpcResponse<Option<u64>>
```
Le wrapper :
- conserve le message sérialisé comme chaîne opaque et ne tente ni base64 decode ni désérialisation locale ;
- sérialise `commitment` et `minContextSlot` lorsqu'ils sont présents ;
- omet la config lorsqu'elle est absente ou vide ;
- préserve `value: null` sous `Option::None` ;
- laisse une erreur de décodage/paramètre distante dans le domaine `RPC_APPLICATION_ERROR`.
### `getLatestBlockhash`
Signature publique conceptuelle :
```text
role + Option<SolanaContextConfig>
-> SolanaRpcResponse<SolanaLatestBlockhash>
```
Le wrapper active en production le décodeur `SolanaLatestBlockhash` préparé en `pre.002` et conserve :
```text
blockhash
lastValidBlockHeight
context.slot
context.apiVersion?
```
Un blockhash de réponse vide est rejeté comme `ERROR_CODE_INVALID_RESPONSE`. KSP ne décode pas cryptographiquement la chaîne.
### `getTransactionCount`
Signature publique conceptuelle :
```text
role + Option<SolanaContextConfig>
-> u64
```
La méthode conserve la forme simple du résultat tout en sérialisant la config contextuelle optionnelle dans le tableau `params` exact.
### `isBlockhashValid`
Signature publique conceptuelle :
```text
role + blockhash opaque + Option<SolanaContextConfig>
-> SolanaRpcResponse<bool>
```
Le blockhash d'entrée est transmis tel quel au runtime : `pre.003` n'ajoute ni `solana-hash`, ni validation base58, ni normalisation silencieuse.
## Infrastructure Transaction activée
`rpc_transactions.rs` ajoute un helper interne unique pour les wrappers de cette famille :
```text
execute_transaction_rpc
-> transaction_descriptor
-> execute_standard_rpc
```
`transaction_descriptor` refuse de fonctionner si la méthode demandée n'est pas classée :
```text
HttpRpcCategory::Transactions
HttpRpcCoverageRelease::V0_2_3
```
Les trois réponses contextuelles de cette tranche réutilisent un décodeur interne commun qui préserve `SolanaRpcContext` avant de décoder la
valeur métier.
Seuls les helpers réellement utilisés deviennent production-live dans cette tranche :
```text
SolanaLatestBlockhash::decode_wire
WireLatestBlockhash
invalid_transaction_wire
```
Les décodeurs/configs préparatoires des sept wrappers suivants restent sous `#[cfg(test)]` jusqu'à leur tranche propriétaire afin de conserver
une build non-test sans `dead_code` artificiel.
## Fixtures HTTP déterministes ajoutées
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.null.json
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_latest_blockhash.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_latest_blockhash.invalid_empty.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction_count.success.json
crates/ksp-onchain-transport-lib/fixtures/http/is_blockhash_valid.success.json
```
Les tests utilisent un serveur HTTP loopback local et n'accèdent pas à Internet.
## Couverture de tests ajoutée
Sept tests HTTP unitaires couvrent :
- `getFeeForMessage` avec paramètres exacts et config contextuelle complète ;
- `getFeeForMessage` avec `value: null` et config absente ;
- propagation d'une erreur JSON-RPC applicative pour un message refusé par le runtime ;
- `getLatestBlockhash` avec config explicitement vide, donc omise ;
- rejet d'un blockhash vide renvoyé par le provider ;
- `getTransactionCount` avec commitment ;
- `isBlockhashValid` avec blockhash opaque, commitment et `minContextSlot`.
Le test public compile explicitement les quatre nouvelles méthodes sur `HttpTransportPool`.
Une canarie release fige le sous-ensemble `pre.003` :
```text
getFeeForMessage
getLatestBlockhash
getTransactionCount
isBlockhashValid
```
et vérifie pour chacune :
```text
Transactions / V0_2_3 / Read / RetrySafe
```
La couverture typed complète `0.2.3 exact == 11` reste volontairement fermée : les sept wrappers restants appartiennent aux tranches
`pre.004` à `pre.007`.
Après application, la cible Transport attendue devient :
```text
152 unit tests
15 public API tests
9 release completeness tests
```
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.null.json
crates/ksp-onchain-transport-lib/fixtures/http/get_fee_for_message.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_latest_blockhash.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_latest_blockhash.invalid_empty.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction_count.success.json
crates/ksp-onchain-transport-lib/fixtures/http/is_blockhash_valid.success.json
deltas/0.2.3/pre.003.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.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/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
crates/ksp-onchain-transport-lib/Cargo.toml
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/executor.rs
crates/ksp-onchain-transport-lib/src/rpc_method.rs
crates/ksp-config-lib/**
config/**
```
Aucune méthode `0.2.4` n'est avancée.
## Validations exécutées
- prise en compte de la validation opérateur propre de `pre.002-fix.001` comme base ;
- contrôle JSON syntaxique des sept nouvelles fixtures ;
- contrôle différentiel exact contre la base validée ;
- contrôle statique que les quatre wrappers passent par `execute_transaction_rpc -> execute_standard_rpc` ;
- contrôle statique de l'absence de `reqwest`, `tracing`, client RPC parallèle ou boucle de retry dans `rpc_transactions.rs` ;
- contrôle statique de l'absence de nouvelle dépendance/feature Cargo ;
- contrôle statique des helpers préparatoires restés sous `#[cfg(test)]` ;
- contrôle statique de l'absence de `unwrap`, `expect`, `panic!` et `?` dans la source de production modifiée ;
- contrôle statique des lignes Rust modifiées à `<= 160` colonnes ;
- contrôle que `CHANGELOG.md`, `ROADMAP.md`, le plan `010`, `executor.rs` et `rpc_method.rs` restent inchangés.
## 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. Aucun `cargo tree` n'est requis par cette tranche puisqu'aucune dépendance
ni feature n'a changé.
Le commit attendu après application et validations suit `VER-GIT-001` :
```text
v0.2.3-pre.003
```
## Décisions prises
- réutiliser `SolanaContextConfig` et `SolanaRpcResponse<T>` sans créer de DTO de config redondant ;
- ne pas décoder localement les messages ou blockhashs d'entrée ;
- omettre une config contextuelle explicitement vide ;
- activer en production uniquement les helpers wire réellement consommés par cette tranche ;
- centraliser la sélection des descriptors Transaction sans contourner `execute_standard_rpc` ;
- conserver les erreurs JSON-RPC applicatives comme non-retryables au niveau applicatif.
## Questions ouvertes
Aucune question bloquante pour `pre.004`.
## Suite
`0.2.3-pre.004` : implémenter `getRecentPrioritizationFees`, `getSignaturesForAddress` et `getSignatureStatuses`, avec limites locales exactes
`128 / 1000 / 256`, ordre serveur, pagination et `null` positionnels.

346
deltas/0.2.3/pre.004.md Normal file
View File

@@ -0,0 +1,346 @@
<!-- file: deltas/0.2.3/pre.004.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.004` — lectures Transaction avec cardinalités et statuts positionnels
## Base requise
Livraison précédente validée localement par l'opérateur :
```text
0.2.3-pre.003
workspace.package.version = "0.2.3-pre.3"
```
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
152 unit tests
15 public API tests
9 release completeness tests
0 warning signalé par check/clippy
```
Le plan canonique reste `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` version 3.
## Objectif
Implémenter les trois wrappers Transaction `Read / RetrySafe` prévus par la tranche `pre.004` :
```text
getRecentPrioritizationFees
getSignaturesForAddress
getSignatureStatuses
```
Ils rejoignent les quatre reads de `pre.003`, portant la surface Transaction typée exécutée à :
```text
7 / 11 wrappers
```
Les quatre méthodes restantes restent volontairement différées :
```text
getTransaction
requestAirdrop
sendTransaction
simulateTransaction
```
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.3-pre.3 -> 0.2.3-pre.4
```
Aucune dépendance ni feature Cargo n'est ajoutée.
## `getRecentPrioritizationFees`
Surface publique conceptuelle :
```text
role + Option<&[Pubkey]>
-> Vec<SolanaPrioritizationFee>
```
Le tableau d'adresses reste optionnel :
- `None` omet entièrement le paramètre ;
- `Some(slice)` sérialise exactement un tableau d'adresses ;
- l'ordre des adresses caller est conservé ;
- les résultats restent dans l'ordre renvoyé par le provider.
La cardinalité runtime documentée est appliquée avant I/O :
```text
0..=128 accepté
129+ ERROR_CODE_INVALID_RPC_PARAMETERS
```
Le test couvre explicitement la borne `128` puis le rejet de `129`.
Aucune règle locale n'est créée à partir de la profondeur actuelle de cache des prioritization fees : la valeur d'environ 150 blocs est une
caractéristique runtime du noeud et non une cardinalité client.
## `getSignaturesForAddress`
Surface publique conceptuelle :
```text
role + Pubkey + Option<SolanaSignaturesForAddressConfig>
-> Vec<SolanaSignatureInfo>
```
La config préparée en `pre.002` devient production-live pour cette méthode :
```text
before
until
limit
commitment
minContextSlot
```
Une config absente ou entièrement vide est omise. La limite est validée avant I/O exactement selon le runtime audité :
```text
1..=1000 accepté quand limit est fourni
0 rejeté
1001+ rejeté
```
La fixture de succès utilise explicitement `limit = 1000`, puis les tests rejettent `0` et `1001`.
Le résultat conserve notamment :
```text
signature
slot
err nullable
memo nullable
blockTime nullable
confirmationStatus nullable
transactionIndex optionnel
```
L'ordre `newest -> oldest` du provider n'est jamais retrié côté KSP. Les signatures restent des chaînes wire opaques dans cette release.
Une fixture JSON-RPC d'erreur vérifie qu'une indisponibilité de transaction history reste une `RPC_APPLICATION_ERROR`, sans être transformée en
retry Transport.
## `getSignatureStatuses`
Surface publique conceptuelle :
```text
role + &[String] + Option<SolanaSignatureStatusesConfig>
-> SolanaRpcResponse<Vec<Option<SolanaSignatureStatus>>>
```
La config `searchTransactionHistory` préparée en `pre.002` devient production-live. Une config vide est omise.
Le tableau d'entrée suit exactement la borne Agave auditée :
```text
0..=256 accepté
257+ ERROR_CODE_INVALID_RPC_PARAMETERS
```
Le tableau vide reste volontairement accepté, conformément au runtime `v4.2.1` audité en `pre.001`. La borne `256` est exercée par une fixture
contenant 256 positions `null` et `257` est rejeté avant I/O.
Le résultat conserve strictement la correspondance positionnelle :
```text
entrée[i] <-> value[i]
null -> None
objet -> Some(SolanaSignatureStatus)
```
KSP vérifie maintenant que le provider retourne exactement autant de positions que de signatures demandées. Une longueur différente produit
`ERROR_CODE_INVALID_RESPONSE`, car continuer masquerait la correspondance signature/statut.
Pour un statut présent, les champs suivants restent préservés :
```text
slot
confirmations nullable
status legacy lossless JSON
err nullable
confirmationStatus nullable
```
La forme `status` demeure un champ legacy du wire courant ; elle n'est pas confondue avec les anciennes méthodes RPC Deprecated.
## Helpers activés en production
Seuls les helpers nécessaires à cette tranche quittent `#[cfg(test)]` :
```text
SolanaSignaturesForAddressConfig::{is_empty,to_json_value}
SolanaSignatureStatusesConfig::{is_empty,to_json_value}
SolanaPrioritizationFee::decode_wire
SolanaSignatureInfo::decode_wire
SolanaSignatureStatus::decode_wire
decode_confirmation_status
WirePrioritizationFee
WireSignatureInfo
WireSignatureStatus
```
Les helpers de `getTransaction`, `requestAirdrop`, `sendTransaction` et `simulateTransaction` restent staged/test-only jusqu'à leur tranche
propriétaire. Aucun `#[allow(dead_code)]` n'est introduit.
## Fixtures HTTP déterministes ajoutées
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_recent_prioritization_fees.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.empty.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.max_256.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.count_mismatch.json
```
Les tests HTTP utilisent uniquement un serveur loopback local.
## Couverture de tests ajoutée
Neuf tests unitaires HTTP supplémentaires couvrent :
- paramètres exacts de `getRecentPrioritizationFees` et ordre serveur ;
- omission du paramètre optionnel ;
- acceptation de 128 adresses et rejet local de 129 ;
- pagination/config complète de `getSignaturesForAddress` avec `limit = 1000` ;
- rejet local de `limit = 0` et `limit = 1001` ;
- propagation d'une erreur JSON-RPC applicative ;
- `getSignatureStatuses` avec `searchTransactionHistory = true` et positions `null` ;
- tableau vide + config vide omise ;
- borne 256 acceptée, 257 rejetée et longueur de réponse incohérente rejetée.
Un test public compile les trois nouveaux wrappers depuis la crate root.
Une nouvelle canarie release fige le sous-ensemble Read exécuté cumulé de `pre.003 + pre.004` :
```text
getFeeForMessage
getLatestBlockhash
getRecentPrioritizationFees
getSignaturesForAddress
getSignatureStatuses
getTransactionCount
isBlockhashValid
```
Chaque descriptor reste :
```text
Transactions / V0_2_3 / Read / RetrySafe
```
La canarie confirme aussi que les quatre méthodes différées restent enregistrées dans `V0_2_3` sans les compter comme surface typée achevée.
Après application, la cible Transport attendue devient :
```text
161 unit tests
16 public API tests
10 release completeness tests
```
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_recent_prioritization_fees.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signatures_for_address.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.empty.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.max_256.json
crates/ksp-onchain-transport-lib/fixtures/http/get_signature_statuses.count_mismatch.json
deltas/0.2.3/pre.004.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
```
Restent inchangés dans cette tranche :
```text
CHANGELOG.md
ROADMAP.md
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
crates/ksp-onchain-transport-lib/Cargo.toml
crates/ksp-onchain-transport-lib/src/executor.rs
crates/ksp-onchain-transport-lib/src/resilience.rs
crates/ksp-onchain-transport-lib/src/rpc_method.rs
```
## Contrôles statiques effectués dans l'environnement d'échange
- les sept nouvelles fixtures sont du JSON valide ;
- aucune dépendance n'est ajoutée ;
- aucun `reqwest`, `tracing`, retry local ou client parallèle n'est introduit par le diff ;
- aucun `#[allow(dead_code)]` n'est introduit ;
- les helpers des tranches futures restent `#[cfg(test)]` ;
- aucune ligne Rust modifiée ne dépasse 160 colonnes ;
- `CHANGELOG.md`, `ROADMAP.md`, le plan `010`, `executor.rs`, `resilience.rs` et `rpc_method.rs` restent identiques à `pre.003`.
`cargo`, `rustc` et `rustfmt` ne sont pas installés dans l'environnement d'échange. Aucune validation Cargo de `pre.004` n'est donc déclarée
réussie ici.
## Validation opérateur requise
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
La validation doit notamment confirmer :
```text
0 warning check/clippy
161 unit tests
16 public API tests
10 release completeness tests
```
Le smoke Devnet reste opt-in et n'est pas requis pour cette tranche locale déterministe.
## Hors scope maintenu
`pre.004` ne traite pas :
- `getTransaction` moderne/legacy ;
- `requestAirdrop` ;
- `sendTransaction` ;
- la preuve end-to-end no-resend des writes ;
- `simulateTransaction` ;
- les 15 méthodes `0.2.4` Blocks/Economics ;
- un nouveau smoke cross-crates.
La prochaine tranche reste `pre.005` : `getTransaction` moderne, compatibilité legacy et wire transaction/meta/version.

408
deltas/0.2.3/pre.005.md Normal file
View File

@@ -0,0 +1,408 @@
<!-- file: deltas/0.2.3/pre.005.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.005` — `getTransaction` complet, forme moderne et compatibilité legacy
## Base requise
Livraison précédente validée localement par l'opérateur :
```text
0.2.3-pre.004
workspace.package.version = "0.2.3-pre.4"
```
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
161 unit tests
16 public API tests
10 release completeness tests
0 warning signalé par check/clippy
```
## Objectif
Implémenter `getTransaction` comme huitième wrapper Transaction `Read / RetrySafe` de `0.2.3`, sans réduire la méthode à un sous-ensemble de
convenance.
La tranche couvre :
```text
forme moderne objet
forme bare encoding legacy dépréciée
commitment
encoding
maxSupportedTransactionVersion
result = null
transaction chaîne legacy
transaction tuple base58/base64
transaction JSON/jsonParsed
meta lossless
version legacy/numérique/omise/null
transactionIndex valeur/omission/null
erreurs RPC applicatives
```
Après cette tranche :
```text
8 / 11 wrappers Transactions exécutés
```
Restent différés :
```text
requestAirdrop
sendTransaction
simulateTransaction
```
## Règle générale de complétude RPC
La précision opérateur formulée avant cette tranche devient une règle durable : un wrapper de transport KSP n'est pas considéré complet lorsqu'il
n'expose qu'un sous-ensemble arbitraire des possibilités d'une méthode RPC.
`KSP-TRANSPORT-007` est ajouté dans `docs/rules/RULES_KSP.md` :
- tous les paramètres et champs de config audités doivent rester accessibles ;
- les variantes/overloads courants doivent être exposés ;
- les formes legacy encore supportées restent accessibles avec statut explicite ;
- les contraintes déterministes connues sont appliquées localement lorsque KSP peut le faire sans prendre une responsabilité wire étrangère ;
- les variantes, `null` et omissions significatives de réponse sont préservés ;
- un sous-arbre riche peut rester `serde_json::Value` lorsqu'il est conservé losslessly ;
- toute limitation volontaire doit être explicitement documentée.
`docs/architecture/003-COMPONENT_CONTRACTS.md` est synchronisé avec cette règle.
Le plan `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` passe en version 4 et demande désormais une canarie de complétude sémantique pour les
wrappers de la release, pas uniquement une canarie du nombre de méthodes.
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.3-pre.4 -> 0.2.3-pre.5
```
Aucune dépendance ni feature Cargo n'est ajoutée.
## Surface moderne `getTransaction`
API publique :
```text
HttpTransportPool::get_transaction(
role,
signature,
Option<&SolanaGetTransactionConfig>,
)
-> Result<Option<SolanaConfirmedTransaction>>
```
La signature reste une chaîne base58 opaque pour Transport : KSP ne prend pas de dépendance `solana-signature` uniquement pour répliquer la
validation du provider.
Le second paramètre possède trois usages intentionnels :
```text
None -> second paramètre omis
Some(default config) -> objet moderne explicite {}
Some(config) -> objet moderne avec tous les champs fournis
```
Cette distinction permet d'exposer réellement la forme objet moderne sans empêcher la forme sans second paramètre.
`SolanaGetTransactionConfig` conserve :
```text
commitment
encoding
maxSupportedTransactionVersion
```
La documentation publique courante borne `commitment` à :
```text
confirmed
finalized
```
`processed` est donc rejeté localement avec `ERROR_CODE_INVALID_RPC_PARAMETERS` avant I/O.
`maxSupportedTransactionVersion` reste un `Option<u8>` plutôt qu'une constante figée à `0`, afin de ne pas fermer la surface KSP aux futures
versions wire que le runtime pourra supporter.
## Encodings complets
La documentation publique moderne expose :
```text
base58
base64
json
jsonParsed
```
Agave `v4.2.1` utilise encore `UiTransactionEncoding` pour `RpcTransactionConfig` et accepte également l'alias historique :
```text
binary
```
KSP conserve donc les cinq labels dans `SolanaTransactionEncoding` :
```text
Binary
Base58
Base64
Json
JsonParsed
```
`Binary` est une compatibilité runtime/legacy et n'est pas présenté comme le choix moderne recommandé.
Les cinq labels sont exercés par le wrapper moderne afin de garantir que KSP ne filtre pas une possibilité supportée par le runtime ciblé.
## Forme legacy bare encoding
La documentation Solana courante conserve :
```text
getTransaction(signature, "<encoding>")
```
mais marque explicitement cette forme bare comme dépréciée.
KSP expose donc séparément :
```text
HttpTransportPool::get_transaction_legacy(role, signature, encoding)
```
Cette API :
- est annotée `#[deprecated]` côté Rust ;
- émet un `warn` via `ksp-logging-lib` lorsqu'elle est appelée ;
- sérialise exactement la chaîne d'encoding comme second paramètre ;
- accepte les cinq labels du runtime `v4.2.1` ;
- réutilise exactement le même executor/décodeur que la forme moderne.
Le wrapper legacy ne crée donc ni nouveau client HTTP ni logique de retry parallèle.
## Réponse complète et lossless
`getTransaction` renvoie :
```text
Option<SolanaConfirmedTransaction>
```
`result = null` devient `None` sans être confondu avec une erreur RPC.
Un résultat présent conserve :
```text
slot
blockTime
transaction
meta
version
transactionIndex
```
### Transaction
`SolanaEncodedTransaction` devient production-live et conserve les formes Agave :
```text
LegacyBinary(String)
Binary { data, Base58|Base64 }
Json(serde_json::Value)
```
La variante `Json` couvre `json` et `jsonParsed` sans réimplémenter les structures Program-specific du SDK Solana. Aucun champ n'est supprimé.
### Metadata
`meta` reste :
```text
SolanaWireField<serde_json::Value>
```
Cette représentation conserve :
```text
Omitted
Null
Value(object)
```
La fixture riche couvre notamment les champs actuels :
```text
err
status legacy
fee
preBalances
postBalances
innerInstructions
logMessages
preTokenBalances
postTokenBalances
rewards
loadedAddresses
returnData
computeUnitsConsumed
costUnits
```
Le choix lossless permet aussi de transporter de nouveaux champs provider/Agave sans les effacer avant qu'un modèle KSP plus spécialisé soit
justifié.
### Version et transaction index
`version` conserve :
```text
Omitted
Null
Legacy
Number(u8)
```
`transactionIndex`, présent dans Agave `v4.2.1` mais pas historiquement chez tous les providers, conserve également :
```text
Omitted
Null
Value(u32)
```
Les fixtures préparatoires de `pre.002` qui vérifient déjà ces trois états restent actives.
## Helpers activés en production
Seuls les helpers nécessaires à `getTransaction` quittent `#[cfg(test)]` :
```text
SolanaTransactionBinaryEncoding::from_wire
SolanaGetTransactionConfig::to_json_value
SolanaEncodedTransaction::decode_wire
SolanaTransactionVersion::decode_wire
SolanaConfirmedTransaction::decode_wire
decode_binary_transaction_tuple
decode_transaction_version_field
WireConfirmedTransaction
```
Les helpers write/simulation de `pre.006``pre.007` restent staged/test-only. Aucun `#[allow(dead_code)]` global n'est ajouté.
## Fixtures HTTP déterministes ajoutées
```text
get_transaction.null.json
get_transaction.binary_legacy.json
get_transaction.base58.json
get_transaction.base64.json
get_transaction.json.json
get_transaction.json_parsed.json
get_transaction.error_unsupported_version.json
```
Elles couvrent les formes de résultat et les encodings sans décoder les bytes transactionnels.
## Couverture de tests ajoutée
Sept tests unitaires HTTP supplémentaires couvrent :
- second paramètre omis et objet moderne vide explicite ;
- config moderne complète ;
- rejet local de `commitment=processed` ;
- cinq encodings runtime via la forme moderne ;
- cinq encodings via la forme bare legacy dépréciée ;
- préservation d'un `jsonParsed` riche ;
- préservation du JSON brut, du meta courant, de la version et de `transactionIndex` ;
- erreur RPC `unsupported transaction version` préservée comme `RPC_APPLICATION_ERROR`.
Les tests préparatoires existants continuent en plus à couvrir :
- tuple avec encoding non binaire rejeté ;
- forme de version inconnue rejetée ;
- `meta/version/transactionIndex` omis/null/présents.
Un test public compile les deux request forms depuis la crate root.
Une nouvelle canarie release porte le sous-ensemble Read Transaction exécuté à huit méthodes et vérifie que `getTransaction` conserve
`StableWithDeprecatedLegacy` :
```text
getFeeForMessage
getLatestBlockhash
getRecentPrioritizationFees
getSignaturesForAddress
getSignatureStatuses
getTransaction
getTransactionCount
isBlockhashValid
```
Les trois opérations write/simulation restent différées.
Après application, la cible Transport attendue devient :
```text
168 unit tests
17 public API tests
11 release completeness tests
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
docs/rules/RULES_KSP.md
docs/architecture/003-COMPONENT_CONTRACTS.md
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
```
Fichiers ajoutés :
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.null.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.binary_legacy.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.base58.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.base64.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.json.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.json_parsed.json
crates/ksp-onchain-transport-lib/fixtures/http/get_transaction.error_unsupported_version.json
deltas/0.2.3/pre.005.md
```
`CHANGELOG.md`, `ROADMAP.md`, `rpc_method.rs`, `executor.rs` et `resilience.rs` restent inchangés.
## Validations attendues
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
L'environnement de préparation du delta ne possède pas Cargo/Rustfmt ; ces commandes ne sont donc pas déclarées réussies avant preuve opérateur.

View File

@@ -0,0 +1,159 @@
<!-- file: deltas/0.2.3/pre.006-fix.001.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.006-fix.001` — type URL des fixtures write
## Base requise
Ce correctif s'applique après :
```text
0.2.3-pre.006
workspace.package.version = "0.2.3-pre.6"
```
Le commit de livraison attendu pour la base est :
```text
v0.2.3-pre.006
```
## Motif du fix
Les validations opérateur du 2026-08-18 ont établi :
```text
cargo fmt --all OK
cargo check --workspace OK
cargo clippy --workspace --all-targets ÉCHEC dans lib test
cargo test -p ksp-onchain-transport-lib ÉCHEC à la compilation de lib test
```
Le défaut est strictement situé dans le helper de fixtures HTTP multi-endpoints ajouté par `pre.006` :
```rust
for (index, (url, priority)) in urls.iter().enumerate() {
// ...
HttpEndpointUrl::parse(url)
}
```
`urls` est de type `&[(&str, u32)]`. L'itération par référence produit donc `url: &&str`, alors que `HttpEndpointUrl::parse` attend une valeur implémentant `Into<String>`. `&&str` n'implémente pas cette conversion.
Le compilateur propose correctement de déréférencer une fois la valeur :
```rust
HttpEndpointUrl::parse(*url)
```
Aucun défaut de production, de policy write ou de no-resend n'est mis en évidence par cette erreur ; la compilation échoue avant l'exécution des nouveaux tests de `pre.006`.
## Version technique
Le correctif modifie une source Rust de test. Conformément au signal technique KSP :
```text
0.2.3-pre.6 -> 0.2.3-pre.6.fix.1
```
Le header du `Cargo.toml` passe de `version: 126` à `version: 127`.
Le commit de livraison attendu est :
```text
v0.2.3-pre.006-fix.001
```
## Correction
Dans :
```text
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
```
la construction des endpoints de fixture passe désormais la chaîne référencée elle-même :
```rust
crate::HttpEndpointUrl::parse(*url).expect("fixture URL must parse")
```
Le header du fichier passe de `version: 6` à `version: 7`.
Cette modification ne change ni l'URL, ni l'ordre des endpoints, ni leurs priorités, ni les paramètres de retry. Elle corrige uniquement le niveau de référence transmis au constructeur typé.
## Contrats inchangés
Le correctif ne change pas :
- `requestAirdrop` ;
- `sendTransaction` ;
- leurs configs publiques ;
- les encodings `base58` / `base64` ;
- la distinction `sendTransaction.maxRetries` / retry HTTP KSP ;
- les descriptors `WriteSubmission / NeverAfterDispatch` ;
- la policy centrale no-resend après dispatch ambigu ;
- les fixtures JSON de `pre.006` ;
- le plan `010` ;
- `KSP-TRANSPORT-007` ;
- les dépendances ;
- le nombre ou le contenu fonctionnel des tests ajoutés par `pre.006`.
Aucun fichier de production de `ksp-onchain-transport-lib` n'est modifié.
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
```
## Fichier ajouté
```text
deltas/0.2.3/pre.006-fix.001.md
```
## Dépendances
Aucune dépendance ajoutée, supprimée ou modifiée.
## Validations à rejouer
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Résultat attendu après compilation du test :
```text
175 unit tests
18 public API tests
12 release completeness tests
1 smoke Devnet ignored / opt-in
0 échec
```
Les tests write de `pre.006` doivent notamment pouvoir s'exécuter et démontrer les scénarios no-resend 429 / 503 / timeout ainsi que le fallback autorisé après `NotDispatched`.
Aucune validation du fix lui-même n'est déclarée réussie sans exécution réelle sur le dépôt opérateur.
## Suite
Après validation et commit de :
```text
v0.2.3-pre.006-fix.001
```
reprendre la tranche planifiée :
```text
0.2.3-pre.007
simulateTransaction complet
```
Le réaudit rétroactif `KSP-TRANSPORT-007` reste planifié dans une prerelease dédiée avant la tranche finale de clôture.

282
deltas/0.2.3/pre.006.md Normal file
View File

@@ -0,0 +1,282 @@
<!-- file: deltas/0.2.3/pre.006.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.006` — `requestAirdrop` + `sendTransaction` et preuve no-resend
## Base requise
Livraison précédente validée localement par l'opérateur :
```text
0.2.3-pre.005
workspace.package.version = "0.2.3-pre.5"
```
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
168 unit tests
17 public API tests
11 release completeness tests
0 warning signalé par check/clippy
```
## Objectif
Activer les deux écritures de la famille Transactions :
```text
requestAirdrop
sendTransaction
```
Les deux wrappers restent attachés aux descriptors centraux déjà audités :
```text
RpcOperationKind::WriteSubmission
TransportRetryClass::NeverAfterDispatch
```
Après cette tranche :
```text
10 / 11 wrappers Transactions exécutés
8 Read
2 WriteSubmission
1 Simulation encore différée
```
`simulateTransaction` reste réservée à `pre.007`.
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.3-pre.5 -> 0.2.3-pre.6
```
Aucune dépendance ni feature Cargo n'est ajoutée.
## Complétude `requestAirdrop`
API publique :
```text
HttpTransportPool::request_airdrop(
role,
recipient: &Pubkey,
lamports: u64,
Option<&SolanaRequestAirdropConfig>,
)
-> Result<String>
```
La page publique Solana courante documente `commitment` dans l'objet de config. La source primaire Agave `v4.2.1` conserve en plus :
```text
recentBlockhash: Option<String>
```
KSP l'expose donc conformément à `KSP-TRANSPORT-007` au lieu de réduire la surface au seul exemple/document public visible.
Le résultat reste la signature de transaction retournée par le faucet sous forme de chaîne wire. Transport ne prend pas une dépendance Signature uniquement
pour redécoder une valeur que le provider vient de produire.
Une config vide est canonicalisée vers l'omission du troisième paramètre, syntaxe strictement équivalente autorisée par `KSP-TRANSPORT-007`.
## Complétude `sendTransaction`
API publique :
```text
HttpTransportPool::send_transaction(
role,
transaction: &str,
Option<&SolanaSendTransactionConfig>,
)
-> Result<String>
```
Transport reçoit une transaction déjà construite, signée et encodée. Il ne la décode, ne la signe et ne la modifie pas.
La config expose la surface courante complète :
```text
encoding Base58 | Base64
skipPreflight Option<bool>
preflightCommitment Option<SolanaCommitment>
maxRetries Option<usize>
minContextSlot Option<u64>
```
Les deux encodings binaires sont exercés par fixtures HTTP locales.
Une config vide est canonicalisée vers l'omission du second paramètre.
### Distinction impérative des retries
```text
SolanaSendTransactionConfig.maxRetries = retransmissions node-side après acceptation RPC
HttpRetrySettings = retries HTTP Transport KSP
```
Le premier champ n'accorde aucune permission de resoumission HTTP au wrapper.
## Preuves end-to-end de no-resend
Les tests ne se limitent pas à `evaluate_transport_retry`.
Ils exercent réellement :
```text
wrapper typed
-> descriptor central
-> execute_standard_rpc
-> client HTTP fixture
```
Pour **chacun** de `requestAirdrop` et `sendTransaction`, un serveur local compte les requêtes reçues.
Cas ambigus après dispatch :
```text
HTTP 429 -> erreur rate_limited -> compteur = 1
HTTP 503 -> erreur http_request_failed -> compteur = 1
timeout -> erreur timeout -> compteur = 1
```
Même avec plusieurs retries configurés dans `HttpRetrySettings`, aucune seconde soumission n'est émise après ces trois états ambigus.
Cas explicitement sûr :
```text
connexion refusée -> ERROR_CODE_HTTP_CONNECTION_FAILED -> NotDispatched
```
Avec deux endpoints de même priorité, la première tentative échoue avant dispatch et le retry central peut atteindre le second endpoint. Cette preuve est
exercée séparément pour les deux wrappers.
## Erreurs RPC applicatives
Les fixtures couvrent aussi :
- une erreur `requestAirdrop` de paramètres/blockhash ;
- une erreur `sendTransaction` de preflight/simulation.
Ces réponses restent `ERROR_CODE_RPC_APPLICATION_ERROR` et ne deviennent jamais des retries transport.
## `KSP-TRANSPORT-007` rétroactif
La question opérateur sur les wrappers antérieurs est enregistrée dans le plan `010`.
Les audits `0.2.1`/`0.2.2` avaient déjà recherché la surface complète. Un contrôle ciblé pendant cette tranche confirme notamment l'alignement KSP avec
Agave `v4.2.1` pour :
```text
RpcAccountInfoConfig
RpcProgramAccountsConfig
RpcLargestAccountsConfig
RpcLeaderScheduleConfig
RpcGetVoteAccountsConfig
```
Mais la règle n'était pas encore un critère de clôture nommé. La prévision devient donc :
```text
pre.007 simulateTransaction complet
pre.008 audit rétroactif KSP-TRANSPORT-007 sur 0.2.1 -> 0.2.3 + corrections éventuelles
pre.009 clôture finale documentaire/validation/smoke/prompt 0.2.4
```
Cette tranche supplémentaire évite de transformer la clôture en remédiation fonctionnelle tardive.
## Documentation/source synchronisée
`crates/ksp-onchain-transport-lib/src/lib.rs` est corrigé pour refléter la surface réellement disponible après `pre.006` :
```text
8 reads Transactions
2 write submissions
simulateTransaction encore staged
```
Le plan `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` passe en version 5 et enregistre le nouveau découpage jusqu'à `pre.009`.
`CHANGELOG.md` reste réservé à `0.2.3-rel.001`.
## Tests ajoutés
Sept tests unitaires couvrent :
```text
requestAirdrop config complète + canonicalisation config vide
sendTransaction config complète + base58/base64 + config vide
erreurs RPC applicatives des deux writes
no-resend après HTTP 429 pour les deux writes
no-resend après HTTP 503 pour les deux writes
no-resend après timeout ambigu pour les deux writes
retry/fallback autorisé après connexion NotDispatched pour les deux writes
```
Un test public vérifie la disponibilité des deux wrappers/configs à la racine de crate.
Une canarie release vérifie le sous-ensemble `pre.006` :
```text
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
simulateTransaction encore différée
```
Cible après application :
```text
175 unit tests
18 public API tests
12 release completeness tests
```
## Fichiers du delta
Modifiés :
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
```
Ajoutés :
```text
crates/ksp-onchain-transport-lib/fixtures/http/request_airdrop.success.json
crates/ksp-onchain-transport-lib/fixtures/http/request_airdrop.error.json
crates/ksp-onchain-transport-lib/fixtures/http/send_transaction.success.json
crates/ksp-onchain-transport-lib/fixtures/http/send_transaction.preflight_error.json
deltas/0.2.3/pre.006.md
```
## Validations attendues opérateur
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
L'environnement de préparation du delta ne possède pas Cargo/Rustfmt. Aucune de ces commandes n'est donc déclarée réussie avant preuve opérateur.

313
deltas/0.2.3/pre.007.md Normal file
View File

@@ -0,0 +1,313 @@
<!-- file: deltas/0.2.3/pre.007.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.007` — `simulateTransaction` complet
## Base requise
Livraison précédente corrigée et validée localement par l'opérateur :
```text
0.2.3-pre.006-fix.001
workspace.package.version = "0.2.3-pre.6.fix.1"
```
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
175 unit tests
18 public API tests
12 release completeness tests
1 smoke Devnet ignored / opt-in
0 warning signalé par check/clippy
```
## Objectif
Activer la dernière méthode Transactions de `0.2.3` :
```text
simulateTransaction
```
Après cette tranche :
```text
11 / 11 wrappers Transactions exécutés
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
1 Simulation / RetrySafe
```
La tranche ne décode ni ne construit une transaction Solana et n'ajoute aucune dépendance codec/SDK.
## Version Cargo
Conformément à `VER-ID-009` :
```text
0.2.3-pre.6.fix.1 -> 0.2.3-pre.7
```
Le header du `Cargo.toml` passe de `version: 127` à `version: 128`.
Aucune dépendance ni feature Cargo n'est ajoutée.
## Complétude `KSP-TRANSPORT-007`
La page Solana RPC courante documente pour `simulateTransaction` :
```text
transaction string
commitment
encoding = base58 | base64
replaceRecentBlockhash
sigVerify
minContextSlot
innerInstructions
accounts
```
La source primaire Agave `v4.2.1` confirme les mêmes champs dans `RpcSimulateTransactionConfig`, avec des booléens runtime par défaut à `false`.
KSP expose donc la config complète via `SolanaSimulateTransactionConfig`. Les booléens restent `Option<bool>` côté KSP afin de distinguer l'omission de
l'envoi explicite de `false` sans modifier la sémantique RPC.
Les deux encodings de transaction réellement acceptés sont couverts :
```text
base58
base64
```
La transaction reste une chaîne opaque : Transport ne tente pas de reproduire le décodage, la désérialisation ou la sanitization Agave.
## Sous-config `accounts`
Agave `v4.2.1` utilise `RpcSimulateTransactionAccountsConfig` avec :
```text
encoding: Option<UiAccountEncoding>
addresses: Vec<String>
```
La source runtime rejette explicitement les encodings Account legacy :
```text
binary
base58
```
KSP accepte donc les variantes actuellement compatibles avec ce retour :
```text
base64
base64+zstd
jsonParsed
```
Ces trois variantes sont exercées par tests HTTP. `binary` et `base58` sont rejetées avant I/O avec `ERROR_CODE_INVALID_RPC_PARAMETERS`.
Quand aucun encoding Account n'est fourni, KSP omet le champ et laisse le runtime appliquer son défaut `base64`.
Agave borne dynamiquement le nombre d'adresses demandées au nombre de comptes contenu dans la transaction. Comme KSP ne décode pas la transaction dans
cette release, cette limite reste volontairement côté runtime/provider au lieu d'introduire une validation partielle ou un codec transactionnel.
## Invariant `sigVerify` / `replaceRecentBlockhash`
Agave `v4.2.1` refuse explicitement :
```text
sigVerify = true
replaceRecentBlockhash = true
```
avec l'erreur de paramètres indiquant que `sigVerify` ne peut pas être utilisé avec `replaceRecentBlockhash`.
Cet invariant est déterministe et ne dépend pas du contenu encodé de la transaction. KSP le rejette donc avant toute sélection/exécution HTTP.
## Résultat riche et lossless
`SolanaSimulateTransactionResult` devient le décodeur production du résultat contextualisé.
Les champs courants Agave `v4.2.1` sont tous préservés :
```text
err
logs
accounts
unitsConsumed
loadedAccountsDataSize
returnData
innerInstructions
replacementBlockhash
fee
preBalances
postBalances
preTokenBalances
postTokenBalances
loadedAddresses
```
La page publique Solana résume seulement un sous-ensemble de ces champs. KSP conserve également les champs runtime supplémentaires afin de respecter
`KSP-TRANSPORT-007` et de ne pas perdre de données disponibles.
Les champs optionnels utilisent `SolanaWireField<T>` lorsque l'absence, le `null` explicite et la valeur concrète doivent rester distinguables :
```text
Omitted
Null
Value(T)
```
Les comptes retournés réutilisent `SolanaAccount` et conservent les `null` positionnels. Les sous-arbres Program/SPL riches (`returnData`, inner
instructions, token balances, loaded addresses) restent lossless via `serde_json::Value` aux frontières déjà prévues, sans imposer les crates
transaction-status à Transport.
## Retry de simulation
Le descriptor existant reste :
```text
RpcOperationKind::Simulation
TransportRetryClass::RetrySafe
```
Contrairement à `requestAirdrop` et `sendTransaction`, la simulation n'est pas soumise à la règle no-resend d'une écriture : elle ne diffuse pas la
transaction au cluster.
Un test end-to-end exerce réellement :
```text
simulate_transaction
-> descriptor central
-> execute_standard_rpc
-> HTTP 503
-> retry central
-> HTTP 200
-> résultat typé
```
Le test démontre donc que la classification `RetrySafe` est utilisée par le vrai chemin wrapper/executor et pas uniquement par une fonction pure de
policy.
## Tests ajoutés
Sept tests unitaires ajoutent :
```text
config complète + résultat riche
base58 + canonicalisation config vide
base64 / base64+zstd / jsonParsed pour accounts
rejet avant I/O du conflit sigVerify/replaceRecentBlockhash et de binary/base58 account encoding
préservation omitted/null/value d'un résultat partiel
préservation d'une erreur RPC applicative
retry sûr après HTTP 503 puis succès
```
Un test public vérifie la disponibilité du wrapper et de la config complète à la racine de crate.
Une canarie release vérifie la couverture finale exacte :
```text
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
1 Simulation / RetrySafe
11 / 11 méthodes Transactions V0_2_3
```
Résultat attendu après application :
```text
182 unit tests
19 public API tests
13 release completeness tests
1 smoke Devnet ignored / opt-in
```
## Documentation synchronisée
`crates/ksp-onchain-transport-lib/src/lib.rs` indique désormais que les 11 wrappers Transactions sont actifs après `pre.007`.
`docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` passe en version 6 et enregistre le résultat de la tranche.
Le planning reste :
```text
pre.008 audit rétroactif KSP-TRANSPORT-007 sur 0.2.1 -> 0.2.3 + remédiations éventuelles
pre.009 clôture finale documentaire/validation/smoke/prompt 0.2.4
```
`CHANGELOG.md` reste réservé à `0.2.3-rel.001`.
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/rpc_transactions.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
```
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction.success.json
crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction.partial.json
crates/ksp-onchain-transport-lib/fixtures/http/simulate_transaction.error.json
deltas/0.2.3/pre.007.md
```
## Dépendances
Aucune dépendance ajoutée, supprimée ou modifiée.
En particulier, restent absentes :
```text
base64 direct dans Transport
bs58 direct dans Transport
wincode
solana-client
crate RPC SDK
transaction-status client types
```
## Validations à exécuter
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Aucune commande n'est déclarée réussie sans exécution réelle ou preuve opérateur.
## Suite
Après validation et commit attendu :
```text
v0.2.3-pre.007
```
passer à :
```text
0.2.3-pre.008
réaudit rétroactif KSP-TRANSPORT-007 sur les wrappers HTTP 0.2.1 -> 0.2.3
+ remédiations éventuelles avant la clôture
```

117
deltas/0.2.3/pre.008.md Normal file
View File

@@ -0,0 +1,117 @@
<!-- file: deltas/0.2.3/pre.008.md -->
<!-- version: 1 -->
# Delta `0.2.3-pre.008` — réaudit rétroactif `KSP-TRANSPORT-007`
## Base requise
```text
0.2.3-pre.007
```
La base opérateur a été validée avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-onchain-transport-lib` : 182 tests unitaires, 19 tests public API et 13 tests release completeness passent ; le smoke Devnet Transport reste opt-in/ignored.
## Objectif
Appliquer rétroactivement `KSP-TRANSPORT-007` à tous les wrappers HTTP typés courants livrés depuis `0.2.1`, avant la tranche de clôture finale :
```text
4 Foundation
22 Accounts/Tokens/Cluster
11 Transactions
37 wrappers typés courants
```
L'audit doit détecter toute possibilité RPC supportée mais absente : paramètre, config, overload, forme legacy, contrainte déterministe ou information de réponse significative.
## Audit effectué
Le contrôle croise :
- documentation HTTP Solana courante au 18 août 2026 ;
- Agave `v4.2.1` `rpc.rs` ;
- Agave `v4.2.1` `rpc-client-types/config.rs` ;
- Agave `v4.2.1` `rpc-client-types/response.rs` ;
- Agave `v4.2.1` `transaction-status-client-types/lib.rs` ;
- surfaces publiques et tests KSP existants.
`v4.2.1` reste la génération runtime stable retenue : `v4.2` est recommandée pour adoption générale Mainnet-beta depuis le 10 août 2026 et ses activations Mainnet-beta ont commencé le 17 août 2026. Le `master` Agave est déjà en `4.3.0-alpha` et n'est pas pris comme contrat stable de cette release.
## Verdict
**Aucune remédiation fonctionnelle requise.** Les 37 wrappers couvrent déjà toute la surface sémantique supportée retenue par l'audit.
Le réaudit confirme notamment les extensions KSP qui vont au-delà de certaines pages publiques mais correspondent au runtime Agave : `binary`, `sortResults`, `tokenAccountState`, `clientId`, `inflationRewardsCommissionBps`, `transactionIndex`, `recentBlockhash` et les champs riches de `simulateTransaction`.
La forme bare encoding legacy de `getTransaction` reste distincte et deprecated. Les syntaxes strictement équivalentes restent canonicalisées sans retrait de capacité.
## Modifications
### Version workspace
```text
0.2.3-pre.7 -> 0.2.3-pre.8
```
### Preuve durable
Ajout :
```text
docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md
```
La matrice contient 37 lignes, une par wrapper courant typé.
### Validation index
`docs/validation/000-README.md` référence la nouvelle matrice.
### Canarie release
`crates/ksp-onchain-transport-lib/tests/release_completeness.rs` ajoute une canarie dédiée qui :
- sélectionne exactement les descriptors `V0_2_1`, `V0_2_2` et `V0_2_3` ;
- exige exactement 37 méthodes ;
- exige `RuntimeStatus::Supported` ;
- exige `RetrySafe` pour Read/Simulation ;
- exige `NeverAfterDispatch` pour WriteSubmission ;
- vérifie que `getTransaction` conserve le marqueur de forme legacy deprecated.
### Plan
`docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` enregistre le résultat de `pre.008` et confirme `pre.009` comme tranche de clôture finale.
## Non-modifications intentionnelles
Aucun wrapper, DTO wire/config/result, executor, retry policy, fixture HTTP, dépendance Cargo ou contrat public n'est modifié : l'audit ne révèle aucun manque à corriger.
`CHANGELOG.md` et `ROADMAP.md` restent inchangés ; le changelog reste réservé à la release finale selon les règles du projet.
## Validation opérateur attendue
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Résultat attendu après ajout de la canarie :
```text
182 unit tests
19 public API tests
14 release completeness tests
1 smoke Devnet ignored / opt-in
```
## Commit attendu
```text
v0.2.3-pre.008
```
## Suite
`0.2.3-pre.009` : réaudit final, canaries/smoke opt-in si pertinent, README/USAGE, matrice finale, validations complètes, archivage/nettoyage requis et prompt de démarrage `0.2.4 — HTTP Blocks/Economics`.

293
deltas/0.2.3/pre.009.md Normal file
View File

@@ -0,0 +1,293 @@
<!-- file: deltas/0.2.3/pre.009.md -->
<!-- version: 1 -->
# Delta `v0.2.3-pre.009`
## Base
Base attendue :
```text
v0.2.3-pre.008
```
La base `pre.008` a été validée localement par l'opérateur le 2026-08-18 avec :
```text
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
Résultats Transport communiqués :
```text
182 unit tests passed
19 public API tests passed
14 release completeness tests passed
1 smoke live ignored par défaut
0 failure
0 warning clippy signalé
```
La matrice `docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md` a été corrigée manuellement par l'opérateur pour réaligner son tableau Markdown avant cette validation. Cette version `2` corrigée constitue la base documentaire de `pre.009` et n'est pas réécrite par ce delta.
Version Cargo cible :
```text
0.2.3-pre.9
```
## Objectif
Amener `0.2.3 — HTTP Transactions` au statut **candidate de clôture** sans ajouter de capacité RPC fonctionnelle :
- refaire le dernier contrôle de l'inventaire HTTP officiel ;
- figer la surface candidate 37 wrappers typés, dont 11/11 Transactions ;
- synchroniser README/USAGE et la documentation durable ;
- produire la matrice de clôture `0.2.3` ;
- étendre le smoke Devnet Transport pur à trois reads Transactions sans effet de bord ;
- préparer le prompt `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale` ;
- préparer un `rel.001` strictement publicationnel.
`CHANGELOG.md` reste volontairement inchangé jusqu'à `0.2.3-rel.001`.
## Réaudit officiel final
La documentation Solana courante a été revérifiée le 2026-08-18 :
```text
https://solana.com/docs/rpc/http
https://solana.com/docs/rpc/deprecated/confirmtransaction
https://solana.com/docs/rpc/json-structures
```
Le résultat reste :
```text
52 méthodes HTTP courantes
14 méthodes historiques Deprecated
```
La partition KSP reste donc :
```text
V0_2_1 4
V0_2_2 22
V0_2_3 11
V0_2_4 15
```
Aucun recalibrage du registre n'est requis.
## Surface candidate `0.2.3`
Les 11 wrappers Transactions restent complets conformément au plan et à `KSP-TRANSPORT-007` :
```text
getFeeForMessage
getLatestBlockhash
getRecentPrioritizationFees
getSignaturesForAddress
getSignatureStatuses
getTransaction
getTransactionCount
isBlockhashValid
requestAirdrop
sendTransaction
simulateTransaction
```
Classification :
```text
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
1 Simulation / RetrySafe
```
Le réaudit rétroactif `pre.008` reste la preuve que les 37 wrappers typés courants de `0.2.1``0.2.3` ne manquent aucune possibilité RPC supportée retenue par l'audit.
## Smoke Devnet Transport pur étendu
Le smoke existant reste dans :
```text
crates/ksp-onchain-transport-lib/tests/transport_devnet_smoke.rs
```
Il conserve Accounts/Tokens/Cluster et ajoute trois reads Transaction :
```text
getLatestBlockhash(finalized)
isBlockhashValid(blockhash précédent, finalized)
getTransactionCount(finalized)
```
La branche ajoutée est volontairement sans effet de bord :
- aucun `requestAirdrop` ;
- aucun `sendTransaction` ;
- aucune transaction sérialisée nécessaire ;
- aucune nouvelle ownership boundary.
Les fixtures locales restent les gates déterministes de la surface Transaction complète.
Commande opt-in :
```bash
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
```
## Documentation de clôture
Nouveau document :
```text
docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md
```
Il rassemble :
- inventaire 52+14 ;
- partition 4/22/11/15 ;
- matrice des 11 Transactions ;
- sécurité write/simulation ;
- complétude `KSP-TRANSPORT-007` ;
- canaries déterministes ;
- smoke Transport ;
- firewall de dépendances ;
- commandes de validation de candidate ;
- contrat publicationnel `rel.001`.
README/USAGE Transport passent de la photographie stable `0.2.2` à la candidate `0.2.3-pre.009` avec 37 wrappers typés et 15 Blocks/Economics restants.
## Prompt `0.2.4`
Nouveau prompt :
```text
prompts/009-V0_2_4_START_PROMPT.md
```
Il cible exactement :
```text
10 Blocks
5 Economics
15 wrappers V0_2_4
```
et impose :
- nouvel audit officiel/Agave à `pre.001` ;
- gate de sizing ;
- `KSP-TRANSPORT-007` dès chaque wrapper ;
- réutilisation des wires Account/Transaction existants ;
- traitement explicite des overloads et legacy, notamment `getBlock` ;
- compliance finale 52/52 current + 14/14 historical ;
- préparation du prompt `0.2.5 — Wallet foundation` à la clôture.
## Préparation de `rel.001`
Si toutes les validations de candidate passent :
```text
workspace.package.version -> 0.2.3
ROADMAP : 0.2.3 -> [X]
CHANGELOG : synthèse stable 0.2.3
plan 010 / validation 006 : preuves opérateur finales
deltas/0.2.3/rel.001.md
commit v0.2.3-rel.001
tag stable v0.2.3 après validation
```
Aucun nouveau wrapper, DTO ou comportement runtime ne doit entrer dans `rel.001`.
## Fichiers ajoutés
```text
docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md
prompts/009-V0_2_4_START_PROMPT.md
deltas/0.2.3/pre.009.md
```
## Fichiers modifiés
```text
Cargo.toml
ROADMAP.md
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/tests/transport_devnet_smoke.rs
docs/000-README.md
docs/architecture/004-COMPONENT_INVENTORY.md
docs/plans/000-README.md
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
docs/validation/000-README.md
prompts/000-README.md
```
## Fichiers non modifiés volontairement
```text
CHANGELOG.md
crates/ksp-onchain-transport-lib/src/
crates/ksp-onchain-transport-lib/unit_tests/
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md
```
Aucune dépendance et aucune feature Cargo ne sont ajoutées.
## Contrôles statiques exécutés pendant la préparation
- version Cargo `0.2.3-pre.9` ;
- aucune modification de source Rust de production ;
- aucune modification du registre RPC ou des wrappers ;
- smoke live toujours `#[ignore]` ;
- branche Transaction du smoke strictement read-only ;
- matrice audit rétroactif opérateur conservée byte-for-byte depuis la base corrigée ;
- nouveaux tableaux Markdown alignés ;
- index docs/plans/validation/prompts synchronisés ;
- aucune nouvelle dépendance/feature ;
- archive réextraite puis comparée au payload préparé.
Cargo n'est pas disponible dans l'environnement de préparation ; aucune validation Cargo de `pre.009` n'est donc déclarée réussie ici.
## Validations opérateur requises
```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
cargo tree -p ksp-config-lib
cargo tree -p ksp-config-lib -d
cargo tree -p ksp-config-lib -e features
cargo tree -p ksp-config-lib -e normal
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
cargo test -p ksp-config-lib --test transport_devnet_smoke -- --ignored --nocapture
```
Résultat déterministe Transport attendu avant les smokes live :
```text
182 unit tests
19 public API tests
14 release completeness tests
1 Transport Devnet smoke ignored par défaut
```

144
deltas/0.2.3/rel.001.md Normal file
View File

@@ -0,0 +1,144 @@
<!-- file: deltas/0.2.3/rel.001.md -->
<!-- version: 1 -->
# Delta `v0.2.3-rel.001`
## Base
Base attendue :
```text
v0.2.3-pre.009
```
Version Cargo cible :
```text
0.2.3
```
La candidate `pre.009` a été validée localement par l'opérateur le 2026-08-18 avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets`, les tests ciblés Transport/Config/Core/Config Desk, `cargo test --workspace`, les quatre graphes Cargo pour Transport et Config, puis les deux smokes Devnet opt-in.
## Objectif
Publier `0.2.3 — HTTP Transactions` sans ajouter de capacité fonctionnelle après `pre.009`.
`rel.001` est strictement publicationnelle :
- passage du workspace à la version stable `0.2.3` ;
- clôture `[X]` de `0.2.3` dans le ROADMAP ;
- ajout de l'entrée stable `0.2.3` au CHANGELOG ;
- clôture du plan `010` et de la matrice `validation/006` avec les preuves opérateur ;
- synchronisation des index, de l'inventaire composant et des README/USAGE Transport vers le statut stable ;
- conservation du prompt `prompts/009-V0_2_4_START_PROMPT.md` comme point d'ouverture de `0.2.4`.
Aucun fichier Rust de production, aucune API publique, aucune configuration runtime, aucune dépendance et aucune feature Cargo ne changent dans cette livraison.
## Surface stable publiée
`0.2.3` ajoute exactement 11 wrappers Transactions :
```text
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
1 Simulation / RetrySafe
```
Avec `0.2.1` et `0.2.2`, la surface HTTP typée atteint :
```text
37 wrappers typés courants
52 méthodes HTTP courantes enregistrées
14 méthodes historiques Deprecated / Removed
15 méthodes Blocks/Economics restantes pour 0.2.4
```
Contrats stabilisés notamment : `getFeeForMessage`, latest blockhash, prioritization fees, pagination signatures, statuses positionnels, `getTransaction` moderne + bare encoding legacy deprecated, transaction/version/meta/index lossless, airdrop, soumission signée avec no-resend après dispatch ambigu et `simulateTransaction` complet.
`KSP-TRANSPORT-007` est désormais une règle formelle : un wrapper RPC KSP doit couvrir les possibilités supportées retenues par l'audit — paramètres/options, overloads/formes legacy encore supportés, contraintes déterministes utiles et variantes de réponse pertinentes sans perte. Le réaudit `pre.008` conclut les **37/37 wrappers conformes sans remédiation fonctionnelle**.
## Validation de la candidate
La candidate `0.2.3-pre.009` a confirmé :
```text
cargo fmt --all OK
cargo check --workspace OK
cargo clippy --workspace --all-targets OK
cargo test --workspace OK
```
Transport :
```text
182 unit
19 public API
14 release completeness
1 smoke live ignored par défaut
```
Les tests ciblés Config/Core/Config Desk passent également. Les graphes `cargo tree`, `cargo tree -d`, `cargo tree -e features` et `cargo tree -e normal` ont été inspectés pour Transport et Config. La frontière reste :
```text
ksp-config-lib -> ksp-onchain-transport-lib
ksp-onchain-transport-lib -X-> ksp-config-lib
Transport -X-> Store/Program/tracing direct
```
Les doublons observés restent transitifs/proc-macro, notamment `syn` 2.x/3.x ; aucune seconde stack HTTP KSP n'est introduite.
Les deux smokes ont ensuite été exécutés explicitement :
```text
Transport pur read-only : Accounts/Tokens/Cluster + trois reads Transactions 1 passed
Config -> Transport -> foundation 1 passed
```
Le smoke Config -> Transport reste une exception transitoire cross-crates et devra migrer vers une future surface d'intégration/orchestration/demo lorsqu'elle existera.
## Documentation de clôture
Mises à jour :
```text
CHANGELOG.md
ROADMAP.md
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
docs/000-README.md
docs/architecture/004-COMPONENT_INVENTORY.md
docs/plans/000-README.md
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
docs/validation/000-README.md
docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md
```
La matrice rétroactive `docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`, corrigée par l'opérateur avant `pre.009`, reste inchangée byte-for-byte. Le prompt `prompts/009-V0_2_4_START_PROMPT.md` reste également inchangé et attend la base stable `v0.2.3`.
## Commit et tag
Identifiant de commit attendu :
```text
v0.2.3-rel.001
```
Le tag stable ne doit être créé qu'après application et validation de ce delta :
```text
v0.2.3
```
## Validation finale après application
Comme `rel.001` ne modifie aucun code de production et ne change que le signal de version et la documentation, la gate finale reste :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
```
Après succès : commit `v0.2.3-rel.001`, puis création du tag `v0.2.3`. La prochaine session s'ouvre avec `prompts/009-V0_2_4_START_PROMPT.md`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md --> <!-- file: docs/000-README.md -->
<!-- version: 27 --> <!-- version: 30 -->
# Documentation KSP # Documentation KSP
@@ -41,12 +41,16 @@ docs/
│ ├── 006-V0_1_4_CONFIG_DESKTOP_PLAN.md │ ├── 006-V0_1_4_CONFIG_DESKTOP_PLAN.md
│ ├── 007-V0_2_0_SERIES_PLANNING.md │ ├── 007-V0_2_0_SERIES_PLANNING.md
│ ├── 008-V0_2_1_ONCHAIN_HTTP_PLAN.md │ ├── 008-V0_2_1_ONCHAIN_HTTP_PLAN.md
── 009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md ── 009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md
│ └── 010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
├── validation/ ├── validation/
│ ├── 000-README.md │ ├── 000-README.md
│ ├── 001-V0_1_4_CONFIG_DESKTOP.md │ ├── 001-V0_1_4_CONFIG_DESKTOP.md
│ ├── 002-V0_2_0_SERIES_PLANNING.md │ ├── 002-V0_2_0_SERIES_PLANNING.md
── 003-V0_2_1_ONCHAIN_HTTP.md ── 003-V0_2_1_ONCHAIN_HTTP.md
│ ├── 004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md
│ ├── 005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md
│ └── 006-V0_2_3_HTTP_TRANSACTIONS.md
└── rules/ └── rules/
├── FILE_CONTRACTS.md ├── FILE_CONTRACTS.md
├── PROMPT_STRUCTURE.md ├── PROMPT_STRUCTURE.md
@@ -63,7 +67,7 @@ D'autres sous-répertoires seront ajoutés uniquement lorsque leur rôle aura é
## Documents de planification ## Documents de planification
Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.2` est conservé comme historique clôturé dans [`plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.3 — Configuration foundation` est conservé comme historique clôturé dans [`plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.4 — ksp-app-config-desk` est conservé comme historique clôturé dans [`plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md`](plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md), avec sa matrice finale [`validation/001-V0_1_4_CONFIG_DESKTOP.md`](validation/001-V0_1_4_CONFIG_DESKTOP.md). Son prompt d'ouverture historique reste [`../prompts/004-V0_1_4_START_PROMPT.md`](../prompts/004-V0_1_4_START_PROMPT.md). La release stable `0.2.0` clôt l'audit de bot3 et le découpage de la série. Son plan directeur est conservé comme historique clôturé dans [`plans/007-V0_2_0_SERIES_PLANNING.md`](plans/007-V0_2_0_SERIES_PLANNING.md), avec sa matrice finale [`validation/002-V0_2_0_SERIES_PLANNING.md`](validation/002-V0_2_0_SERIES_PLANNING.md). La release stable `0.2.1 — HTTP Solana foundation` a été ouverte par [`../prompts/006-V0_2_1_START_PROMPT.md`](../prompts/006-V0_2_1_START_PROMPT.md). Son gate de sizing et sa matrice exhaustive sont conservés dans [`plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md), avec la validation finale [`validation/003-V0_2_1_ONCHAIN_HTTP.md`](validation/003-V0_2_1_ONCHAIN_HTTP.md), README/USAGE Transport et le smoke Devnet opt-in de composition Config -> Transport. Le prompt [`../prompts/007-V0_2_2_START_PROMPT.md`](../prompts/007-V0_2_2_START_PROMPT.md) a ouvert la release stable `0.2.2 — HTTP Accounts + Tokens + Cluster`. Son plan clôturé [`plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) conserve l'audit et l'implémentation des 22 wrappers typés, tandis que [`validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) enregistre les validations déterministes, les graphes Cargo et les deux smokes Devnet passés avant publication. Le prompt [`../prompts/008-V0_2_3_START_PROMPT.md`](../prompts/008-V0_2_3_START_PROMPT.md) ouvre la release suivante `0.2.3 — HTTP Transactions`. Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.2` est conservé comme historique clôturé dans [`plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.3 — Configuration foundation` est conservé comme historique clôturé dans [`plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md). Le plan détaillé de la release stable `0.1.4 — ksp-app-config-desk` est conservé comme historique clôturé dans [`plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md`](plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md), avec sa matrice finale [`validation/001-V0_1_4_CONFIG_DESKTOP.md`](validation/001-V0_1_4_CONFIG_DESKTOP.md). Son prompt d'ouverture historique reste [`../prompts/004-V0_1_4_START_PROMPT.md`](../prompts/004-V0_1_4_START_PROMPT.md). La release stable `0.2.0` clôt l'audit de bot3 et le découpage de la série. Son plan directeur est conservé comme historique clôturé dans [`plans/007-V0_2_0_SERIES_PLANNING.md`](plans/007-V0_2_0_SERIES_PLANNING.md), avec sa matrice finale [`validation/002-V0_2_0_SERIES_PLANNING.md`](validation/002-V0_2_0_SERIES_PLANNING.md). La release stable `0.2.1 — HTTP Solana foundation` a été ouverte par [`../prompts/006-V0_2_1_START_PROMPT.md`](../prompts/006-V0_2_1_START_PROMPT.md). Son gate de sizing et sa matrice exhaustive sont conservés dans [`plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md), avec la validation finale [`validation/003-V0_2_1_ONCHAIN_HTTP.md`](validation/003-V0_2_1_ONCHAIN_HTTP.md), README/USAGE Transport et le smoke Devnet opt-in de composition Config -> Transport. Le prompt [`../prompts/007-V0_2_2_START_PROMPT.md`](../prompts/007-V0_2_2_START_PROMPT.md) a ouvert la release stable `0.2.2 — HTTP Accounts + Tokens + Cluster`. Son plan clôturé [`plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) conserve l'audit et l'implémentation des 22 wrappers typés, tandis que [`validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) enregistre les validations déterministes, les graphes Cargo et les deux smokes Devnet passés avant publication. Le prompt [`../prompts/008-V0_2_3_START_PROMPT.md`](../prompts/008-V0_2_3_START_PROMPT.md) a ouvert la release stable `0.2.3 — HTTP Transactions`. Son plan clôturé [`plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) conserve l'audit et l'implémentation des 11 wrappers ; le réaudit [`validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) confirme la complétude des 37 wrappers HTTP typés et [`validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](validation/006-V0_2_3_HTTP_TRANSACTIONS.md) enregistre les validations finales, graphes Cargo et deux smokes Devnet passés avant publication. Le prompt [`../prompts/009-V0_2_4_START_PROMPT.md`](../prompts/009-V0_2_4_START_PROMPT.md) ouvre `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale`.
`IDEAS.md` conserve les pistes et questions qui ne sont pas encore des engagements du roadmap ni des décisions architecturales. `IDEAS.md` conserve les pistes et questions qui ne sont pas encore des engagements du roadmap ni des décisions architecturales.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/003-COMPONENT_CONTRACTS.md --> <!-- file: docs/architecture/003-COMPONENT_CONTRACTS.md -->
<!-- version: 6 --> <!-- version: 7 -->
# Contrats initiaux des composants KSP # Contrats initiaux des composants KSP
@@ -66,6 +66,8 @@ Il ne dépend pas de Config, Store ou Program.
Pour toute surface normative ciblée, toutes les méthodes documentées sont inventoriées/implémentées sauf impossibilité documentée. Les méthodes deprecated/obsolete encore fonctionnelles et unstable/experimental émettent un warning KSP à l'utilisation. Pour toute surface normative ciblée, toutes les méthodes documentées sont inventoriées/implémentées sauf impossibilité documentée. Les méthodes deprecated/obsolete encore fonctionnelles et unstable/experimental émettent un warning KSP à l'utilisation.
La complétude vaut aussi à l'intérieur de chaque opération : paramètres, options, overloads et formes legacy supportées sont exposés, et les variantes de réponse sont préservées sans perte. KSP n'est pas tenu de dupliquer un SDK externe lorsque des sous-arbres wire lossless suffisent.
## Transport off-chain ## Transport off-chain
Aucune `ksp-offchain-transport-api` commune n'est prévue. Aucune `ksp-offchain-transport-api` commune n'est prévue.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/004-COMPONENT_INVENTORY.md --> <!-- file: docs/architecture/004-COMPONENT_INVENTORY.md -->
<!-- version: 10 --> <!-- version: 12 -->
# Inventaire initial des composants KSP # Inventaire initial des composants KSP
@@ -23,7 +23,7 @@ Ce document maintient l'inventaire synthétique des composants retenus ou presse
| Logging | `ksp-logging-lib` | lib | Stable | `0.1.2` | façade unique tracing KSP | | Logging | `ksp-logging-lib` | lib | Stable | `0.1.2` | façade unique tracing KSP |
| Config | `ksp-config-lib` | lib | Stable | `0.1.3` | documents, profils, env et persistence Config | | Config | `ksp-config-lib` | lib | Stable | `0.1.3` | documents, profils, env et persistence Config |
| Config Desk | `ksp-app-config-desk` | app | Stable | `0.1.4` | validation/management Config | | Config Desk | `ksp-app-config-desk` | app | Stable | `0.1.4` | validation/management Config |
| On-chain HTTP | `ksp-onchain-transport-lib` | lib | Stable | `0.2.1` | foundation HTTP + 26 wrappers typés stables après 0.2.2 | | On-chain HTTP | `ksp-onchain-transport-lib` | lib | Stable | `0.2.1` | foundation HTTP + 37 wrappers typés stables après 0.2.3 |
| Wallet | `ksp-wallet-lib` | lib | Retenu | `0.2.5` | `.kspwallet`, secrets, signature, import/export | | Wallet | `ksp-wallet-lib` | lib | Retenu | `0.2.5` | `.kspwallet`, secrets, signature, import/export |
| Wallet Desk | `ksp-app-wallet-desk` | app | Retenu | `0.2.6` | Wallet + Config composite + HTTP/balance | | Wallet Desk | `ksp-app-wallet-desk` | app | Retenu | `0.2.6` | Wallet + Config composite + HTTP/balance |
| Standard WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.7` | WebSocket Solana complet, sessions/subscriptions | | Standard WS | `ksp-onchain-transport-lib` | lib | Retenu | `0.2.7` | WebSocket Solana complet, sessions/subscriptions |
@@ -78,7 +78,7 @@ ksp-data-api
## Transport ## Transport
`ksp-onchain-transport-lib` doit couvrir l'intégralité des opérations documentées de la surface ciblée par chaque release. `0.2.1` stabilise la foundation HTTP et quatre wrappers typés canari. `0.2.2` stabilise 22 wrappers Accounts/Tokens/Cluster supplémentaires, soit 26 wrappers typés au total ; les 26 méthodes Transactions/Blocks/Economics restantes restent affectées à `0.2.3``0.2.4`. Les statuts deprecated/obsolete encore fonctionnels et unstable/experimental restent exposés avec warning runtime KSP. `ksp-onchain-transport-lib` doit couvrir l'intégralité des opérations documentées de la surface ciblée par chaque release. `0.2.1` stabilise la foundation HTTP et quatre wrappers typés canari. `0.2.2` stabilise 22 wrappers Accounts/Tokens/Cluster supplémentaires. `0.2.3` stabilise les 11 Transactions et porte la surface typed à 37 méthodes ; les 15 méthodes Blocks/Economics restent affectées à `0.2.4`, qui exécutera aussi la compliance finale de la surface 52 current + 14 historiques. Les statuts deprecated/obsolete encore fonctionnels et unstable/experimental restent exposés avec warning runtime KSP.
La Config standard Transport appartient à `ksp-config-lib`, qui adapte vers les settings publics du transport ; le transport ne dépend jamais de Config. La Config standard Transport appartient à `ksp-config-lib`, qui adapte vers les settings publics du transport ; le transport ne dépend jamais de Config.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/000-README.md --> <!-- file: docs/plans/000-README.md -->
<!-- version: 34 --> <!-- version: 37 -->
# Plans KSP # Plans KSP
@@ -18,6 +18,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
- [`007-V0_2_0_SERIES_PLANNING.md`](007-V0_2_0_SERIES_PLANNING.md) — plan historique clôturé de la release stable `0.2.0`, ouvert par `pre.001`, consolidé par `pre.002`, audité par `pre.003` puis publié par `rel.001`; il fixe l'ordre `0.2.1+`, la stratégie RAW/CORE/DECODE/SPECIALIZED, les vertical slices Program et le prompt `0.2.1`. - [`007-V0_2_0_SERIES_PLANNING.md`](007-V0_2_0_SERIES_PLANNING.md) — plan historique clôturé de la release stable `0.2.0`, ouvert par `pre.001`, consolidé par `pre.002`, audité par `pre.003` puis publié par `rel.001`; il fixe l'ordre `0.2.1+`, la stratégie RAW/CORE/DECODE/SPECIALIZED, les vertical slices Program et le prompt `0.2.1`.
- [`008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](008-V0_2_1_ONCHAIN_HTTP_PLAN.md) — plan de `0.2.1`, établi par `0.2.1-pre.001`, recalibré par `pre.001-fix.001` et amené en clôture candidate par `pre.007`; il conserve l'inventaire 52 méthodes HTTP courantes + 14 Deprecated historiques, le design Transport/Config et le split de couverture typée sur `0.2.1``0.2.4`. - [`008-V0_2_1_ONCHAIN_HTTP_PLAN.md`](008-V0_2_1_ONCHAIN_HTTP_PLAN.md) — plan de `0.2.1`, établi par `0.2.1-pre.001`, recalibré par `pre.001-fix.001` et amené en clôture candidate par `pre.007`; il conserve l'inventaire 52 méthodes HTTP courantes + 14 Deprecated historiques, le design Transport/Config et le split de couverture typée sur `0.2.1``0.2.4`.
- [`009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — plan clôturé de la release stable `0.2.2`, établi par `pre.001`, corrigé après réaudit Agave v4.2.1 puis exécuté jusqu'à `pre.007-fix.002`; il couvre les 22 wrappers Accounts/Tokens/Cluster, le smoke Transport opt-in et la préparation de `0.2.3`. - [`009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md`](009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md) — plan clôturé de la release stable `0.2.2`, établi par `pre.001`, corrigé après réaudit Agave v4.2.1 puis exécuté jusqu'à `pre.007-fix.002`; il couvre les 22 wrappers Accounts/Tokens/Cluster, le smoke Transport opt-in et la préparation de `0.2.3`.
- [`010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`](010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md) — plan historique clôturé de la release stable `0.2.3 — HTTP Transactions`, ouvert par `pre.001`, exécuté jusqu'à `pre.009` puis publié par `rel.001`; il couvre les 11 méthodes, la classification `8 Read / 2 WriteSubmission / 1 Simulation`, `KSP-TRANSPORT-007`, le no-resend et la préparation de `0.2.4`.
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre. Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md --> <!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
<!-- version: 36 --> <!-- version: 39 -->
# Séquence des releases fonctionnelles KSP # Séquence des releases fonctionnelles KSP
@@ -392,6 +392,8 @@ Chaque `pre.001` réaudite la documentation officielle actuelle. Les méthodes D
`0.2.2-pre.001` a confirmé la partition de 22 méthodes et son fix documentaire a recoupé les formes wire avec Agave v4.2.1. Les tranches `pre.002``pre.006` ont livré les DTOs puis les 5 Accounts, 5 Tokens et 12 Cluster. `pre.007`, puis `pre.007-fix.001` et `pre.007-fix.002`, ont fermé les canaries exactes 22/22, le smoke Devnet Transport pur, README/USAGE, la matrice de validation `004` et le prompt `0.2.3`. `0.2.2-rel.001` publie cette surface stable après validation du workspace et des deux smokes Devnet. Le smoke cross-crates Config -> Transport de `0.2.1` reste séparé et transitoire. `0.2.2-pre.001` a confirmé la partition de 22 méthodes et son fix documentaire a recoupé les formes wire avec Agave v4.2.1. Les tranches `pre.002``pre.006` ont livré les DTOs puis les 5 Accounts, 5 Tokens et 12 Cluster. `pre.007`, puis `pre.007-fix.001` et `pre.007-fix.002`, ont fermé les canaries exactes 22/22, le smoke Devnet Transport pur, README/USAGE, la matrice de validation `004` et le prompt `0.2.3`. `0.2.2-rel.001` publie cette surface stable après validation du workspace et des deux smokes Devnet. Le smoke cross-crates Config -> Transport de `0.2.1` reste séparé et transitoire.
`0.2.3-pre.001` réaudite le 2026-08-18 la catégorie Transactions contre la documentation Solana actuelle et Agave v4.2.1 : les 11 méthodes prévues restent exactes, la classification `8 Read / RetrySafe`, `2 WriteSubmission / NeverAfterDispatch` et `1 Simulation / RetrySafe` reste correcte, et le gate de sizing est positif. `pre.002``pre.007` livrent ensuite les primitives wire puis les 11 wrappers, `pre.008` réaudite rétroactivement `KSP-TRANSPORT-007` sur les 37 wrappers HTTP typés sans remédiation fonctionnelle, et `pre.009` prépare la candidate finale avec documentation, smoke Transport read-only étendu et prompt `0.2.4`. `0.2.3-rel.001` publie cette surface stable après validation du workspace, des graphes Cargo Transport/Config et des deux smokes Devnet. Aucun `base64`, `bs58`, `wincode` ni client RPC Solana supplémentaire n'est ajouté : les payloads sérialisés restent opaques dans Transport tant qu'un besoin de décodage local n'est pas démontré. Le plan détaillé clôturé est `docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md`.
## `0.2.5` — Wallet foundation ## `0.2.5` — Wallet foundation
Mission : créer `ksp-wallet-lib` et le format `.kspwallet`. Mission : créer `ksp-wallet-lib` et le format `.kspwallet`.

View File

@@ -0,0 +1,791 @@
<!-- file: docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md -->
<!-- version: 9 -->
# 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 1520 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<T>` 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<Option<u64>>` | message base64 opaque ; `null` préservé |
| `getLatestBlockhash` | `SolanaContextConfig?` | contexte + `{ blockhash, lastValidBlockHeight }` | blockhash wire non vide ; contexte conservé |
| `getRecentPrioritizationFees` | `Vec<Pubkey>?` | `Vec<{ slot, prioritizationFee }>` | maximum 128 adresses ; ordre serveur conservé |
| `getSignaturesForAddress` | `Pubkey`, config pagination | `Vec<SignatureInfo>` | `limit` `1..=1000`; newest -> oldest; nulls préservés |
| `getSignatureStatuses` | `Vec<signature>`, config history? | contexte + `Vec<Option<SignatureStatus>>` | maximum 256; positions/nulls conservés; tableau vide accepté par Agave courant |
| `getTransaction` | signature, config moderne **ou** encoding bare legacy | `Option<ConfirmedTransaction>` | transaction absente = `null`; encoding/version/meta lossless |
| `getTransactionCount` | `SolanaContextConfig?` | `u64` | forme simple, config contextuelle |
| `isBlockhashValid` | blockhash, `SolanaContextConfig?` | `SolanaRpcResponse<bool>` | 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<String>
blockTime Option<i64>
confirmationStatus Option<Processed|Confirmed|Finalized>
transactionIndex Option<u32>
```
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<SignatureStatus>
```
Un statut présent conserve :
```text
slot u64
confirmations Option<usize/u64>
err transaction error nullable
status forme legacy de résultat, encore présente sur le wire
confirmationStatus Option<Processed|Confirmed|Finalized>
```
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<SolanaCommitment>
encoding Option<TransactionEncoding>
maxSupportedTransactionVersion Option<u8>
```
La compatibilité auditée garde en plus une forme legacy explicite :
```text
getTransaction(signature, "<encoding>")
```
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<i64>
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<u32>` 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<T>` 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<T>` 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<SolanaCommitment>
minContextSlot Option<u64>
limit Option<usize>
before Option<String/newtype signature>
until Option<String/newtype signature>
```
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<String/newtype signature>
searchTransactionHistory Option<bool>
```
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<SolanaCommitment>
recentBlockhash Option<String>
```
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<Base58|Base64>
skipPreflight Option/default false
preflightCommitment Option<SolanaCommitment>
maxRetries Option<usize>
minContextSlot Option<u64>
```
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<SolanaCommitment>
encoding Option<Base58|Base64>
replaceRecentBlockhash bool/default false
sigVerify bool/default false
minContextSlot Option<u64>
innerInstructions bool/default false
accounts Option<SimulationAccountsConfig>
```
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<T>` 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<T>` ;
- 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.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_KSP.md --> <!-- file: docs/rules/RULES_KSP.md -->
<!-- version: 32 --> <!-- version: 33 -->
# Règles spécifiques à KSP # Règles spécifiques à KSP
@@ -255,5 +255,6 @@
- **KSP-REL-015** — Une application Tauri complétée ne crée `PRESENTATION.md` que si elle possède réellement une vue de présentation embarquée ; dans ce cas le fichier est finalisé comme contenu UI sans liens navigables et reste distinct du `README.md` et du `USAGE.md`. - **KSP-REL-015** — Une application Tauri complétée ne crée `PRESENTATION.md` que si elle possède réellement une vue de présentation embarquée ; dans ce cas le fichier est finalisé comme contenu UI sans liens navigables et reste distinct du `README.md` et du `USAGE.md`.
- **KSP-REL-016** — Une prerelease vise environ 15 à 20 minutes de travail effectif. Le `pre.001` dimensionne aussi la release concrète entière : une release doit pouvoir être ouverte, développée, validée et clôturée dans une seule session de chat. Si cette clôture paraît incertaine, la release est scindée avant l'implémentation fonctionnelle lourde ; une version volontairement répartie sur plusieurs sessions est interdite. - **KSP-REL-016** — Une prerelease vise environ 15 à 20 minutes de travail effectif. Le `pre.001` dimensionne aussi la release concrète entière : une release doit pouvoir être ouverte, développée, validée et clôturée dans une seule session de chat. Si cette clôture paraît incertaine, la release est scindée avant l'implémentation fonctionnelle lourde ; une version volontairement répartie sur plusieurs sessions est interdite.
- **KSP-TRANSPORT-006** — Pour une surface de transport explicitement ciblée, KSP inventorie et implémente toutes les méthodes/opérations exposées par la documentation normative retenue, sauf impossibilité technique explicitement documentée. L'inventaire couvre aussi les sections officielles séparées `deprecated`/`obsolete` et `unstable`/`experimental` lorsqu'elles existent. Les opérations deprecated/obsolete encore réellement fonctionnelles et unstable/experimental restent utilisables mais émettent un `warn` via `ksp-logging-lib` à chaque utilisation concernée ; leur statut est décrit par une metadata centralisée et non par des warnings dispersés. - **KSP-TRANSPORT-006** — Pour une surface de transport explicitement ciblée, KSP inventorie et implémente toutes les méthodes/opérations exposées par la documentation normative retenue, sauf impossibilité technique explicitement documentée. L'inventaire couvre aussi les sections officielles séparées `deprecated`/`obsolete` et `unstable`/`experimental` lorsqu'elles existent. Les opérations deprecated/obsolete encore réellement fonctionnelles et unstable/experimental restent utilisables mais émettent un `warn` via `ksp-logging-lib` à chaque utilisation concernée ; leur statut est décrit par une metadata centralisée et non par des warnings dispersés.
- **KSP-TRANSPORT-007** — La complétude d'un wrapper de transport standard couvre toute la surface sémantique de requête auditée : paramètres, options de configuration, variantes/overloads courants, formes legacy encore supportées et contraintes déterministes connues. Les formes de réponse pertinentes sont conservées losslessly, y compris les variantes, `null` et omissions significatives. KSP peut canonicaliser des syntaxes strictement équivalentes et conserver des sous-arbres wire riches via `serde_json::Value` tant qu'aucune information n'est perdue ; toute limitation volontaire d'une possibilité normative/runtime supportée doit être explicitement justifiée et documentée.
- **KSP-FLOW-001** — La progression durable canonique est `RAW -> CORE -> DECODE -> SPECIALIZED`. RAW et CORE ne nécessitent aucun decoder Program ; le passage RAW -> CORE reste une normalisation générique de la blockchain Solana. À partir de DECODE, KSP progresse verticalement par groupe fonctionnel à travers wire, décodage, matérialisation, projection spécialisée si utile, préparation d'exécution, policy, exécution et scénarios de validation. - **KSP-FLOW-001** — La progression durable canonique est `RAW -> CORE -> DECODE -> SPECIALIZED`. RAW et CORE ne nécessitent aucun decoder Program ; le passage RAW -> CORE reste une normalisation générique de la blockchain Solana. À partir de DECODE, KSP progresse verticalement par groupe fonctionnel à travers wire, décodage, matérialisation, projection spécialisée si utile, préparation d'exécution, policy, exécution et scénarios de validation.
- **KSP-FLOW-002** — Un programme ou composant satellite nécessaire à la compréhension, la matérialisation ou l'exécution correcte d'un protocole appartient au groupe de ce protocole. Il n'est pas reporté artificiellement dans une catégorie `trading-adjacent`. - **KSP-FLOW-002** — Un programme ou composant satellite nécessaire à la compréhension, la matérialisation ou l'exécution correcte d'un protocole appartient au groupe de ce protocole. Il n'est pas reporté artificiellement dans une catégorie `trading-adjacent`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/000-README.md --> <!-- file: docs/validation/000-README.md -->
<!-- version: 6 --> <!-- version: 9 -->
# Validations KSP # Validations KSP
@@ -13,3 +13,6 @@ Documents :
- [`002-V0_2_0_SERIES_PLANNING.md`](002-V0_2_0_SERIES_PLANNING.md) — matrice finale de la release stable `0.2.0`, avec audit de cohérence et preuves opérateur de `pre.003`. - [`002-V0_2_0_SERIES_PLANNING.md`](002-V0_2_0_SERIES_PLANNING.md) — matrice finale de la release stable `0.2.0`, avec audit de cohérence et preuves opérateur de `pre.003`.
- [`003-V0_2_1_ONCHAIN_HTTP.md`](003-V0_2_1_ONCHAIN_HTTP.md) — matrice de clôture de `0.2.1 — HTTP Solana foundation`, registry 52+14, résilience, Config -> Transport, quatre canaris et smoke Devnet opt-in. - [`003-V0_2_1_ONCHAIN_HTTP.md`](003-V0_2_1_ONCHAIN_HTTP.md) — matrice de clôture de `0.2.1 — HTTP Solana foundation`, registry 52+14, résilience, Config -> Transport, quatre canaris et smoke Devnet opt-in.
- [`004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée de `0.2.2`, 22 wrappers Accounts/Tokens/Cluster, canaries 52+14, graphes Cargo, smoke Devnet Transport pur, smoke historique Config -> Transport et préparation de `0.2.3`. - [`004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée de `0.2.2`, 22 wrappers Accounts/Tokens/Cluster, canaries 52+14, graphes Cargo, smoke Devnet Transport pur, smoke historique Config -> Transport et préparation de `0.2.3`.
- [`005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) — réaudit rétroactif de complétude `KSP-TRANSPORT-007` des 37 wrappers HTTP typés livrés de `0.2.1` à `0.2.3-pre.007`, avec preuves Solana/Agave et verdict méthode par méthode.
- [`006-V0_2_3_HTTP_TRANSACTIONS.md`](006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée de `0.2.3`, 11 wrappers Transactions, sécurité write/simulation, réaudit 52+14, `KSP-TRANSPORT-007` 37/37, graphes Cargo et deux smokes Devnet passés avant publication stable.

View File

@@ -0,0 +1,137 @@
<!-- file: docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md -->
<!-- version: 2 -->
# Réaudit rétroactif `KSP-TRANSPORT-007` — HTTP `0.2.1` à `0.2.3`
## Objet
Cette matrice est la preuve durable du réaudit rétroactif demandé par `0.2.3-pre.008`. Elle applique explicitement `KSP-TRANSPORT-007` aux **37 wrappers HTTP typés courants** livrés entre `0.2.1` et `0.2.3-pre.007` :
```text
0.2.1 4 wrappers Foundation
0.2.2 5 Accounts + 5 Tokens + 12 Cluster = 22 wrappers
0.2.3 11 Transactions
Total 37 wrappers courants typés
```
Le contrôle porte sur : paramètres obligatoires et optionnels, champs de configuration, overloads/variantes courants, formes legacy encore supportées, contraintes déterministes connues, formes de réponse, `null`/omissions significatives et extensions runtime retenues.
## Sources normatives retenues
Audit effectué le **18 août 2026**.
Sources principales :
- documentation HTTP Solana courante : <https://solana.com/docs/rpc/http> ;
- Agave `v4.2.1`, `rpc/src/rpc.rs` : <https://github.com/anza-xyz/agave/blob/v4.2.1/rpc/src/rpc.rs> ;
- Agave `v4.2.1`, `rpc-client-types/src/config.rs` : <https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/config.rs> ;
- Agave `v4.2.1`, `rpc-client-types/src/response.rs` : <https://github.com/anza-xyz/agave/blob/v4.2.1/rpc-client-types/src/response.rs> ;
- Agave `v4.2.1`, `transaction-status-client-types/src/lib.rs` : <https://github.com/anza-xyz/agave/blob/v4.2.1/transaction-status-client-types/src/lib.rs>.
Le choix de `v4.2.1` est volontaire : la branche `v4.2` est la génération recommandée pour adoption générale Mainnet-beta depuis le 10 août 2026 et ses activations Mainnet-beta ont commencé le 17 août 2026. Le `master` Agave est déjà en `4.3.0-alpha` et n'est pas retenu comme contrat stable pour cette release.
La documentation publique n'énumère pas toujours toutes les extensions runtime. Lorsqu'Agave `v4.2.1` expose une possibilité supplémentaire supportée, KSP la conserve conformément à `KSP-TRANSPORT-007`.
## Verdict global
**Conforme sans remédiation fonctionnelle.** Aucun paramètre, champ de config, overload, forme legacy encore supportée ou variante de réponse pertinente n'est manquant dans les 37 wrappers audités.
Les extensions runtime déjà présentes dans KSP restent nécessaires, notamment :
- `binary` pour les formes Account/Transaction legacy encore comprises par Agave ;
- `sortResults` sur les configs runtime concernées ;
- filtre `tokenAccountState` de `getProgramAccounts` ;
- `clientId` et endpoints étendus de `getClusterNodes` ;
- `inflationRewardsCommissionBps` de `getVoteAccounts` ;
- `transactionIndex` pour signatures/transaction confirmée ;
- `recentBlockhash` de `requestAirdrop` ;
- résultat riche de `simulateTransaction`, y compris balances, token balances, fee et loaded addresses.
Les syntaxes strictement équivalentes restent canonicalisées lorsque cela ne retire aucune capacité. Exemple : l'absence de config et un objet config vide ne nécessitent pas deux APIs publiques distinctes lorsqu'elles ont le même effet RPC. La forme bare encoding dépréciée de `getTransaction`, qui n'est pas strictement équivalente du point de vue du contrat historique, reste au contraire exposée séparément et marquée deprecated.
## Matrice méthode par méthode
| Release | Méthode | Requête auditée / points sensibles | Réponse auditée / points sensibles | Verdict |
|---------|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|----------|
| 0.2.1 | `getBalance` | pubkey + `commitment/minContextSlot` | contexte + `u64` | Conforme |
| 0.2.1 | `getGenesisHash` | aucun paramètre | hash string | Conforme |
| 0.2.1 | `getHealth` | aucun paramètre | `ok` ou erreur RPC de santé | Conforme |
| 0.2.1 | `getVersion` | aucun paramètre | `solana-core`, `feature-set` | Conforme |
| 0.2.2 | `getAccountInfo` | pubkey + encoding/dataSlice/commitment/minContextSlot ; encodings docs + legacy runtime | `Account` ou `null`, data tuple/jsonParsed, `space` | Conforme |
| 0.2.2 | `getLargestAccounts` | commitment/filter + extension runtime `sortResults` | contexte + liste address/lamports | Conforme |
| 0.2.2 | `getMinimumBalanceForRentExemption` | data length + commitment | `u64` | Conforme |
| 0.2.2 | `getMultipleAccounts` | jusqu'à 100 pubkeys + config Account complète | ordre conservé + `null` positionnels + Account complet | Conforme |
| 0.2.2 | `getProgramAccounts` | config Account + filters dataSize/memcmp/tokenAccountState + withContext + sortResults | array nu ou contexte selon `withContext` | Conforme |
| 0.2.2 | `getTokenAccountBalance` | token account + commitment | contexte + amount/decimals/uiAmount/uiAmountString | Conforme |
| 0.2.2 | `getTokenAccountsByDelegate` | delegate + selector exclusif mint/programId + config Account complète | contexte + keyed accounts | Conforme |
| 0.2.2 | `getTokenAccountsByOwner` | owner + selector exclusif mint/programId + config Account complète | contexte + keyed accounts | Conforme |
| 0.2.2 | `getTokenLargestAccounts` | mint + commitment | contexte + ordered token account balances | Conforme |
| 0.2.2 | `getTokenSupply` | mint + commitment | contexte + token amount complet | Conforme |
| 0.2.2 | `getClusterNodes` | aucun paramètre | champs documentés + extensions runtime optionnelles : gossip/rpc/pubsub/tpu/tvu/repair/quic/forwards/vote/version/featureSet/clientId | Conforme |
| 0.2.2 | `getEpochInfo` | commitment/minContextSlot | absoluteSlot/blockHeight/epoch/slotIndex/slotsInEpoch/transactionCount nullable | Conforme |
| 0.2.2 | `getEpochSchedule` | aucun paramètre | cinq champs schedule | Conforme |
| 0.2.2 | `getHighestSnapshotSlot` | aucun paramètre | full + incremental nullable ; erreur RPC absence snapshot | Conforme |
| 0.2.2 | `getIdentity` | aucun paramètre | pubkey identité | Conforme |
| 0.2.2 | `getLeaderSchedule` | current epoch ou slot ; config identity/commitment ; overload config-only/slot+config canonicalisé explicitement | map identité -> indices ou `null` | Conforme |
| 0.2.2 | `getMaxRetransmitSlot` | aucun paramètre | `u64` | Conforme |
| 0.2.2 | `getMaxShredInsertSlot` | aucun paramètre | `u64` | Conforme |
| 0.2.2 | `getSlot` | commitment/minContextSlot | `u64` | Conforme |
| 0.2.2 | `getSlotLeader` | commitment/minContextSlot | pubkey | Conforme |
| 0.2.2 | `getSlotLeaders` | start slot + limit `1..=5000` | ordered pubkeys | Conforme |
| 0.2.2 | `getVoteAccounts` | commitment/votePubkey/keepUnstakedDelinquents/delinquentSlotDistance | current+delinquent, epochCredits, commission + inflationRewardsCommissionBps optionnel | Conforme |
| 0.2.3 | `getFeeForMessage` | message base64 opaque + commitment/minContextSlot | contexte + fee `u64` ou `null` | Conforme |
| 0.2.3 | `getLatestBlockhash` | commitment/minContextSlot | contexte + blockhash/lastValidBlockHeight | Conforme |
| 0.2.3 | `getRecentPrioritizationFees` | liste optionnelle de comptes, max 128 | liste ordonnée slot/prioritizationFee | Conforme |
| 0.2.3 | `getSignaturesForAddress` | address + before/until/limit `1..=1000`/commitment/minContextSlot | newest-first ; err/memo/blockTime/confirmationStatus/transactionIndex optionnels | Conforme |
| 0.2.3 | `getSignatureStatuses` | jusqu'à 256 signatures + searchTransactionHistory ; liste vide acceptée runtime | contexte + `null` positionnels + status legacy/current | Conforme |
| 0.2.3 | `getTransaction` | forme objet moderne complète + bare encoding legacy deprecated ; encodings binary/base58/base64/json/jsonParsed ; confirmed/finalized ; maxSupportedTransactionVersion | `null` ou transaction binaire/JSON/jsonParsed ; meta/version/transactionIndex conservés losslessly | Conforme |
| 0.2.3 | `getTransactionCount` | commitment/minContextSlot | `u64` | Conforme |
| 0.2.3 | `isBlockhashValid` | blockhash opaque + commitment/minContextSlot | contexte + bool | Conforme |
| 0.2.3 | `requestAirdrop` | recipient + lamports + commitment + extension runtime recentBlockhash | signature string | Conforme |
| 0.2.3 | `sendTransaction` | transaction opaque base58/base64 + skipPreflight/preflightCommitment/maxRetries/minContextSlot | signature string ; no-resend KSP après dispatch ambigu | Conforme |
| 0.2.3 | `simulateTransaction` | base58/base64 + commitment/replaceRecentBlockhash/sigVerify/minContextSlot/innerInstructions/accounts ; encodings comptes supportés ; invariant sigVerify/replace | contexte + résultat riche complet et états null/omitted | Conforme |
## Contrôles transverses
### Encodings Account
KSP expose `binary`, `base58`, `base64`, `jsonParsed` et `base64+zstd`. Les pages Solana courantes mettent surtout en avant `base58/base64/base64+zstd/jsonParsed`, mais Agave conserve la variante `Binary` pour compatibilité. La sous-config `accounts` de `simulateTransaction` rejette spécifiquement `binary/base58`; KSP applique cette contrainte avant I/O tout en conservant les autres encodings supportés.
### Overloads et formes legacy
- `getLeaderSchedule` conserve les formes current epoch, slot, config et slot+config via un enum de requête non ambigu ;
- `getTransaction` conserve la forme moderne et le bare encoding legacy séparé, explicitement deprecated ;
- les configs vides/absentes strictement équivalentes sont canonicalisées sans perte de capacité.
### Cardinalités
Les bornes déterministes connues et testables sans décodage métier sont déjà appliquées avant I/O :
```text
getMultipleAccounts <= 100
getProgramAccounts filters <= 4
memcmp raw bytes <= 128 bytes
getSlotLeaders 1..=5000
getRecentPrioritizationFees <= 128 comptes
getSignaturesForAddress.limit 1..=1000
getSignatureStatuses <= 256 signatures
```
La limite de `simulateTransaction.accounts.addresses` dépend du nombre de comptes de la transaction sérialisée et reste donc une validation runtime : Transport ne décode pas la transaction uniquement pour reproduire cette vérification.
### Résilience
Les 37 descriptors restent `Supported`. Les lectures et la simulation restent `RetrySafe`. `requestAirdrop` et `sendTransaction` restent `WriteSubmission / NeverAfterDispatch`, avec retry autorisé uniquement si Transport prouve `NotDispatched`.
## Remédiations de `pre.008`
Aucune remédiation fonctionnelle n'est requise par cet audit. Ajouter artificiellement des variantes ou des DTOs aurait au contraire créé des doublons sans possibilité RPC supplémentaire.
`pre.008` ajoute donc uniquement :
- cette matrice de preuve durable ;
- une canarie release explicitement nommée `KSP-TRANSPORT-007` couvrant les 37 descriptors `0.2.1``0.2.3` et leurs classes de retry ;
- la synchronisation du plan `0.2.3` ;
- l'incrément technique `0.2.3-pre.8`, car la canarie Rust participe au build/test.
La tranche suivante reste `pre.009`, réservée à la clôture finale, la documentation utilisateur, les canaries/smokes pertinents, la validation complète et le prompt de démarrage `0.2.4`.

View File

@@ -0,0 +1,252 @@
<!-- file: docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md -->
<!-- version: 2 -->
# Validation finale `0.2.3` — HTTP Transactions
## Objet
Cette matrice enregistre la clôture validée et la publication stable de `0.2.3 — HTTP Transactions`.
Elle complète le réaudit transversal [`005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md), qui vérifie la complétude de requête/réponse des 37 wrappers HTTP typés courants.
La publication stable est réalisée par `0.2.3-rel.001` après validation opérateur complète de `pre.009`.
## Réaudit final de l'inventaire
Dernier contrôle effectué le **18 août 2026** contre :
```text
https://solana.com/docs/rpc/http
https://solana.com/docs/rpc/deprecated/confirmtransaction
https://solana.com/docs/rpc/json-structures
```
L'inventaire reste :
```text
52 méthodes HTTP courantes
14 méthodes historiques Deprecated
```
Partition KSP stable :
```text
0.2.1 foundation 4
0.2.2 Accounts/Tokens/Cluster 22
0.2.3 Transactions 11
surface typée stable 37
0.2.4 Blocks/Economics restant 15
```
Aucun recalibrage de `HttpRpcCoverageRelease` n'est nécessaire.
## Surface Transactions stable
| Méthode | Classe KSP | Contrat de clôture principal |
|-------------------------------|--------------------------------------|-------------------------------------------------------------------------------------------------|
| `getFeeForMessage` | Read / RetrySafe | message base64 opaque, contexte, fee nullable |
| `getLatestBlockhash` | Read / RetrySafe | contexte, blockhash non vide, lastValidBlockHeight |
| `getRecentPrioritizationFees` | Read / RetrySafe | comptes optionnels <= 128, ordre serveur |
| `getSignaturesForAddress` | Read / RetrySafe | pagination before/until/1..=1000, newest-first, transactionIndex optionnel |
| `getSignatureStatuses` | Read / RetrySafe | <= 256, liste vide runtime, null positionnels, searchTransactionHistory |
| `getTransaction` | Read / RetrySafe | config moderne complète + bare encoding deprecated, encodings/version/meta/index lossless |
| `getTransactionCount` | Read / RetrySafe | contexte + u64 |
| `isBlockhashValid` | Read / RetrySafe | blockhash opaque + contexte + bool |
| `requestAirdrop` | WriteSubmission / NeverAfterDispatch | commitment + recentBlockhash runtime, signature, aucune resoumission après dispatch ambigu |
| `sendTransaction` | WriteSubmission / NeverAfterDispatch | base58/base64 + toutes options, maxRetries node-side, aucune resoumission après dispatch ambigu |
| `simulateTransaction` | Simulation / RetrySafe | config complète, invariants locaux, résultat riche lossless |
Classification exacte :
```text
8 Read / RetrySafe
2 WriteSubmission / NeverAfterDispatch
1 Simulation / RetrySafe
```
## Complétude `KSP-TRANSPORT-007`
Le réaudit `pre.008` conclut **37/37 conformes sans remédiation fonctionnelle**.
Points particulièrement sensibles conservés :
- encodings Account/Transaction legacy encore supportés ;
- `getLeaderSchedule` et `getTransaction` avec leurs formes de requête distinctes ;
- `transactionIndex` courant ;
- `requestAirdrop.recentBlockhash` runtime ;
- `sendTransaction.maxRetries` distinct du retry HTTP KSP ;
- `simulateTransaction.accounts` avec encodings de retour supportés et rejet local de `binary/base58` ;
- résultats wire riches conservés sans introduire de dépendance SDK/RPC haut niveau.
## Résilience et no-resend
Les deux writes utilisent le descriptor central `WriteSubmission / NeverAfterDispatch`.
Les fixtures end-to-end déjà livrées prouvent :
```text
HTTP 429 après dispatch -> une seule requête
HTTP 503 après dispatch -> une seule requête
timeout après dispatch -> une seule requête
NotDispatched prouvé -> retry/fallback central autorisé
```
`simulateTransaction` reste retry-safe et possède un scénario déterministe HTTP 503 -> succès.
## Canaries déterministes
La release stable conserve :
```text
current registry == 52
historical registry == 14
V0_2_1 exact == 4
V0_2_2 exact == 22
V0_2_3 exact == 11
V0_2_4 restant == 15
KSP-TRANSPORT-007 == 37 wrappers courants audités
```
À la base validée `pre.008`, l'opérateur a confirmé :
```text
182 tests unitaires Transport passed
19 tests public API passed
14 tests release completeness passed
1 smoke Transport live ignored par défaut
0 failure
0 warning clippy signalé
```
## Smoke Devnet Transport pur
`pre.009` étend le smoke Transport existant sans créer de nouvelle ownership boundary.
La séquence reste read-only :
```text
settings programmatiques
-> getAccountInfo
-> getTokenAccountsByOwner
-> getEpochInfo
-> getVoteAccounts
-> getLatestBlockhash
-> isBlockhashValid
-> getTransactionCount
```
La branche Transaction ne déclenche ni `requestAirdrop`, ni `sendTransaction`, ni simulation nécessitant une transaction sérialisée. Les fixtures locales restent la preuve déterministe complète des 11 wrappers.
Commande opt-in :
```bash
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
```
Le smoke historique Config -> Transport reste séparé et transitoire :
```bash
cargo test -p ksp-config-lib --test transport_devnet_smoke -- --ignored --nocapture
```
## Frontières et dépendances attendues
À clôture :
```text
ksp-config-lib -> ksp-onchain-transport-lib
ksp-onchain-transport-lib -> ksp-core-lib
ksp-onchain-transport-lib -> ksp-logging-lib
ksp-onchain-transport-lib -X-> ksp-config-lib
ksp-onchain-transport-lib -X-> Store
ksp-onchain-transport-lib -X-> Program
ksp-onchain-transport-lib -X-> tracing direct
```
Aucune nouvelle dépendance `base64`, `bs58`, `wincode`, `solana-client` ou client RPC haut niveau n'est introduite par `0.2.3`.
## Preuves opérateur finales
La candidate `0.2.3-pre.009` a été validée le **18 août 2026** avec succès :
```text
cargo fmt --all OK
cargo check --workspace OK
cargo clippy --workspace --all-targets OK, sans warning signalé
Transport
182 unit passed
19 public API passed
14 release completeness passed
1 smoke live ignored par défaut
Config
95 unit passed
5 ownership passed
13 public API passed
1 smoke live ignored par défaut
Core
14 unit passed
3 public API passed
2 workspace dependencies passed
1 workspace logging passed
Config Desk
63 unit passed
2 desktop contract passed
2 desktop security passed
1 public API passed
cargo test --workspace OK
```
Le probe diagnostic d'overhead Logging reste volontairement `ignored`; il ne constitue pas un échec.
Les graphes suivants ont été inspectés pour Transport et Config :
```text
cargo tree
cargo tree -d
cargo tree -e features
cargo tree -e normal
```
Ils confirment la frontière attendue `ksp-config-lib -> ksp-onchain-transport-lib`, sans dépendance inverse Transport -> Config/Store/Program et sans import direct `tracing` dans Transport. Les doublons notables restent transitifs/proc-macro, notamment `syn` 2.x/3.x.
Les deux smokes live ont ensuite été exécutés explicitement et passent :
```text
Transport pur read-only
programmatic_devnet_transport_reaches_accounts_tokens_cluster_and_transaction_read_wrappers
-> 1 passed; 0 failed
Config -> Transport transitoire
committed_devnet_transport_profile_reaches_all_foundation_canaries
-> 1 passed; 0 failed
```
## Publication `rel.001`
`0.2.3-rel.001` reste strictement publicationnelle :
```text
workspace.package.version = 0.2.3
ROADMAP : 0.2.3 -> [X]
CHANGELOG : synthèse stable 0.2.3
commit attendu : v0.2.3-rel.001
tag stable après validation : v0.2.3
```
Aucune nouvelle méthode HTTP, aucun nouveau DTO, aucune dépendance, aucune feature et aucun nouveau comportement runtime ne sont introduits pendant `rel.001`.
Après application du delta publicationnel, la gate finale est :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
```
Après succès, créer le commit `v0.2.3-rel.001`, puis le tag stable `v0.2.3`. La prochaine session s'ouvre avec `prompts/009-V0_2_4_START_PROMPT.md`.

View File

@@ -1,5 +1,5 @@
<!-- file: prompts/000-README.md --> <!-- file: prompts/000-README.md -->
<!-- version: 12 --> <!-- version: 13 -->
# Prompts KSP # Prompts KSP
@@ -29,3 +29,4 @@ Le prompt générique `0.1.x` a été affiné pendant `0.0.3` puis remplacé par
- [`006-V0_2_1_START_PROMPT.md`](006-V0_2_1_START_PROMPT.md) — prompt finalisé par `0.2.0-pre.003`, destiné à ouvrir `0.2.1 — ksp-onchain-transport-lib / HTTP Solana foundation` après publication stable de `0.2.0`; il impose l'audit exhaustif des surfaces HTTP courantes et deprecated/unstable officiellement documentées, la séparation Config/Transport, les pools/rôles et le gate de sizing « une release = une session » ; - [`006-V0_2_1_START_PROMPT.md`](006-V0_2_1_START_PROMPT.md) — prompt finalisé par `0.2.0-pre.003`, destiné à ouvrir `0.2.1 — ksp-onchain-transport-lib / HTTP Solana foundation` après publication stable de `0.2.0`; il impose l'audit exhaustif des surfaces HTTP courantes et deprecated/unstable officiellement documentées, la séparation Config/Transport, les pools/rôles et le gate de sizing « une release = une session » ;
- [`007-V0_2_2_START_PROMPT.md`](007-V0_2_2_START_PROMPT.md) — prompt préparé par la dernière prerelease de `0.2.1`, destiné à ouvrir `0.2.2 — HTTP Accounts + Tokens + Cluster` après publication stable de `0.2.1`; il cible les 22 wrappers typés restants de ces familles et impose un nouvel audit officiel/gate de sizing à `pre.001`. - [`007-V0_2_2_START_PROMPT.md`](007-V0_2_2_START_PROMPT.md) — prompt préparé par la dernière prerelease de `0.2.1`, destiné à ouvrir `0.2.2 — HTTP Accounts + Tokens + Cluster` après publication stable de `0.2.1`; il cible les 22 wrappers typés restants de ces familles et impose un nouvel audit officiel/gate de sizing à `pre.001`.
- [`008-V0_2_3_START_PROMPT.md`](008-V0_2_3_START_PROMPT.md) — prompt préparé par la dernière prerelease de `0.2.2`, destiné à ouvrir `0.2.3 — HTTP Transactions` après publication stable de `0.2.2`; il cible les 11 méthodes Transactions et impose un audit actuel ainsi que la politique no-resend des write submissions. - [`008-V0_2_3_START_PROMPT.md`](008-V0_2_3_START_PROMPT.md) — prompt préparé par la dernière prerelease de `0.2.2`, destiné à ouvrir `0.2.3 — HTTP Transactions` après publication stable de `0.2.2`; il cible les 11 méthodes Transactions et impose un audit actuel ainsi que la politique no-resend des write submissions.
- [`009-V0_2_4_START_PROMPT.md`](009-V0_2_4_START_PROMPT.md) — prompt préparé par `0.2.3-pre.009`, destiné à ouvrir `0.2.4 — HTTP Blocks + Economics + compliance HTTP finale` après publication stable de `0.2.3`; il cible les 15 wrappers restants et impose `KSP-TRANSPORT-007` ainsi qu'un nouvel audit/sizing à `pre.001`.

View File

@@ -0,0 +1,381 @@
<!-- file: prompts/009-V0_2_4_START_PROMPT.md -->
<!-- version: 1 -->
# Prompt de démarrage `0.2.4` — HTTP Blocks + Economics + compliance HTTP finale
## 1. Contexte de reprise
La base attendue est la release stable :
```text
v0.2.3
```
La surface HTTP acquise doit être :
```text
52 méthodes HTTP courantes enregistrées
14 méthodes historiques Deprecated / runtime Removed
37 wrappers typed courants :
4 foundation
22 Accounts/Tokens/Cluster
11 Transactions
15 wrappers typed restants : 10 Blocks + 5 Economics
```
`0.2.3` a aussi formalisé `KSP-TRANSPORT-007` : un wrapper RPC KSP ne compte comme complet que s'il expose toutes les possibilités supportées retenues par l'audit — paramètres, options, overloads/formes legacy encore supportés, contraintes déterministes utiles et variantes de réponse pertinentes sans perte.
La release à ouvrir est :
```text
0.2.4 — HTTP Blocks + Economics + compliance HTTP finale
```
La première tranche est `0.2.4-pre.001` et commence par **audit officiel actuel + brainstorming + sizing**, avant toute implémentation lourde.
## 2. Mission
Compléter exactement les 15 méthodes actuellement affectées à `HttpRpcCoverageRelease::V0_2_4`.
### Blocks — 10
```text
getBlock
getBlockCommitment
getBlockHeight
getBlockProduction
getBlocks
getBlocksWithLimit
getBlockTime
getFirstAvailableBlock
getRecentPerformanceSamples
minimumLedgerSlot
```
### Economics — 5
```text
getInflationGovernor
getInflationRate
getInflationReward
getStakeMinimumDelegation
getSupply
```
La partition doit être revérifiée contre la documentation Solana du jour avant confirmation.
Après ces 15 wrappers, `0.2.4` doit exécuter la **compliance finale de toute la surface HTTP** :
```text
52 current
14 historical Deprecated / Removed
52 wrappers typed courants
```
## 3. Gate de sizing obligatoire
Répondre explicitement à `pre.001` :
```text
Les 15 wrappers Blocks/Economics, leurs DTOs/wires, les overloads/legacy,
les tests, la compliance 52+14 et la documentation peuvent-ils être
clôturés proprement dans cette release/session ?
```
Si NON, scinder avant implémentation fonctionnelle lourde.
Une prerelease vise environ 1520 minutes de travail effectif.
## 4. Sources internes obligatoires
Relire avant modification :
```text
ROADMAP.md
CHANGELOG.md
RULES.md
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md
docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md
docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md
docs/validation/003-V0_2_1_ONCHAIN_HTTP.md
docs/validation/004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md
docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md
docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
docs/architecture/003-COMPONENT_CONTRACTS.md
docs/architecture/004-COMPONENT_INVENTORY.md
docs/architecture/005-DEPENDENCY_GRAPH.md
docs/rules/RULES_DEPENDENCIES.md
docs/rules/RULES_RUST.md
docs/rules/RULES_KSP.md
docs/rules/FILE_CONTRACTS.md
docs/rules/VERSION_WORKFLOW.md
docs/rules/PROMPT_STRUCTURE.md
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/
crates/ksp-onchain-transport-lib/unit_tests/
crates/ksp-onchain-transport-lib/tests/
```
Les deltas historiques ne sont pas réécrits.
## 5. Sources externes normatives
Au début de `pre.001`, réauditer :
```text
https://solana.com/docs/rpc/http
https://solana.com/docs/rpc/json-structures
```
Recouper avec les sources primaires Agave stables actuelles lorsque la documentation publique ne détaille pas une option, un overload, une limite ou un champ wire.
Ne pas supposer que `v4.2.1` est encore la référence au moment de l'ouverture de `0.2.4` : vérifier la génération Agave effectivement stable/recommandée ce jour-là.
## 6. Règle `KSP-TRANSPORT-007`
Pour **chaque** wrapper Blocks/Economics :
- couvrir tous les paramètres ordonnés ;
- couvrir tous les champs de config supportés ;
- conserver les overloads distincts ;
- conserver les formes legacy encore supportées, marquées deprecated si nécessaire ;
- appliquer avant I/O les contraintes déterministes connues lorsqu'elles n'exigent pas de décodage métier disproportionné ;
- préserver `null`, omissions significatives, ordre et cardinalités ;
- conserver losslessly les sous-arbres wire riches lorsque leur typage intégral créerait un couplage SDK inutile.
Une simplification volontaire n'est acceptable que si elle est explicitement justifiée et ne retire aucune capacité RPC.
## 7. Points sensibles Blocks
### `getBlock`
Auditer en priorité :
- config moderne complète ;
- forme bare encoding legacy si elle est toujours supportée ;
- encodings actuels ;
- transactionDetails ;
- rewards ;
- commitment autorisé ;
- maxSupportedTransactionVersion ;
- résultat `null` ;
- transaction/meta/version/rewards/blockTime/blockHeight/numRewardPartitions ;
- erreurs de version/non-disponibilité pertinentes.
La stratégie wire doit réutiliser les primitives Transaction de `0.2.3` lorsque pertinentes, sans copier `solana-rpc-client`.
### `getBlockCommitment`
Préserver commitment nullable et totalStake.
### `getBlockHeight`
Auditer config contextuelle et contraintes de commitment/minContextSlot.
### `getBlockProduction`
Auditer identity, range firstSlot/lastSlot, commitment et forme contextualisée.
### `getBlocks`
Vérifier les overloads actuels autour de start/end/config. Ne pas réduire la surface à la seule signature d'un client SDK.
### `getBlocksWithLimit`
Auditer start slot, limit, config et limite runtime éventuelle.
### `getBlockTime`
Préserver `i64|null` et les erreurs significatives.
### `getFirstAvailableBlock`
Pas de config si le contrat courant reste sans paramètre.
### `getRecentPerformanceSamples`
Auditer limite optionnelle/default/max et tous les champs de sample.
### `minimumLedgerSlot`
Pas de config si le contrat courant reste sans paramètre ; préserver les erreurs RPC runtime.
## 8. Points sensibles Economics
### `getInflationGovernor`
Auditer commitment éventuel et tous les champs governor.
### `getInflationRate`
Préserver total/validator/foundation/epoch.
### `getInflationReward`
Auditer :
- liste d'adresses et limite éventuelle ;
- epoch ;
- commitment ;
- minContextSlot ;
- ordre et `null` positionnels ;
- commission et extension runtime `commissionBps` si toujours supportée.
### `getStakeMinimumDelegation`
Auditer config contextuelle et résultat contextualisé.
### `getSupply`
Auditer commitment et `excludeNonCirculatingAccountsList`, puis total/circulating/nonCirculating/liste de comptes.
## 9. Architecture Transport
Conserver le flux unique :
```text
wrapper typed
-> descriptor central
-> execute_standard_rpc
-> pool/admission
-> executor HTTP
-> validation JSON-RPC
-> decode typed
```
Interdits :
```text
client HTTP parallèle
reqwest direct par wrapper
retry/deadline/admission bypass
Transport -> Config
Transport -> Store/Program
tracing direct
solana-rpc-client pour masquer les possibilités RPC
```
## 10. Réutilisation des wires
Réutiliser les contrats `0.2.1``0.2.3` lorsqu'ils représentent réellement le même wire :
- `SolanaCommitment` / configs contextuelles ;
- `SolanaRpcContext` / `SolanaRpcResponse<T>` ;
- Account encodings/types ;
- Transaction encodings/version/meta et `SolanaWireField<T>`.
Ne pas dédupliquer artificiellement des contrats qui ont des sémantiques différentes.
## 11. Tests déterministes
Pour chaque wrapper :
- request JSON exacte ;
- omission/config vide ;
- toutes options et overloads significatifs ;
- encodings ;
- success typed ;
- `null`/omitted ;
- ordre/cardinalité ;
- erreurs RPC ;
- limites avant I/O pertinentes.
Conserver les canaries acquises :
```text
52 current registry
14 historical
0.2.1 exact == 4
0.2.2 exact == 22
0.2.3 exact == 11
0.2.4 exact == 15
KSP-TRANSPORT-007 sur les 37 wrappers précédents
```
À la clôture `0.2.4`, ajouter la preuve finale :
```text
52/52 méthodes courantes couvertes par wrapper typed
14/14 historiques conservées pour compliance
```
## 12. Smokes live
Les smokes live restent opt-in et ne remplacent jamais les fixtures locales.
Le smoke Transport pur peut être étendu à quelques reads Blocks/Economics stables si cela apporte une vraie preuve sans dépendre d'un état Devnet fragile.
Éviter les écritures ou scénarios nécessitant des fonds/wallets dans la couche Transport seule.
Le smoke Config -> Transport reste transitoire et ne doit pas devenir la destination générale des scénarios cross-crates.
## 13. Dépendances
Ne pas ajouter une crate RPC/client Solana haut niveau.
Toute nouvelle dépendance doit :
- répondre à un besoin réel non couvert par les primitives existantes ;
- être déclarée sous `[workspace.dependencies]` ;
- respecter le firewall Transport ;
- être justifiée dans le delta/plan.
## 14. Dernière prerelease et publication
La dernière prerelease de `0.2.4` doit :
- réauditer une dernière fois l'inventaire courant/deprecated ;
- figer la compliance **52/52 + 14/14** ;
- synchroniser README/USAGE et matrices ;
- exécuter les smokes pertinents ;
- auditer les graphes de dépendances ;
- préparer le prompt `0.2.5 — Wallet foundation` ;
- laisser `CHANGELOG.md` à `rel.001`.
`0.2.4-rel.001` doit rester strictement publicationnelle.
## 15. Validations
Pendant le développement :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
À 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
cargo tree -p ksp-config-lib
cargo tree -p ksp-config-lib -d
cargo tree -p ksp-config-lib -e features
cargo tree -p ksp-config-lib -e normal
cargo test -p ksp-onchain-transport-lib --test transport_devnet_smoke -- --ignored --nocapture
cargo test -p ksp-config-lib --test transport_devnet_smoke -- --ignored --nocapture
```
Ne jamais déclarer une commande réussie sans preuve opérateur ou exécution réelle.