v0.2.11-pre.009
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<!-- file: docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md -->
|
||||
<!-- version: 15 -->
|
||||
<!-- version: 16 -->
|
||||
|
||||
# Plan `0.2.11` — Off-chain price transport SOL/USD multi-provider
|
||||
|
||||
**Statut courant : `0.2.11-pre.008-fix.001` corrige le gate de `pre.008` sans modifier son contrat fonctionnel. `MarketPriceService` possède toujours le dispatch provider, le registry runtime et les transitions d'availability ; les consumers utilisent uniquement les provider ids opaques, `registry()`, `refresh`, `refresh_many` et `refresh_all`. Le fix supprime un warning Clippy `collapsible_if` et remplace un canari lexical trop large sur le mot `consensus` par des vérifications de surfaces exécutables réellement interdites. `MarketPriceProviderSetup` reste la frontière provider-specific destinée à la composition/Config de `pre.009`.**
|
||||
**Statut courant : `0.2.11-pre.009` matérialise la frontière Config -> Off-chain Transport. `cfg.std.offchain_transport` et `schema.std.offchain_transport` possèdent désormais un domaine `market_price` avec les huit providers V1, des profils `public_keyless` et `all_free`, les credentials résolus exclusivement depuis une provenance Config classée Secret, et une adresse de paire DexScreener publique lorsqu'elle provient de l'environnement. `ResolvedOffchainTransportConfig` construit `MarketPriceService` sans créer de dépendance inverse depuis Off-chain Transport. Les limites provider restent possédées par la crate runtime et ne deviennent pas des cadences libres de Config.**
|
||||
|
||||
## 1. Base et autorité
|
||||
|
||||
@@ -520,28 +520,43 @@ Le limiter `pre.003` est non bloquant. Une cadence fixe est matérialisée par u
|
||||
|
||||
## 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 :
|
||||
Config reste l'unique propriétaire des documents, de l'environnement et des secrets. `pre.009` matérialise les identifiants durables :
|
||||
|
||||
```text
|
||||
file_id = std.offchain_transport
|
||||
file_id document = cfg.std.offchain_transport
|
||||
file_id schema = schema.std.offchain_transport
|
||||
fichier = std.offchain_transport.json
|
||||
schema = std.offchain_transport.schema.json
|
||||
format_version = 1
|
||||
```
|
||||
|
||||
Les branches de configuration correspondent aux capacités réelles de chaque provider.
|
||||
Le document reste générique Off-chain Transport et place la capacité actuelle sous `market_price`. Cette structure évite de transformer le document durable en Config dédiée uniquement au prix lorsque d'autres familles telles que `swap_quote` apparaîtront.
|
||||
|
||||
| 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é |
|
||||
Deux profils versionnés servent de canaries :
|
||||
|
||||
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`.
|
||||
```text
|
||||
public_keyless = providers réellement utilisables sans secret ; Birdeye et DexScreener désactivés
|
||||
all_free = modes gratuits à clé activés + paire DexScreener explicite
|
||||
```
|
||||
|
||||
Les branches correspondent aux capacités réelles de chaque provider.
|
||||
|
||||
| Provider | Champs spécifiques V1 |
|
||||
|-------------------|---------------------------------------------------------------|
|
||||
| CoinGecko | enabled, access_mode keyless ou demo, api_key conditionnelle |
|
||||
| CoinMarketCap | enabled, access_mode keyless ou basic, api_key conditionnelle |
|
||||
| CoinPaprika | enabled |
|
||||
| Kraken | enabled |
|
||||
| Coinbase Exchange | enabled |
|
||||
| Jupiter | enabled, access_mode keyless ou free, api_key conditionnelle |
|
||||
| Birdeye | enabled, api_key requise si activé |
|
||||
| DexScreener | enabled, sol_usd_pair_address requise si activé |
|
||||
|
||||
Le schema conditionne les credentials au mode choisi et interdit un faux champ `api_key` sur les modes keyless. L'adapter effectif applique en plus la provenance : une API key provider doit provenir d'une variable classée Secret (`KSP_SECRET_*` ou namespace KSPB secret admis par Config), même si un littéral non vide est syntaxiquement valide JSON. Les erreurs et `Debug` ne recopient jamais le credential.
|
||||
|
||||
La paire DexScreener n'est pas un secret. Un littéral validé comme Pubkey Solana est admis ; si la valeur vient de l'environnement, sa provenance doit rester Public, avec le canari versionné `KSP_PUBLIC_DEXSCREENER_SOL_USD_PAIR_ADDRESS`. Pour respecter « requise seulement si activé », `MarketPriceDexScreenerSettings` accepte désormais l'absence de paire lorsque le provider est désactivé et la refuse toujours lorsqu'il est activé.
|
||||
|
||||
`.env.example` inventorie les variables nécessaires sans valeur réelle. Les applications desktop empaquetent aussi le nouveau document et son schema parce que `prepare_packaged_runtime` synchronise l'intégralité du registry Config.
|
||||
|
||||
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.
|
||||
|
||||
@@ -736,7 +751,7 @@ Implémentation des deux adapters exchange keyless avec DTOs wire privés et end
|
||||
|
||||
**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.
|
||||
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 lorsqu'il est activé, 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
|
||||
|
||||
@@ -754,9 +769,9 @@ Implémentation de Birdeye Standard avec `X-API-KEY`, endpoint Price Single Sola
|
||||
|
||||
### `pre.009` — Config Off-chain Transport
|
||||
|
||||
**Statut : planifié.**
|
||||
**Statut : réalisé ; gate Cargo opérateur à rejouer.**
|
||||
|
||||
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.
|
||||
Ajout de `cfg.std.offchain_transport` / `schema.std.offchain_transport`, du document standard V1, de son schema strict, d'un exemple et de la fixture Config. Le domaine `market_price` configure les huit providers sans rendre leurs cadences modifiables. `public_keyless` fonctionne sans secret ; `all_free` référence quatre credentials `KSP_SECRET_*` et une paire DexScreener `KSP_PUBLIC_*`. `ResolvedOffchainTransportConfig` résout l'environnement, contrôle la provenance des credentials/public fields et construit `MarketPriceService` via `MarketPriceProviderSetup`, sans dépendance inverse. Les deux applications desktop embarquent les nouvelles ressources Config. La tranche réconcilie aussi DexScreener pour qu'une paire soit requise uniquement quand le provider est activé.
|
||||
|
||||
### `pre.010` — Hardening et complétude technique
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md -->
|
||||
<!-- version: 14 -->
|
||||
<!-- version: 15 -->
|
||||
|
||||
# Validation `0.2.11` — Off-chain price transport SOL/USD
|
||||
|
||||
@@ -261,30 +261,57 @@ Les tests déterministes de `pre.007` couvrent l'auth Birdeye et sa redaction, l
|
||||
|
||||
## 3.11 Gate `0.2.11-pre.008`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|-------------------------------------------------------------------------|---------|--------------------------------------------|
|
||||
| version workspace `0.2.11-pre.8` | PASS | `Cargo.toml` racine |
|
||||
| `MarketPriceService` provider-agnostic public | PASS | `market_price_service.rs` |
|
||||
| setup provider-specific limité à la composition | PASS | `MarketPriceProviderSetup` |
|
||||
| registry détachable sans dispatch provider | PASS | `MarketPriceService::registry` |
|
||||
| refresh individuel par `MarketPriceProviderId` | PASS | `MarketPriceService::refresh` |
|
||||
| refresh multiple par liste d'identifiants opaques | PASS | `MarketPriceService::refresh_many` |
|
||||
| refresh all en ordre provider déterministe | PASS | `MarketPriceService::refresh_all` |
|
||||
| doublons / provider inconnu rejetés avant dispatch | PASS | tests `market_price_service` |
|
||||
| provider non éligible projeté sans requête réseau | PASS | eligibility + test huit providers disabled |
|
||||
| `429` / defer local projetés en `CoolingDown` | PASS | classification générique |
|
||||
| `401/403` keyed projetés en `AuthenticationUnavailable` | PASS | classification auth-aware |
|
||||
| transport temporaire projeté sans rendre le service global inutilisable | PASS | outcome provider-neutral |
|
||||
| aucune attente/sleep de rate limit dans le service | PASS | dependency boundary |
|
||||
| aucun fallback, consensus ou agrégation multi-provider | PASS | scope + dependency boundary |
|
||||
| Config, scheduling périodique et smoke live non avancés | PASS | scope réservé à `pre.009+` |
|
||||
| audit Rust sandbox | PASS | clean, 0 candidate export |
|
||||
| audit Markdown sandbox | PASS | clean, 122 tables / 113 fichiers |
|
||||
| gate `pre.008` brut | FAIL | 1 warning Clippy + 1 canari boundary FAIL |
|
||||
| fix `pre.008-fix.001` statique | PASS | audits Rust/Markdown sandbox |
|
||||
| gate Cargo du fix | PLANNED | à exécuter par l'opérateur |
|
||||
| Critère | Statut | Preuve |
|
||||
|-------------------------------------------------------------------------|--------|--------------------------------------------|
|
||||
| version workspace `0.2.11-pre.8` | PASS | `Cargo.toml` racine |
|
||||
| `MarketPriceService` provider-agnostic public | PASS | `market_price_service.rs` |
|
||||
| setup provider-specific limité à la composition | PASS | `MarketPriceProviderSetup` |
|
||||
| registry détachable sans dispatch provider | PASS | `MarketPriceService::registry` |
|
||||
| refresh individuel par `MarketPriceProviderId` | PASS | `MarketPriceService::refresh` |
|
||||
| refresh multiple par liste d'identifiants opaques | PASS | `MarketPriceService::refresh_many` |
|
||||
| refresh all en ordre provider déterministe | PASS | `MarketPriceService::refresh_all` |
|
||||
| doublons / provider inconnu rejetés avant dispatch | PASS | tests `market_price_service` |
|
||||
| provider non éligible projeté sans requête réseau | PASS | eligibility + test huit providers disabled |
|
||||
| `429` / defer local projetés en `CoolingDown` | PASS | classification générique |
|
||||
| `401/403` keyed projetés en `AuthenticationUnavailable` | PASS | classification auth-aware |
|
||||
| transport temporaire projeté sans rendre le service global inutilisable | PASS | outcome provider-neutral |
|
||||
| aucune attente/sleep de rate limit dans le service | PASS | dependency boundary |
|
||||
| aucun fallback, consensus ou agrégation multi-provider | PASS | scope + dependency boundary |
|
||||
| Config, scheduling périodique et smoke live non avancés | PASS | scope réservé à `pre.009+` |
|
||||
| audit Rust sandbox | PASS | clean, 0 candidate export |
|
||||
| audit Markdown sandbox | PASS | clean, 122 tables / 113 fichiers |
|
||||
| gate `pre.008` brut | FAIL | 1 warning Clippy + 1 canari boundary FAIL |
|
||||
| fix `pre.008-fix.001` statique | PASS | audits Rust/Markdown sandbox |
|
||||
| gate Cargo du fix | PASS | gate opérateur complet du 2026-08-26 |
|
||||
|
||||
Les tests déterministes de `pre.008` vérifient le registry de service sur les huit setups V1, `refresh_all` sans réseau lorsque tous les providers sont désactivés, le rejet pré-dispatch des doublons/providers inconnus, les classes auth/rate-limit/temporaire/local misconfiguration et l'éligibilité temporelle des cooldowns. Les méthodes multiples restent séquentielles et déterministes dans V1 ; elles ne dorment jamais pour attendre un provider et ne font aucun fallback/consensus. Le gate opérateur initial a toutefois trouvé un warning `clippy::collapsible_if` et un canari boundary trop large (`!service.contains("consensus")`) qui échouait sur la rustdoc décrivant justement l'absence de consensus. `pre.008-fix.001` corrige ces deux points sans modifier le comportement runtime.
|
||||
Les tests déterministes de `pre.008` vérifient le registry de service sur les huit setups V1, `refresh_all` sans réseau lorsque tous les providers sont désactivés, le rejet pré-dispatch des doublons/providers inconnus, les classes auth/rate-limit/temporaire/local misconfiguration et l'éligibilité temporelle des cooldowns. Les méthodes multiples restent séquentielles et déterministes dans V1 ; elles ne dorment jamais pour attendre un provider et ne font aucun fallback/consensus. Le gate opérateur initial a toutefois trouvé un warning `clippy::collapsible_if` et un canari boundary trop large (`!service.contains("consensus")`) qui échouait sur la rustdoc décrivant justement l'absence de consensus. `pre.008-fix.001` corrige ces deux points sans modifier le comportement runtime. Le gate rejoué sur `0.2.11-pre.8.fix.1` est intégralement PASS : audits Rust/Markdown, `cargo check --workspace`, `cargo clippy --workspace --all-targets`, 54 tests unitaires + 6 boundary + 7 public API Off-chain, puis `cargo test --workspace` avec uniquement les smokes/timing explicitement ignorés.
|
||||
|
||||
## 3.12 Gate `0.2.11-pre.009`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|----------------------------------------------------------------------|---------|----------------------------------------------------------------|
|
||||
| version workspace `0.2.11-pre.9` | PASS | `Cargo.toml` racine |
|
||||
| document `cfg.std.offchain_transport` enregistré | PASS | registry Config + `std.offchain_transport.json` |
|
||||
| schema `schema.std.offchain_transport` enregistré | PASS | registry Config + schema Draft 2020-12 |
|
||||
| domaine actuel imbriqué sous `market_price` | PASS | document/schema V1 |
|
||||
| profils `public_keyless` et `all_free` versionnés | PASS | document standard + exemple |
|
||||
| huit branches provider Config obligatoires | PASS | schema + fixture |
|
||||
| credentials conditionnés par mode/provider | PASS | `if/then` du schema |
|
||||
| credentials effectifs exigent une provenance Config Secret | PASS | adapter `offchain_transport.rs` + tests |
|
||||
| littéral credential rejeté par l'adapter effectif | PASS | test `literal_or_nonsecret_provider_credentials...` |
|
||||
| DexScreener pair requis seulement lorsque le provider est activé | PASS | schema + `MarketPriceDexScreenerSettings` |
|
||||
| Dex pair via environnement exige une provenance Public | PASS | adapter Config + test |
|
||||
| `.env.example` inventorie quatre secrets et la paire publique | PASS | `.env.example` |
|
||||
| Config construit `MarketPriceService` via `MarketPriceProviderSetup` | PASS | `ResolvedOffchainTransportConfig` |
|
||||
| Off-chain Transport ne dépend pas de Config | PASS | dependency ownership + manifest |
|
||||
| aucune cadence provider libre ajoutée à Config | PASS | schema/document sans rate-limit override |
|
||||
| Config Debug/safe view ne divulgue pas les API keys | PASS | tests adapter |
|
||||
| applications desktop embarquent document + schema | PASS | deux `tauri.conf.json` + canaries desktop |
|
||||
| audit Rust sandbox | PASS | clean, 0 candidate export |
|
||||
| audit Markdown sandbox | PASS | clean, 123 tables / 115 fichiers |
|
||||
| `cargo check` / Clippy / tests Config et workspace | PLANNED | gate opérateur requis après application de l'archive `pre.009` |
|
||||
|
||||
La tranche n'ajoute aucune URL provider configurable, aucun SDK provider et aucune lecture directe de l'environnement dans `ksp-offchain-transport-lib`. Les secrets restent résolus par `ksp-config-lib`; le service runtime reçoit uniquement les settings typés nécessaires. La modification DexScreener est capability-aware : une paire absente est valide uniquement lorsque l'adapter est désactivé, ce qui permet de conserver son entrée dans l'inventaire générique sans fabriquer de fausse configuration.
|
||||
|
||||
## 4. Matrice provider prévue
|
||||
|
||||
@@ -374,32 +401,32 @@ Avant la stable, les conditions d'usage et la persistance des offres gratuites d
|
||||
|
||||
## 9. DexScreener V1
|
||||
|
||||
| Invariant | Statut |
|
||||
|----------------------------------------------|--------|
|
||||
| pair address SOL/USD explicite dans settings | PASS |
|
||||
| `chainId = solana` vérifié | PASS |
|
||||
| identité SOL de la paire vérifiée | PASS |
|
||||
| `priceUsd` utilisé comme prix commun | PASS |
|
||||
| aucune recherche automatique de pool | PASS |
|
||||
| aucun tri automatique par liquidité | PASS |
|
||||
| aucune moyenne/consensus entre pools | PASS |
|
||||
| Invariant | Statut |
|
||||
|--------------------------------------------------|--------|
|
||||
| pair address SOL/USD explicite si provider actif | PASS |
|
||||
| `chainId = solana` vérifié | PASS |
|
||||
| identité SOL de la paire vérifiée | PASS |
|
||||
| `priceUsd` utilisé comme prix commun | PASS |
|
||||
| aucune recherche automatique de pool | PASS |
|
||||
| aucun tri automatique par liquidité | PASS |
|
||||
| aucune moyenne/consensus entre pools | PASS |
|
||||
|
||||
## 10. Config -> Off-chain Transport
|
||||
|
||||
| Invariant | Statut |
|
||||
|------------------------------------------------------------------|---------|
|
||||
| Off-chain Transport ne dépend pas de Config | PLANNED |
|
||||
| document standard offchain dédié | PLANNED |
|
||||
| branches provider conditionnelles dans schema | PLANNED |
|
||||
| CoinGecko keyless/Demo représentés | PLANNED |
|
||||
| CoinMarketCap keyless/Basic représentés | PLANNED |
|
||||
| Jupiter keyless/Free représentés | PLANNED |
|
||||
| Birdeye exige credential lorsqu'activé | PLANNED |
|
||||
| DexScreener exige pair address lorsqu'activé | PLANNED |
|
||||
| providers sans auth n'exposent pas de faux champ API key | PLANNED |
|
||||
| secrets via Config uniquement | PLANNED |
|
||||
| `.env.example` synchronisé pour les secrets réellement ajoutés | PLANNED |
|
||||
| aucune cadence provider configurable au-dessus de la limite sûre | PLANNED |
|
||||
| Invariant | Statut |
|
||||
|------------------------------------------------------------------|--------|
|
||||
| Off-chain Transport ne dépend pas de Config | PASS |
|
||||
| document standard offchain dédié | PASS |
|
||||
| branches provider conditionnelles dans schema | PASS |
|
||||
| CoinGecko keyless/Demo représentés | PASS |
|
||||
| CoinMarketCap keyless/Basic représentés | PASS |
|
||||
| Jupiter keyless/Free représentés | PASS |
|
||||
| Birdeye exige credential lorsqu'activé | PASS |
|
||||
| DexScreener exige pair address lorsqu'activé | PASS |
|
||||
| providers sans auth n'exposent pas de faux champ API key | PASS |
|
||||
| secrets via Config uniquement | PASS |
|
||||
| `.env.example` synchronisé pour les secrets réellement ajoutés | PASS |
|
||||
| aucune cadence provider configurable au-dessus de la limite sûre | PASS |
|
||||
|
||||
## 11. Frontière future `ksp-app-solprices-desk`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user