v0.2.1-pre.002-fix.001

This commit is contained in:
2026-08-17 18:46:52 +02:00
parent 0cff0406ab
commit d3fc0c6d69
8 changed files with 209 additions and 33 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 97 # version: 98
[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.1-pre.2" version = "0.2.1-pre.2.fix.1"
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: 27 --> <!-- version: 28 -->
# Roadmap KSP # Roadmap KSP
@@ -48,6 +48,7 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
- [X] `0.2.1-pre.001` — Audit HTTP officiel/bot3, matrice exhaustive, architecture et gate de sizing : scope monolithique refusé, premier split de la couverture HTTP sur `0.2.1``0.2.6`, `0.2.1` réduite déclarée raisonnablement clôturable. - [X] `0.2.1-pre.001` — Audit HTTP officiel/bot3, matrice exhaustive, architecture et gate de sizing : scope monolithique refusé, premier split de la couverture HTTP sur `0.2.1``0.2.6`, `0.2.1` réduite déclarée raisonnablement clôturable.
- [X] `0.2.1-pre.001-fix.001` — Recalibrer le split HTTP sur `0.2.1``0.2.4` : `0.2.2` Accounts + Tokens + Cluster, `0.2.3` Transactions, `0.2.4` Blocks + Economics + compliance finale ; autoriser l'enchaînement de plusieurs releases complètement clôturées dans une même session lorsque le sizing le permet. - [X] `0.2.1-pre.001-fix.001` — Recalibrer le split HTTP sur `0.2.1``0.2.4` : `0.2.2` Accounts + Tokens + Cluster, `0.2.3` Transactions, `0.2.4` Blocks + Economics + compliance finale ; autoriser l'enchaînement de plusieurs releases complètement clôturées dans une même session lorsque le sizing le permet.
- [X] `0.2.1-pre.002` — Créer la crate `ksp-onchain-transport-lib`, fixer ses settings runtime publics/validation, les envelopes JSON-RPC HTTP, les codes d'erreur, le registre central 52 current + 14 historiques et la base de warnings KSP de statut. - [X] `0.2.1-pre.002` — Créer la crate `ksp-onchain-transport-lib`, fixer ses settings runtime publics/validation, les envelopes JSON-RPC HTTP, les codes d'erreur, le registre central 52 current + 14 historiques et la base de warnings KSP de statut.
- [X] `0.2.1-pre.002-fix.001` — Nettoyer les warnings Clippy/missing-docs révélés par la validation locale de `pre.002`, sans changer son périmètre fonctionnel ni ses contrats publics.
### Releases fonctionnelles décidées/pressenties ### Releases fonctionnelles décidées/pressenties

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/src/settings.rs // file: crates/ksp-onchain-transport-lib/src/settings.rs
// version: 1 // version: 2
/// Runtime HTTP endpoint URL owned by Transport. /// Runtime HTTP endpoint URL owned by Transport.
/// ///
@@ -475,14 +475,14 @@ fn validate_endpoint(endpoint: &crate::HttpEndpointSettings, endpoint_index: usi
if endpoint.request_timeout().is_zero() { if endpoint.request_timeout().is_zero() {
return invalid_settings("HTTP request timeout must be greater than zero", format!("endpoints[{endpoint_index}].request_timeout").as_str()); return invalid_settings("HTTP request timeout must be greater than zero", format!("endpoints[{endpoint_index}].request_timeout").as_str());
} }
if let std::option::Option::Some(max_idle) = endpoint.max_idle_connections_per_host() { if let std::option::Option::Some(max_idle) = endpoint.max_idle_connections_per_host()
if max_idle == 0 { && max_idle == 0
{
return invalid_settings( return invalid_settings(
"max idle connections per host must be greater than zero when configured", "max idle connections per host must be greater than zero when configured",
format!("endpoints[{endpoint_index}].max_idle_connections_per_host").as_str(), format!("endpoints[{endpoint_index}].max_idle_connections_per_host").as_str(),
); );
} }
}
if endpoint.roles().is_empty() { if endpoint.roles().is_empty() {
return invalid_settings("HTTP endpoint must declare at least one role", format!("endpoints[{endpoint_index}].roles").as_str()); return invalid_settings("HTTP endpoint must declare at least one role", format!("endpoints[{endpoint_index}].roles").as_str());
} }
@@ -548,14 +548,14 @@ fn validate_role(role: &crate::HttpEndpointRoleSettings, endpoint_index: usize,
format!("endpoints[{endpoint_index}].roles[{role_index}].limits.burst_capacity").as_str(), format!("endpoints[{endpoint_index}].roles[{role_index}].limits.burst_capacity").as_str(),
); );
} }
if let std::option::Option::Some(pause) = role.limits().pause_after_rate_limit() { if let std::option::Option::Some(pause) = role.limits().pause_after_rate_limit()
if pause.is_zero() { && pause.is_zero()
{
return invalid_settings( return invalid_settings(
"rate-limit cooldown must be greater than zero when configured", "rate-limit cooldown must be greater than zero when configured",
format!("endpoints[{endpoint_index}].roles[{role_index}].limits.pause_after_rate_limit").as_str(), format!("endpoints[{endpoint_index}].roles[{role_index}].limits.pause_after_rate_limit").as_str(),
); );
} }
}
return std::result::Result::Ok(()); return std::result::Result::Ok(());
} }

