Files
khadhroony-solana-project/docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
2026-08-25 21:00:19 +02:00

34 KiB

Plan 0.2.11 — Off-chain price transport SOL/USD multi-provider

Statut courant : 0.2.11-pre.003 matérialise le HTTP REST commun et le rate limiting provider-neutral sans encore ajouter d'adapter provider. Les primitives http_* restent internes à la crate et réutilisables par les futures familles off-chain ; market_price_* reste la seule famille métier actuelle et demeure limitée à SOL/USD.

1. Base et autorité

Base stable autoritaire :

v0.2.10

État vérifié dans l'archive Gitea fournie :

workspace.package.version = 0.2.10
deltas/0.2.10/rel.001.md présent
prompts/016-V0_2_11_START_PROMPT.md présent
ksp-offchain-transport-lib absente
metadata .git absente de l'archive Gitea

Cette tranche ouvre :

workspace.package.version = 0.2.11-pre.1
commit attendu            = v0.2.11-pre.001
aucun tag prerelease

Ordre d'autorité pendant 0.2.11 :

règles normatives KSP
archive stable v0.2.10 et code réellement livré
décisions opérateur consignées dans le présent plan
validation 014 et deltas immuables de 0.2.11
prompt 016 pour les contraintes non supersédées
sources provider officielles actuelles pour les faits externes

2. Supersessions explicites du prompt d'ouverture

Le brainstorming opérateur du 2026-08-25 remplace plusieurs hypothèses préparatoires du prompt 016.

minimum V1                 SOL/USD uniquement
nombre de providers        un ou plusieurs, sans limite artificielle à un provider initial
providers ciblés           tous les candidats gratuits retenus par le gate pre.001
transport provider         HTTP REST avec reqwest uniquement
SDK provider               interdit dans 0.2.11
SOL/EUR                     hors scope de cette première release
fallback automatique       hors scope
consensus/agrégation KSP    hors scope
future application         ksp-app-solprices-desk en 0.2.12
rôle de l'application      HID pure, aucune connaissance d'un provider
DexScreener V1             un client SOL/USD sur une paire configurée et validée

Le retrait de SOL/EUR n'interdit pas son ajout ultérieur. Il évite de forcer dès V1 une conversion fiat externe ou de privilégier artificiellement les providers multi-fiat.

3. Mission opérationnelle

0.2.11 doit créer ksp-offchain-transport-lib comme propriétaire de la récupération de prix off-chain SOL/USD et des différences opérationnelles entre providers.

La surface commune doit permettre à un consumer de :

lister les providers de prix connus du service
observer leur description et leur sémantique générique
observer leur disponibilité runtime
observer leur capacité de refresh et le prochain instant admissible
rafraîchir un provider par identifiant opaque
rafraîchir plusieurs providers sans violer leurs limites respectives
obtenir une observation SOL/USD typée et sa provenance
obtenir une absence/erreur/cooldown sans connaissance du fournisseur

La crate possède les exceptions provider. Un consumer ne doit pas coder :

URL provider
header d'auth provider
ID CoinGecko ou CoinMarketCap
mint Jupiter/Birdeye
paire Kraken/Coinbase
pair address DexScreener
rate limit provider
forme JSON wire provider
mapping de status HTTP provider

3.1 Taxonomie interne durable de ksp-offchain-transport-lib

ksp-offchain-transport-lib est une crate de transport off-chain hétérogène. 0.2.11 n'en définit que la première famille fonctionnelle ; la crate elle-même ne doit pas être structurée comme si toutes ses responsabilités futures étaient des prix.

La convention retenue à partir de pre.002-fix.001 est :

constants.rs                    préoccupations partagées à toute la crate
error.rs                        erreurs partagées / codes crate-wide
http_*                          mécanique HTTP réutilisable entre familles lorsqu'elle sera matérialisée
market_price_*                  prix de marché / spot et observations normalisées
swap_quote_*                    réservé aux futures quotes montant/route, uniquement lorsqu'elles seront réellement implémentées
<future_capability>_*           nouvelle famille uniquement lorsqu'un scope réel l'exige

