v0.2.11-pre.004

This commit is contained in:
2026-08-25 21:47:47 +02:00
parent f4413ebbb0
commit 60afb51451
23 changed files with 1862 additions and 117 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Validation `0.2.11` — Off-chain price transport SOL/USD
@@ -105,24 +105,25 @@ Cette correction reste dans la responsabilité de `pre.002` : elle stabilise la
## 3.4 Gate `0.2.11-pre.003`
| Critère | Statut | Preuve |
|-----------------------------------------------------------------------|---------|-----------------------------------------------------|
| version workspace `0.2.11-pre.3` | PASS | `Cargo.toml` racine |
| `reqwest` utilisé directement, sans SDK provider | PASS | manifest `ksp-offchain-transport-lib` |
| primitives HTTP communes sous modules `http_*` crate-private | PASS | `http_client`, `http_settings`, `http_admission` |
| client HTTP générique non exporté aux consumers | PASS | façade `lib.rs` |
| redirects, Referer, proxy système et retries reqwest désactivés | PASS | construction `HttpRestClient` |
| connect/request timeouts bornés | PASS | `HttpClientSettings` |
| body borné pendant lecture chunked avant désérialisation | PASS | `HttpRestClient::get_json` |
| JSON syntaxiquement validé sans normalisation numérique intermédiaire | PASS | `serde::de::IgnoredAny` sur bytes bruts |
| 401/403, 429, 408/5xx et autres statuts distingués | PASS | codes d'erreur HTTP dédiés |
| URL reqwest supprimée des sources d'erreur | PASS | `reqwest::Error::without_url` |
| body remote non recopié dans les erreurs | PASS | erreurs construites uniquement depuis metadata safe |
| limiter fixe lissé et burst absent traité conservativement | PASS | `HttpAdmissionController` |
| limite dynamique n'invente pas de cadence locale | PASS | `HttpAdmissionPolicy::Dynamic` |
| cooldown `Retry-After` borné et admission non bloquante | PASS | `record_rate_limited` + `try_admit` |
| adapters CoinGecko/Jupiter/etc. ajoutés | N/A | explicitement réservés à `pre.004+` |
| gate Cargo complet sur `pre.003-fix.001` | PENDING | à rejouer par l'opérateur après le correctif |
| Critère | Statut | Preuve |
|-----------------------------------------------------------------------|--------|-----------------------------------------------------|
| version workspace `0.2.11-pre.3` | PASS | `Cargo.toml` racine |
| `reqwest` utilisé directement, sans SDK provider | PASS | manifest `ksp-offchain-transport-lib` |
| primitives HTTP communes sous modules `http_*` crate-private | PASS | `http_client`, `http_settings`, `http_admission` |
| client HTTP générique non exporté aux consumers | PASS | façade `lib.rs` |
| redirects, Referer, proxy système et retries reqwest désactivés | PASS | construction `HttpRestClient` |
| connect/request timeouts bornés | PASS | `HttpClientSettings` |
| body borné pendant lecture chunked avant désérialisation | PASS | `HttpRestClient::get_json` |
| JSON syntaxiquement validé sans normalisation numérique intermédiaire | PASS | `serde::de::IgnoredAny` sur bytes bruts |
| 401/403, 429, 408/5xx et autres statuts distingués | PASS | codes d'erreur HTTP dédiés |
| URL reqwest supprimée des sources d'erreur | PASS | `reqwest::Error::without_url` |
| body remote non recopié dans les erreurs | PASS | erreurs construites uniquement depuis metadata safe |
| limiter fixe lissé et burst absent traité conservativement | PASS | `HttpAdmissionController` |
| limite dynamique n'invente pas de cadence locale | PASS | `HttpAdmissionPolicy::Dynamic` |
| cooldown `Retry-After` borné et admission non bloquante | PASS | `record_rate_limited` + `try_admit` |
| adapters CoinGecko/Jupiter/etc. ajoutés | N/A | explicitement réservés à `pre.004+` |
| gate Cargo `check`/`clippy`/tests Off-chain sur `pre.003-fix.001` | PASS | résultats opérateur du 2026-08-25 |
| audit Rust final de `pre.003-fix.001` | CARRY | seul `RUST-FMT-108`, cause supprimée en `pre.004` |
Les tests déterministes de `pre.003` couvrent en particulier le body chunked dépassant la limite, le refus des redirects, un `429` avec `Retry-After`, la non-propagation d'un body distant canari, le JSON invalide et le refill/cooldown du limiter.
@@ -141,15 +142,43 @@ contrat limiter : burst documenté indépendant de la cadence moyenne et autoris
Le cas `1 req/s` avec `burst 2` devient un canari déterministe ; il protège notamment la représentabilité du cas Coinbase documenté dans le plan à `10 req/s, burst 15`. Les modules `http_*` restent donc testés et prêts en `pre.003`, mais leur compilation normale sera activée en `pre.004` lorsque les premiers adapters de production les consommeront réellement.
La version Cargo du correctif est `0.2.11-pre.3.fix.1`. Les audits statiques du sandbox sont propres ; le gate Cargo complet doit être rejoué par l'opérateur.
La version Cargo du correctif est `0.2.11-pre.3.fix.1`. Le gate opérateur du `2026-08-25` confirme `cargo check --workspace` PASS, `cargo clippy --workspace --all-targets` PASS et `cargo test -p ksp-offchain-transport-lib` PASS avec 22 unitaires, 2 boundary et 2 public API. L'audit Rust signale uniquement `RUST-FMT-108` dans `src/lib.rs`, conséquence directe du staging `#[cfg(test)]` des modules `http_*`. L'opérateur a explicitement décidé de ne pas publier un fix artificiel pour ce point puisque `pre.004` retire ce staging avec les premiers consumers de production.
## 3.6 Gate `0.2.11-pre.004`
| Critère | Statut | Preuve |
|------------------------------------------------------------------------|---------|-----------------------------------------------------------|
| version workspace `0.2.11-pre.4` | PASS | `Cargo.toml` racine |
| modules `http_*` actifs en production, sans staging crate-root test | PASS | `src/lib.rs` |
| cause `RUST-FMT-108` de `pre.003-fix.001` supprimée | PASS | modules production avant tests |
| CoinGecko SOL/USD adapter public | PASS | `market_price_coingecko.rs` |
| CoinGecko keyless et Demo key distingués | PASS | settings + descriptor + header sensible |
| CoinMarketCap SOL/USD adapter public | PASS | `market_price_coinmarketcap.rs` |
| CoinMarketCap Simple Price V2 utilisé, V1 deprecated absent du runtime | PASS | endpoints V2 fixes + canari dependency boundary |
| CoinMarketCap keyless et Basic key distingués | PASS | settings + descriptor + header sensible |
| CoinPaprika SOL/USD adapter public | PASS | `market_price_coinpaprika.rs` |
| CoinPaprika sans faux credential | PASS | settings keyless uniquement |
| prix JSON provider parsé exactement sans passage par `f64` | PASS | `RawValue` -> `MarketPriceDecimal::parse_json_raw` |
| timestamps provider conservés lorsqu'ils existent | PASS | Unix seconds CoinGecko, RFC3339 CoinMarketCap/CoinPaprika |
| DTOs wire provider privés | PASS | structs privées dans chaque module provider |
| endpoints provider fixes et HTTPS | PASS | constantes privées + `HttpGetRequest::new_https` |
| API keys absentes de `Debug` et diagnostics | PASS | `MarketPriceApiKey` redacted + tests settings |
| `429` alimente le cooldown local partagé | PASS | `get_json` -> `record_rate_limited` |
| aucun SDK provider | PASS | manifest + boundary tests |
| Config, registry global et refresh multiple non avancés | PASS | scopes réservés à `pre.007+` / `pre.009` |
| audit Rust sandbox | PASS | clean, 0 candidate export |
| audit Markdown sandbox | PASS | à recalculer après finalisation documentaire |
| gate Cargo complet `pre.004` | PENDING | opérateur |
Les tests déterministes de `pre.004` couvrent les modes d'auth, les headers sans fuite de credential, les URLs/query fixes, le parsing des réponses SOL/USD, le rejet d'identités ou schémas incohérents et le parsing exact des nombres JSON. Aucun smoke réseau n'est revendiqué dans cette tranche.
## 4. Matrice provider prévue
| Provider | SOL/USD V1 | Gratuit V1 | Mode auth prévu | Test déterministe | Smoke live | Statut courant |
|-------------------|------------|------------|----------------------|-------------------|------------|----------------|
| CoinGecko | Oui | Oui | keyless ou Demo key | PLANNED | PLANNED | AUDITED |
| CoinMarketCap | Oui | Oui | keyless ou Basic key | PLANNED | PLANNED | AUDITED |
| CoinPaprika | Oui | Oui | aucune | PLANNED | PLANNED | AUDITED |
| CoinGecko | Oui | Oui | keyless ou Demo key | PASS | PLANNED | IMPLEMENTED |
| CoinMarketCap | Oui | Oui | keyless ou Basic key | PASS | PLANNED | IMPLEMENTED |
| CoinPaprika | Oui | Oui | aucune | PASS | PLANNED | IMPLEMENTED |
| Kraken | Oui | Oui | aucune | PLANNED | PLANNED | AUDITED |
| Coinbase Exchange | Oui | Oui | aucune | PLANNED | PLANNED | AUDITED |
| Jupiter Price V3 | Oui | Oui | keyless ou Free key | PLANNED | PLANNED | AUDITED |
@@ -185,8 +214,8 @@ Avant la stable, les conditions d'usage et la persistance des offres gratuites d
| cadence locale fixe représentable | PASS |
| burst documenté supérieur à la cadence moyenne représentable | PASS |
| limite dynamique keyless représentable | PASS |
| `429` classé | PLANNED |
| `Retry-After` honoré lorsqu'exploitable | PLANNED |
| `429` classé | PASS |
| `Retry-After` honoré lorsqu'exploitable | PASS |
| cooldown expose prochain instant admissible | PLANNED |
| refresh all ne lance que les providers éligibles | PLANNED |
| provider en cooldown ne bloque pas les autres | PLANNED |
@@ -197,36 +226,36 @@ Avant la stable, les conditions d'usage et la persistance des offres gratuites d
## 7. Numeric safety
| Cas | Statut |
|-----------------------------------------------------|---------|
| décimal string valide | PASS |
| JSON number valide sans passage canonique par `f64` | PLANNED |
| notation scientifique bornée | PASS |
| coefficient/scale overflow rejeté | PASS |
| valeur négative rejetée | PASS |
| zéro rejeté pour une observation réussie | PASS |
| NaN/Inf impossibles dans le type canonique | PASS |
| serialization canonique sans perte | PASS |
| round-trip public déterministe | PASS |
| Cas | Statut |
|-----------------------------------------------------|--------|
| décimal string valide | PASS |
| JSON number valide sans passage canonique par `f64` | PASS |
| notation scientifique bornée | PASS |
| coefficient/scale overflow rejeté | PASS |
| valeur négative rejetée | PASS |
| zéro rejeté pour une observation réussie | PASS |
| NaN/Inf impossibles dans le type canonique | PASS |
| serialization canonique sans perte | PASS |
| round-trip public déterministe | PASS |
## 8. HTTP et sécurité
| Invariant | Statut |
|------------------------------------------------|---------|
| `reqwest` seul client provider | PLANNED |
| aucun SDK provider | PLANNED |
| endpoint provider officiel fixe en V1 | PLANNED |
| redirects désactivés | PLANNED |
| proxy implicite désactivé selon policy KSP | PLANNED |
| connect timeout borné | PLANNED |
| request timeout borné | PLANNED |
| body réponse borné avant parsing | PLANNED |
| URL retirée des erreurs reqwest | PLANNED |
| réponse remote brute absente des KspError/logs | PLANNED |
| API key absente de Debug/log/error | PLANNED |
| 401/403 classés auth/access | PLANNED |
| 429 classé rate limit | PLANNED |
| 5xx classé transient | PLANNED |
| `reqwest` seul client provider | PASS |
| aucun SDK provider | PASS |
| endpoint provider officiel fixe en V1 | PASS |
| redirects désactivés | PASS |
| proxy implicite désactivé selon policy KSP | PASS |
| connect timeout borné | PASS |
| request timeout borné | PASS |
| body réponse borné avant parsing | PASS |
| URL retirée des erreurs reqwest | PASS |
| réponse remote brute absente des KspError/logs | PASS |
| API key absente de Debug/log/error | PASS |
| 401/403 classés auth/access | PASS |
| 429 classé rate limit | PASS |
| 5xx classé transient | PASS |
| schema drift classé provider protocol | PLANNED |
## 9. DexScreener V1