Files
2026-08-27 10:02:46 +02:00

9.0 KiB

Delta 0.2.12-pre.004 — runtime prix, registry rows et DTOs

1. Base requise

Cette tranche s'applique exclusivement après :

v0.2.11
+ 0.2.12-pre.001
+ 0.2.12-pre.001-fix.001
+ 0.2.12-pre.002
+ 0.2.12-pre.002-fix.001
+ 0.2.12-pre.003
+ 0.2.12-pre.003-fix.001

Le retour opérateur du 27 août 2026 clôt pre.003-fix.001 pour la progression de release : cargo fmt, audits Rust/Markdown, cargo check --workspace, Clippy workspace, cargo test -p ksp-app-solprices-desk et cargo tauri dev passent. Le runtime Tauri journalise le bootstrap Logging, le profil composite public_keyless, le profil Off-chain public_keyless et provider_count=8. cargo test --workspace n'est pas présent dans ce retour précis et n'est donc pas revendiqué comme exécuté.

La version workspace passe à :

0.2.12-pre.4

Les versions package.json et tauri.conf.json de SOL Prices Desk sont synchronisées sur la même prerelease.

2. Responsabilité de la tranche

pre.004 matérialise uniquement la couche applicative provider-neutral entre le MarketPriceService déjà construit par Config et la future UX de refresh :

MarketPriceRuntime backend
état de présentation courant en mémoire uniquement
projection du registry en lignes stables
MarketPriceRuntimeStatusDto
MarketPriceProviderRowDto
commande list_market_prices
états frontend loading / empty / table
projection initiale sans observation ni prix

La tranche n'appelle ni MarketPriceService::refresh, ni refresh_many, ni refresh_all. Aucun bouton de refresh ou scheduler n'est introduit avant les tranches prévues.

3. Ownership du runtime prix

AppState possède désormais un MarketPriceRuntime. Celui-ci retient :

OffchainTransportStartup
  -> ResolvedOffchainTransportConfig
  -> MarketPriceService

presentation: Mutex<...>
  -> une entrée par provider_id opaque
  -> loading bool
  -> dernière observation optionnelle

La présentation n'est persistée ni dans Config, ni dans Store, ni sur le filesystem frontend, ni dans localStorage/sessionStorage.

L'inventaire initial est dérivé du MarketPriceService::registry() détaché. Chaque ligne commence avec :

loading   = false
observation = None
price     = None
refreshed = false

L'availability initiale reste celle possédée par Off-chain Transport (Ready, Disabled, etc.).

4. DTOs provider-neutral

MarketPriceRuntimeStatusDto remplace le nom bootstrap générique précédent et expose uniquement :

application/config/composite/logging/offchain metadata sûrs
provider_count
ready_provider_count
unavailable_provider_count
startup_diagnostic sûr

MarketPriceProviderRowDto expose uniquement la projection générique décidée par le plan :

provider_id opaque
display_name
pair = SOL/USD
semantics générique
auth_mode générique
availability générique
loading
refreshed
price optionnel
provider_timestamp optionnel
received_at optionnel
retry_at optionnel

Le prix exact traverse l'IPC sous forme de Option<String> issue de MarketPriceDecimal::to_canonical_string(). Les timestamps traversent eux aussi sous forme de chaînes de millisecondes Unix afin de ne pas introduire de perte d'entier JavaScript. Aucun f64 n'est une vérité IPC.

Les enums Off-chain #[non_exhaustive] sont projetés en codes génériques bornés avec fallback unknown; aucune enum provider-specific n'est exposée au frontend.

5. Commande d'inventaire

La nouvelle commande Tauri centralisée est :

list_market_prices

Elle n'accepte aucun argument et retourne :

Vec<MarketPriceProviderRowDto>

Elle ne déclenche aucun réseau. L'ordre des lignes suit l'ordre stable du registry Off-chain.

La surface command reste donc à cette tranche :

emit_frontend_log
get_runtime_status
list_market_prices
splash_frontend_ready

Les commandes refresh_market_price, refresh_market_prices et refresh_all_market_prices restent absentes par contrat.

6. Frontend initial

La vue Prices remplace le placeholder de pre.003 par trois états explicites :

loading
empty
table provider-neutral

La table initiale affiche les capacités et l'availability du registry. Comme aucun refresh n'a encore eu lieu, les prix et timestamps d'observation s'affichent comme absents.