Les fichiers génériques decimal.rs, observation.rs, provider.rs et settings.rs introduits initialement par pre.002 sont donc corrigés avant toute extension runtime : la fonctionnalité actuelle est préfixée market_price_*. Les futurs domaines ne doivent pas être ajoutés dans ces modules uniquement parce qu'ils utilisent eux aussi un provider HTTP.

La même frontière s'applique à la façade publique. À partir de pre.002-fix.003, tout symbole public spécifique à cette famille porte un nom explicitement MarketPrice* ou MARKET_PRICE_* : MarketPriceDecimal, MarketPriceObservation, MarketPriceProviderId, MarketPriceProviderDescriptor, MarketPriceProviderRateLimit, etc. Aucun alias public Price* n'est conservé pendant cette prerelease, car il figerait précisément l'ambiguïté que le correctif supprime. Une future famille swap_quote_* devra employer son propre préfixe public SwapQuote*; une abstraction sans préfixe de famille ne pourra être créée que lorsqu'un invariant réellement partagé aura été démontré.

La règle est responsabilité avant taille : un module commun n'est promu au niveau crate-wide que lorsqu'au moins deux familles réelles partagent le même invariant. Ainsi, le HTTP, le scheduling ou une identité provider pourront être factorisés plus tard si leur partage est effectivement démontré ; aucune abstraction générique n'est créée aujourd'hui uniquement pour anticiper Jupiter Quotes.

3.2 Lecture, écriture et verbes HTTP

La capacité market_price de 0.2.11 est strictement read-only. La crate n'est toutefois pas déclarée architecturalement read-only pour toutes ses versions futures.

L'ownership dépend de la sémantique métier, pas du verbe HTTP :

GET/POST qui récupère ou calcule une donnée off-chain       peut appartenir à Off-chain Transport
quote de swap dépendante d'un montant et d'une route        future famille swap_quote, pas market_price
construction distante d'un payload sans soumission          à auditer selon le contrat futur
soumission/signature d'une transaction Solana               reste hors d'Off-chain Transport
écriture distante ayant un effet métier externe             nécessite un scope/contrat explicite avant ajout

Un futur endpoint Jupiter utilisant POST ne devient donc pas automatiquement une « écriture » KSP. Inversement, aucune opération mutante distante n'est autorisée implicitement sous prétexte qu'elle passe par reqwest.

4. Frontière avec la future ksp-app-solprices-desk

La release suivante doit créer :

ksp-app-solprices-desk

Son rôle est purement HID.

Elle dépend de la façade publique de ksp-offchain-transport-lib et ne connaît aucun provider individuellement. Son premier tableau pourra afficher génériquement :

nom d'affichage provider
prix SOL/USD
fraîcheur disponible
état runtime
prochain refresh possible
bouton refresh

Un bouton de refresh multiple/all appelle une opération générique du service. L'application ne fait aucun sleep, aucun token bucket, aucun retry provider et aucun dispatch par nom de provider.

La composition Rust de l'application peut utiliser Config pour obtenir les settings puis construire le service Off-chain Transport, mais elle ne matche pas les variantes provider pour exécuter une requête.

5. Baseline technique interne

L'inventaire de v0.2.10 confirme que les primitives génériques nécessaires existent déjà au workspace :

reqwest    ^0.13
serde      ^1.0
serde_json ^1.0
tokio      ^1.53
http       ^1.5
chrono     ^0.4 si parsing timestamp réellement nécessaire

Décision de dépendances V1 :

aucun SDK CoinGecko
aucun SDK CoinMarketCap
aucun SDK CoinPaprika
aucun SDK Kraken
aucun SDK Coinbase
aucun SDK Jupiter
aucun SDK Birdeye
aucun SDK DexScreener
aucune bibliothèque decimal provider/externe ajoutée par facilité

