v0.2.11-pre.007

This commit is contained in:
2026-08-26 10:06:21 +02:00
parent 98093d859b
commit 5aeff5ca14
14 changed files with 1142 additions and 45 deletions

View File

@@ -1,9 +1,9 @@
<!-- file: docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md -->
<!-- version: 12 -->
<!-- version: 13 -->
# Plan `0.2.11` — Off-chain price transport SOL/USD multi-provider
**Statut courant : `0.2.11-pre.006` ajoute Jupiter Price V3 et DexScreener à la famille `market_price`. Jupiter supporte keyless ou Free key sur `api.jup.ag`, conserve `SolanaHeuristic` et le `blockId` comme provenance sans inventer de timestamp de prix. DexScreener utilise exclusivement l'endpoint direct d'une paire Solana explicitement configurée, vérifie `chainId`, pair address et identité WSOL avant d'accepter `priceUsd`. Le gate opérateur ciblé de `pre.005` est PASS ; `cargo test --workspace` n'a pas été rejoué sur l'état exact `pre.005`.**
**Statut courant : `0.2.11-pre.007` complète les huit adapters `market_price` avec Birdeye Standard et matérialise le registry provider-neutral. Birdeye exige `X-API-KEY`, utilise `/defi/price` sur Solana/WSOL, modélise 1 RPS par compte, 30 000 compute units de quota informatif et 3 compute units par requête SOL/USD. Le registry expose uniquement descriptor + état générique en ordre déterministe ; le dispatch/refresh reste réservé à `pre.008`. Le gate opérateur ciblé de `pre.006` est PASS ; `cargo test --workspace` n'a pas été rejoué sur l'état exact `pre.006`.**
## 1. Base et autorité
@@ -245,6 +245,8 @@ Réaudit `pre.004` : CoinMarketCap Simple Price est implémenté sur la surface
Réaudit `pre.006` : le Developer Platform Jupiter courant utilise `https://api.jup.ag` pour les accès keyless et API-key. Le keyless est documenté à 0,5 RPS et le plan Free à 1 RPS. Price V3 expose `usdPrice` comme prix USD unique et `blockId` comme information de récence ; `createdAt` décrit la création du token et ne doit pas être transformé en timestamp du prix. DexScreener documente l'endpoint direct `/latest/dex/pairs/{chainId}/{pairId}` à 300 requêtes par minute. KSP sélectionne uniquement `chainId = solana` et interdit dans V1 les endpoints de search ou de découverte de pools.
Réaudit `pre.007` : Birdeye Standard reste gratuit à 30 000 compute units inclus et 1 RPS au niveau du compte. L'endpoint Price Single `GET /defi/price` consomme actuellement 3 compute units, exige `X-API-KEY`, accepte `x-chain: solana` et le mint canonique WSOL, et fournit `value` plus `updateUnixTime`. Le quota et le coût par requête sont des metadata informatives ; KSP ne décrémente jamais localement le quota comme une vérité authoritative.
### 6.1 Gratuité technique et conditions d'usage
Le verdict `IN` signifie ici qu'un accès HTTP gratuit permet techniquement de développer et live-tester le provider dans `0.2.11`. Il ne constitue pas une affirmation de gratuité commerciale permanente.
@@ -420,7 +422,7 @@ limitation générique
support SOL/USD
```
`pre.002` fixe `MarketPriceProviderId`, `MarketPriceProviderDescriptor`, `MarketPriceProviderAuthMode`, `MarketPriceProviderRateLimit`, `MarketPriceProviderLongTermQuota` et leurs enums de scope/période/unité. Les limites fixes exigent un budget et une fenêtre non nuls ; les limites dynamiques restent explicitement distinctes. Les quotas longs termes sont descriptifs et ne deviennent jamais un compteur local de quota restant.
`pre.002` fixe `MarketPriceProviderId`, `MarketPriceProviderDescriptor`, `MarketPriceProviderAuthMode`, `MarketPriceProviderRateLimit`, `MarketPriceProviderLongTermQuota` et leurs enums de scope/période/unité. `pre.007` ajoute `MarketPriceProviderRequestCost` et l'unité `ComputeUnits` afin de représenter sans perte le modèle Birdeye. Les limites fixes exigent un budget et une fenêtre non nuls ; les limites dynamiques restent explicitement distinctes. Les quotas longs termes et coûts unitaires sont descriptifs et ne deviennent jamais un compteur local de quota restant.
L'état runtime peut représenter au minimum :
@@ -434,7 +436,9 @@ misconfigured
disabled
```
`MarketPriceProviderAvailability` et `MarketPriceProviderState` matérialisent cette projection générique dès `pre.002`; le registry et les transitions runtime effectives restent prévus en `pre.007`.
`MarketPriceProviderAvailability` et `MarketPriceProviderState` matérialisent cette projection générique dès `pre.002`. `pre.007` ajoute `MarketPriceProviderRegistry` et `MarketPriceProviderRegistryEntry` : le registry est borné, trié de façon déterministe par `provider_id`, rejette les doublons et n'expose que `descriptor + state`. Son module ne contient aucun dispatch par nom de provider. Le registry reste une projection générique sans méthode de dispatch ni transition réseau ; le futur service `pre.008` possédera les mutations runtime et republiera les états mis à jour.
`MarketPriceProviderAvailability` expose aussi génériquement l'éligibilité immédiate au refresh et un `retry_at` lorsqu'il est réellement connu. `AuthenticationUnavailable`, `QuotaUnavailable`, `Misconfigured`, `Disabled`, `CoolingDown`, `TemporarilyUnavailable` et `Ready` restent distincts sans parsing provider dans les consumers.
Les noms Rust de cette fondation sont désormais matérialisés ; aucun consumer ne doit parser des strings d'erreur pour connaître cet état.
@@ -730,15 +734,15 @@ Implémentation des deux adapters exchange keyless avec DTOs wire privés et end
### `pre.006` — Jupiter et DexScreener
**Statut : réalisé, gate Cargo opérateur à exécuter.**
**Statut : réalisé, gate opérateur ciblé PASS ; workspace complet non rejoué.**
Implémentation des adapters Jupiter Price V3 et DexScreener avec DTOs wire privés et endpoints HTTPS officiels fixes. Jupiter distingue keyless à 0,5 requête par seconde et Free key à 1 requête par seconde sur le même `api.jup.ag`, utilise uniquement le mint WSOL et conserve `blockId` comme provenance de récence sans le convertir en timestamp. DexScreener exige un pair address Solana explicite dans ses settings, appelle uniquement `/latest/dex/pairs/solana/{pairId}`, vérifie `chainId = solana`, le pair address retourné et le mint WSOL comme base avant de lire `priceUsd`. Aucune découverte de pool, aucun tri de liquidité, aucun consensus et aucun registry global ne sont avancés.
### `pre.007` — Birdeye, registry et availability
**Statut : planifié.**
**Statut : réalisé, gate Cargo opérateur à exécuter.**
Implémentation de Birdeye avec son auth provider, finalisation du registry multi-provider et des états génériques d'indisponibilité.
Implémentation de Birdeye Standard avec `X-API-KEY`, endpoint Price Single Solana/WSOL, prix exact et timestamp provider réel. Le descriptor modélise 1 RPS par compte, 30 000 compute units de quota informatif et 3 compute units par refresh SOL/USD. `MarketPriceProviderRegistry` finalise l'inventaire runtime provider-neutral des huit adapters sous forme d'entrées `descriptor + state`, avec ordre déterministe et doublons rejetés. Les transitions runtime et le dispatch restent réservés à `pre.008`. Aucun dispatch de refresh, Config ou smoke live n'est avancé.
### `pre.008` — Refresh individuel et multiple

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md -->
<!-- version: 11 -->
<!-- version: 12 -->
# Validation `0.2.11` — Off-chain price transport SOL/USD
@@ -209,27 +209,55 @@ Les tests déterministes de `pre.005` couvrent les descriptors exchange, la pré
## 3.9 Gate `0.2.11-pre.006`
| Critère | Statut | Preuve |
|-----------------------------------------------------------------|---------|---------------------------------------------------------|
| version workspace `0.2.11-pre.6` | PASS | `Cargo.toml` racine |
| Jupiter Price V3 adapter public | PASS | `market_price_jupiter.rs` |
| Jupiter keyless et Free key distingués | PASS | settings + descriptor + header sensible |
| Jupiter keyless 0,5 RPS et Free 1 RPS représentés | PASS | descriptors + canaries unitaires |
| Jupiter utilise uniquement le mint WSOL | PASS | query `ids` fixe |
| `usdPrice` Jupiter parsé exactement sans `f64` canonique | PASS | `RawValue` -> `MarketPriceDecimal` |
| `blockId` Jupiter conservé en provenance sans faux timestamp | PASS | provenance bornée + `provider_timestamp = None` |
| DexScreener adapter public avec pair address explicite | PASS | `MarketPriceDexScreenerSettings` |
| DexScreener endpoint direct pair uniquement | PASS | `/latest/dex/pairs/solana/{pairId}` |
| DexScreener vérifie `chainId`, pair address et identité WSOL | PASS | parser provider |
| DexScreener utilise uniquement `priceUsd` | PASS | DTO wire privé + parsing exact |
| DexScreener 300 req/min représenté | PASS | descriptor provider |
| aucune découverte/selection/ranking automatique de pool | PASS | dependency boundary + absence search/token-pairs/tokens |
| aucun SDK provider, Config, registry ou refresh multiple avancé | PASS | manifest + scope des modules |
| audit Rust sandbox | PASS | clean, 0 candidate export |
| audit Markdown sandbox | PLANNED | à exécuter après réconciliation documentaire |
| gate Cargo | PLANNED | à exécuter par l'opérateur |
| Critère | Statut | Preuve |
|-----------------------------------------------------------------|--------|---------------------------------------------------------|
| version workspace `0.2.11-pre.6` | PASS | `Cargo.toml` racine |
| Jupiter Price V3 adapter public | PASS | `market_price_jupiter.rs` |
| Jupiter keyless et Free key distingués | PASS | settings + descriptor + header sensible |
| Jupiter keyless 0,5 RPS et Free 1 RPS représentés | PASS | descriptors + canaries unitaires |
| Jupiter utilise uniquement le mint WSOL | PASS | query `ids` fixe |
| `usdPrice` Jupiter parsé exactement sans `f64` canonique | PASS | `RawValue` -> `MarketPriceDecimal` |
| `blockId` Jupiter conservé en provenance sans faux timestamp | PASS | provenance bornée + `provider_timestamp = None` |
| DexScreener adapter public avec pair address explicite | PASS | `MarketPriceDexScreenerSettings` |
| DexScreener endpoint direct pair uniquement | PASS | `/latest/dex/pairs/solana/{pairId}` |
| DexScreener vérifie `chainId`, pair address et identité WSOL | PASS | parser provider |
| DexScreener utilise uniquement `priceUsd` | PASS | DTO wire privé + parsing exact |
| DexScreener 300 req/min représenté | PASS | descriptor provider |
| aucune découverte/selection/ranking automatique de pool | PASS | dependency boundary + absence search/token-pairs/tokens |
| aucun SDK provider, Config, registry ou refresh multiple avancé | PASS | manifest + scope des modules |
| audit Rust sandbox | PASS | clean, 0 candidate export |
| audit Markdown sandbox | PASS | clean, 120 tables / 111 fichiers |
| `cargo check` / Clippy / tests Off-chain | PASS | résultats opérateur du 2026-08-25 |
| `cargo test --workspace` sur état exact `pre.006` | N/R | non rejoué avant passage explicite à `pre.007` |
Les fixtures de `pre.006` couvrent Jupiter keyless/Free, redaction de la clé, prix exact, identité WSOL, `blockId`, absence volontaire de faux timestamp, ainsi que DexScreener avec pair Solana explicite, `priceUsd`, rejet de chain/pair/base invalides, réponse multiple et prix absent. Aucun smoke live n'est revendiqué dans cette tranche.
Les fixtures de `pre.006` couvrent Jupiter keyless/Free, redaction de la clé, prix exact, identité WSOL, `blockId`, absence volontaire de faux timestamp, ainsi que DexScreener avec pair Solana explicite, `priceUsd`, rejet de chain/pair/base invalides, réponse multiple et prix absent. Le gate opérateur ciblé du `2026-08-25` est PASS : audit Rust clean, audit Markdown clean à 120 tables / 111 fichiers, `cargo check --workspace` PASS, `cargo clippy --workspace --all-targets` PASS et `cargo test -p ksp-offchain-transport-lib` PASS avec 43 unitaires + 4 boundary + 5 public API. `cargo test --workspace` n'a pas été rejoué sur cet état exact.
## 3.10 Gate `0.2.11-pre.007`
| Critère | Statut | Preuve |
|------------------------------------------------------------------|---------|---------------------------------------|
| version workspace `0.2.11-pre.7` | PASS | `Cargo.toml` racine |
| Birdeye Standard SOL/USD adapter public | PASS | `market_price_birdeye.rs` |
| Birdeye exige `X-API-KEY` lorsqu'activé | PASS | settings + header sensible |
| Birdeye fixe `x-chain = solana` et le mint WSOL | PASS | request builder |
| Birdeye Price Single `value` parsé exactement | PASS | `RawValue` -> `MarketPriceDecimal` |
| Birdeye `updateUnixTime` conservé comme timestamp provider | PASS | parser provider |
| Birdeye Standard 1 RPS compte modélisé | PASS | descriptor provider |
| quota Birdeye 30 000 compute units informatif | PASS | `MarketPriceProviderLongTermQuota` |
| coût Price Single 3 compute units informatif | PASS | `MarketPriceProviderRequestCost` |
| registry provider-neutral matérialisé | PASS | `MarketPriceProviderRegistry` |
| huit providers V1 présents dans le canari de complétude registry | PASS | test `market_price_registry` |
| registry trié par provider id et doublons rejetés | PASS | constructeur public générique + tests |
| entry publique limitée à descriptor + état générique | PASS | `MarketPriceProviderRegistryEntry` |
| availability expose éligibilité et `retry_at` génériques | PASS | `MarketPriceProviderAvailability` |
| registry sans mutation ou dispatch réseau | PASS | projection générique publique |
| registry ne contient aucun dispatch/name provider | PASS | dependency boundary |
| refresh single/multiple, Config et smoke live non avancés | PASS | scope réservé à `pre.008+` |
| audit Rust sandbox | PASS | clean, 0 candidate export |
| audit Markdown sandbox | PASS | clean, 121 tables / 112 fichiers |
| gate Cargo | PLANNED | à exécuter par l'opérateur |
Les tests déterministes de `pre.007` couvrent l'auth Birdeye et sa redaction, le descriptor 1 RPS / 30 000 CU / 3 CU, le parsing exact du prix et du timestamp, les réponses invalides, ainsi que le registry complet des huit providers, son ordre déterministe, le rejet de doublons et les projections d'availability. Aucun refresh réseau générique ni smoke live n'est revendiqué dans cette tranche.
## 4. Matrice provider prévue
@@ -241,7 +269,7 @@ Les fixtures de `pre.006` couvrent Jupiter keyless/Free, redaction de la clé, p
| Kraken | Oui | Oui | aucune | PASS | PLANNED | IMPLEMENTED |
| Coinbase Exchange | Oui | Oui | aucune | PASS | PLANNED | IMPLEMENTED |
| Jupiter Price V3 | Oui | Oui | keyless ou Free key | PASS | PLANNED | IMPLEMENTED |
| Birdeye | Oui | Oui | API key Standard | PLANNED | PLANNED | AUDITED |
| Birdeye | Oui | Oui | API key Standard | PASS | PLANNED | IMPLEMENTED |
| DexScreener | Oui | Oui | aucune | PASS | PLANNED | IMPLEMENTED |
`AUDITED` signifie uniquement que la documentation officielle actuelle satisfait le gate d'entrée. Ce statut ne vaut pas preuve d'un smoke réseau KSP.
@@ -262,7 +290,7 @@ Avant la stable, les conditions d'usage et la persistance des offres gratuites d
| `f64` non utilisé comme canon public | PASS |
| aucune structure wire provider exportée | PASS |
| aucune URL/header/asset id provider requis côté app | PASS |
| registry provider et état runtime possédés par Off-chain Transport | PLANNED |
| registry provider et état runtime possédés par Off-chain Transport | PASS |
| refresh provider par identifiant générique | PLANNED |
| refresh multiple sans connaissance provider côté consumer | PLANNED |
@@ -275,13 +303,13 @@ Avant la stable, les conditions d'usage et la persistance des offres gratuites d
| limite dynamique keyless représentable | PASS |
| `429` classé | PASS |
| `Retry-After` honoré lorsqu'exploitable | PASS |
| cooldown expose prochain instant admissible | PLANNED |
| cooldown expose prochain instant admissible | PASS |
| refresh all ne lance que les providers éligibles | PLANNED |
| provider en cooldown ne bloque pas les autres | PLANNED |
| provider down ne rend pas le service global inutilisable | PLANNED |
| auth manquante distinguée d'un transport down | PLANNED |
| quota indisponible distingué d'un transport down | PLANNED |
| quota mensuel local non présenté comme compteur authoritative | PLANNED |
| quota mensuel local non présenté comme compteur authoritative | PASS |
## 7. Numeric safety