v0.2.12-pre.001

This commit is contained in:
2026-08-26 20:41:45 +02:00
parent db1f8d4a53
commit 9a7eda1aa6
8 changed files with 899 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 62 -->
<!-- version: 63 -->
# Plans KSP
@@ -26,7 +26,8 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
- [`015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md`](015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md) — plan historique clôturé de la release stable `0.2.8 — Helius LaserStream WebSocket`, ouvert par `pre.001`, fermé techniquement/documentairement par `pre.011` puis publié par `rel.001`; il conserve la surface finale Helius `7 standard + transaction`, heartbeat/Config/secrets, lhistorique des fixes heartbeat, la stratégie live architecture-safe, les graphes Cargo finaux et la préparation du prompt `0.2.9`.
- [`016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md`](016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md) — plan historique clôturé de la release stable `0.2.9 — Yellowstone gRPC standard/provider-neutral`, publiée par `rel.001`; il fixe le moteur N1, le standard N2, Config V3, le replay prudent et la validation PublicNode Mainnet/Testnet.
- [`017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md`](017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md) — plan historique clôturé de la release stable `0.2.10 — OrbitFlare Yellowstone gRPC`; il conserve le Devnet gRPC gratuit, N1/N2 immuables, la License Key `x-token` et le smoke final `Slot + Ping`.
- [`018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md`](018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md) — plan actif de `0.2.11 — Off-chain price transport`, ouvert par `pre.001`; il fixe SOL/USD V1, huit providers REST gratuits sans SDK, le modèle provider/rate-limit/availability, la Config capability-aware et la frontière HID de `ksp-app-solprices-desk`.
- [`018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md`](018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md) — plan historique clôturé de `0.2.11 — Off-chain price transport`; SOL/USD V1, huit providers REST sans SDK, registry/availability/rate limits Off-chain et Config `std.offchain_transport`.
- [`019-V0_2_12_SOL_PRICES_DESK_PLAN.md`](019-V0_2_12_SOL_PRICES_DESK_PLAN.md) — plan actif de `0.2.12 — SOL Prices Desk + intégration prix Wallet Desk`; il fixe le gabarit 1434/1435, le composite Config, les DTO/commands provider-neutral, le threat model et la trajectoire dintégration Wallet.
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
<!-- version: 91 -->
<!-- version: 92 -->
# Séquence des releases fonctionnelles KSP
@@ -512,7 +512,7 @@ Ces providers ne déplacent pas la séquence active et ne reçoivent ni façade,
`0.2.11` introduit `ksp-offchain-transport-lib` avec une première surface volontairement limitée à SOL/USD. La release retient huit adapters REST (`CoinGecko`, `CoinMarketCap`, `CoinPaprika`, `Kraken`, `Coinbase Exchange`, `Jupiter Price V3`, `Birdeye`, `DexScreener`) utilisant `reqwest` et des DTOs KSP privés, sans SDK provider. Off-chain Transport possède le registry, les capacités/rate limits, les indisponibilités et les refresh individuels/multiples séquentiels ; Config construit le service depuis `std.offchain_transport`. Le gate live final keyless passe `7/7` après correction du paramètre CoinMarketCap Simple Price V2. Aucun consensus, fallback automatique ou découverte de pool DexScreener n'est introduit.
`0.2.12` ajoute `ksp-app-solprices-desk`, HID pure qui ne connaît aucun provider et consomme uniquement les descriptors, observations, états et opérations génériques de `ksp-offchain-transport-lib`. Sa première vue liste les providers/prix et permet refresh individuel/multiple en laissant entièrement les limitations au service. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé.
`0.2.12` ajoute `ksp-app-solprices-desk`, HID pure qui ne connaît aucun provider et consomme uniquement les descriptors, observations, états et opérations génériques de `ksp-offchain-transport-lib`. Sa première vue liste les providers/prix et permet refresh individuel/multiple en laissant entièrement les limitations au service. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé. Le gate actif est [`019-V0_2_12_SOL_PRICES_DESK_PLAN.md`](019-V0_2_12_SOL_PRICES_DESK_PLAN.md) avec [`../validation/015-V0_2_12_SOL_PRICES_DESK.md`](../validation/015-V0_2_12_SOL_PRICES_DESK.md) : composite Price Desk dédié, ports 1434/1435, état de présentation backend en mémoire, auto-refresh et valorisation USD du solde hors scope.
Metadata HTTP/IPFS/Arweave viendra au premier besoin Metadata réel. SOL/EUR et les autres quotes restent une extension ultérieure explicite, sans conversion fiat cachée.

