v0.2.12-pre.009-fix.001

This commit is contained in:
2026-08-27 17:57:50 +02:00
parent 233aaf9bd8
commit ca6af3d904
12 changed files with 242 additions and 183 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 298 # version: 299
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"] members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
[workspace.package] [workspace.package]
version = "0.2.12-pre.9" version = "0.2.12-pre.9.fix.1"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,7 +1,6 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "KSP Config Desk", "productName": "KSP Config Desk",
"version": "0.2.6",
"identifier": "com.sasedev.ksp-app-config-desk", "identifier": "com.sasedev.ksp-app-config-desk",
"build": { "build": {
"beforeDevCommand": { "beforeDevCommand": {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/tests/desktop_contract.rs // file: crates/ksp-app-config-desk/tests/desktop_contract.rs
// version: 9 // version: 10
//! Desktop build/shell contract audits for Config Desk. //! Desktop build/shell contract audits for Config Desk.
@@ -26,43 +26,6 @@ fn read_json(path: &std::path::Path) -> serde_json::Value {
}; };
} }
fn parse_semver_core(value: &str) -> std::option::Option<(u64, u64, u64)> {
let core = match value.split_once('-') {
std::option::Option::Some((core, _)) => core,
std::option::Option::None => value,
};
let mut parts = core.split('.');
let major = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let minor = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let patch = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
if parts.next().is_some() {
return std::option::Option::None;
}
return std::option::Option::Some((major, minor, patch));
}
fn assert_packaged_version_floor(value: std::option::Option<&str>, field: &str) {
assert!(value.is_some(), "{field} packaged version must exist");
let value = match value {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let parsed = parse_semver_core(value);
assert!(parsed.is_some(), "{field} packaged version must be SemVer-like");
if let std::option::Option::Some(parsed) = parsed {
assert!(parsed >= (0, 2, 6), "{field} packaged version must be >= 0.2.6");
}
}
#[test] #[test]
fn tauri_and_frontend_build_contracts_remain_explicit() { fn tauri_and_frontend_build_contracts_remain_explicit() {
let root = app_root(); let root = app_root();
@@ -141,12 +104,9 @@ fn pre_014_template_uses_sidebar_navigation_and_kbot_style_splash_contract() {
fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writable_root() { fn pre_018_packaged_runtime_bundles_config_resources_and_activates_shared_writable_root() {
let root = app_root(); let root = app_root();
let tauri = read_json(root.join("tauri.conf.json").as_path()); let tauri = read_json(root.join("tauri.conf.json").as_path());
let tauri_version = tauri.pointer("/version").and_then(serde_json::Value::as_str); assert!(tauri.pointer("/version").is_none(), "Config Desk must let Tauri derive the bundle version from Cargo");
assert_packaged_version_floor(tauri_version, "tauri.conf.json");
let package = read_json(root.join("package.json").as_path()); let package = read_json(root.join("package.json").as_path());
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str); assert_eq!(package.pointer("/private").and_then(serde_json::Value::as_bool), std::option::Option::Some(true));
assert_packaged_version_floor(package_version, "package.json");
assert_eq!(tauri_version, package_version, "desktop package metadata versions must remain synchronized");
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
assert!(resources.is_some(), "packaged Config resources map must exist"); assert!(resources.is_some(), "packaged Config resources map must exist");
if let std::option::Option::Some(resources) = resources { if let std::option::Option::Some(resources) = resources {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-solprices-desk/frontend/ts/main.ts // file: crates/ksp-app-solprices-desk/frontend/ts/main.ts
// version: 7 // version: 8
import "bootstrap"; import "bootstrap";
import ResizeObserver from "resize-observer-polyfill"; import ResizeObserver from "resize-observer-polyfill";
@@ -94,16 +94,6 @@ function bindNavigation(): void {
frontendTrace("main", "SOL Prices Desk navigation handlers installed"); frontendTrace("main", "SOL Prices Desk navigation handlers installed");
} }
function appendMarketPriceCell(row: HTMLTableRowElement, value: string, className?: string): HTMLTableCellElement {
const cell = document.createElement("td");
cell.textContent = value;
if (className) {
cell.className = className;
}
row.append(cell);
return cell;
}
function clearPricesDiagnostic(): void { function clearPricesDiagnostic(): void {
const diagnostic = document.querySelector<HTMLElement>("#pricesDiagnostic"); const diagnostic = document.querySelector<HTMLElement>("#pricesDiagnostic");
if (diagnostic) { if (diagnostic) {

View File

@@ -1,7 +1,6 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "KSP SOL Prices Desk", "productName": "KSP SOL Prices Desk",
"version": "0.2.12-pre.9",
"identifier": "com.sasedev.ksp-app-solprices-desk", "identifier": "com.sasedev.ksp-app-solprices-desk",
"build": { "build": {
"beforeDevCommand": { "beforeDevCommand": {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs // file: crates/ksp-app-solprices-desk/tests/desktop_contract.rs
// version: 8 // version: 9
//! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`. //! Desktop scaffold, shared-template and Config packaging contract audits for SOL Prices Desk `0.2.12`.
@@ -31,56 +31,15 @@ fn read_text(path: &std::path::Path) -> String {
}; };
} }
fn parse_semver_core(value: &str) -> std::option::Option<(u64, u64, u64)> {
let core = match value.split_once('-') {
std::option::Option::Some((core, _)) => core,
std::option::Option::None => value,
};
let mut parts = core.split('.');
let major = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let minor = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let patch = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
if parts.next().is_some() {
return std::option::Option::None;
}
return std::option::Option::Some((major, minor, patch));
}
fn assert_packaged_version_floor(value: std::option::Option<&str>, field: &str) {
assert!(value.is_some(), "{field} packaged version must exist");
let value = match value {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let parsed = parse_semver_core(value);
assert!(parsed.is_some(), "{field} packaged version must be SemVer-like");
if let std::option::Option::Some(parsed) = parsed {
assert!(parsed >= (0, 2, 6), "{field} packaged version must be >= 0.2.6");
}
}
#[test] #[test]
fn pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths() { fn pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths() {
let root = app_root(); let root = app_root();
let tauri = read_json(root.join("tauri.conf.json").as_path()); let tauri = read_json(root.join("tauri.conf.json").as_path());
assert_eq!(tauri.pointer("/productName").and_then(serde_json::Value::as_str), std::option::Option::Some("KSP SOL Prices Desk")); assert_eq!(tauri.pointer("/productName").and_then(serde_json::Value::as_str), std::option::Option::Some("KSP SOL Prices Desk"));
assert_eq!(tauri.pointer("/identifier").and_then(serde_json::Value::as_str), std::option::Option::Some("com.sasedev.ksp-app-solprices-desk")); assert_eq!(tauri.pointer("/identifier").and_then(serde_json::Value::as_str), std::option::Option::Some("com.sasedev.ksp-app-solprices-desk"));
let tauri_version = tauri.pointer("/version").and_then(serde_json::Value::as_str); assert!(tauri.pointer("/version").is_none(), "SOL Prices Desk must let Tauri derive the bundle version from Cargo");
assert_packaged_version_floor(tauri_version, "tauri.conf.json");
let package = read_json(root.join("package.json").as_path()); let package = read_json(root.join("package.json").as_path());
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str); assert_eq!(package.pointer("/private").and_then(serde_json::Value::as_bool), std::option::Option::Some(true));
assert_packaged_version_floor(package_version, "package.json");
assert_eq!(tauri_version, package_version, "desktop package metadata versions must remain synchronized");
assert_eq!(tauri_version, std::option::Option::Some(env!("CARGO_PKG_VERSION")), "SOL Prices Desk package metadata must match the current Cargo release");
assert_eq!(tauri.pointer("/build/devUrl").and_then(serde_json::Value::as_str), std::option::Option::Some("http://localhost:1434")); assert_eq!(tauri.pointer("/build/devUrl").and_then(serde_json::Value::as_str), std::option::Option::Some("http://localhost:1434"));
assert_eq!(tauri.pointer("/build/beforeDevCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run dev")); assert_eq!(tauri.pointer("/build/beforeDevCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run dev"));
assert_eq!(tauri.pointer("/build/beforeDevCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some(".")); assert_eq!(tauri.pointer("/build/beforeDevCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some("."));

View File

@@ -1,7 +1,6 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "KSP Wallet Desk", "productName": "KSP Wallet Desk",
"version": "0.2.12-pre.9",
"identifier": "com.sasedev.ksp-app-wallet-desk", "identifier": "com.sasedev.ksp-app-wallet-desk",
"build": { "build": {
"beforeDevCommand": { "beforeDevCommand": {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs // file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs
// version: 29 // version: 30
//! Desktop build, shell and Config-status contract audits for Wallet Desk. //! Desktop build, shell and Config-status contract audits for Wallet Desk.
@@ -31,43 +31,6 @@ fn read_json(path: &std::path::Path) -> serde_json::Value {
}; };
} }
fn parse_semver_core(value: &str) -> std::option::Option<(u64, u64, u64)> {
let core = match value.split_once('-') {
std::option::Option::Some((core, _)) => core,
std::option::Option::None => value,
};
let mut parts = core.split('.');
let major = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let minor = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let patch = match parts.next().and_then(|part| return part.parse::<u64>().ok()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
if parts.next().is_some() {
return std::option::Option::None;
}
return std::option::Option::Some((major, minor, patch));
}
fn assert_packaged_version_floor(value: std::option::Option<&str>, field: &str) {
assert!(value.is_some(), "{field} packaged version must exist");
let value = match value {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let parsed = parse_semver_core(value);
assert!(parsed.is_some(), "{field} packaged version must be SemVer-like");
if let std::option::Option::Some(parsed) = parsed {
assert!(parsed >= (0, 2, 6), "{field} packaged version must be >= 0.2.6");
}
}
#[test] #[test]
fn tauri_shell_uses_reserved_wallet_desk_ports_and_template_windows() { fn tauri_shell_uses_reserved_wallet_desk_ports_and_template_windows() {
let root = app_root(); let root = app_root();
@@ -463,13 +426,9 @@ fn pre_017_wallet_desk_open_paths_remain_non_migrating() {
fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_version_coherent() { fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_version_coherent() {
let root = app_root(); let root = app_root();
let tauri = read_json(root.join("tauri.conf.json").as_path()); let tauri = read_json(root.join("tauri.conf.json").as_path());
let tauri_version = tauri.pointer("/version").and_then(serde_json::Value::as_str); assert!(tauri.pointer("/version").is_none(), "Wallet Desk must let Tauri derive the bundle version from Cargo");
assert_packaged_version_floor(tauri_version, "tauri.conf.json");
let package = read_json(root.join("package.json").as_path()); let package = read_json(root.join("package.json").as_path());
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str); assert_eq!(package.pointer("/private").and_then(serde_json::Value::as_bool), std::option::Option::Some(true));
assert_packaged_version_floor(package_version, "package.json");
assert_eq!(tauri_version, package_version, "desktop package metadata versions must remain synchronized");
assert_eq!(tauri_version, std::option::Option::Some(env!("CARGO_PKG_VERSION")), "Wallet Desk package metadata must match the current Cargo release");
let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object);
assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist"); assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist");
if let std::option::Option::Some(resources) = resources { if let std::option::Option::Some(resources) = resources {

View File

@@ -0,0 +1,135 @@
<!-- file: deltas/0.2.12/pre.009-fix.001.md -->
<!-- version: 1 -->
# Delta `0.2.12-pre.009-fix.001` — build Price Desk et source de vérité de version Tauri
## Base requise
```text
0.2.12-pre.009
```
## Cause
Le gate opérateur de `pre.009` passe intégralement jusqu'aux builds finaux :
```text
fmt/audits/check/clippy/tests/workspace PASS
smoke live composite SOL Prices PASS
cargo tauri build Wallet Desk PASS
cargo tauri build SOL Prices Desk FAIL
```
Le `beforeBuildCommand` du Price Desk exécute `tsc && vite build` et TypeScript rejette une fonction morte :
```text
TS6133
appendMarketPriceCell is declared but its value is never read
```
Le gate a également montré qu'un canari ajouté en `pre.009` couplait à tort `package.json`, `tauri.conf.json` et `CARGO_PKG_VERSION`. Cette égalité aurait imposé de modifier toutes les apps Tauri à chaque bump global du workspace, même hors scope.
## Version technique
```text
delivery 0.2.12-pre.009-fix.001
workspace Cargo 0.2.12-pre.9.fix.1
```
Conformément à `VER-ID-007`, le fix modifie une source TypeScript consommée par le build et avance donc la version Cargo.
## Correction build
`crates/ksp-app-solprices-desk/frontend/ts/main.ts` supprime `appendMarketPriceCell`, devenue inutilisée après le rendu UX actuel. Aucun appel n'est remplacé et aucun comportement de refresh/rendu n'est changé.
## Correction version desktop
La politique durable devient :
```text
Cargo/workspace version source de vérité KSP
tauri.conf.json top-level version absent
Tauri bundle version dérivée de Cargo
package.json version metadata frontend privée non autoritative
```
Les trois Desks Config/Wallet/SOL Prices sont alignés immédiatement sur ce contrat. Leurs `tauri.conf.json` omettent `version` et leurs canaris n'exigent plus d'égalité avec `package.json` ou `CARGO_PKG_VERSION`.
Les `package.json` ne sont pas modifiés par ce fix : ils restent `private: true` et ne participent pas à l'identité de release KSP.
## Règles
Ajout dans `docs/rules/VERSION_WORKFLOW.md` :
```text
VER-ID-015 version bundle Tauri dérivée de Cargo; pas de version dupliquée dans tauri.conf
VER-ID-016 package.json privé non autoritatif et non couplé au workspace
```
## Fichiers ajoutés
```text
deltas/0.2.12/pre.009-fix.001.md
```
## Fichiers modifiés
```text
Cargo.toml
docs/rules/VERSION_WORKFLOW.md
crates/ksp-app-config-desk/tauri.conf.json
crates/ksp-app-config-desk/tests/desktop_contract.rs
crates/ksp-app-wallet-desk/tauri.conf.json
crates/ksp-app-wallet-desk/tests/desktop_contract.rs
crates/ksp-app-solprices-desk/tauri.conf.json
crates/ksp-app-solprices-desk/tests/desktop_contract.rs
crates/ksp-app-solprices-desk/frontend/ts/main.ts
docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md
docs/validation/015-V0_2_12_SOL_PRICES_DESK.md
```
## Fichiers supprimés
```text
aucun
```
## Hors scope préservé
```text
MarketPriceService/providers/wire
MarketPriceRuntime hors build fix
refresh individuel/multiple/global
Wallet balance/moyenne/équivalent
Config/composites/resources
frontend UX hors suppression dead code
CHANGELOG/ROADMAP/prompt suivant
```
## Validations sandbox
```text
python3 scripts/audit_rust_workspace_rules.py PASS
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
JSON Tauri/package PASS
trois tauri.conf.json sans champ version PASS
package.json des trois apps private=true PASS
contrôle TypeScript noResolve: TS6133 absent PASS
cargo fmt/check/clippy/test/tauri build NOT RUN — cargo/deps frontend indisponibles dans le sandbox
```
## Gate opérateur attendu
```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-solprices-desk
cargo test --workspace
cargo test -p ksp-app-solprices-desk --test market_price_composition_live_smoke -- --ignored --nocapture
(cd crates/ksp-app-solprices-desk && cargo tauri build)
```
Le critère décisif de fermeture est le `cargo tauri build` Price Desk. Une fois vert, `pre.009` est fermée et `pre.010` peut rester strictement documentaire/mécanique.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md --> <!-- file: docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md -->
<!-- version: 18 --> <!-- version: 19 -->
# Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk # Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk
@@ -161,7 +161,7 @@ La base confirme :
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. 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. La version de release desktop est désormais explicitement Cargo-owned : les `tauri.conf.json` des Desks omettent leur champ `version`, ce qui laisse Tauri dériver la version du package Rust résolu. Les `package.json` sont des manifests frontend privés de dépendances/scripts et ne sont pas des sources de vérité de release ; leur propriété `version`, lorsqu'elle est conservée, peut donc rester indépendante du bump global du workspace. Cette règle évite qu'une prerelease KSP sans travail sur une app force des modifications artificielles de ses manifests desktop.
## 6. Audit externe desktop du 2026-08-26 ## 6. Audit externe desktop du 2026-08-26
@@ -582,9 +582,13 @@ Le gate de `pre.008-fix.002` confirme le fonctionnement runtime et visuel attend
### `pre.009` — Hardening transversal + gate technique/live final ### `pre.009` — Hardening transversal + gate technique/live final
**Statut : implémenté ; gate opérateur live/build à confirmer.** **Statut : réalisé ; gate opérateur Rust/workspace/live PASS, build Wallet PASS, build Price Desk à corriger par `fix.001`.**
Fusion des anciens hardenings `pre.008`/`pre.012` et du gate `pre.013` : la sélection batch Price Desk est bornée à `1..=64` avant parsing des IDs opaques, les canaris capabilities/resources/CWD/version/package et provider-neutralité Wallet sont renforcés, et un smoke live opt-in prouve le chemin composite SOL Prices Desk -> Config -> `MarketPriceService::refresh_all` avec au moins une observation keyless. Les métadonnées npm/Tauri des deux Desks modifiés sont synchronisées avec `0.2.12-pre.9` pour les builds de production finaux. Aucun nouveau comportement métier n'est ouvert ; les seuls gates restant opérateur sont le workspace complet, le smoke live et les deux `cargo tauri build` crate-local. Fusion des anciens hardenings `pre.008`/`pre.012` et du gate `pre.013` : la sélection batch Price Desk est bornée à `1..=64` avant parsing des IDs opaques, les canaris capabilities/resources/CWD et provider-neutralité Wallet sont renforcés, et un smoke live opt-in prouve le chemin composite SOL Prices Desk -> Config -> `MarketPriceService::refresh_all` avec au moins une observation keyless. Le gate opérateur confirme `fmt`, audits, `check`, Clippy, tests ciblés, workspace complet et smoke live. Le build Wallet produit ses trois bundles Linux ; le build Price Desk s'arrête uniquement au `beforeBuildCommand` TypeScript sur `TS6133` parce que `appendMarketPriceCell` est devenue inutilisée après le polish `pre.007`.
#### `pre.009-fix.001` — Build Price Desk + source de vérité de version Tauri
Le fix supprime la fonction TypeScript morte et formalise la politique de version desktop : `workspace.package.version` est l'identité KSP autoritative ; les trois `tauri.conf.json` omettent `version` afin que Tauri la dérive de Cargo ; les `package.json` privés restent des manifests frontend non couplés au bump workspace. Les canaris Config/Wallet/SOL Prices vérifient désormais ce fallback plutôt qu'une égalité artificielle `package.json == tauri.conf.json == CARGO_PKG_VERSION`. Aucun comportement prix, Wallet ou Config n'est modifié.
### `pre.010` — Réconciliation documentaire + préparation de publication ### `pre.010` — Réconciliation documentaire + préparation de publication

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/VERSION_WORKFLOW.md --> <!-- file: docs/rules/VERSION_WORKFLOW.md -->
<!-- version: 7 --> <!-- version: 8 -->
# Versionnement, sessions et livraisons # Versionnement, sessions et livraisons
@@ -31,6 +31,8 @@ Les règles `VER-*` définissent la progression des versions KSP, les identifian
- **VER-ID-012** — Avant `0.1.x`, les prereleases et releases sont les points de commit normaux ; les correctifs intermédiaires peuvent rester des livraisons d'échange non commitées. - **VER-ID-012** — Avant `0.1.x`, les prereleases et releases sont les points de commit normaux ; les correctifs intermédiaires peuvent rester des livraisons d'échange non commitées.
- **VER-ID-013** — À partir de `0.1.x`, chaque delta est commité, y compris lorsqu'il contient un état imparfait qui sera corrigé par un delta `fix` ultérieur. L'historique Git doit conserver la séquence réelle des travaux et corrections. - **VER-ID-013** — À partir de `0.1.x`, chaque delta est commité, y compris lorsqu'il contient un état imparfait qui sera corrigé par un delta `fix` ultérieur. L'historique Git doit conserver la séquence réelle des travaux et corrections.
- **VER-ID-014** — Une livraison `rel.NNN` peut être corrigée avant la publication stable par `rel.NNN-fix.NNN` ou remplacée par une nouvelle livraison `rel.NNN` selon le besoin. Une release déjà considérée comme stable et taguée `vX.Y.Z` n'est normalement pas réécrite ; une correction fonctionnelle ultérieure ouvre une nouvelle version appropriée. - **VER-ID-014** — Une livraison `rel.NNN` peut être corrigée avant la publication stable par `rel.NNN-fix.NNN` ou remplacée par une nouvelle livraison `rel.NNN` selon le besoin. Une release déjà considérée comme stable et taguée `vX.Y.Z` n'est normalement pas réécrite ; une correction fonctionnelle ultérieure ouvre une nouvelle version appropriée.
- **VER-ID-015** — Pour une application Tauri KSP, `workspace.package.version`/la version Cargo résolue est la source de vérité de version du binaire et du bundle. `tauri.conf.json` omet donc son champ top-level `version` et laisse Tauri dériver la version depuis Cargo ; un bump du workspace ne provoque pas une modification artificielle de chaque `tauri.conf.json`.
- **VER-ID-016** — Le `package.json` d'une application Tauri KSP est un manifeste frontend privé de dépendances et de scripts, pas une source de vérité de la release KSP. Sa propriété `version`, lorsqu'elle est conservée, n'est pas synchronisée automatiquement avec `workspace.package.version` et aucun canari KSP ne doit exiger leur égalité. Les gates de release desktop utilisent la version Cargo/Tauri dérivée et les métadonnées de bundle produites par `cargo tauri build`.
## Git ## Git

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/015-V0_2_12_SOL_PRICES_DESK.md --> <!-- file: docs/validation/015-V0_2_12_SOL_PRICES_DESK.md -->
<!-- version: 17 --> <!-- version: 18 -->
# Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk # Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk
@@ -148,7 +148,7 @@ NOT RUN commande non exécutée dans le contexte indiqué
## 9. Tauri/package matrix ## 9. Tauri/package matrix
| Contrat | Attendu | Statut | | Contrat | Attendu | Statut |
|------------------------------------|------------------------------------|---------| |------------------------------------|--------------------------------------|--------|
| Price Desk ports | 1434/1435 strict | PASS | | Price Desk ports | 1434/1435 strict | PASS |
| windows | splash + main | PASS | | windows | splash + main | PASS |
| Rust package | lib + bin; `main.rs` mince | PASS | | Rust package | lib + bin; `main.rs` mince | PASS |
@@ -158,25 +158,25 @@ NOT RUN commande non exécutée dans le contexte indiqué
| backend cross-app | aucune référence Wallet par erreur | PASS | | backend cross-app | aucune référence Wallet par erreur | PASS |
| resources | registry complet packagé | PASS | | resources | registry complet packagé | PASS |
| bundle | targets/icons cohérents | PASS | | bundle | targets/icons cohérents | PASS |
| versions apps modifiées | npm/Tauri = Cargo `0.2.12-pre.9` | PASS | | version bundle Tauri | dérivée de Cargo; pas de duplication | PASS |
| Tauri production build Price Desk | crate-local PASS attendu | PENDING | | Tauri production build Price Desk | pre.009 TS6133; fix retest | RETEST |
| Tauri production build Wallet Desk | crate-local PASS attendu | PENDING | | Tauri production build Wallet Desk | pre.009 .deb/.rpm/.AppImage | PASS |
## 10. Gates techniques/live finaux ## 10. Gates techniques/live finaux
| Gate | Statut | | Gate | Statut |
|--------------------------------------------------------------|---------| |--------------------------------------------------------------|--------|
| `cargo fmt --all` | PENDING | | `cargo fmt --all` | PASS |
| `python3 scripts/audit_rust_workspace_rules.py` | PENDING | | `python3 scripts/audit_rust_workspace_rules.py` | PASS |
| `python3 scripts/audit_markdown_tables.py ... deltas/0.2.12` | PENDING | | `python3 scripts/audit_markdown_tables.py ... deltas/0.2.12` | PASS |
| `cargo check --workspace` | PENDING | | `cargo check --workspace` | PASS |
| `cargo clippy --workspace --all-targets` | PENDING | | `cargo clippy --workspace --all-targets` | PASS |
| `cargo test --workspace` | PENDING | | `cargo test --workspace` | PASS |
| Price Desk functional dev path | PASS | | Price Desk functional dev path | PASS |
| Wallet Desk functional price path | PASS | | Wallet Desk functional price path | PASS |
| keyless app-composition live smoke | PENDING | | keyless app-composition live smoke | PASS |
| Price Desk `cargo tauri build` | PENDING | | Price Desk `cargo tauri build` | RETEST |
| Wallet Desk `cargo tauri build` | PENDING | | Wallet Desk `cargo tauri build` | PASS |
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. 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.
@@ -750,8 +750,8 @@ Price Desk batch IPC garde 1..=64 avant parsing des provider
batch vide rejet KSP sûr batch vide rejet KSP sûr
batch hostile 65 IDs rejet KSP sûr avant parsing provider batch hostile 65 IDs rejet KSP sûr avant parsing provider
Price Desk manual refresh aucun scheduler/fetch/browser persistence Price Desk manual refresh aucun scheduler/fetch/browser persistence
Price Desk package metadata npm/Tauri == CARGO_PKG_VERSION Price Desk version bundle Cargo autoritatif; Tauri config sans version
Wallet package metadata npm/Tauri == CARGO_PKG_VERSION Wallet version bundle Cargo autoritatif; Tauri config sans version
Wallet frontendDist chemin Wallet dédié canarisé Wallet frontendDist chemin Wallet dédié canarisé
Wallet provider-neutrality aucun type provider concret dans src/ Wallet provider-neutrality aucun type provider concret dans src/
Wallet exactness aucun f64/f32 backend, aucun calcul flottant frontend Wallet exactness aucun f64/f32 backend, aucun calcul flottant frontend
@@ -771,7 +771,10 @@ python3 scripts/audit_rust_workspace_rules.py PASS
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
JSON package/tauri des deux apps modifiées PASS JSON package/tauri des deux apps modifiées PASS
contrôles statiques versions/resources/frontières PASS contrôles statiques versions/resources/frontières PASS
cargo fmt/check/clippy/test/live/tauri build NOT RUN — cargo indisponible cargo fmt/check/clippy/test/workspace opérateur PASS
smoke live composition keyless opérateur PASS
Wallet Desk cargo tauri build PASS — deb/rpm/AppImage
SOL Prices Desk cargo tauri build FAIL — TS6133 fonction frontend inutilisée
``` ```
Il doit résoudre le composite committed `public_keyless`, mapper `ResolvedOffchainTransportConfig`, conserver exactement les huit entrées génériques du registry, exécuter `MarketPriceService::refresh_all` et obtenir au moins une observation SOL/USD. Il ne réaudite pas les huit wire adapters individuellement. Il doit résoudre le composite committed `public_keyless`, mapper `ResolvedOffchainTransportConfig`, conserver exactement les huit entrées génériques du registry, exécuter `MarketPriceService::refresh_all` et obtenir au moins une observation SOL/USD. Il ne réaudite pas les huit wire adapters individuellement.
@@ -794,3 +797,53 @@ cargo test -p ksp-app-solprices-desk --test market_price_composition_live_smoke
Conformément à `KSP-APP-034`, les deux `cargo tauri build` restent les dernières opérations lourdes. Conformément à `KSP-APP-034`, les deux `cargo tauri build` restent les dernières opérations lourdes.
## 29. Fix `0.2.12-pre.009-fix.001` — build Price Desk et version Tauri Cargo-owned
Le gate opérateur de `pre.009` est techniquement propre jusqu'aux builds finaux :
```text
cargo fmt --all PASS
audits Rust/Markdown PASS
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS
cargo test -p ksp-app-solprices-desk PASS
cargo test --workspace PASS
market_price_composition_live_smoke PASS
cargo tauri build — Wallet Desk PASS
cargo tauri build — SOL Prices Desk FAIL
```
L'échec Price Desk est strictement frontend/build :
```text
TS6133: appendMarketPriceCell is declared but its value is never read
```
La fonction n'est plus utilisée depuis le rendu UX de `pre.007`; elle est supprimée sans remplacement.
Le même gate a conduit à supprimer le couplage artificiel des trois sources de version desktop. Le contrat retenu est :
```text
workspace.package.version / Cargo package source de vérité KSP
tauri.conf.json.version absent
Tauri bundle version dérivée automatiquement de Cargo
package.json manifest frontend privé, non autoritatif
```
Conséquence opérateur : un bump du workspace ne demande plus de modifier `tauri.conf.json` ou `package.json` d'une app hors scope. Les trois Desks utilisent le même contrat et leurs canaris vérifient l'absence de version Tauri dupliquée ainsi que `private: true` côté npm.
Gate 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-solprices-desk
cargo test --workspace
cargo test -p ksp-app-solprices-desk --test market_price_composition_live_smoke -- --ignored --nocapture
(cd crates/ksp-app-solprices-desk && cargo tauri build)
```
Le build Wallet n'a pas besoin d'être rejoué pour valider la correction TypeScript Price Desk, mais un build opportuniste reste autorisé pour confirmer le fallback Cargo sur une autre app.