v0.2.11-pre.003
This commit is contained in:
300
deltas/0.2.11/pre.003.md
Normal file
300
deltas/0.2.11/pre.003.md
Normal file
@@ -0,0 +1,300 @@
|
||||
<!-- file: deltas/0.2.11/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.11-pre.003` — HTTP REST commun et rate limiting
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement après :
|
||||
|
||||
```text
|
||||
v0.2.10
|
||||
+ 0.2.11-pre.001
|
||||
+ 0.2.11-pre.001-fix.001
|
||||
+ 0.2.11-pre.002
|
||||
+ 0.2.11-pre.002-fix.001
|
||||
+ 0.2.11-pre.002-fix.002
|
||||
+ 0.2.11-pre.002-fix.003
|
||||
```
|
||||
|
||||
La version Cargo attendue à l'entrée est :
|
||||
|
||||
```text
|
||||
0.2.11-pre.2.fix.3
|
||||
```
|
||||
|
||||
La version Cargo de sortie est :
|
||||
|
||||
```text
|
||||
0.2.11-pre.3
|
||||
```
|
||||
|
||||
## 2. Gate d'entrée acquis
|
||||
|
||||
L'opérateur a validé `0.2.11-pre.002-fix.003` le `2026-08-25` avec :
|
||||
|
||||
```text
|
||||
cargo fmt --all exécuté
|
||||
python3 scripts/audit_rust_workspace_rules.py clean
|
||||
python3 scripts/audit_markdown_tables.py clean, 116 tables / 105 files
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-offchain-transport-lib PASS, 10 unit + 1 boundary + 2 public API
|
||||
```
|
||||
|
||||
`cargo test --workspace` n'a pas été fourni pour cet état exact et n'est pas déclaré PASS ici.
|
||||
|
||||
## 3. Objectif
|
||||
|
||||
Matérialiser les primitives HTTP REST communes de `ksp-offchain-transport-lib` et le rate limiting local sans avancer aucun provider.
|
||||
|
||||
La tranche doit préparer directement `pre.004+` tout en conservant les frontières :
|
||||
|
||||
```text
|
||||
http_* = mécanique transport crate-wide et crate-private
|
||||
market_price_* = première capacité métier, SOL/USD uniquement
|
||||
aucun client HTTP générique exporté aux consumers
|
||||
aucun SDK provider
|
||||
aucun Config -> Off-chain ajouté avant pre.009
|
||||
aucun refresh registry/service avant pre.007/pre.008
|
||||
```
|
||||
|
||||
## 4. HTTP REST commun
|
||||
|
||||
`http_client.rs` matérialise un `reqwest::Client` réutilisable par les adapters internes.
|
||||
|
||||
La construction impose explicitement :
|
||||
|
||||
```text
|
||||
rustls
|
||||
redirects désactivés
|
||||
Referer automatique désactivé
|
||||
proxy système désactivé
|
||||
retries implicites reqwest désactivés
|
||||
User-Agent KSP explicite
|
||||
connect timeout borné
|
||||
request timeout borné
|
||||
```
|
||||
|
||||
`reqwest` reste une dépendance directe de la crate et aucun SDK provider n'est ajouté.
|
||||
|
||||
La requête GET interne :
|
||||
|
||||
```text
|
||||
accepte uniquement HTTPS pour les adapters runtime
|
||||
refuse credentials dans l'URL
|
||||
encode les query pairs via Url
|
||||
permet des headers sensibles marqués sensitive
|
||||
redacte URL et headers dans Debug
|
||||
```
|
||||
|
||||
Un constructeur HTTP non HTTPS existe uniquement sous `cfg(test)` pour les serveurs loopback déterministes.
|
||||
|
||||
## 5. Bornes de réponse et JSON
|
||||
|
||||
Les valeurs initiales sont :
|
||||
|
||||
```text
|
||||
connect timeout défaut = 5 s
|
||||
connect timeout hard max = 30 s
|
||||
request timeout défaut = 10 s
|
||||
request timeout hard max = 120 s
|
||||
body défaut = 1 MiB
|
||||
body hard max = 4 MiB
|
||||
```
|
||||
|
||||
Le body est borné pendant sa lecture par chunks. La présence ou l'absence de `Content-Length` ne permet donc pas de contourner la limite.
|
||||
|
||||
Après lecture, la syntaxe JSON est validée avec `serde::de::IgnoredAny`. Le document brut borné reste disponible pour le futur adapter typed, ce qui évite de faire passer un nombre provider par une représentation générique `f64` avant le parsing `MarketPriceDecimal`.
|
||||
|
||||
## 6. Classification HTTP
|
||||
|
||||
Les codes crate-wide ajoutés sous le domaine `offchain_transport` distinguent :
|
||||
|
||||
```text
|
||||
http_settings_invalid
|
||||
http_client_build_failed
|
||||
http_request_invalid
|
||||
http_connection_failed
|
||||
http_timeout
|
||||
http_request_failed
|
||||
http_access_denied
|
||||
http_rate_limited
|
||||
http_temporary_failure
|
||||
http_response_too_large
|
||||
http_invalid_json
|
||||
http_rate_limit_invalid
|
||||
```
|
||||
|
||||
La classification de statut est :
|
||||
|
||||
```text
|
||||
401/403 -> access denied
|
||||
429 -> rate limited
|
||||
408 et 5xx -> temporary failure
|
||||
autre non-2xx -> request failed
|
||||
2xx -> body borné puis JSON syntaxiquement validé
|
||||
```
|
||||
|
||||
Les erreurs `reqwest` sont converties après `without_url()`. Aucun body remote n'est recopié dans `KspError`.
|
||||
|
||||
`Retry-After` est actuellement exploité sous sa forme `delta-seconds`, bornée défensivement à une heure. Une forme HTTP-date non parseable reste ignorée plutôt que devinée.
|
||||
|
||||
## 7. Admission et cooldown
|
||||
|
||||
`http_admission.rs` fournit un limiter non bloquant.
|
||||
|
||||
Les policies internes sont :
|
||||
|
||||
```text
|
||||
Fixed
|
||||
Dynamic
|
||||
Unlimited
|
||||
```
|
||||
|
||||
Une policy fixe utilise un token bucket lissé :
|
||||
|
||||
```text
|
||||
requests/window
|
||||
burst explicite uniquement lorsqu'il est documenté
|
||||
burst absent -> capacité locale conservatrice de 1
|
||||
```
|
||||
|
||||
Une policy dynamique n'invente aucune cadence locale. Elle applique seulement les cooldowns appris du provider.
|
||||
|
||||
`try_admit()` ne dort jamais : il retourne immédiatement `Ready` ou `Deferred(duration)`. Cette propriété prépare le `refresh multiple/all` de `pre.008`, qui devra continuer avec les autres providers au lieu d'attendre un provider en cooldown.
|
||||
|
||||
Un `429` peut étendre le cooldown avec `Retry-After`; la durée provider est bornée à une heure et comparée au fallback local.
|
||||
|
||||
## 8. Tests ajoutés
|
||||
|
||||
Les nouveaux tests unitaires couvrent :
|
||||
|
||||
```text
|
||||
settings HTTP par défaut et bornes pathologiques
|
||||
policy fixe invalide
|
||||
burst absent lissé conservativement
|
||||
burst documenté consommé atomiquement
|
||||
refill déterministe du token bucket
|
||||
cooldown provider et borne Retry-After
|
||||
Debug request sans URL/credential
|
||||
GET JSON valide
|
||||
redirect refusé
|
||||
body chunked dépassant la limite
|
||||
429 + Retry-After sans propagation du body canari
|
||||
JSON invalide après statut 2xx
|
||||
```
|
||||
|
||||
Les canaries d'intégration vérifient aussi :
|
||||
|
||||
```text
|
||||
reqwest rustls présent
|
||||
Config toujours absent
|
||||
SDK providers toujours absents
|
||||
tracing direct toujours absent
|
||||
modules http_* présents
|
||||
HttpRestClient non exporté publiquement
|
||||
redirect/no-proxy/no-retry/without_url explicites dans le client
|
||||
codes d'erreur HTTP dans le domaine offchain_transport
|
||||
```
|
||||
|
||||
## 9. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-offchain-transport-lib/src/http_admission.rs
|
||||
crates/ksp-offchain-transport-lib/src/http_client.rs
|
||||
crates/ksp-offchain-transport-lib/src/http_settings.rs
|
||||
crates/ksp-offchain-transport-lib/unit_tests/http_admission.rs
|
||||
crates/ksp-offchain-transport-lib/unit_tests/http_client.rs
|
||||
crates/ksp-offchain-transport-lib/unit_tests/http_settings.rs
|
||||
deltas/0.2.11/pre.003.md
|
||||
```
|
||||
|
||||
## 10. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-offchain-transport-lib/Cargo.toml
|
||||
crates/ksp-offchain-transport-lib/src/error.rs
|
||||
crates/ksp-offchain-transport-lib/src/lib.rs
|
||||
crates/ksp-offchain-transport-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-offchain-transport-lib/tests/public_api.rs
|
||||
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
|
||||
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
|
||||
```
|
||||
|
||||
## 11. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 12. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
README.md
|
||||
.env.example
|
||||
config/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
`ROADMAP.md` et `CHANGELOG.md` restent hors de la tranche conformément à leur ownership de release.
|
||||
|
||||
## 13. Validations exécutées dans le sandbox
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.11
|
||||
clean
|
||||
|
||||
contrôle lignes Rust > 160 sur ksp-offchain-transport-lib
|
||||
PASS
|
||||
|
||||
inspection diff contre 0.2.11-pre.002-fix.003
|
||||
aucun provider adapter ajouté
|
||||
aucune dépendance ksp-config-lib ajoutée
|
||||
aucune dépendance tracing directe ajoutée
|
||||
```
|
||||
|
||||
## 14. Validations non exécutées dans le sandbox
|
||||
|
||||
Le sandbox de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`.
|
||||
|
||||
Après application, exécuter :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.11
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-offchain-transport-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
## 15. Décisions et points différés
|
||||
|
||||
Aucune question ne bloque `pre.004`.
|
||||
|
||||
Restent volontairement différés :
|
||||
|
||||
```text
|
||||
mapping MarketPriceProviderRateLimit -> HttpAdmissionPolicy par provider
|
||||
CoinGecko/CoinMarketCap/CoinPaprika wire DTOs et endpoints
|
||||
credentials provider effectifs
|
||||
registry et availability runtime
|
||||
refresh single/multiple
|
||||
Config std.offchain_transport
|
||||
Retry-After HTTP-date si un provider retenu l'exige réellement
|
||||
POST/écritures HTTP pour futures familles off-chain
|
||||
```
|
||||
|
||||
`pre.004` reste propriétaire du premier lot d'adapters : CoinGecko, CoinMarketCap et CoinPaprika.
|
||||
Reference in New Issue
Block a user