Les adapters utilisent reqwest et des DTOs wire privés KSP. 0.2.11-pre.001 n'ajoute encore aucune crate ni dépendance.

6. Audit provider actuel du 2026-08-25

Les huit providers ci-dessous satisfont le critère fonctionnel retenu : accès gratuit actuel, HTTP REST simple et possibilité de produire SOL/USD sans SDK provider.

Provider Accès gratuit V1 Auth V1 Limite ou quota à modéliser Sémantique SOL/USD Verdict
CoinGecko keyless ou Demo aucune ou Demo key keyless dynamique IP, Demo 100 par min et 10k mois agrégateur marché CoinGecko IN
CoinMarketCap keyless ou Basic aucune ou API key keyless dynamique IP, Basic 50 par min et 15k mois agrégateur marché CoinMarketCap IN
CoinPaprika Free aucune 10 par sec IP et 20k mois, refresh moyen 5 min agrégateur marché CoinPaprika IN
Kraken public Spot REST aucune cadence sûre documentée à 1 par sec ou moins dernier trade du marché Kraken SOL/USD IN
Coinbase Exchange public Exchange REST aucune 10 par sec IP, burst 15 dernier trade du produit Coinbase SOL-USD IN
Jupiter Price V3 keyless ou Free aucune ou API key keyless 0.5 RPS, Free 1 RPS heuristique de prix USD orientée Solana IN
Birdeye Standard X-API-KEY obligatoire 1 RPS compte, 30k CU, Price Single 3 CU spot USD token Solana Birdeye IN
DexScreener API publique gratuite aucune 300 par min pour pairs/tokens priceUsd de la paire DEX Solana configurée IN

Sources officielles principales auditées :

https://docs.coingecko.com/docs/keyless-public-api
https://docs.coingecko.com/reference/simple-price
https://www.coingecko.com/en/api/pricing

https://coinmarketcap.com/api/documentation/pro-api-reference/keyless-public-api
https://coinmarketcap.com/api/documentation/pro-api-reference/cryptocurrency
https://coinmarketcap.com/api/pricing

https://docs.coinpaprika.com/api-reference/rest-api/introduction
https://docs.coinpaprika.com/api-reference/tickers/get-ticker-for-a-specific-coin
https://docs.coinpaprika.com/api-plans

https://support.kraken.com/articles/206548367-what-are-the-api-rate-limits-
https://support.kraken.com/hc/articles/360000919986-public-endpoint-examples-you-can-try-them-directly-in-a-web-browser-
https://docs.kraken.com/api/docs/rest-api/get-ticker-information

https://docs.cdp.coinbase.com/exchange/rest-api/rate-limits
https://docs.cdp.coinbase.com/api-reference/exchange-api/rest-api/products/get-product-ticker
https://docs.cdp.coinbase.com/api-reference/exchange-api/rest-api/products/get-single-product

https://developers.jup.ag/docs/portal/migration
https://developers.jup.ag/pricing
https://developers.jup.ag/docs/price

https://docs.birdeye.so/docs/pricing
https://docs.birdeye.so/docs/rate-limiting
https://docs.birdeye.so/reference/get-defi-price
https://docs.birdeye.so/docs/compute-unit-cost

https://docs.dexscreener.com/api/reference
https://docs.dexscreener.com/

Les chiffres externes sont une photographie d'audit, pas une constante éternelle. Les adapters doivent rester capables de classer 429 et les informations serveur sans supposer que la documentation ne changera jamais.

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.

L'audit du 2026-08-25 relève notamment :

CoinGecko keyless est présenté pour faible volume, expérimentation/prototypage et usages assimilés ; le plan Demo porte ses propres conditions et attribution
CoinMarketCap keyless est présenté pour évaluation/prototypage ; un plan authentifié reste la voie documentée pour un usage avec allowance dédiée
CoinPaprika Free est annoncé pour usage personnel ; l'usage commercial relève des offres payantes actuelles