View File

@@ -1,5 +1,7 @@
// file: crates/ksp-onchain-transport-lib/tests/dependency_boundary.rs // file: crates/ksp-onchain-transport-lib/tests/dependency_boundary.rs
// version: 1 // version: 2
//! Integration canary for the direct dependency firewall of `ksp-onchain-transport-lib`.
#[test] #[test]
fn transport_manifest_preserves_ksp_dependency_firewall() { fn transport_manifest_preserves_ksp_dependency_firewall() {

View File

@@ -1,5 +1,7 @@
// file: crates/ksp-onchain-transport-lib/tests/public_api.rs // file: crates/ksp-onchain-transport-lib/tests/public_api.rs
// version: 1 // version: 2
//! Integration tests for the public `ksp-onchain-transport-lib` consumer contract.
#[test] #[test]
fn public_settings_contract_is_constructible_without_config_dependency() { fn public_settings_contract_is_constructible_without_config_dependency() {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/unit_tests/json_rpc.rs // file: crates/ksp-onchain-transport-lib/unit_tests/json_rpc.rs
// version: 1 // version: 2
#[test] #[test]
fn request_serialization_matches_json_rpc_2_0_shape() { fn request_serialization_matches_json_rpc_2_0_shape() {
@@ -22,9 +22,9 @@ fn request_rejects_empty_or_untrimmed_method() {
#[test] #[test]
fn response_parser_preserves_null_success_result() { fn response_parser_preserves_null_success_result() {
let response = super::parse_json_rpc_response_text(r#"{"jsonrpc":"2.0","result":null,"id":9}"#, 9).expect("null result is a valid success payload"); let response = super::parse_json_rpc_response_text(r#"{"jsonrpc":"2.0","result":null,"id":9}"#, 9).expect("null result is a valid success payload");
match response { assert!(matches!(&response, super::JsonRpcResponse::Success(_)), "success response must not parse as error");
super::JsonRpcResponse::Success(success) => assert!(success.result().is_null()), if let super::JsonRpcResponse::Success(success) = response {
super::JsonRpcResponse::Error(_) => assert!(false, "success response must not parse as error"), assert!(success.result().is_null());
} }
} }
@@ -35,13 +35,11 @@ fn response_parser_preserves_rpc_error_payload() {
4, 4,
) )
.expect("valid JSON-RPC error envelope must parse"); .expect("valid JSON-RPC error envelope must parse");
match response { assert!(matches!(&response, super::JsonRpcResponse::Error(_)), "RPC error response must not parse as success");
super::JsonRpcResponse::Error(error_response) => { if let super::JsonRpcResponse::Error(error_response) = response {
assert_eq!(error_response.error().code(), -32005); assert_eq!(error_response.error().code(), -32005);
assert_eq!(error_response.error().message(), "Node is unhealthy"); assert_eq!(error_response.error().message(), "Node is unhealthy");
assert_eq!(error_response.error().data(), std::option::Option::Some(&serde_json::json!({"numSlotsBehind":12}))); assert_eq!(error_response.error().data(), std::option::Option::Some(&serde_json::json!({"numSlotsBehind":12})));
},
super::JsonRpcResponse::Success(_) => assert!(false, "RPC error response must not parse as success"),
} }
} }

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_method.rs // file: crates/ksp-onchain-transport-lib/unit_tests/rpc_method.rs
// version: 1 // version: 2
#[test] #[test]
fn audited_registry_has_expected_current_and_historical_counts() { fn audited_registry_has_expected_current_and_historical_counts() {
@@ -25,15 +25,17 @@ fn coverage_release_counts_match_recalibrated_matrix() {
let mut accounts_tokens_cluster = 0_usize; let mut accounts_tokens_cluster = 0_usize;
let mut transactions = 0_usize; let mut transactions = 0_usize;
let mut blocks_economics = 0_usize; let mut blocks_economics = 0_usize;
let mut historical = 0_usize;
for descriptor in super::current_http_rpc_methods() { for descriptor in super::current_http_rpc_methods() {
match descriptor.coverage_release() { match descriptor.coverage_release() {
super::HttpRpcCoverageRelease::V0_2_1 => foundation += 1, super::HttpRpcCoverageRelease::V0_2_1 => foundation += 1,
super::HttpRpcCoverageRelease::V0_2_2 => accounts_tokens_cluster += 1, super::HttpRpcCoverageRelease::V0_2_2 => accounts_tokens_cluster += 1,
super::HttpRpcCoverageRelease::V0_2_3 => transactions += 1, super::HttpRpcCoverageRelease::V0_2_3 => transactions += 1,
super::HttpRpcCoverageRelease::V0_2_4 => blocks_economics += 1, super::HttpRpcCoverageRelease::V0_2_4 => blocks_economics += 1,
super::HttpRpcCoverageRelease::Historical => assert!(false, "current method must not be historical"), super::HttpRpcCoverageRelease::Historical => historical += 1,
} }
} }
assert_eq!(historical, 0);
assert_eq!(foundation, 4); assert_eq!(foundation, 4);
assert_eq!(accounts_tokens_cluster, 22); assert_eq!(accounts_tokens_cluster, 22);
assert_eq!(transactions, 11); assert_eq!(transactions, 11);

View File

@@ -0,0 +1,171 @@
<!-- file: deltas/0.2.1/pre.002-fix.001.md -->
<!-- version: 1 -->
# Delta `0.2.1-pre.002-fix.001` — nettoyage Clippy et documentation des tests
## Base requise
```text
release : 0.2.1
prerelease corrigée : pre.002
identifiant de commit attendu : v0.2.1-pre.002-fix.001
workspace.package.version : 0.2.1-pre.2.fix.1
base : v0.2.1-pre.002
```
Le correctif est ouvert à partir de la validation locale transmise après application de `pre.002`.
## Objectif
Corriger exclusivement les warnings révélés par `cargo clippy --workspace --all-targets` et `cargo test`, sans modifier le périmètre fonctionnel ni les contrats publics introduits par `pre.002` :
- supprimer trois usages de `assert!(false, ...)` signalés par `clippy::assertions_on_constants` dans les tests unitaires ;
- appliquer les deux simplifications `clippy::collapsible_if` dans la validation des settings ;
- documenter les deux crates de tests d'intégration afin de satisfaire `missing_docs` ;
- conserver inchangés le registre 52 current + 14 historiques, les settings publics, les envelopes JSON-RPC, les codes d'erreur, les descriptors et le firewall de dépendances.
## Version Cargo
Le correctif touche du Rust de production et de test. Conformément à `VER-ID-007` et `VER-ID-010` :
```text
0.2.1-pre.2 -> 0.2.1-pre.2.fix.1
```
Toutes les crates membres continuent d'hériter `version.workspace = true`.
## Corrections Rust
### Validation des settings
Les deux validations imbriquées suivantes sont exprimées sous forme de let-chain Rust 2024 :
```text
max_idle_connections_per_host = Some(0)
pause_after_rate_limit = Some(Duration::ZERO)
```
La sémantique reste strictement identique : les valeurs nulles configurées restent rejetées avec `ERROR_CODE_INVALID_SETTINGS`.
### Tests JSON-RPC
Les tests qui validaient la variante attendue avec un `match` et `assert!(false, ...)` utilisent désormais :
1. une assertion `matches!` sur la variante attendue ;
2. un `if let` pour vérifier le payload de cette variante.
Aucun `panic!`/`unreachable!` explicite n'est introduit.
### Test de matrice de couverture
Le cas `HttpRpcCoverageRelease::Historical` rencontré dans `current_http_rpc_methods()` est désormais comptabilisé dans un compteur local puis vérifié avec :
```text
historical == 0
```
La preuve reste donc explicite sans assertion constante fausse.
### Tests d'intégration
Les targets Cargo :
```text
tests/public_api.rs
tests/dependency_boundary.rs
```
possèdent maintenant une documentation de crate `//!`, ce qui satisfait le lint workspace `missing_docs` sans masquer le warning global.
## Graphe de dépendances
Les quatre commandes `cargo tree` ont été exécutées localement sur `pre.002` avant ce fix.
Constats :
- aucune dépendance directe interdite Transport -> Config/Store/Program/tracing n'apparaît ;
- `reqwest 0.13.4` reste la dépendance HTTP retenue par `pre.002` ;
- `cargo tree -d` ne rapporte comme duplication que `syn 2.0.119` / `syn 3.0.3`, issue des chaînes proc-macro/ICU/Serde et ne justifiant pas une modification du graphe KSP dans ce correctif ;
- aucune dépendance n'est ajoutée ou retirée par `fix.001`.
## Fichiers ajoutés
```text
deltas/0.2.1/pre.002-fix.001.md
```
## Fichiers modifiés
```text
Cargo.toml
ROADMAP.md
crates/ksp-onchain-transport-lib/src/settings.rs
crates/ksp-onchain-transport-lib/unit_tests/json_rpc.rs
crates/ksp-onchain-transport-lib/unit_tests/rpc_method.rs
crates/ksp-onchain-transport-lib/tests/dependency_boundary.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
```
## Fichiers supprimés
Aucun.
## Validation de `pre.002` ayant déclenché le correctif
Les commandes suivantes ont été exécutées par le user sur `v0.2.1-pre.002` avant création du fix :
```text
cargo fmt --all : exécuté
cargo check --workspace : OK
cargo clippy --workspace --all-targets : terminé avec warnings
cargo test -p ksp-onchain-transport-lib : OK, 40 tests passés
cargo test --workspace : OK ; 1 test diagnostic ignoré comme prévu
cargo tree -p ksp-onchain-transport-lib : exécuté
cargo tree -p ksp-onchain-transport-lib -d : exécuté
cargo tree -p ksp-onchain-transport-lib -e features : exécuté
cargo tree -p ksp-onchain-transport-lib -e normal : exécuté
```
Warnings observés et ciblés par ce fix :
```text
3 x clippy::assertions_on_constants
2 x clippy::collapsible_if
2 x missing documentation for integration-test crate
```
## Validations du correctif
Le sandbox de préparation ne possède pas `cargo`, `rustc` ni `rustfmt`. Les validations Rust du correctif ne peuvent donc pas y être exécutées et ne sont pas déclarées réussies.
Après application du delta, exécuter dans cet ordre :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
cargo test --workspace
```
Les quatre `cargo tree` ne sont pas obligatoires à répéter pour ce fix puisqu'aucune dépendance n'a changé. Ils peuvent être relancés si une vérification de non-régression du graphe est souhaitée.
## Contrôles statiques effectués pendant la préparation
- aucune occurrence restante de `assert!(false` dans la crate Transport ;
- les deux blocs signalés `collapsible_if` ont été remplacés ;
- les deux tests d'intégration possèdent une rustdoc de crate ;
- les headers/version des fichiers modifiés ont été incrémentés ;
- `pre.002.md` n'est pas modifié ;
- le périmètre public de `pre.002` reste inchangé.
## Décisions prises
- ne pas masquer les lints par `#[allow(...)]` ; corriger leur cause ;
- ne pas remplacer `assert!(false)` par `panic!()` ou `unreachable!()` ;
- ne pas modifier le graphe de dépendances pour le seul doublon `syn 2/3` ;
- conserver ce travail sous un vrai `pre.002-fix.001`, conformément à l'historique Git KSP.
## Questions ouvertes
Aucune pour ce correctif. Après validation et commit, `0.2.1` peut reprendre avec la prerelease suivante prévue par le plan `008`.