Files
2026-08-18 08:17:10 +02:00

270 lines
9.0 KiB
Markdown

<!-- file: deltas/0.2.2/pre.005.md -->
<!-- version: 1 -->
# Delta `0.2.2-pre.005` — sept wrappers HTTP Cluster simples typés
## Base requise
Livraison précédente validée localement par l'opérateur :
```text
0.2.2-pre.004
workspace.package.version = "0.2.2-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
106 unit tests
11 public API tests
4 release completeness tests
0 warning signalé par check/clippy
```
Le plan canonique reste `docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md` version 3.
## Contrôle documentaire avant nouvelle tranche
Le contrôle de cohérence demandé entre prereleases confirme :
- `ROADMAP.md` conserve correctement `0.2.2` en cours `[/]` ;
- le plan `009` attribue exactement à `pre.005` les sept méthodes Cluster simples implémentées ici ;
- `pre.006` conserve exactement cinq méthodes différées : `getLeaderSchedule`, `getSlot`, `getSlotLeader`, `getSlotLeaders`, `getVoteAccounts` ;
- les index `docs/000-README.md`, `docs/plans/000-README.md` et `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` restent cohérents et ne nécessitent aucune modification.
## Objectif
Implémenter les sept wrappers publics typés Cluster simples prévus par le plan :
```text
getClusterNodes
getEpochInfo
getEpochSchedule
getHighestSnapshotSlot
getIdentity
getMaxRetransmitSlot
getMaxShredInsertSlot
```
Tous passent par la foundation HTTP commune :
```text
wrapper typé
-> descriptor audité
-> execute_standard_rpc
-> pool/admission/retry/deadline
-> reqwest HTTP
-> JSON-RPC validation
-> décodage DTO KSP
```
Aucun wrapper Cluster ne contacte `reqwest` directement.
## Version Cargo
Conformément au cycle prerelease KSP :
```text
0.2.2-pre.4 -> 0.2.2-pre.5
```
Aucune dépendance ni feature Cargo n'est ajoutée ou retirée.
## Réaudit ciblé du contrat courant
Les pages RPC Solana courantes ont été revérifiées le 2026-08-18 :
```text
https://solana.com/docs/rpc/http/getclusternodes
https://solana.com/docs/rpc/http/getepochinfo
https://solana.com/docs/rpc/http/getepochschedule
https://solana.com/docs/rpc/http/gethighestsnapshotslot
https://solana.com/docs/rpc/http/getidentity
https://solana.com/docs/rpc/http/getmaxretransmitslot
https://solana.com/docs/rpc/http/getmaxshredinsertslot
```
Le contrat reste cohérent avec le plan `009` :
- `getClusterNodes` ne prend aucun paramètre et renvoie une liste de contacts de noeuds ;
- `getEpochInfo` accepte uniquement la config commune `commitment/minContextSlot` et conserve `transactionCount` nullable ;
- `getEpochSchedule` ne prend aucun paramètre et renvoie la structure fixe d'epoch schedule ;
- `getHighestSnapshotSlot` ne prend aucun paramètre, conserve `incremental` nullable et laisse l'absence de snapshot comme erreur JSON-RPC distante ;
- `getIdentity` ne prend aucun paramètre et renvoie l'objet `{ identity }`, converti en `Pubkey` KSP ;
- `getMaxRetransmitSlot` et `getMaxShredInsertSlot` ne prennent aucun paramètre et renvoient chacun un `u64`.
Le champ Agave `v4.2.1` `clientId: Option<String>` identifié par `pre.001-fix.001` reste conservé par `SolanaClusterNode`, sans devenir obligatoire.
## Surface typée Cluster simple
### `getClusterNodes`
```text
role -> Vec<SolanaClusterNode>
```
Chaque `pubkey` est validée et convertie en `ksp_core_lib::Pubkey`. Les endpoints réseau restent des chaînes optionnelles. Les champs optionnels absents, y compris `clientId`, restent `None`.
### `getEpochInfo`
```text
role + Option<SolanaContextConfig> -> SolanaEpochInfo
```
Un config explicitement vide est omis de `params`. `transactionCount: null` reste `None`.
### `getEpochSchedule`
```text
role -> SolanaEpochSchedule
```
Aucune transformation métier n'est introduite.
### `getHighestSnapshotSlot`
```text
role -> SolanaSnapshotSlotInfo
```
`incremental` reste optionnel. Une erreur RPC « no snapshot » n'est pas convertie en valeur sentinelle.
### `getIdentity`
```text
role -> Pubkey
```
Le wrapper valide la chaîne `identity` avant de l'exposer comme `Pubkey`, sans recopier une valeur wire invalide dans le diagnostic.
### `getMaxRetransmitSlot` / `getMaxShredInsertSlot`
```text
role -> u64
```
Les deux wrappers partagent un chemin privé simple de décodage `u64` et ne créent aucun DTO artificiel.
## Activation ciblée des helpers préparés en `pre.002`
Les helpers Cluster nécessaires à cette tranche deviennent production-live uniquement maintenant qu'ils ont des consommateurs runtime :
- `SolanaClusterNode::decode_wire` + `WireClusterNode` ;
- `SolanaEpochInfo::decode_wire` + `WireEpochInfo` ;
- `SolanaEpochSchedule::decode_wire` + `WireEpochSchedule` ;
- `SolanaSnapshotSlotInfo::decode_wire` + `WireSnapshotSlotInfo`.
Les helpers spécifiques à `getLeaderSchedule` et `getVoteAccounts` restent sous `#[cfg(test)]` jusqu'à `pre.006`. Aucun `#[allow(dead_code)]` n'est ajouté.
## Fixtures HTTP déterministes ajoutées
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_cluster_nodes.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_cluster_nodes.invalid_pubkey.json
crates/ksp-onchain-transport-lib/fixtures/http/get_epoch_info.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_epoch_schedule.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_highest_snapshot_slot.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_highest_snapshot_slot.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_identity.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_identity.invalid_pubkey.json
crates/ksp-onchain-transport-lib/fixtures/http/get_max_retransmit_slot.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_max_shred_insert_slot.success.json
```
Les tests utilisent uniquement un serveur HTTP loopback local.
## Couverture de tests ajoutée
Les tests couvrent notamment :
- requête sans paramètres pour les six méthodes sans config ;
- sérialisation exacte `commitment + minContextSlot` pour `getEpochInfo` ;
- omission d'un `SolanaContextConfig` explicitement vide ;
- `transactionCount: null` ;
- champs ClusterNode optionnels présents et absents ;
- conservation de `clientId` Agave `v4.2.1` ;
- rejet d'une `pubkey` de noeud invalide ;
- `incremental: null` ;
- propagation d'une erreur RPC « no snapshot » ;
- validation de l'identity `Pubkey` ;
- décodage des deux slots max comme `u64`.
Le test public compile explicitement les sept nouvelles méthodes depuis `HttpTransportPool`.
Un canari release fige le sous-ensemble `pre.005` exact et vérifie `Read + RetrySafe` pour les sept descriptors, tout en laissant les cinq méthodes Cluster de `pre.006` enregistrées mais différées.
Après application, la cible Transport attendue devient :
```text
116 unit tests
12 public API tests
5 release completeness tests
```
## Fichiers ajoutés
```text
crates/ksp-onchain-transport-lib/fixtures/http/get_cluster_nodes.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_cluster_nodes.invalid_pubkey.json
crates/ksp-onchain-transport-lib/fixtures/http/get_epoch_info.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_epoch_schedule.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_highest_snapshot_slot.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_highest_snapshot_slot.error.json
crates/ksp-onchain-transport-lib/fixtures/http/get_identity.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_identity.invalid_pubkey.json
crates/ksp-onchain-transport-lib/fixtures/http/get_max_retransmit_slot.success.json
crates/ksp-onchain-transport-lib/fixtures/http/get_max_shred_insert_slot.success.json
deltas/0.2.2/pre.005.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-onchain-transport-lib/src/rpc_cluster.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_cluster.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
```
## Fichiers supprimés
Aucun.
## Documentation durable
Aucune modification de ROADMAP/plan/index n'est requise par cette tranche après le contrôle documentaire : les documents existants décrivent déjà exactement ce découpage.
`CHANGELOG.md` reste réservé à la clôture stable.
## Validation à exécuter sur le checkout opérateur
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
```
La livraison n'affirme pas que ces commandes ont été exécutées dans l'environnement de génération.
## Critères de validation de `pre.005`
`pre.005` est validable lorsque :
- les quatre commandes ci-dessus passent sans warning nouveau ;
- les 116 unit tests passent ;
- les 12 tests public API passent ;
- les 5 tests release completeness passent ;
- aucun helper Cluster simple production-live n'est `dead_code` ;
- les cinq wrappers complexes de `pre.006` restent hors de cette tranche.