Conséquence KSP :

les adapters gratuits restent implémentables en V1
aucune documentation stable KSP ne promet une gratuité commerciale durable
les conditions d'usage et plans gratuits sont réaudités au gate live final avant publication stable
un changement de plan/licence peut rendre un provider administrativement indisponible sans casser le contrat provider-neutral

7. Providers écartés de V1

Pyth Hermes

Pyth reste intéressant comme oracle mais la transition Pyth Core annoncée pour le 2026-08-26 rend son modèle d'accès immédiatement mouvant et ne garantit pas un accès gratuit durable après la période d'essai.

Décision :

Pyth = OUT de 0.2.11 V1

Un audit ultérieur pourra l'ajouter comme sémantique oracle distincte.

Binance

Aucune assimilation implicite de SOL/USDT à SOL/USD n'est admise.

Décision :

Binance = OUT tant qu'un produit SOL/USD direct et pertinent n'est pas retenu explicitement

8. Identité et sémantique de la paire V1

Le contrat public V1 ne devient pas un moteur générique de symboles.

La seule paire fonctionnelle exposée est :

SOL/USD

Les identifiants propriétaires restent privés aux adapters ou aux settings provider :

CoinGecko       coin id solana
CoinMarketCap   asset id 5426
CoinPaprika     coin id sol-solana
Kraken          pair SOLUSD
Coinbase        product SOL-USD
Jupiter         mint SOL canonique attendu par Price V3
Birdeye         mint SOL canonique attendu par Price Single
DexScreener     pair address configurée, base SOL vérifiée

Le résultat commun ne prétend pas que les prix sont équivalents. Le descriptor générique expose une classe de sémantique, par exemple :

AggregatedMarket
ExchangeLastTrade
SolanaHeuristic
SolanaSpot
DexPairUsd

Le nom final des variantes appartient à pre.002, mais la distinction sémantique est obligatoire.

9. Cas DexScreener V1

Décision opérateur : 0.2.11 implémente bien DexScreener, mais uniquement comme client SOL/USD.

Le client V1 :

utilise un pair address Solana configuré
appelle l'endpoint pair direct
vérifie chainId = solana
vérifie que la paire correspond au SOL attendu
lit uniquement priceUsd pour le contrat commun
conserve la pair address comme provenance provider sûre
ne recherche pas automatiquement la meilleure pool
ne sélectionne pas par liquidité
ne construit aucun consensus entre pools

Le choix d'une paire explicite évite d'introduire silencieusement une politique de sélection DEX. Une future version pourra remplacer cette stratégie sans modifier le contrat HID de ksp-app-solprices-desk.

10. Représentation numérique

Le gate rejette f64 comme représentation canonique publique du prix.

Décision matérialisée en pre.002 : MarketPriceDecimal est le type décimal KSP borné, sérialisable sans perte et construit depuis la représentation textuelle du provider.

Contrat V1 exact :

coefficient positif u128
scale bornée à 18 décimales
entrée textuelle bornée à 96 octets
normalisation des zéros terminaux
parsing décimal et notation scientifique bornés sans passage par f64
aucun NaN
aucun Inf
overflow rejeté
zéro/négatif rejetés pour un prix réussi
serialization canonique décimale en chaîne

Le wire d'un provider peut être JSON number ou string. L'adapter le convertit vers le type KSP sans utiliser as_f64() comme vérité canonique.

MarketPriceDecimal sérialise toujours sa valeur canonique sous forme de chaîne décimale non scientifique. Le zéro est invalide pour ce type puisqu'il représente exclusivement un prix réussi ; l'absence de prix reste donc hors de la valeur numérique elle-même.

