v0.2.12-pre.008

This commit is contained in:
2026-08-27 14:41:08 +02:00
parent 2042482592
commit f1e365ec97
22 changed files with 631 additions and 129 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk
@@ -29,7 +29,7 @@ Mission concrète de la release :
```text
1. créer ksp-app-solprices-desk comme HID Tauri provider-agnostic
2. valider son contrat Config + MarketPriceService + DTO/commands + UI
3. intégrer ensuite la même capacité générique dans ksp-app-wallet-desk
3. intégrer dans ksp-app-wallet-desk une projection auxiliaire minimale : moyenne SOL/USD calculée lors du refresh de balance
```
Ownership durable :
@@ -242,21 +242,27 @@ splash
Le shell reste volontairement petit : pas de dashboard trading, graphe, historique, quote routing ou éditeur Config.
### Point d'insertion Wallet Desk
### Point d'insertion Wallet Desk — décision opérateur `pre.008`
Le périmètre Wallet Desk est volontairement réduit après validation complète de SOL Prices Desk :
```text
Wallet Desk existing shell
-> Dashboard
-> panneau compact “SOL/USD prices”
-> quelques/toutes lignes provider-neutral selon espace
-> availability + fraîcheur
-> refresh row / refresh all borné
-> aucune dépendance à une Wallet sélectionnée ou déverrouillée
-> Dashboard / Wallet courant
-> Balance SOL existante
-> une seule case “SOL/USD moyen”
-> valeur moyenne dérivée du refresh courant
-> N.A. si aucune observation exploitable
-> bouton Refresh balance existant
-> getBalance On-chain
-> refresh_all Off-chain des providers éligibles
-> moyenne backend
-> projection commune Balance + SOL/USD
```
Le panneau prix est indépendant du lifecycle VIEW/OWNER. Il ne modifie ni la balance SOL ni les opérations Wallet.
Aucun inventaire provider, aucune availability détaillée et aucun bouton prix supplémentaire ne sont dupliqués dans Wallet Desk. Les fonctions avancées restent la responsabilité de `ksp-app-solprices-desk`. Le prix auxiliaire suit le lifecycle du refresh de balance existant et n'ajoute aucun nouveau droit VIEW/OWNER.
**Valorisation USD du solde : hors scope `0.2.12`.** Il n'existe pas de prix KSP canonique et la release ne choisit pas arbitrairement le premier provider.
**Valorisation USD du solde : toujours hors scope `0.2.12`.** La moyenne est seulement affichée comme information SOL/USD ; aucun calcul `balance SOL × prix` n'est introduit.
## 9. DTO map retenue
@@ -299,7 +305,7 @@ Config effective secret values
Aucune command n'accepte URL, credential, header, rate-limit override ou payload provider.
Wallet Desk réutilise la même sémantique de commands (`list/refresh/refresh_all`), avec noms éventuellement préfixés pour éviter collision avec ses commandes existantes. L'input reste uniquement le `provider_id` opaque.
Wallet Desk n'expose finalement **aucune nouvelle command prix**. La command existante `refresh_wallet_balance` orchestre côté Rust le `getBalance` et le `MarketPriceService::refresh_all`; le frontend ne transmet ni `provider_id`, ni URL, ni sélection provider. `WalletBalanceDto` gagne uniquement `sol_usd_average: Option<String>`.
## 11. Refresh UX
@@ -318,35 +324,46 @@ Décisions :
**Auto-refresh périodique : hors scope.** Aucun `setInterval`, scheduler ou worker prix n'est ajouté en `0.2.12`.
## 12. Intégration Wallet Desk
## 12. Intégration Wallet Desk — périmètre simplifié
Wallet Desk ajoutera une dépendance directe à `ksp-offchain-transport-lib` parce qu'il consomme le contrat public générique retourné par Config. Cette direction est déjà admise par l'architecture; Off-chain Transport ne dépend jamais de Wallet ni de Config.
Wallet Desk ajoute une dépendance directe à `ksp-offchain-transport-lib` uniquement pour consommer les contrats publics `MarketPriceService`, `MarketPriceRefreshOutcome` et `MarketPriceDecimal` construits par Config. Aucune logique provider concrète n'est dupliquée.
Flux :
Flux retenu :
```text
Config composite Wallet Desk
-> component offchain_transport / cfg.std.offchain_transport / public_keyless
-> ConfigDocumentEngine::resolve_offchain_transport_config_profile
-> ResolvedOffchainTransportConfig
-> MarketPriceService dans AppState/MarketPriceRuntime
-> DTO provider-neutral
-> panneau Dashboard
-> MarketPriceService conservé côté Rust
refresh_wallet_balance
-> getBalance On-chain
-> en parallèle : MarketPriceService::refresh_all
-> ne garder que les observations réussies du refresh courant
-> moyenne arithmétique backend sans f64, arrondie à 8 décimales maximum
-> WalletBalanceDto { ..., sol_usd_average: Option<String> }
-> une seule case UI “SOL/USD moyen” ou “N.A.”
```
La branche prix est **auxiliaire/best-effort** : un runtime Off-chain indisponible, zéro observation ou un échec structurel prix ne rend pas `getBalance` invalide. La balance SOL reste autoritative et la projection prix devient `None`.
Non-régressions obligatoires :
```text
WalletSession inchangée
VIEW/OWNER inchangés
Wallet secrets inchangés
getBalance On-chain inchangé
aucune Pubkey requise pour obtenir un prix SOL/USD
commande refresh_wallet_balance inchangée côté input
aucun provider_id dans l'IPC Wallet
aucune command prix Wallet supplémentaire
aucun fetch TS
aucune multiplication balance x prix
aucun fallback sur une observation stale
aucun provider canonique
```
Aucun adapter, parser, limiter ou fetch TS n'est copié dans Wallet Desk.
La moyenne n'est ni un consensus de marché, ni un nouveau contrat Off-chain partagé : c'est une présentation auxiliaire propre au Wallet Desk.
## 13. Mutualisation entre applications
@@ -354,7 +371,7 @@ La mutualisation métier existe déjà dans `ksp-offchain-transport-lib` et la m
`pre.001` ne retient **aucune nouvelle crate partagée**. Les deux apps peuvent posséder de petits adapters DTO/runtime propres parce qu'ils sont de la présentation/composition et que leurs `AppState`/runtime status diffèrent déjà.
Un helper partagé ne sera envisagé que si `pre.009``pre.011` démontrent une duplication non triviale, stable et réellement réutilisable. Il ne sera pas créé pour éviter quelques conversions enum -> label.
Le périmètre Wallet simplifié ne justifie aucune nouvelle crate/helper partagé : SOL Prices Desk conserve les projections riches, Wallet Desk ne consomme que le service générique et calcule une moyenne auxiliaire locale.
## 14. Capabilities et plugins
@@ -411,7 +428,7 @@ Canari obligatoire : `ksp-app-solprices-desk` référence son propre `package.js
| CWD/resource confusion cross-app | CWD KSP normalisé + resources registry + canari paths/ports/backend dédiés |
| capabilities trop larges | core + tracing seulement pour Price Desk; aucun network/fs/dialog guest |
| logs frontend sensibles | log seulement action, provider_id, compte, code KSP; jamais DTO brut/secret/body |
| faux prix canonique | semantics visibles; aucune moyenne/fallback/first-provider |
| faux prix canonique | Price Desk sans canonique/fallback; moyenne Wallet explicitement auxiliaire |
| perte de précision JS | prix transmis comme chaîne décimale exacte |
## 17. Stratégie de tests et gates
@@ -427,7 +444,7 @@ Canari obligatoire : `ksp-app-solprices-desk` référence son propre `package.js
| TS-RS | bindings exportés par tests; prix exact en String |
| workspace | fmt + audits + check + clippy + test |
| SOL Prices Desk dev | parcours splash -> table -> row/many/all sur composition réelle |
| Wallet Desk dev | panneau prix + non-régression Wallet/balance |
| Wallet Desk dev | refresh balance + une case moyenne SOL/USD/N.A. + non-régression Wallet |
| live composition | un smoke keyless applicatif opt-in suffit; ne réaudite pas les 8 wires |
| production build | `cargo tauri build` crate-local pour SOL Prices Desk puis Wallet Desk |
@@ -440,7 +457,7 @@ nouveau provider ou modification des 8 adapters V1
SOL/EUR ou token arbitraire
OHLCV/historique/chart
SSE/WebSocket prix
consensus/moyenne/fallback automatique
consensus/fallback automatique
provider canonique
valorisation USD du solde Wallet
auto-refresh/polling périodique
@@ -496,13 +513,13 @@ Correction strictement locale du test `config_composition` : le message d'assert
### `pre.004` — Runtime prix, registry rows et DTOs
**Statut : implémenté ; corrigé par `pre.004-fix.001` puis `pre.004-fix.002`, gate opérateur à confirmer.**
**Statut : réalisé ; corrigé par `pre.004-fix.001` puis `pre.004-fix.002`, gate opérateur intégralement PASS.**
Création du `MarketPriceRuntime` applicatif, projection provider-neutral du registry, DTOs TS-RS et états initiaux/loading/empty. `list_market_prices` projette les lignes depuis le registry sans dispatch réseau ; l'état de présentation reste uniquement en mémoire backend. Les providers restent opaques à l'UI, le prix exact et les timestamps traversent l'IPC sous forme de chaînes exactes, et aucun refresh n'est encore disponible avant `pre.005`.
#### `pre.004-fix.001` — Synchronisation de la fixture composite Config Desk
**Statut : implémenté ; gate opérateur à confirmer.**
**Statut : réalisé ; corrigé par `pre.004-fix.002`, gate opérateur final PASS.**
Correction du gate workspace révélé après `pre.004` : le registry Config contient désormais le composite SOL Prices Desk, donc le jeu de fixtures utilisé par `ksp-app-config-desk` doit contenir le document correspondant. Le fix ajoute la fixture dédiée avec des profils valides dans l'environnement de test et renforce le canari d'inventory pour vérifier explicitement `cfg.composite.ksp-app-solprices-desk`. Aucun runtime prix, provider, DTO ou frontend n'est modifié.
@@ -532,65 +549,35 @@ Ajout de `refresh_market_prices` et `refresh_all_market_prices` sur les APIs gé
### `pre.007` — UX et instrumentation SOL Prices Desk
**Statut : implémenté ; gate opérateur à confirmer.**
**Statut : réalisé ; gate opérateur Cargo/workspace/Tauri et parcours visuel intégralement PASS.**
Finalisation de la table responsive sans changer le contrat de dispatch : résumé providers/ready/observed/attention/refreshing, header sticky, colonnes secondaires adaptatives, badges génériques d'auth/semantics/availability, prix exact conservé en String et timestamps présentés à la fois sous forme humaine et en millisecondes exactes. `provider_timestamp = None` est rendu explicitement comme `Not supplied`, sans substitution par `received_at`. La sélection gagne un contrôle global et `Clear selection`, uniquement frontend. Chaque nouveau contrôle est journalisé en `debug`; les rendus et comptes sûrs restent en `trace`. Les wrappers Tauri journalisent les échecs avec seulement `command`, `error_domain` et `error_code`. Aucun prix, timestamp, payload provider, URL, header ou credential n'entre dans les logs. La tranche reste manuelle : aucune nouvelle commande métier, aucun auto-refresh, scheduler ou persistance navigateur n'est ajouté.
### `pre.008` — Hardening SOL Prices Desk
### `pre.008` — Intégration Wallet minimale + recalibrage de clôture
**Statut : implémenté ; gate opérateur à confirmer.**
Absorption de l'ancien couloir Wallet `pre.009``pre.011` dans une seule tranche : ajout `offchain_transport/public_keyless` au composite Wallet, runtime Off-chain auxiliaire, `refresh_all` lors de `refresh_wallet_balance`, moyenne SOL/USD backend sans `f64`, `WalletBalanceDto.sol_usd_average` et une seule case UI `SOL/USD moyen`/`N.A.`. Aucun panneau provider, aucune command prix Wallet, aucun provider ID frontend et aucune valorisation USD du solde. La tranche réconcilie également le présent forecast avec cette réduction de scope.
### `pre.009` — Hardening transversal + gate technique/live final
**Statut : planifié.**
Durcissement des boundaries desktop/security/package, canaris de capabilities minimales, parcours fonctionnel complet et non-régression du bootstrap avant d'étendre Wallet Desk. Le Desk doit être stable isolément à la sortie de cette tranche.
Fusion des anciens hardenings `pre.008`/`pre.012` et du gate `pre.013` : canaris batch hostile/capabilities/resources, non-régression des deux Desks, workspace complet, smoke live keyless de composition, et `cargo tauri build` final des deux applications modifiées. Aucun nouveau comportement métier n'est ouvert.
### `pre.009` — Extension composite/runtime Wallet Desk
### `pre.010` — Réconciliation documentaire + préparation de publication
**Statut : planifié.**
Extension additive du composite Wallet Desk avec Off-chain Transport et intégration du runtime prix backend, sans modifier les contrats Wallet existants, le lifecycle VIEW/OWNER ni le chemin `getBalance`.
### `pre.010` — DTOs et commands prix Wallet Desk
**Statut : planifié.**
Ajout de la surface IPC provider-neutral nécessaire au Wallet Desk pour l'inventaire et le refresh prix. Aucun secret, URL provider, wire provider-specific ou valorisation USD du solde ne traverse cette surface.
### `pre.011` — Panneau prix Wallet Desk
**Statut : planifié.**
Ajout du panneau Dashboard prix avec refresh manuel et projection des observations/availability, puis vérification des non-régressions balance et autorisations VIEW/OWNER. Le solde SOL et les prix restent deux informations distinctes ; aucune valorisation USD canonique n'est calculée.
### `pre.012` — Hardening cross-app et complétude
**Statut : planifié.**
Revue croisée des deux Desks, capabilities/resources, contracts IPC, dépendances, sécurité et canaris de complétude. Cette tranche ferme le comportement applicatif avant le gate technique/live final.
### `pre.013` — Gate technique/live final
**Statut : planifié.**
Gate workspace complet, tests applicatifs pertinents, smoke live keyless de composition application -> Config -> `MarketPriceService`, graphes de dépendances utiles et builds Tauri finaux des applications modifiées. Cette tranche ne réconcilie pas README/USAGE ni les documents finaux.
### `pre.014` — Réconciliation documentaire finale
**Statut : planifié.**
Réconciliation du plan, de la validation, des README/USAGE et autres documents durables concernés avec le runtime réellement livré après le gate technique. Cette tranche ne finalise ni `CHANGELOG.md`, ni `ROADMAP.md`, ni le prompt suivant.
### `pre.015` — Préparation minimale de publication
**Statut : planifié.**
Préparation du prompt de la release suivante, de `CHANGELOG.md` et de `ROADMAP.md`, avec la mécanique Cargo/delta imposée par le workflow. Aucun code, test, plan, validation, README ou USAGE n'est rouvert dans cette dernière prerelease.
Fusion des anciennes tranches `pre.014`/`pre.015` : réconciliation README/USAGE/plan/validation avec le runtime réellement validé, puis prompt suivant, `CHANGELOG.md` et `ROADMAP.md`. Cette tranche reste documentaire/mécanique et ne rouvre aucun code fonctionnel.
### `rel.001` — Publication stable `v0.2.12`
**Statut : planifié.**
Mécanique de publication stable uniquement, après validation de la dernière prerelease et vérification de la cohérence de release. Aucun défaut fonctionnel ou documentaire ne doit être absorbé par `rel.001`.
Mécanique de publication stable uniquement, après validation de `pre.010` et vérification de la cohérence de release. Aucun défaut fonctionnel ou documentaire ne doit être absorbé par `rel.001`.
Le packaging transversal et les refresh manuels du Price Desk sont désormais fermés par les gates opérateur jusquà `pre.006`. Après le polish `pre.007`, le prochain risque fonctionnel est borné au hardening `pre.008` avant louverture du couloir Wallet Desk `pre.009+`, sans remettre en cause le découpage souple ni les responsabilités documentaires de clôture.
Le Price Desk est fermé fonctionnellement après `pre.007`. La décision opérateur de simplifier Wallet Desk réduit le reste de la release à une seule tranche fonctionnelle `pre.008`, un gate/hardening transversal `pre.009`, une clôture documentaire/mécanique `pre.010`, puis `rel.001`.
## 20. Critères de sortie `pre.001`

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/015-V0_2_12_SOL_PRICES_DESK.md -->
<!-- version: 12 -->
<!-- version: 13 -->
# Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk
@@ -46,21 +46,21 @@ NOT RUN commande non exécutée dans le contexte indiqué
## 3. Screen/feature matrix
| Surface | Contrat | Statut |
|------------------------|-----------------------------------------|---------|
| splash Price Desk | lifecycle KSP commun | PASS |
| main shell Price Desk | header/navigation KSP | PASS |
| table providers | registry provider-neutral, ordre stable | PASS |
| table responsive UX | sticky/badges/timestamps distincts | PASS |
| prix exact | String issue de `MarketPriceDecimal` | PASS |
| availability/fraîcheur | état générique + timestamps réels | PASS |
| refresh row | `MarketPriceService::refresh` | PASS |
| refresh selected/many | `MarketPriceService::refresh_many` | PASS |
| refresh all | `MarketPriceService::refresh_all` | PASS |
| Diagnostics | profils/counts sûrs seulement | PASS |
| Wallet price panel | Dashboard compact provider-neutral | PENDING |
| auto-refresh | aucun scheduler/polling | OUT |
| Wallet USD valuation | aucun prix canonique | OUT |
| Surface | Contrat | Statut |
|------------------------|-----------------------------------------|--------|
| splash Price Desk | lifecycle KSP commun | PASS |
| main shell Price Desk | header/navigation KSP | PASS |
| table providers | registry provider-neutral, ordre stable | PASS |
| table responsive UX | sticky/badges/timestamps distincts | PASS |
| prix exact | String issue de `MarketPriceDecimal` | PASS |
| availability/fraîcheur | état générique + timestamps réels | PASS |
| refresh row | `MarketPriceService::refresh` | PASS |
| refresh selected/many | `MarketPriceService::refresh_many` | PASS |
| refresh all | `MarketPriceService::refresh_all` | PASS |
| Diagnostics | profils/counts sûrs seulement | PASS |
| Wallet prix moyen | une case `SOL/USD moyen` / `N.A.` | PASS |
| auto-refresh | aucun scheduler/polling | OUT |
| Wallet USD valuation | aucune multiplication balance × prix | OUT |
## 4. DTO/command matrix
@@ -69,7 +69,7 @@ NOT RUN commande non exécutée dans le contexte indiqué
| `MarketPriceRuntimeStatusDto` | profiles/counts sans secret | PASS |
| `MarketPriceProviderRowDto` | ID/display/pair/semantics/auth/availability/price/timestamps/retry | PASS |
| single refresh direct | provider_id opaque seulement | PASS |
| `MarketPriceRefreshManyRequestDto` | liste dIDs opaques ; borne hostile à durcir en `pre.008` | PASS |
| `MarketPriceRefreshManyRequestDto` | liste dIDs opaques ; borne hostile à durcir en `pre.009` | PASS |
| `MarketPriceRefreshResultDto` | rows/outcome classifiés | PASS |
| runtime/list/refresh/many/all commands | aucun URL/header/API key/body | PASS |
| TS-RS exports | bindings générés non versionnés | PASS |
@@ -115,7 +115,7 @@ NOT RUN commande non exécutée dans le contexte indiqué
| extraction API key/header | aucune projection/log | PASS |
| provider_id inconnu | erreur KSP sûre | PASS |
| batch duplicate | rejet avant dispatch | PASS |
| batch oversized | borne hostile applicative à durcir en `pre.008` | PENDING |
| batch oversized | borne hostile applicative à durcir en `pre.009` | PENDING |
| refresh spam | limites/cooldown Off-chain toujours actifs | PASS |
| stale observation | timestamps/état distingués | PASS |
| double-click race | in-flight/order contrôlés | PASS |
@@ -128,17 +128,22 @@ NOT RUN commande non exécutée dans le contexte indiqué
## 8. Wallet integration matrix
| Contrat | Attendu | Statut |
|----------------------------|-----------------------------------------------------------------|---------|
| Cargo dependency | Wallet Desk -> `ksp-offchain-transport-lib` | PENDING |
| Config component | Wallet composite -> `cfg.std.offchain_transport/public_keyless` | PENDING |
| runtime | ResolvedOffchainTransportConfig -> MarketPriceService | PENDING |
| commands/DTO | provider-neutral | PENDING |
| UI | petit panneau Dashboard | PENDING |
| balance HTTP On-chain | inchangée | PENDING |
| WalletSession VIEW/OWNER | inchangée | PENDING |
| Wallet secret projections | aucune nouvelle | PENDING |
| USD balance multiplication | hors scope | OUT |
| Contrat | Attendu | Statut |
|----------------------------|--------------------------------------------------------------------------|--------|
| Cargo dependency | Wallet Desk -> `ksp-offchain-transport-lib` | PASS |
| Config component | Wallet composite -> `cfg.std.offchain_transport/public_keyless` | PASS |
| runtime | Config -> `ResolvedOffchainTransportConfig` -> `MarketPriceService` | PASS |
| command | `refresh_wallet_balance` existante, aucun input prix/provider | PASS |
| DTO | `WalletBalanceDto.sol_usd_average: Option<String>` | PASS |
| moyenne | observations réussies du refresh courant, backend sans `f64`, 8 déc. max | PASS |
| UI | une seule case `SOL/USD moyen` / `N.A.` | PASS |
| balance HTTP On-chain | `getBalance` inchangé et toujours autoritatif | PASS |
| dégradation prix | échec/absence prix -> `N.A.` sans faire échouer la balance | PASS |
| WalletSession VIEW/OWNER | inchangée | PASS |
| Wallet secret projections | aucune nouvelle | PASS |
| provider ID frontend | aucun | PASS |
| command prix Wallet | aucune | PASS |
| USD balance multiplication | hors scope | OUT |
## 9. Tauri/package matrix
@@ -187,14 +192,14 @@ cargo fmt/check/clippy/test opérateur sur base stable fournie PASS
Après écriture du présent delta, les audits Rust structurel et Markdown ont été rejoués avec `deltas/0.2.12` inclus et sont propres.
## 12. Forecast de clôture
## 12. Forecast de clôture recalibré
Les responsabilités finales restent séparées :
Après décision opérateur de simplifier Wallet Desk, les responsabilités restantes sont condensées sans supprimer les gates de sortie :
```text
pre.013 gate technique/live + builds finaux
pre.014 réconciliation documentaire finale
pre.015 prompt suivant + CHANGELOG + ROADMAP uniquement
pre.008 intégration Wallet minimale + moyenne SOL/USD
pre.009 hardening transversal + gate technique/live + builds finaux
pre.010 réconciliation documentaire + prompt suivant + CHANGELOG + ROADMAP
rel.001 publication stable
```
@@ -531,7 +536,7 @@ python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox
```
Le gate opérateur de `pre.006` fourni le 2026-08-27 ferme ensuite cette tranche : audits, `cargo check`, Clippy, test ciblé et `cargo test --workspace` passent, `cargo tauri dev` démarre correctement et le parcours manuel confirme que le multi-refresh fonctionne. Les lignes `refresh selected/many`, `refresh all`, les deux DTOs batch, l'ordre many, le rejet des doublons et le conflit `in_flight` passent donc à `PASS`. La borne hostile d'une requête batch artificiellement surdimensionnée reste volontairement `PENDING` pour le hardening `pre.008`.
Le gate opérateur de `pre.006` fourni le 2026-08-27 ferme ensuite cette tranche : audits, `cargo check`, Clippy, test ciblé et `cargo test --workspace` passent, `cargo tauri dev` démarre correctement et le parcours manuel confirme que le multi-refresh fonctionne. Les lignes `refresh selected/many`, `refresh all`, les deux DTOs batch, l'ordre many, le rejet des doublons et le conflit `in_flight` passent donc à `PASS`. La borne hostile d'une requête batch artificiellement surdimensionnée reste volontairement `PENDING` pour le hardening `pre.009`.
## 23. Gate `0.2.12-pre.007`
@@ -565,3 +570,36 @@ python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
TypeScript syntax transpile main.ts PASS
cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox
```
Le gate opérateur du `27 août 2026` ferme `pre.007` : `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace`, Clippy workspace, `cargo test -p ksp-app-solprices-desk`, `cargo test --workspace` et `cargo tauri dev` passent. Le parcours visuel confirme la table finale avec 8 providers, états Ready/Disabled/Cooling down, observations distinctes, timestamps provider/KSP et les contrôles de refresh.
## 24. Gate `0.2.12-pre.008` — intégration Wallet minimale
La décision opérateur réduit le besoin Wallet à une seule information auxiliaire liée au refresh de balance :
```text
composite Wallet + offchain_transport/public_keyless implémenté
ksp-app-wallet-desk -> ksp-offchain-transport-lib implémenté
runtime Off-chain Wallet best-effort, erreur -> N.A.
refresh_wallet_balance input inchangé
getBalance + refresh_all lancés dans la même opération backend
observations prises pour moyenne uniquement succès du refresh courant
moyenne backend, aucune conversion f64, 8 décimales max
WalletBalanceDto.sol_usd_average Option<String>
UI Wallet une case SOL/USD moyen / N.A.
provider_id / URL / credential / command prix dans frontend absent
valorisation balance SOL en USD absente
WalletSession / VIEW / OWNER / secrets inchangés
```
Le runtime prix est auxiliaire : une indisponibilité Config/Off-chain ou zéro observation ne doit pas invalider une réponse `getBalance` réussie. Aucun état provider détaillé n'est dupliqué dans Wallet Desk ; l'inspection avancée reste dans SOL Prices Desk.
Validations sandbox après matérialisation :
```text
python3 scripts/audit_rust_workspace_rules.py PASS
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
TypeScript syntax transpile Wallet main.ts PASS
cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox
```