La tranche n'ajoute aucun bouton Refresh. La finalisation responsive/interactions/DataTable reste propriétaire de pre.007.

Diagnostics ajoute les comptes total/ready/unavailable sans exposer endpoint, credential, header ou payload provider.

7. Logging frontend/backend

KSP-APP-027 reste appliqué :

navigation/clic utilisateur                         debug
requête IPC                                          debug via invokeKsp
fin IPC                                              trace
chargement registry start/end                        trace
rendu des lignes                                     trace avec row_count uniquement
erreur de projection/chargement                      warn/error sûr

Aucun log ne sérialise le prix, la row DTO complète, une API key, un header ou une réponse provider.

8. Dépendances et boundaries

SOL Prices Desk ajoute une dépendance directe à ksp-offchain-transport-lib parce que la couche application consomme désormais ses types publics génériques de registry/observation.

Cette dépendance ne donne lieu à aucune connaissance provider-specific :

aucun SDK provider
aucun reqwest direct app
aucun fetch frontend
aucune URL/header/API key dans IPC
aucune branche CoinGecko/Kraken/etc.
aucun limiter/retry/sleep provider dans app

Config reste propriétaire de la construction du service et des secrets.

9. Tests et canaris

Les tests ajoutés/étendus couvrent :

codes génériques auth/availability/semantics
projection initiale sans observation
projection exacte d'un decimal 123.4500 -> "123.45"
provider_timestamp / received_at / retry_at distincts
MarketPriceRuntime présent à partir de pre.004
commande list_market_prices centralisée dans tauri.rs
absence des trois commandes de refresh
états frontend loading/empty/table
aucune conversion parseFloat/Number du prix
aucun reqwest direct dans la crate app
logging registry sans sérialisation métier

Les bindings TS-RS restent générés par les tests et ne sont pas versionnés.

10. Fichiers ajoutés

crates/ksp-app-solprices-desk/src/market_price_runtime.rs
crates/ksp-app-solprices-desk/unit_tests/market_price_runtime.rs
deltas/0.2.12/pre.004.md

11. Fichiers modifiés

Cargo.toml
crates/ksp-app-solprices-desk/Cargo.toml
crates/ksp-app-solprices-desk/package.json
crates/ksp-app-solprices-desk/tauri.conf.json
crates/ksp-app-solprices-desk/frontend/main.html
crates/ksp-app-solprices-desk/frontend/ts/main.ts
crates/ksp-app-solprices-desk/src/app_state.rs
crates/ksp-app-solprices-desk/src/dto_common.rs
crates/ksp-app-solprices-desk/src/lib.rs
crates/ksp-app-solprices-desk/src/tauri.rs
crates/ksp-app-solprices-desk/tests/desktop_contract.rs
crates/ksp-app-solprices-desk/tests/desktop_security.rs
docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md
docs/validation/015-V0_2_12_SOL_PRICES_DESK.md

12. Fichiers volontairement inchangés

crates/ksp-offchain-transport-lib/**
crates/ksp-config-lib/**
crates/ksp-app-wallet-desk/**
crates/ksp-app-config-desk/**
README.md
ROADMAP.md
CHANGELOG.md
prompts/017-V0_2_12_START_PROMPT.md

Aucun provider, wire REST, rate limit ou Config document n'est modifié.

13. Validations exécutées dans le sandbox

Après matérialisation du code avant écriture du delta :

python3 scripts/audit_rust_workspace_rules.py
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
KSP workspace Rust rule audit: clean

Après écriture du présent delta :

python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.12
Markdown table audit: clean (143 table(s), 113 file(s))

validation JSON package.json / tauri.conf.json
JSON validation: clean

Le sandbox ne possède pas cargo; aucune commande Cargo n'est déclarée PASS localement.

14. Gate opérateur attendu

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-solprices-desk
cargo test --workspace
(cd crates/ksp-app-solprices-desk && cargo tauri dev)

Le parcours Tauri attendu doit afficher huit lignes provider-neutral pour le profil public_keyless, avec availability initiale mais sans prix ni timestamp d'observation, et sans effectuer de refresh réseau. Diagnostics doit afficher provider_count=8 avec les comptes ready/unavailable cohérents.

15. Questions ouvertes

Aucune. Si le gate devient propre, pre.005 peut brancher exclusivement le refresh individuel sur ce runtime sans modifier le format Config ni les adapters providers.