Cette solution évite d'ajouter une crate decimal uniquement pour V1 et prépare le passage frontend sans perte IEEE-754.

11. Observation commune et fraîcheur

Une observation SOL/USD commune doit distinguer :

provider_id opaque
prix décimal KSP
sémantique de prix
instant de départ requête KSP
instant de réception KSP
instant provider optionnel lorsqu'il existe réellement
provenance provider sûre et bornée

pre.002 matérialise ce contrat avec MarketPriceObservation, MarketPriceTimestamp (millisecondes UTC depuis Unix epoch) et MarketPriceProvenance bornée à 256 octets sans caractères de contrôle. Le constructeur d'observation rejette un instant de réception antérieur au départ de requête.

Règles :

ne jamais inventer un timestamp provider
ne jamais interpréter un timestamp de création token comme timestamp de prix
ne jamais transformer block id, pair creation time ou autre champ en faux update time
absence de prix != prix zéro
stale != transport indisponible

12. Registry et état runtime

ksp-offchain-transport-lib possède un registry runtime des providers de prix activés/configurés.

Deux surfaces génériques doivent rester distinctes :

capabilities statiques auditées
état runtime courant

Le descriptor statique peut exposer :

provider id opaque
nom d'affichage
sémantique
mode d'auth générique
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.

L'état runtime peut représenter au minimum :

ready
cooling down avec prochain instant admissible
temporarily unavailable
authentication unavailable
quota unavailable
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.

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.

13. Rate limiting et refresh multiple

Le rate limiting appartient entièrement à ksp-offchain-transport-lib.

Le modèle doit savoir représenter :

cadence fixe
burst si documenté
fenêtre par seconde ou minute
quota long terme informatif
limite dynamique/server-driven
scope IP, compte ou organisation lorsque pertinent

Les quotas mensuels provider ne sont pas décrémentés comme une vérité authoritative locale : un autre processus peut consommer le même compte. Ils sont exposés comme capacités documentées ; les réponses provider restent la vérité runtime.

Refresh individuel

Un refresh(provider_id) :

vérifie l'éligibilité locale
exécute si autorisé
met à jour observation et état
classe 429 et Retry-After
ne contourne jamais le cooldown

Refresh multiple/all

Un refresh multiple :

évalue chaque provider indépendamment
lance concurremment les providers éligibles
ne bloque pas Coinbase parce que Jupiter est en cooldown
ne dort pas pour attendre tous les providers non éligibles
retourne un résultat générique par provider
expose le prochain instant admissible pour les providers différés

La future UI peut donc désactiver/annoter un bouton à partir de l'état retourné sans connaître la règle provider.

14. HTTP commun et résilience

Les adapters REST réutilisent les patterns sûrs déjà éprouvés dans KSP sans dépendre de ksp-onchain-transport-lib.

Décisions V1 :

reqwest uniquement
HTTPS officiel fixe dans les adapters V1
redirect désactivé
Referer automatique désactivé
proxy système/implicite désactivé
retries implicites reqwest désactivés
connect timeout borné : défaut 5 s, hard max 30 s
request timeout borné : défaut 10 s, hard max 120 s
GET uniquement pour les prix V1
body réponse borné avant désérialisation : défaut 1 MiB, hard max 4 MiB
JSON syntaxiquement validé avant remise à l'adapter typed
429 classé explicitement
Retry-After delta-seconds honoré et borné à 1 h lorsqu'il est exploitable
408 et 5xx classés transitoires
401/403 classés auth/access
URL retirée des erreurs reqwest avant contexte KSP
aucun body remote brut dans KspError

Il n'existe pas d'URL provider arbitraire dans la Config V1. Cela évite SSRF, redirection de credential et confusion de provenance.

Les primitives http_* sont crate-private : elles ne créent pas un client HTTP générique public contournant les capacités métier. Les adapters market_price_*, puis de futures familles telles que swap_quote_*, les consomment derrière leur propre contrat.

