# Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk ## 1. Objet Cette matrice est ouverte par `0.2.12-pre.001`. Elle suit la création de `ksp-app-solprices-desk`, sa composition Config/Off-chain Transport puis l'intégration provider-neutral dans Wallet Desk. Statuts utilisés : ```text PASS preuve acquise PENDING attendu dans une tranche ultérieure OUT explicitement hors scope NOT RUN commande non exécutée dans le contexte indiqué ``` ## 2. Gate `0.2.12-pre.001` | Critère | Statut | Preuve | |-------------------------------------------------|--------|--------------------------------------------------------------------| | archive stable `v0.2.11` utilisée | PASS | archive Gitea opérateur fournie | | `workspace.package.version = 0.2.11` à l’entrée | PASS | inspection `Cargo.toml` | | `deltas/0.2.11/rel.001.md` présent | PASS | inspection archive | | prompt `017-V0_2_12_START_PROMPT.md` présent | PASS | inspection archive | | metadata `.git` disponible | OUT | archive source sans `.git`; tag non revérifiable localement | | baseline Cargo stable | PASS | preuve opérateur 2026-08-26: fmt/check/clippy/test workspace verts | | audits Python sandbox sur archive | PASS | Rust rules clean; Markdown tables clean avant modification | | règles/architecture obligatoires relues | PASS | audit `pre.001` + plan 019 | | surface Off-chain réelle inventoriée | PASS | plan 019 sections 3/9/10 | | surface Config/composite/packaging inventoriée | PASS | plan 019 section 4 | | gabarits Config/Wallet Desk inventoriés | PASS | plan 019 section 5 | | sources officielles Tauri/TS-RS réauditées | PASS | plan 019 section 6 | | screen map Price Desk + Wallet | PASS | plan 019 section 8 | | DTO/command map | PASS | plan 019 sections 9/10 | | état de présentation décidé | PASS | backend mémoire uniquement; plan 019 section 7 | | Config/composite map | PASS | nouveau composite + extension Wallet; plan 019 section 4 | | threat model desktop | PASS | plan 019 section 16 | | Wallet integration map | PASS | plan 019 section 12 | | auto-refresh | OUT | hors scope confirmé | | valorisation USD du solde | OUT | aucun prix canonique; hors scope confirmé | | forecast souple recalibré | PASS | 15 prereleases + rel; plan 019 section 19 | | scope clôturable | PASS | pas de redécoupage requis avant `pre.002` | | code/scaffold fonctionnel ajouté en `pre.001` | OUT | interdit par le gate | ## 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 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 | Contrat | Entrée/sortie sûre | Statut | |----------------------------------------|--------------------------------------------------------------------|--------| | `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 d’IDs 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 | | provider-specific type dans IPC | interdit | OUT | | prix `f64` comme vérité IPC | interdit | OUT | ## 5. Config/composite matrix | Contrat | Valeur attendue | Statut | |---------------------------------------|--------------------------------------------------------------|---------| | Price Desk composite file | `config/composite.ksp-app-solprices-desk.json` | PASS | | Price Desk file_id | `cfg.composite.ksp-app-solprices-desk` | PASS | | schema | `schema.composite` existant | PASS | | components | `logging`, `offchain_transport` | PASS | | default profile | `public_keyless` | PASS | | optional profile | `all_free` | PASS | | test profile | `tests` -> offchain `public_keyless` | PASS | | Wallet composite | ajoute offchain `public_keyless` à devnet/temporary/tests | PENDING | | registry/resource count | 11 après nouveau composite | PASS | | registry + resources atomiques | Config + Config Desk + Wallet Desk + Price Desk même tranche | PASS | | nouveau schema Config | inutile | OUT | | modification `std.offchain_transport` | pas de lacune identifiée | OUT | ## 6. Provider-agnostic boundary matrix | Canari | Attendu | Statut | |--------------------------------------------|------------------|--------| | app dépend du service/registry générique | oui | PASS | | branche `coingecko`/`kraken`/etc. dans app | aucune | PASS | | SDK provider dans app | aucun | PASS | | reqwest/provider fetch frontend | aucun | PASS | | endpoint/header/API key dans DTO | aucun | PASS | | rate limiter/sleep/retry provider dans app | aucun | PASS | | refresh many ordre service | préservé | PASS | | semantics provider-neutral visibles | oui, sans fusion | PASS | | prix canonique/fallback/moyenne | aucun | OUT | ## 7. Security matrix | Risque/canari | Attendu | Statut | |--------------------------------|-------------------------------------------------|---------| | URL arbitraire depuis frontend | impossible par contrat command | PASS | | 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.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 | | close pendant refresh | aucune persistance/sûreté frontend requise | PENDING | | CWD/resource confusion | canaris propres à chaque app | PENDING | | Price Desk capabilities | `core:default`, `tracing:default` uniquement | PASS | | plugin dialog Price Desk | absent | PASS | | frontend sensitive logging | action/ID/count/code seulement | PASS | | Wallet VIEW/OWNER/secrets | non-régression | PENDING | ## 8. Wallet integration matrix | 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` | 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 | Contrat | Attendu | Statut | |------------------------------------|------------------------------------|---------| | Price Desk ports | 1434/1435 strict | PASS | | windows | splash + main | PASS | | Rust package | lib + bin; `main.rs` mince | PASS | | commands | centralisées `tauri.rs` | PASS | | frontendDist | hors source, path Price Desk dédié | PASS | | hooks | npm dev/build cwd crate | PASS | | backend cross-app | aucune référence Wallet par erreur | PASS | | resources | registry complet packagé | PASS | | bundle | targets/icons cohérents | PASS | | Tauri production build Price Desk | crate-local PASS attendu | PENDING | | Tauri production build Wallet Desk | crate-local PASS attendu | PENDING | ## 10. Gates techniques/live finaux | Gate | Statut | |--------------------------------------------------------------|---------| | `cargo fmt --all` | PENDING | | `python3 scripts/audit_rust_workspace_rules.py` | PENDING | | `python3 scripts/audit_markdown_tables.py ... deltas/0.2.12` | PENDING | | `cargo check --workspace` | PENDING | | `cargo clippy --workspace --all-targets` | PENDING | | `cargo test --workspace` | PENDING | | Price Desk functional dev path | PENDING | | Wallet Desk functional price path | PENDING | | keyless app-composition live smoke | PENDING | | Price Desk `cargo tauri build` | PENDING | | Wallet Desk `cargo tauri build` | PENDING | Le live `0.2.12` valide la composition applicative générique; il ne répète pas l'audit provider `7/7` de `0.2.11` sans raison. ## 11. Validations exécutées pour `pre.001` ```text inspection archive/version/rel/prompt PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py README.md ... crates PASS sources officielles Tauri/TS-RS PASS audit cargo fmt/check/clippy/test dans sandbox NOT RUN — cargo indisponible 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 recalibré 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.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 ``` ## 13. Gate `0.2.12-pre.002` Le scaffold strict est matérialisé sans avancer la composition Off-chain : ```text crate mixte lib/bin ksp-app-solprices-desk PASS ports Vite/HMR 1434/1435 strict PASS fenêtres splash + main PASS frontendDist/hook/backend propres PASS bridge Logging + tauri-plugin-tracing PASS capabilities core:default + tracing:default PASS plugin dialog/fs/http/shell frontend absent resources Config 10/10 registry courant; 11e composite réservé à pre.003 MarketPriceService / refresh / table prix absent par contrat pre.002 ``` 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 cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` Le retour opérateur du `27 août 2026` clôt le gate de tranche : `cargo fmt --all`, installation npm, audits Rust/Markdown, `cargo check --workspace`, Clippy workspace, `cargo test -p ksp-app-solprices-desk` et `cargo tauri dev` passent. Le test applicatif exécute 12 unit tests, 4 canaris `desktop_contract`, 3 canaris `desktop_security` et 1 canari `public_api`, tous PASS. ## 14. Gate `0.2.12-pre.002-fix.001` Le correctif réaligne le nouveau Desk sur le gabarit desktop commun sans ouvrir le runtime prix : ```text package frontend commun : tracing + ResizeObserver + Bootstrap/SimpleBar PASS structurel ResizeObserver installé avant SimpleBar PASS structurel getCurrentWindow() utilisé au bootstrap main PASS structurel commande Tauri get_runtime_status PASS structurel footer commun PASS structurel police DOS_Amazigh + manifeste de provenance PASS structurel partials SCSS communs identiques hors headers de fichier PASS structurel _app.scss réutilise le vocabulaire app-runtime-list/app-placeholder PASS structurel TRACING_DOMAIN_SHELL réellement consommé PASS structurel MarketPriceService / composite / refresh / table prix absent par contrat ``` Le gate opérateur du `27 août 2026` sur `0.2.12-pre.2.fix.1` est propre : audits Rust/Markdown, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-app-solprices-desk` passent sans les deux warnings précédents. `cargo tauri dev` démarre Vite sur `1434` puis le backend Rust sans warning. `cargo test --workspace` n'a pas été rejoué dans ce retour précis et n'est donc pas revendiqué ici. ## 15. Gate `0.2.12-pre.003` La tranche matérialise uniquement la composition Config et le bootstrap Off-chain provider-neutral : ```text composite cfg.composite.ksp-app-solprices-desk PASS structurel profils public_keyless / all_free / tests PASS structurel composants logging + offchain_transport par file_id PASS structurel registry Config 11 descriptors resources Config Desk / Wallet Desk / SOL Prices Desk 11/11 chacune Logging SOL Prices Desk résolu depuis le composite PASS structurel ResolvedOffchainTransportConfig construit au bootstrap PASS structurel service provider-neutral public_keyless 8 entrées attendues par canari MarketPriceRuntime / rows / observations / refresh commands absent par contrat pre.003 navigation et contrôles frontend existants journalisés en debug PASS structurel/canari IPC frontend request/completion debug / trace ``` Le contrat de logging frontend est volontairement durable : action utilisateur et transition de vue en `debug`, étapes techniques fréquentes/fin d'IPC en `trace`, sans sérialiser prix, credentials, headers ni payloads métier. Les futurs boutons de refresh devront reprendre le même bridge et le même niveau de discipline. 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 validation syntaxique des JSON modifiés PASS cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` ## 16. Gate `0.2.12-pre.003-fix.001` Le gate opérateur du `27 août 2026` sur `0.2.12-pre.3` a établi : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets FAIL — compilation du test config_composition cargo test -p ksp-app-solprices-desk FAIL — même défaut de compilation ``` Le défaut est limité au canari `solprices_desk_default_composite_builds_provider_neutral_offchain_service` : son message `assert!` formatait `{environment:?}` sur un `Result`. Comme `ConfigEnvironment` n'implémente volontairement pas `Debug`, ce formatage imposait un contrat non requis au type de succès. `pre.003-fix.001` retire uniquement cette interpolation et conserve le `is_ok()` suivi du `match` explicite existant. Aucun `Debug` n'est ajouté à `ConfigEnvironment`, aucun `unwrap`/`expect`/`panic` n'est introduit, et aucun comportement runtime n'est modifié. Validations sandbox après matérialisation du fix : ```text python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py README.md ... deltas PASS cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` ## 17. Gate `0.2.12-pre.004` La tranche introduit la première projection prix applicative sans effectuer de requête provider : ```text MarketPriceRuntime backend implémenté état présentation mémoire backend uniquement registry -> lignes provider-neutral implémenté MarketPriceProviderRowDto implémenté MarketPriceRuntimeStatusDto implémenté prix exact Option, jamais f64 timestamps observation/retry Option exactes en millisecondes Unix list_market_prices implémenté, aucun dispatch réseau états frontend loading / empty / table implémentés refresh row/many/all absent par contrat pre.004 frontend fetch/localStorage/sessionStorage absent logging chargement/rendu registry trace sans prix/payload ``` Le gate opérateur précédent est désormais fermé après `pre.003-fix.001` : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-app-solprices-desk PASS (cd crates/ksp-app-solprices-desk && cargo tauri dev) PASS cargo test --workspace NOT RUN dans ce retour précis ``` Validations sandbox après matérialisation de `pre.004` : ```text python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py README.md ... deltas PASS cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` ## 18. Fix `0.2.12-pre.004-fix.001` Le gate opérateur de `pre.004` confirme : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-app-solprices-desk PASS cargo tauri dev SOL Prices Desk PASS cargo test --workspace FAIL ``` L'échec workspace est unique et externe au runtime prix : `ksp-app-config-desk::profiles::profile_inventory_exposes_registered_profile_documents` construit son `ConfigManagement` sur `crates/ksp-config-lib/unit_tests/fixtures`. Depuis l'enregistrement de `cfg.composite.ksp-app-solprices-desk`, l'inventory parcourt onze descriptors et tente donc de charger : ```text crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-solprices-desk.json ``` Cette fixture n'avait pas été ajoutée, ce qui produit `config/json_file_read_failed`. Le correctif : ```text ajoute composite.ksp-app-solprices-desk.json dans les fixtures Config conserve les profils composite public_keyless / all_free / tests utilise logging/local_dev, réellement disponible dans la fixture Logging utilise offchain_transport/public_keyless ou all_free selon le profil ajoute au canari Config Desk l'assertion explicite du nouveau composite ne modifie aucun runtime prix, DTO, adapter provider ou frontend ``` La version technique devient `0.2.12-pre.4.fix.1` parce qu'un test Rust compilé est modifié. Les versions applicatives SOL Prices Desk de `package.json` et `tauri.conf.json` sont synchronisées. Validations sandbox après matérialisation du fix : ```text python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py README.md ... deltas PASS cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` Gate opérateur attendu après application : ```bash cargo fmt --all python3 scripts/audit_rust_workspace_rules.py python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.12 cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-app-config-desk cargo test -p ksp-app-solprices-desk cargo test --workspace ``` ## 19. Fix `0.2.12-pre.004-fix.002` Le gate opérateur de `pre.004-fix.001` confirme : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-app-solprices-desk FAIL ``` L'échec est limité à `pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths` : le test attend encore littéralement `0.2.12-pre.4`, alors que `pre.004-fix.001` a correctement synchronisé `package.json` et `tauri.conf.json` sur `0.2.12-pre.4.fix.1`. Le comportement runtime n'est pas en cause. Le correctif aligne SOL Prices Desk sur les contrats déjà utilisés par Config Desk et Wallet Desk : ```text parse SemVer core des versions desktop implémenté plancher version >= 0.2.6 implémenté égalité tauri.conf.json / package.json implémentée chaîne exacte 0.2.12-pre.4 dans le canari supprimée runtime prix / DTO / provider / frontend inchangés ``` La version technique devient `0.2.12-pre.4.fix.2`. Le gate attendu doit confirmer que le canari reste vert avec ce suffixe et continuera de l'être lors des prochaines prereleases. ## 20. Gate `0.2.12-pre.005` Le gate opérateur de clôture de `pre.004-fix.002` est intégralement vert : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-app-solprices-desk PASS cargo test --workspace PASS cargo tauri dev SOL Prices Desk PASS ``` La tranche `pre.005` ajoute uniquement le refresh individuel : ```text MarketPriceService::refresh branché par provider_id opaque mutex présentation détenu pendant await non loading backend par ligne oui observation réussie exacte conservée sous forme string via DTO existant absence de nouvelle observation dernière observation réussie conservée availability/retry source Off-chain Transport, sans réinterprétation app refresh_market_price implémenté refresh_market_prices absent jusqu'à pre.006 refresh_all_market_prices absent jusqu'à pre.006 bouton Refresh par ligne implémenté clic refresh frontend debug, provider_id opaque uniquement IPC request/completion debug / trace via invokeKsp prix/payload/header/URL/API key dans les logs absent par contrat polling / scheduler consommateur absent ``` 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 cargo fmt/check/clippy/test NOT RUN — cargo indisponible dans le sandbox ``` ## 21. Fix `0.2.12-pre.005-fix.001` Le gate opérateur de `pre.005` confirme que le runtime de refresh individuel fonctionne : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo test -p ksp-app-solprices-desk FAIL — canari desktop_security uniquement cargo tauri dev SOL Prices Desk PASS refresh individuel manuel PASS ``` L'unique échec est `pre_005_tauri_commands_remain_centralized_and_only_single_refresh_is_present`. Le test recherchait la chaîne `refresh_market_price` dans tous les fichiers Rust hors `tauri.rs`, ce qui classe à tort `AppState::refresh_market_price` comme plumbing Tauri alors que cette méthode est la frontière applicative appelée par la commande centralisée. Le correctif vérifie désormais la centralisation sur les marqueurs structurels Tauri : ```text #[tauri::command] hors tauri.rs interdit tauri::generate_handler! hors tauri.rs interdit méthode applicative refresh_market_price dans AppState autorisée refresh_market_prices toujours absent avant pre.006 refresh_all_market_prices toujours absent avant pre.006 runtime prix / frontend / providers inchangés ``` La version technique devient `0.2.12-pre.5.fix.1`. Le gate attendu doit confirmer le test ciblé puis le workspace complet avant d'ouvrir `pre.006`. ## 22. Gate `0.2.12-pre.006` Le gate opérateur de `pre.005-fix.001` fourni le 2026-08-27 confirme la fermeture de la tranche précédente : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS python3 scripts/audit_markdown_tables.py ... deltas/0.2.12 PASS cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-app-solprices-desk PASS cargo test --workspace PASS ``` `pre.006` matérialise ensuite le batch manuel provider-neutral : ```text MarketPriceRefreshManyRequestDto implémenté, IDs opaques uniquement MarketPriceRefreshResultDto implémenté, rows + requested/refreshed counts refresh_market_prices implémenté via MarketPriceService::refresh_many refresh_all_market_prices implémenté via MarketPriceService::refresh_all ordre selected ordre courant des rows / requête conservé ordre all ordre stable provider-id du service in-flight backend validation atomique avant mutation doublon / ID inconnu rejet sûr avant état loading partiel mutex présentation pendant await non cooldown / retry_at projection Off-chain existante Refresh selected / Refresh all frontend implémentés logging clic sélection/selected/all debug, compte/ID opaque seulement logging résultat batch trace, requested/refreshed counts seulement polling / setInterval / scheduler / sleep consommateur absent fallback / consensus / moyenne absent ``` 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 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.009`. ## 23. Gate `0.2.12-pre.007` La tranche finalise l'UX et l'instrumentation sans modifier le moteur Off-chain ni ajouter de nouvelle commande métier : ```text résumé Providers / Ready / Observed / Attention / Refreshing implémenté header table sticky + scroll horizontal borné implémenté Semantics/Auth secondaires adaptatifs implémenté availability générique par badge implémenté prix exact String inchangée, aucune coercition float timestamp provider absent Not supplied, jamais remplacé par received_at timestamps présents local/ISO + millisecondes exactes visibles select all / clear selection frontend uniquement clics select-all / clear / row / selected / all / navigation debug rendu table + comptes sûrs trace échec command backend command + error_domain + error_code seulement nouvelle command IPC aucune prix/timestamp/payload/URL/header/API key dans les logs aucun auto-refresh / setInterval / setTimeout / requestAnimationFrame absent localStorage / sessionStorage / fetch / XMLHttpRequest absent ``` Canaris statiques ajoutés : table responsive et états génériques, absence de coercition du prix, instrumentation de tous les contrôles, projection sûre des erreurs backend et maintien du fonctionnement exclusivement manuel. 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 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 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 ```