View File

@@ -0,0 +1,495 @@
<!-- file: docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md -->
<!-- version: 1 -->
# Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk
## 1. Base et autorité
La release est ouverte exclusivement depuis l'archive opérateur stable `v0.2.11` fournie au démarrage de session. L'archive ne contient pas de metadata `.git`; le tag ne peut donc pas être revérifié localement par `git describe`. Les marqueurs internes sont cohérents : `workspace.package.version = 0.2.11`, `deltas/0.2.11/rel.001.md` et `prompts/017-V0_2_12_START_PROMPT.md` sont présents.
Le log opérateur fourni avec la base exécute sur le checkout stable `v0.2.11` :
```text
cargo fmt --all PASS
python3 scripts/audit_rust_workspace_rules.py PASS
python3 scripts/audit_markdown_tables.py ... deltas/0.2.11 PASS
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS
cargo test --workspace PASS
```
Dans le sandbox de préparation, `cargo` n'est pas disponible. Les deux audits Python ont néanmoins été rejoués sur l'archive extraite et sont propres. Aucune commande Cargo non exécutée dans ce sandbox n'est déclarée localement PASS; le gate Cargo de base repose sur la preuve opérateur fournie pour le même état stable.
`0.2.12-pre.001` est une tranche documentaire d'audit/sizing. Elle ne crée ni crate Tauri, ni Config runtime nouveau, ni commande prix, ni code frontend fonctionnel.
## 2. Mission et frontières
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
```
Ownership durable :
```text
ksp-offchain-transport-lib providers, wire REST, endpoints, normalisation, rate limits, cooldowns, dispatch
ksp-config-lib documents, profils, composite, env, secrets, construction MarketPriceService
apps Tauri composition, état de présentation courant, IPC, UI, instrumentation
frontend projection/interaction uniquement; aucun réseau provider ni secret
```
La release ne crée ni `ksp-offchain-transport-api`, ni crate UI partagée spéculative, ni provider supplémentaire.
## 3. Audit de la surface stable Off-chain Transport
La façade publique `0.2.11` suffit au besoin HID. Le nouveau desk n'a pas besoin d'accéder aux adapters concrets.
| Contrat stable | Usage `0.2.12` | Décision |
|-----------------------------------------|------------------------------------------------------------|-------------------------------------------|
| `MarketPriceService::registry` | inventaire détaché provider-neutral | consommer directement |
| `MarketPriceService::refresh` | refresh dun `provider_id` opaque | consommer directement |
| `MarketPriceService::refresh_many` | batch borné, validation avant dispatch, ordre déterministe | consommer directement |
| `MarketPriceService::refresh_all` | refresh de linventaire dans lordre stable | consommer directement |
| `MarketPriceProviderRegistry` / `Entry` | descriptor + état génériques | source unique des lignes |
| `MarketPriceProviderDescriptor` | display name, semantics, auth, limites génériques | projection bornée; pas de wire |
| `MarketPriceProviderAvailability` | Ready/Disabled/CoolingDown/etc. + `retry_at` | projection UI sans scheduler |
| `MarketPriceObservation` | prix exact + timestamps + provenance + semantics | projection sûre |
| `MarketPriceDecimal` | vérité décimale exacte | DTO frontend en chaîne, jamais `f64` |
| `MarketPriceProviderId` | identifiant opaque borné | seul identifiant accepté par les commands |
Constats structurants :
- le service ne constitue pas un cache historique ;
- `refresh_many` rejette les doublons et IDs inconnus avant dispatch ;
- `refresh_many/all` V1 est volontairement séquentiel et ne dort pas pour attendre un provider ;
- disponibilité, cooldown et retry provider sont déjà possédés par Off-chain Transport ;
- les erreurs provider sont normalisées sans recopier de body distant dans les diagnostics sûrs ;
- huit setups concrets existent côté composition, mais ils ne doivent jamais apparaître dans le code applicatif par branche provider.
**Verdict :** aucune modification de `ksp-offchain-transport-lib` n'est nécessaire pour ouvrir la HID.
## 4. Audit Config et composition
`ResolvedOffchainTransportConfig` transporte déjà la sélection Config résolue, la provenance sûre et un `MarketPriceService`. `ConfigDocumentEngine` expose les chemins `load_resolved_offchain_transport_config` et `resolve_offchain_transport_config_profile`; l'application n'a donc pas à reconstruire les setups providers.
La base stable possède :
```text
cfg.std.offchain_transport
schema.std.offchain_transport
format_version = 1
default profile = public_keyless
explicit profile = all_free
schema.composite générique
cfg.composite.ksp-app-wallet-desk
```
### 4.1 Composite SOL Prices Desk retenu
Créer pendant `pre.003` :
```text
filename config/composite.ksp-app-solprices-desk.json
file_id cfg.composite.ksp-app-solprices-desk
schema schema.composite existant
component_id logging
component_id offchain_transport
```
Profils retenus :
| Composite profile | Logging | Off-chain Transport | Rôle |
|----------------------------|----------------|---------------------|-------------------------------------------------------------|
| `public_keyless` (default) | `console_info` | `public_keyless` | démarrage sans credential et profil de référence stable |
| `all_free` | `console_info` | `all_free` | opt-in Config; credentials résolus exclusivement par Config |
| `tests` | `console_info` | `public_keyless` | tests déterministes sans secrets |
`console_info` est retenu pour les profils de référence afin de ne pas créer en `0.2.12` une dépendance artificielle à des filtres/fichiers de logging spécialisés. L'instrumentation `trace` reste présente dans le code frontend/Rust conformément aux règles KSP, même si ce profil stable ne l'affiche pas par défaut.
Aucun nouveau schema composite n'est nécessaire.
### 4.2 Extension Wallet Desk retenue
Chaque profil du composite Wallet Desk (`devnet`, `temporary`, `tests`) recevra :
```text
component_id = offchain_transport
file_id = cfg.std.offchain_transport
profile_id = public_keyless
```
Le défaut Wallet reste donc keyless et ne gagne aucune exigence de secret. `all_free` n'est pas injecté arbitrairement dans Wallet Desk.
### 4.3 Contrainte atomique registry/packaging
`prepare_packaged_runtime` parcourt **tous** les descriptors de `ConfigFileRegistry::defaults()`. L'ajout du composite SOL Prices Desk augmente donc l'inventaire de ressources packagées de 10 à 11.
La tranche qui ajoute le descriptor doit synchroniser dans le même delta :
```text
Config registry
nouveau document composite
Config unit/public tests
resources Tauri ksp-app-config-desk
resources Tauri ksp-app-wallet-desk
resources Tauri ksp-app-solprices-desk
tests desktop/package qui comptent ou valident les resources
```
Il ne faut pas publier un état intermédiaire dans lequel le registry exige le nouveau composite mais un Desk packagé ne l'embarque pas.
## 5. Audit des gabarits desktop stables
La base confirme :
| Surface | Config Desk | Wallet Desk | Décision SOL Prices Desk |
|------------------|-------------------------------|-------------------------------------|----------------------------|
| ports Vite/HMR | 1430 / 1431 | 1432 / 1433 | 1434 / 1435 |
| Rust package | lib + bin | lib + bin | lib + bin |
| windows | splash + main | splash + main | splash + main |
| commands | centralisés `tauri.rs` | centralisés `tauri.rs` | même pattern |
| window modules | `tw_splash`, `tw_main` | `tw_splash`, `tw_main` | même pattern |
| frontendDist | hors source sous `builds/...` | hors source sous `builds/...` | même pattern dédié |
| Vite | strictPort + HMR dédié | strictPort + HMR dédié | strictPort 1434 + HMR 1435 |
| capabilities | core + tracing | core + tracing | core + tracing seulement |
| dialog plugin | absent | Rust-side pour import/export Wallet | absent |
| browser network | aucun fetch direct attendu | aucun fetch direct attendu | interdit |
| Config resources | 10 resources registry | 10 resources registry | 11 après nouveau composite |
Le nouveau desk doit avoir ses propres `productName`, `identifier`, chemins `frontendDist`, hooks NPM et backend Rust. Un canari doit empêcher une copie erronée qui lancerait Vite ou le backend Wallet Desk.
Les versions `package.json`/`tauri.conf.json` des deux Desks historiques sont encore `0.2.6` alors que leurs crates héritent de la version workspace `0.2.11`. Les tests stables imposent seulement un plancher `>= 0.2.6`. Cette release ne lancera pas une harmonisation globale de versions d'apps historiques par principe. Le nouveau package SOL Prices Desk utilisera la version de release `0.2.12-pre.*`/`0.2.12` selon le mécanisme retenu dans son scaffold, et toute modification du package Wallet sera auditée pour cohérence sans élargir la release à Config Desk.
## 6. Audit externe desktop du 2026-08-26
Sources officielles réauditées :
```text
https://v2.tauri.app/reference/config/
https://v2.tauri.app/security/
https://v2.tauri.app/security/capabilities/
https://v2.tauri.app/reference/acl/core-permissions/
https://github.com/tauri-apps/tauri/releases
https://github.com/Aleph-Alpha/ts-rs
https://github.com/Aleph-Alpha/ts-rs/releases
```
Constats :
- Tauri documente toujours `beforeDevCommand`, `beforeBuildCommand`, `devUrl` et `frontendDist` dans `tauri.conf.json` ; le pattern KSP actuel reste aligné ;
- les capabilities restent la frontière d'autorisation du WebView vers les commandes/plugin permissions ; `core:default` est toujours un permission set officiel ;
- la release Tauri courante observée est `2.11.5`, cohérente avec la contrainte workspace `tauri = ^2.11` ;
- TS-RS publie `12.0.0` comme release courante et recommande `ts-rs = "12.0"`, cohérent avec `ts-rs = ^12.0` déjà présent ;
- aucun besoin `pre.001` ne justifie une mise à niveau globale de Tauri, TS-RS ou des dépendances frontend.
Le nouveau desk réutilisera le baseline frontend actuel uniquement pour les dépendances réellement utilisées. `tauri-plugin-dialog` n'est pas retenu pour SOL Prices Desk.
## 7. État de présentation courant
Décision : **backend Tauri en mémoire**.
Un runtime applicatif dédié possède :
```text
Resolved Off-chain profile metadata sûre
MarketPriceService
snapshot courant des lignes de présentation
état in-flight borné par provider pour éviter les races d'affichage
```
Le snapshot de présentation n'est ni un historique, ni une source métier, ni une nouvelle vérité de marché. Une observation vient toujours d'un `MarketPriceRefreshOutcome` Off-chain.
Règles :
- aucun prix n'est persisté dans Config, Store, filesystem navigateur, `localStorage` ou `sessionStorage` ;
- l'inventaire initial provient du `registry()` et affiche `price = None` avant première observation ;
- une erreur de refresh peut conserver l'ancienne observation uniquement si elle reste explicitement marquée comme antérieure et accompagnée du nouvel état provider ;
- `received_at` et `provider_timestamp` sont projetés séparément ; l'UI ne fabrique jamais un timestamp provider ;
- l'UI ne remplace un snapshot que par un résultat backend ordonné/accepté, évitant qu'une réponse plus ancienne écrase une plus récente.
Cette décision reste dans la couche application et ne transforme pas Off-chain Transport en store UI.
## 8. Screen map SOL Prices Desk
```text
splash
-> bootstrap Config + Logging + Off-chain runtime
-> main shell
-> Prices (vue par défaut)
-> runtime summary compact
-> table provider-neutral SOL/USD
provider display name
semantics
auth capability générique
availability
exact price ou “aucune observation”
provider timestamp ou “non fourni”
received_at
retry_at si présent
row refresh
-> selection DataTable optionnelle
-> Refresh selected
-> Refresh all
-> loading / empty / classified error states
-> Diagnostics
-> app/composite/offchain profile
-> provider count / ready count / unavailable count
-> aucun endpoint/credential/header
```
Le shell reste volontairement petit : pas de dashboard trading, graphe, historique, quote routing ou éditeur Config.
### Point d'insertion Wallet 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
```
Le panneau prix est indépendant du lifecycle VIEW/OWNER. Il ne modifie ni la balance SOL ni les opérations Wallet.
**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.
## 9. DTO map retenue
Les DTO sont applicatifs, sérialisables et exportés TS-RS. Les enums évolutifs de la crate Off-chain ne sont pas exposés directement si cela rigidifie l'IPC ; ils sont projetés en codes/labels génériques bornés.
Le prix exact traverse IPC comme chaîne décimale, jamais comme `f64`. Les timestamps sont des millisecondes Unix ou chaînes de présentation selon le canari TS-RS final; la source de vérité reste `MarketPriceTimestamp`.
| DTO | Champs principaux | Sensibilité |
|------------------------------------|----------------------------------------------------------------------------------------------------------------|--------------------|
| `MarketPriceRuntimeStatusDto` | app version, composite profile, offchain profile, provider counts, fallback logging | Public/safe |
| `MarketPriceProviderRowDto` | provider_id, display_name, pair, semantics, auth_mode, availability, price?, timestamps?, retry_at?, refreshed | Public/safe |
| `MarketPriceRefreshRequestDto` | provider_id opaque | Public input borné |
| `MarketPriceRefreshManyRequestDto` | provider_ids opaques bornés | Public input borné |
| `MarketPriceRefreshResultDto` | rows affectées + refreshed/classification | Public/safe |
| `CommandErrorDto` | domain/code/message borné sans context sensible | Public/safe |
Explicitement exclus de tout DTO :
```text
API key
header name/value
endpoint URL
raw response provider
provider-specific request/response DTO
bucket/token internals
Config effective secret values
```
## 10. Command map SOL Prices Desk
| Command | Input | Output | Owner | Sensibilité |
|-----------------------------|--------------------------------------|----------------------------------|----------------------------------|-----------------------|
| `runtime_status` | aucun | `MarketPriceRuntimeStatusDto` | AppState/Config runtime | safe |
| `list_market_prices` | aucun | `Vec<MarketPriceProviderRowDto>` | MarketPriceRuntime + registry | safe |
| `refresh_market_price` | `provider_id` | `MarketPriceRefreshResultDto` | MarketPriceService::refresh | safe ID |
| `refresh_market_prices` | liste bornée `provider_id` | `MarketPriceRefreshResultDto` | MarketPriceService::refresh_many | safe IDs |
| `refresh_all_market_prices` | aucun | `MarketPriceRefreshResultDto` | MarketPriceService::refresh_all | safe |
| `splash_frontend_ready` | fenêtre invoquante | ordre splash existant | Tauri window lifecycle | safe |
| `frontend_log` | niveau/target/message déjà contrôlés | ack | logging bridge | safe-only by contract |
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.
## 11. Refresh UX
Décisions :
- ordre initial des lignes = ordre stable du registry ; un tri visuel DataTable ne change pas l'ordre de dispatch backend ;
- bouton row désactivé pendant le refresh de cette ligne ;
- batch : sélection bornée, doublons éliminés/rejetés côté UI pour UX mais validation authoritative conservée par Off-chain ;
- `refresh_many/all` suit l'implémentation séquentielle V1, sans parallélisme ajouté par l'app ;
- un provider non éligible est représenté par son availability, pas par un retry/sleep local ;
- `CoolingDown` affiche `retry_at` si disponible ; aucun countdown actif n'est nécessaire ;
- `AuthenticationUnavailable`, `Misconfigured`, `Disabled`, `QuotaUnavailable`, `TemporarilyUnavailable` restent des états génériques ;
- `provider_timestamp = None` s'affiche comme « non fourni par le provider », pas comme heure de réception ;
- une observation précédente peut rester visible après un échec seulement avec sa fraîcheur réelle et le nouvel état provider clairement distingués ;
- fermeture de fenêtre : la commande/backend peut terminer/cancel selon lifecycle Tauri, mais aucun état frontend persistant ne doit être requis pour la sûreté.
**Auto-refresh périodique : hors scope.** Aucun `setInterval`, scheduler ou worker prix n'est ajouté en `0.2.12`.
## 12. Intégration Wallet Desk
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.
Flux :
```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
```
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
aucune multiplication balance x prix
aucun provider canonique
```
Aucun adapter, parser, limiter ou fetch TS n'est copié dans Wallet Desk.
## 13. Mutualisation entre applications
La mutualisation métier existe déjà dans `ksp-offchain-transport-lib` et la mutualisation de construction dans `ksp-config-lib`.
`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.
## 14. Capabilities et plugins
SOL Prices Desk :
```text
permissions core:default
tracing:default
plugins tauri-plugin-tracing uniquement
```
Aucun plugin filesystem, HTTP, shell, CLI ou dialog n'est nécessaire au WebView.
Wallet Desk conserve sa capability actuelle `core:default + tracing:default`. Son `tauri-plugin-dialog` Rust-side reste limité aux workflows Wallet existants et n'est pas utilisé par les prix.
Le threat model considère le WebView comme moins fiable que le core Rust : les commands Rust restent la frontière de validation et n'exposent que les capacités applicatives nécessaires.
## 15. Packaging et build
SOL Prices Desk :
```text
productName KSP SOL Prices Desk
identifier com.sasedev.ksp-app-solprices-desk
dev URL http://localhost:1434
Vite HMR 1435 strict
frontendDist ../../../builds/khadhroony-solana-project/ksp-app-solprices-desk/dist
windows splash + main
bundle targets all, comme le gabarit stable
icons même baseline KSP, copiée explicitement dans la nouvelle crate
beforeDevCommand npm run dev, cwd .
beforeBuildCommand npm run build, cwd .
```
Les commandes Tauri de validation finales sont exécutées depuis chaque crate ciblée. Aucun `cargo tauri ... -c` ne sert de sélecteur de crate.
Canari obligatoire : `ksp-app-solprices-desk` référence son propre `package.json`, son propre Vite config, ses ports 1434/1435, son `frontendDist` et son backend; aucune chaîne `ksp-app-wallet-desk` ne doit apparaître dans les hooks/paths qui sélectionnent le runtime.
## 16. Threat model desktop `0.2.12`
| Risque | Contrôle retenu |
|------------------------------------------|----------------------------------------------------------------------------------|
| frontend compromis choisit une URL | aucun champ URL dans IPC; origine possédée par adapter Off-chain |
| frontend demande API key/header | aucun DTO/command ne les expose; secrets restent Config -> service |
| provider_id arbitraire/inconnu | validation par registry/service; erreur KSP sûre |
| batch oversized/duplicate | borne app + validation authoritative `refresh_many` avant dispatch |
| spam refresh | admission/rate limits/cooldown Off-chain; UI disable seulement ergonomique |
| cooldown non expiré | availability générique; aucun sleep/retry dans app |
| provider unavailable | ligne reste visible avec état générique; autres providers indépendants |
| raw error body hostile | projection `CommandErrorDto` classifiée; jamais de body brut |
| stale observation affichée comme fraîche | timestamps réels conservés; état provider séparé; pas de timestamp inventé |
| race double-click | état in-flight backend + UI disable; ordre de snapshot contrôlé |
| fermeture fenêtre pendant refresh | aucune persistance requise; lifecycle/cancel borné testé |
| 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 |
| perte de précision JS | prix transmis comme chaîne décimale exacte |
## 17. Stratégie de tests et gates
| Gate | Preuve attendue |
|---------------------|--------------------------------------------------------------------------------------|
| unit Rust app | mapping descriptor/state/outcome -> DTO; exact decimal string; stale/in-flight/error |
| Config composition | composite Price Desk et extension Wallet résolus par file_id/profile exacts |
| Config packaging | 11 descriptors/resources synchronisés, seed/schemas propres |
| public/API boundary | aucun provider-specific type requis par lapp; dépendances exactes |
| desktop contract | ports, windows, hooks, frontendDist, header, DataTable, backend propre |
| desktop security | aucun fetch/network/fs/secret storage; capabilities minimales; DTO sans URL/key/body |
| 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 |
| 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 |
Le live gate `0.2.12` vérifie la composition application -> Config -> service avec au moins un provider keyless disponible. Il ne répète pas le smoke exhaustif `7/7` de `0.2.11` sauf contradiction live réelle.
## 18. Hors périmètre confirmé
```text
nouveau provider ou modification des 8 adapters V1
SOL/EUR ou token arbitraire
OHLCV/historique/chart
SSE/WebSocket prix
consensus/moyenne/fallback automatique
provider canonique
valorisation USD du solde Wallet
auto-refresh/polling périodique
Store/worker/job prix
éditeur Config dans Price Desk
filesystem/network/dialog plugin frontend
nouvelle crate API/UI partagée spéculative
```
## 19. Forecast souple recalibré
| Tranche | Responsabilité | Dépendances/gate |
|-----------|---------------------------------------------------------------------------------------------------|----------------------------------------------------|
| `pre.001` | audit/sizing, screen map, DTO/commands, Config, sécurité, Wallet map | présent document + validation |
| `pre.002` | scaffold `ksp-app-solprices-desk`, lib/bin/Tauri, splash/shell/logging, 1434/1435 | aucune logique prix |
| `pre.003` | composite Price Desk + registry Config + resources **atomiques des 3 apps** + bootstrap Off-chain | packaging Config vert |
| `pre.004` | MarketPriceRuntime, registry rows, DTOs, état initial/loading/empty | TS-RS + unit tests |
| `pre.005` | refresh row, observation exacte, availability/fraîcheur, erreur sûre | single refresh |
| `pre.006` | refresh selected/many/all, in-flight, ordre, cooldown/retry projection | batch déterministe |
| `pre.007` | UX table/responsive/instrumentation/polish Price Desk | aucun auto-refresh |
| `pre.008` | hardening Price Desk, desktop/security/package, parcours fonctionnel | Price Desk stable avant Wallet |
| `pre.009` | extension composite Wallet + dépendance/runtime Off-chain | non-régression bootstrap Wallet |
| `pre.010` | DTO/commands prix Wallet provider-neutral | aucun secret/wire |
| `pre.011` | panneau Dashboard Wallet + refresh + non-régression balance/VIEW/OWNER | aucune valorisation USD |
| `pre.012` | hardening cross-app, capabilities/resources/completeness | tests deux Desks |
| `pre.013` | gate technique/live final + builds Tauri finaux des apps modifiées | workspace + live composition |
| `pre.014` | réconciliation documentaire finale | plan/validation/README/USAGE |
| `pre.015` | préparation publication minimale | prompt suivant + CHANGELOG + ROADMAP + Cargo/delta |
| `rel.001` | publication stable `v0.2.12` | mécanique uniquement |
Chaque tranche intermédiaire reste dimensionnée à environ 1520 minutes effectives. Le point le plus risqué est `pre.003`; son scope reste néanmoins borné parce qu'il ne contient aucune UI prix et traite ensemble le seul invariant de packaging transversal. Le scope global reste raisonnablement clôturable dans une session de release KSP : aucun redécoupage n'est requis avant `pre.002`.
## 20. Critères de sortie `pre.001`
| Critère | Verdict |
|-------------------------------------------------------|---------|
| base stable `v0.2.11` cohérente | PASS |
| règles/architecture relues | PASS |
| baseline opérateur verte; limites sandbox documentées | PASS |
| surface Off-chain/Config réelle inventoriée | PASS |
| gabarits Config/Wallet Desk audités | PASS |
| audit Tauri/TS-RS actuel | PASS |
| screen map | PASS |
| DTO/command map | PASS |
| Config/composite map | PASS |
| threat model | PASS |
| Wallet integration map | PASS |
| tests/build/live strategy | PASS |
| forecast recalibré | PASS |
| scope clôturable | PASS |
`pre.001` n'autorise aucune implémentation fonctionnelle supplémentaire dans ce delta. La prochaine responsabilité est exclusivement `pre.002` : scaffold du nouveau Desk et canaris de gabarit.