Le limiter pre.003 est non bloquant. Une cadence fixe est matérialisée par un token bucket lissé ; lorsqu'aucun burst n'est documenté, la capacité locale initiale reste volontairement 1. Une limite dynamique n'invente aucune cadence locale et apprend seulement des réponses provider, notamment 429. Un Retry-After serveur peut prolonger le cooldown mais ne peut pas dépasser une borne défensive d'une heure. Aucune primitive HTTP commune ne dort en attendant la disponibilité : elle expose un délai de defer que l'orchestrateur pre.008 pourra projeter provider par provider.

15. Config provider-capability-aware

Config reste l'unique propriétaire des documents/env/secrets.

Off-chain Transport expose ses settings publics ; Config adapte un futur document standard dédié, pressenti :

file_id = std.offchain_transport

Les branches de configuration correspondent aux capacités réelles de chaque provider.

Provider Champs spécifiques V1 attendus
CoinGecko enabled, access_mode keyless ou demo, api_key optionnelle
CoinMarketCap enabled, access_mode keyless ou basic, api_key optionnelle
CoinPaprika enabled
Kraken enabled
Coinbase Exchange enabled
Jupiter enabled, access_mode keyless ou free, api_key optionnelle
Birdeye enabled, api_key requise si activé
DexScreener enabled, sol_usd_pair_address requise si activé

Le schema final doit conditionner la présence des credentials au mode choisi. Aucun secret n'est versionné. Toute variable d'environnement ajoutée respecte KSP_SECRET_* et est inventoriée dans .env.example.

Les limites provider ne deviennent pas des valeurs libres permettant à Config/UI d'augmenter la cadence. Une future policy pourra permettre un throttle plus strict si un besoin réel apparaît.

16. Ownership des erreurs et indisponibilités

Une panne d'un provider ne doit pas rendre tous les autres inexploitables.

Le service classe par provider :

configuration manquante/invalide
DNS/connect/timeout
TLS
HTTP 4xx
HTTP 429
HTTP 5xx
JSON invalide ou schema drift
asset/pair mismatch
prix absent
prix numérique invalide
staleness provider si mesurable

Un refresh multiple retourne donc des outcomes partiels. Le service peut conserver un provider dans l'inventaire avec un état indisponible, au lieu de forcer l'application à connaître pourquoi Birdeye ou un autre provider manque.

17. Threat model V1

Risque Contrôle prévu
fuite API key Config propriétaire, header privé, redaction logs/debug/erreurs
SSRF ou exfiltration vers URL configurée origines provider fixes en V1, aucun endpoint arbitraire
redirect credential redirects HTTP désactivés
proxy environnement implicite policy no-proxy cohérente avec les clients KSP sensibles
réponse JSON énorme limite de taille avant désérialisation
prix NaN, Inf, négatif ou overflow parser décimal KSP borné
faux asset par collision de symbole IDs provider fixes et validations d'identité
mauvaise paire DexScreener pair address explicite et identité SOL vérifiée
429 répétés limiter local, Retry-After, cooldown provider
provider down état provider séparé, autres providers continuent
stale data timestamps réels conservés, aucune fraîcheur inventée
schema drift DTOs wire privés stricts et erreur provider classée
quota partagé hors processus quota local non présenté comme authoritative
différences de prix sémantique/provenance visible, aucun consensus KSP V1
log d'une réponse sensible aucun payload remote brut dans les erreurs/logs

18. Tests et smokes attendus

Tests déterministes

Prévoir :

parsing décimal string/JSON number/scientifique
limites et overflow
mapping de chaque wire provider
asset/pair mismatch
prix null/absent
HTTP status classification
429 et Retry-After
rate limiter par policy
cooldown
états unavailable/auth/quota
refresh single
refresh all partiel
un provider en échec n'empêche pas les autres
redaction credential
Config branches provider
public API sans type wire provider

Smokes live opt-in

Une tranche technique dédiée en fin de release doit tester les adapters réellement retenus avec un accès gratuit courant.

Le smoke :

ne hardcode aucun secret
n'affiche aucun secret
interroge uniquement SOL/USD
vérifie prix positif et parseable
vérifie provider et identité attendue
respecte chaque cadence
ne compare pas à un prix exact figé
n'échoue pas tout le batch parce qu'un provider externe est indisponible

Les providers keyed gratuits peuvent nécessiter des credentials opérateur via Config. Les smokes keyless restent séparables pour ne pas obliger à posséder toutes les clés au même instant.

19. Hors périmètre 0.2.11

SOL/EUR
autres fiat
prix d'autres assets ou SPL tokens publics
Price Desk Tauri
modification Wallet Desk
provider SDK
WebSocket/SSE price streaming
OHLCV/candles
historique/backfill prix
order books
quotes/routing/swap
metadata token/IPFS/Arweave
consensus multi-provider
moyenne/médiane KSP
fallback automatique
choix automatique de pool DexScreener
cache durable
nouvelle abstraction réseau universelle
Pyth
Binance sans SOL/USD direct retenu

Le fait que Jupiter/Birdeye/DexScreener soient capables de couvrir d'autres tokens ne les met pas dans la surface publique V1.

20. Forecast souple des prereleases

Chaque tranche technique vise environ 15 à 20 minutes de travail effectif lorsque le sujet s'y prête. Cette durée est une cible de granularité et pas une durée maximale : un build lent, un live test, un diagnostic ou une difficulté réelle peut légitimement prolonger une tranche.

Le forecast reste volontairement souple. Une tranche peut être scindée, fusionnée ou réordonnée par delta si la réalité technique l'exige, à condition de préserver les responsabilités de clôture. Le nombre de prereleases prévu n'impose ni une session de conversation par tranche, ni une scission de session : plusieurs prereleases peuvent être réalisées dans une même session de travail.

Chaque entrée porte désormais un statut directement modifiable. Lorsqu'un fix d'une tranche est nécessaire, il peut être ajouté sous la prerelease concernée avec un titre ####, sans transformer le forecast en tableau ni casser sa lisibilité.

pre.001 — Audit, sizing et cadrage multi-provider

Statut : réalisé.

Audit externe des providers, comparaison des sémantiques, réduction du scope V1 à SOL/USD, architecture HID de la future application, threat model, numeric design, sizing et planification.

pre.001-fix.001 — Forecast souple éditable

Statut : réalisé.

Remplacement du forecast tabulaire par des sous-sections éditables, clarification de la cible de 15 à 20 minutes et de l'absence de relation obligatoire entre prerelease et session de conversation. Aucun changement du scope technique de 0.2.11.

pre.002 — Fondation de ksp-offchain-transport-lib

Statut : réalisé.

Création de la crate et de sa façade publique initiale : MarketPriceDecimal, paire SOL/USD, observation/provenance/timestamps, identifiants/descriptors provider, capacités auth/rate-limit/quota, settings communs minimaux et états d'availability provider-neutral. Aucun HTTP, limiter actif, credential provider ou adapter wire n'est avancé depuis pre.003+.

pre.002-fix.001 — Rustdoc, Logging et taxonomie Off-chain

Statut : réalisé.

Correction des deux warnings missing_docs des tests d'intégration, ajout de ksp-logging-lib avec src/constants.rs et TRACING_TARGET = "ksp-offchain-transport-lib", instrumentation KSP des validations/constructions comportementales, et renommage des modules actuels en market_price_* pour préparer les futures familles hétérogènes telles que swap_quote_* sans transformer la crate entière en module de prix.

pre.002-fix.002 — Conformité Clippy implicit_return

Statut : réalisé.

Correction du canari dependency_boundary pour respecter -D clippy::implicit-return, sans changement de contrat ni de comportement runtime. La version technique workspace devient 0.2.11-pre.2.fix.2.

pre.002-fix.003 — Nommage public MarketPrice*

Statut : réalisé.

Préfixage de toute la surface publique spécifique à la famille market_price en MarketPrice* / MARKET_PRICE_*, y compris observation, décimal, timestamps, provenance, provider settings/descriptors/limits/availability et codes d'erreur. Aucun alias Price* n'est conservé : le correctif évite de devoir renommer ces API lorsque d'autres familles telles que swap_quote_* seront ajoutées. La version technique workspace devient 0.2.11-pre.2.fix.3.

pre.003 — HTTP REST commun et rate limiting

Statut : réalisé.

Client HTTP REST commun crate-private, classification d'erreurs HTTP/reqwest, bornes de body et timeouts, redaction, désactivation explicite des redirects/proxy/retries implicites, JSON syntaxiquement validé, limiter token-bucket générique non bloquant et cooldown provider-driven borné. Aucun adapter provider n'est avancé.

pre.004 — CoinGecko, CoinMarketCap et CoinPaprika

Statut : planifié.

Implémentation des trois adapters d'agrégateurs avec leurs DTOs wire privés et tests dédiés.

pre.005 — Kraken et Coinbase Exchange

Statut : planifié.

Implémentation des deux adapters exchange, conservation de leur sémantique de marché propre et tests dédiés.

pre.006 — Jupiter et DexScreener

Statut : planifié.

Implémentation des adapters Jupiter et DexScreener. DexScreener reste limité en V1 à la paire SOL/USD explicite configurée et validée.

pre.007 — Birdeye, registry et availability

Statut : planifié.

Implémentation de Birdeye avec son auth provider, finalisation du registry multi-provider et des états génériques d'indisponibilité.

pre.008 — Refresh individuel et multiple

Statut : planifié.

Service de refresh single/multiple, orchestration rate-limit-aware et tests cross-provider sans scheduling provider dans les consumers.

pre.009 — Config Off-chain Transport

Statut : planifié.

Document standard std.offchain_transport, schema, exemples, secrets d'environnement nécessaires et adapter Config -> Off-chain Transport conforme aux capacités de chaque provider.

pre.010 — Hardening et complétude technique

Statut : planifié.

Hardening de l'API publique, tests adversariaux/completeness et brouillons techniques README/USAGE sans réconciliation documentaire finale.

pre.011 — Gate technique et live final

Statut : planifié.

Smokes gratuits possibles, graphes Cargo, validations techniques finales et caractérisation actuelle des providers.

pre.012 — Réconciliation documentaire finale

Statut : planifié.

Réconciliation finale du plan, de la validation, des README/USAGE, de l'architecture et des références durables après les gates techniques.

pre.013 — Préparation minimale de publication

Statut : planifié.

Prompt 0.2.12, CHANGELOG.md, ROADMAP.md et mécanique de version uniquement, sans reprendre les responsabilités techniques ou documentaires des deux tranches précédentes.

rel.001 — Publication stable v0.2.11

Statut : planifié.

Publication stable après validation de la dernière prerelease et vérification de la cohérence de release.

Les responsabilités de clôture restent strictement séparées :

pre.011 = technique/live
pre.012 = documentation finale
pre.013 = prompt suivant + CHANGELOG + ROADMAP seulement

21. Gate de sizing pre.001

Verdict : GO sans split de release.

Justification :

huit adapters REST sont petits et indépendants
aucun SDK provider n'est nécessaire
les primitives HTTP/serde/tokio sont déjà au workspace
la seule paire publique est SOL/USD
le contrat commun reste volontairement petit
la complexité réelle est isolée dans registry/rate limiting/availability
les adapters peuvent être livrés par groupes de prereleases courtes

0.2.11 reste toutefois une release multi-provider et ne doit pas compresser artificiellement les gates de sécurité/live.