v0.2.12-pre.009
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 297
|
# version: 298
|
||||||
|
|
||||||
[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.8.fix.3"
|
version = "0.2.12-pre.9"
|
||||||
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"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ksp-app-solprices-desk",
|
"name": "ksp-app-solprices-desk",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.12-pre.7",
|
"version": "0.2.12-pre.9",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
// file: crates/ksp-app-solprices-desk/src/market_price_runtime.rs
|
// file: crates/ksp-app-solprices-desk/src/market_price_runtime.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Provider-neutral market-price presentation runtime owned by SOL Prices Desk.
|
//! Provider-neutral market-price presentation runtime owned by SOL Prices Desk.
|
||||||
|
|
||||||
use ts_rs::TS; // rust-rules: trait-import
|
use ts_rs::TS; // rust-rules: trait-import
|
||||||
|
|
||||||
|
const MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS: usize = 64;
|
||||||
|
|
||||||
/// Safe provider-neutral row projected to the SOL Prices Desk frontend.
|
/// Safe provider-neutral row projected to the SOL Prices Desk frontend.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -534,6 +536,16 @@ fn lock_presentation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_provider_ids(provider_ids: std::vec::Vec<String>) -> ksp_core_lib::Result<std::vec::Vec<ksp_offchain_transport_lib::MarketPriceProviderId>> {
|
fn parse_provider_ids(provider_ids: std::vec::Vec<String>) -> ksp_core_lib::Result<std::vec::Vec<ksp_offchain_transport_lib::MarketPriceProviderId>> {
|
||||||
|
if provider_ids.is_empty() || provider_ids.len() > MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS {
|
||||||
|
return std::result::Result::Err(
|
||||||
|
ksp_core_lib::Error::new(
|
||||||
|
crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID,
|
||||||
|
"SOL Prices Desk market-price refresh selection has an invalid provider count",
|
||||||
|
)
|
||||||
|
.with_context("provider_count", provider_ids.len().to_string())
|
||||||
|
.with_context("max_provider_count", MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS.to_string()),
|
||||||
|
);
|
||||||
|
}
|
||||||
let mut parsed = std::vec::Vec::with_capacity(provider_ids.len());
|
let mut parsed = std::vec::Vec::with_capacity(provider_ids.len());
|
||||||
for provider_id in provider_ids {
|
for provider_id in provider_ids {
|
||||||
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new(provider_id);
|
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new(provider_id);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$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.7",
|
"version": "0.2.12-pre.9",
|
||||||
"identifier": "com.sasedev.ksp-app-solprices-desk",
|
"identifier": "com.sasedev.ksp-app-solprices-desk",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": {
|
"beforeDevCommand": {
|
||||||
|
|||||||
@@ -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: 7
|
// version: 8
|
||||||
|
|
||||||
//! 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`.
|
||||||
|
|
||||||
@@ -80,6 +80,7 @@ fn pre_002_shell_uses_reserved_ports_windows_and_owned_backend_paths() {
|
|||||||
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str);
|
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str);
|
||||||
assert_packaged_version_floor(package_version, "package.json");
|
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, 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("."));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-solprices-desk/tests/desktop_security.rs
|
// file: crates/ksp-app-solprices-desk/tests/desktop_security.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
//! Security, ownership and frontend instrumentation canaries for SOL Prices Desk.
|
//! Security, ownership and frontend instrumentation canaries for SOL Prices Desk.
|
||||||
|
|
||||||
@@ -186,3 +186,16 @@ fn pre_007_remains_manual_without_browser_persistence_or_price_scheduler() {
|
|||||||
assert!(!main.contains(forbidden), "pre.007 must remain manual and backend-owned: {forbidden}");
|
assert!(!main.contains(forbidden), "pre.007 must remain manual and backend-owned: {forbidden}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_009_hardening_bounds_hostile_batches_and_preserves_manual_backend_owned_refresh() {
|
||||||
|
let root = app_root();
|
||||||
|
let runtime = read_text(root.join("src/market_price_runtime.rs").as_path());
|
||||||
|
assert!(runtime.contains("const MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS: usize = 64;"));
|
||||||
|
assert!(runtime.contains("provider_ids.is_empty() || provider_ids.len() > MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS"));
|
||||||
|
assert!(runtime.contains("ERROR_CODE_MARKET_PRICE_SELECTION_INVALID"));
|
||||||
|
let main = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||||
|
for forbidden in ["setInterval(", "setTimeout(", "requestAnimationFrame(", "fetch(", "XMLHttpRequest", "localStorage", "sessionStorage"] {
|
||||||
|
assert!(!main.contains(forbidden), "release hardening must preserve manual backend-owned refresh: {forbidden}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
// file: crates/ksp-app-solprices-desk/tests/market_price_composition_live_smoke.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Opt-in live smoke proving SOL Prices Desk composite -> Config -> generic MarketPriceService composition.
|
||||||
|
|
||||||
|
fn workspace_engine() -> ksp_core_lib::Result<ksp_config_lib::ConfigDocumentEngine> {
|
||||||
|
let workspace = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||||
|
let bootstrap = ksp_config_lib::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
|
||||||
|
let bootstrap = match bootstrap {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let registry = ksp_config_lib::ConfigFileRegistry::defaults();
|
||||||
|
return match registry {
|
||||||
|
std::result::Result::Ok(value) => std::result::Result::Ok(ksp_config_lib::ConfigDocumentEngine::new(bootstrap, value)),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
#[ignore = "opt-in live SOL Prices Desk composition smoke; resolves the committed public_keyless composite and performs external SOL/USD HTTPS refreshes"]
|
||||||
|
async fn committed_solprices_composite_refreshes_at_least_one_keyless_provider() {
|
||||||
|
let engine = workspace_engine();
|
||||||
|
assert!(engine.is_ok(), "workspace Config engine should be constructible");
|
||||||
|
let engine = match engine {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_SOLPRICES_DESK);
|
||||||
|
assert!(file_id.is_ok(), "SOL Prices Desk composite file_id should be valid");
|
||||||
|
let file_id = match file_id {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
||||||
|
assert!(composite.is_ok(), "committed SOL Prices Desk composite should resolve");
|
||||||
|
let composite = match composite {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(composite.profile_id(), "public_keyless");
|
||||||
|
let component = composite.component("offchain_transport");
|
||||||
|
assert!(component.is_some(), "SOL Prices Desk composite should contain Off-chain Transport");
|
||||||
|
let component = match component {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||||
|
assert!(environment.is_ok(), "Config-owned environment snapshot should load");
|
||||||
|
let environment = match environment {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let resolved = engine.resolve_offchain_transport_config_profile(component.resolved(), &environment);
|
||||||
|
assert!(resolved.is_ok(), "composite-selected public_keyless Off-chain Transport should map");
|
||||||
|
let resolved = match resolved {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(resolved.profile_id(), "public_keyless");
|
||||||
|
assert_eq!(resolved.selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
|
||||||
|
let registry = resolved.service().registry();
|
||||||
|
assert_eq!(registry.len(), 8);
|
||||||
|
let outcomes = resolved.service().refresh_all().await;
|
||||||
|
assert!(outcomes.is_ok(), "generic public_keyless refresh_all should complete without provider-specific application branching");
|
||||||
|
let outcomes = match outcomes {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(outcomes.len(), registry.len());
|
||||||
|
let refreshed_count = outcomes.iter().filter(|outcome| return outcome.refreshed()).count();
|
||||||
|
assert!(refreshed_count > 0, "at least one public_keyless provider should produce one live SOL/USD observation");
|
||||||
|
for outcome in outcomes {
|
||||||
|
assert!(registry.entry(outcome.provider_id()).is_some(), "live outcome provider must belong to the generic registry");
|
||||||
|
if let std::option::Option::Some(observation) = outcome.observation() {
|
||||||
|
assert_eq!(observation.pair(), ksp_offchain_transport_lib::MarketPricePair::SolUsd);
|
||||||
|
assert_eq!(observation.provider_id(), outcome.provider_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-solprices-desk/unit_tests/market_price_runtime.rs
|
// file: crates/ksp-app-solprices-desk/unit_tests/market_price_runtime.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
fn descriptor() -> std::option::Option<ksp_offchain_transport_lib::MarketPriceProviderDescriptor> {
|
fn descriptor() -> std::option::Option<ksp_offchain_transport_lib::MarketPriceProviderDescriptor> {
|
||||||
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new("test-provider");
|
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new("test-provider");
|
||||||
@@ -278,3 +278,25 @@ fn batch_loading_validation_rejects_in_flight_provider_without_marking_other_row
|
|||||||
}
|
}
|
||||||
return std::result::Result::Ok(());
|
return std::result::Result::Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hostile_batch_size_is_rejected_before_provider_id_parsing() {
|
||||||
|
let provider_ids = (0..=super::MARKET_PRICE_REFRESH_MAX_PROVIDER_IDS)
|
||||||
|
.map(|index| return std::format!("invalid provider payload {index}"))
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
let result = super::parse_provider_ids(provider_ids);
|
||||||
|
assert!(result.is_err());
|
||||||
|
if let std::result::Result::Err(error) = result {
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID);
|
||||||
|
assert_eq!(error.context().len(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_batch_is_rejected_at_the_application_boundary() {
|
||||||
|
let result = super::parse_provider_ids(std::vec::Vec::new());
|
||||||
|
assert!(result.is_err());
|
||||||
|
if let std::result::Result::Err(error) = result {
|
||||||
|
assert_eq!(error.code(), crate::ERROR_CODE_MARKET_PRICE_SELECTION_INVALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ksp-app-wallet-desk",
|
"name": "ksp-app-wallet-desk",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.12-pre.8.fix.3",
|
"version": "0.2.12-pre.9",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$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.8.fix.3",
|
"version": "0.2.12-pre.9",
|
||||||
"identifier": "com.sasedev.ksp-app-wallet-desk",
|
"identifier": "com.sasedev.ksp-app-wallet-desk",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": {
|
"beforeDevCommand": {
|
||||||
|
|||||||
@@ -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: 28
|
// version: 29
|
||||||
|
|
||||||
//! Desktop build, shell and Config-status contract audits for Wallet Desk.
|
//! Desktop build, shell and Config-status contract audits for Wallet Desk.
|
||||||
|
|
||||||
@@ -77,6 +77,10 @@ fn tauri_shell_uses_reserved_wallet_desk_ports_and_template_windows() {
|
|||||||
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("."));
|
||||||
assert_eq!(tauri.pointer("/build/beforeBuildCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run build"));
|
assert_eq!(tauri.pointer("/build/beforeBuildCommand/script").and_then(serde_json::Value::as_str), std::option::Option::Some("npm run build"));
|
||||||
assert_eq!(tauri.pointer("/build/beforeBuildCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some("."));
|
assert_eq!(tauri.pointer("/build/beforeBuildCommand/cwd").and_then(serde_json::Value::as_str), std::option::Option::Some("."));
|
||||||
|
assert_eq!(
|
||||||
|
tauri.pointer("/build/frontendDist").and_then(serde_json::Value::as_str),
|
||||||
|
std::option::Option::Some("../../../builds/khadhroony-solana-project/ksp-app-wallet-desk/dist"),
|
||||||
|
);
|
||||||
assert_eq!(tauri.pointer("/app/security/csp"), std::option::Option::Some(&serde_json::Value::Null));
|
assert_eq!(tauri.pointer("/app/security/csp"), std::option::Option::Some(&serde_json::Value::Null));
|
||||||
let manifest = read_text(root.join("Cargo.toml").as_path());
|
let manifest = read_text(root.join("Cargo.toml").as_path());
|
||||||
assert!(manifest.contains("name = \"ksp-app-wallet-desk\""));
|
assert!(manifest.contains("name = \"ksp-app-wallet-desk\""));
|
||||||
@@ -465,6 +469,7 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi
|
|||||||
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str);
|
let package_version = package.pointer("/version").and_then(serde_json::Value::as_str);
|
||||||
assert_packaged_version_floor(package_version, "package.json");
|
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, 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 {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-wallet-desk/tests/release_compliance.rs
|
// file: crates/ksp-app-wallet-desk/tests/release_compliance.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
//! Release-wide deterministic compliance canaries for Wallet Desk.
|
//! Release-wide deterministic compliance canaries for Wallet Desk.
|
||||||
|
|
||||||
@@ -215,3 +215,29 @@ fn packaged_resources_include_only_registered_config_sources_and_schemas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn v0_2_12_wallet_market_price_projection_remains_provider_neutral_and_exact() {
|
||||||
|
let root = app_root();
|
||||||
|
let source = read_rust_source_tree(root.join("src").as_path());
|
||||||
|
for forbidden in [
|
||||||
|
"MarketPriceBirdeye",
|
||||||
|
"MarketPriceCoinbaseExchange",
|
||||||
|
"MarketPriceCoinGecko",
|
||||||
|
"MarketPriceCoinMarketCap",
|
||||||
|
"MarketPriceCoinPaprika",
|
||||||
|
"MarketPriceDexScreener",
|
||||||
|
"MarketPriceJupiter",
|
||||||
|
"MarketPriceKraken",
|
||||||
|
] {
|
||||||
|
assert!(!source.contains(forbidden), "Wallet Desk must not branch on concrete market-price providers: {forbidden}");
|
||||||
|
}
|
||||||
|
let balance = read_text(root.join("src/wallet_balance.rs").as_path());
|
||||||
|
assert!(!balance.contains("f64"));
|
||||||
|
assert!(!balance.contains("f32"));
|
||||||
|
let main = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||||
|
assert!(!main.contains("parseFloat("));
|
||||||
|
assert!(!main.contains("Number(balance.sol"));
|
||||||
|
assert!(!main.contains("providerId"));
|
||||||
|
assert!(!main.contains("refresh_market_price"));
|
||||||
|
}
|
||||||
|
|||||||
168
deltas/0.2.12/pre.009.md
Normal file
168
deltas/0.2.12/pre.009.md
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<!-- file: deltas/0.2.12/pre.009.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.2.12-pre.009` — hardening transversal et gate technique/live final
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.2.12-pre.008-fix.003
|
||||||
|
```
|
||||||
|
|
||||||
|
Le gate opérateur de cette base est propre : `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace`, Clippy `--all-targets`, `cargo test -p ksp-app-wallet-desk` et `cargo test --workspace` passent. Le parcours fonctionnel Wallet avait déjà confirmé le refresh balance, la moyenne SOL/USD, l'équivalent USD et la version dynamique.
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Fermer le couloir technique de `0.2.12` sans ouvrir de nouvelle fonctionnalité métier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
borne batch hostile Price Desk avant parsing provider ID
|
||||||
|
canaris packages/CWD/resources/provider-neutralité cross-app
|
||||||
|
smoke live keyless de composition applicative générique
|
||||||
|
synchronisation npm/Tauri des deux apps modifiées sur pre.9
|
||||||
|
préparation du gate workspace + deux builds Tauri finaux
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version technique
|
||||||
|
|
||||||
|
```text
|
||||||
|
delivery 0.2.12-pre.009
|
||||||
|
workspace Cargo 0.2.12-pre.9
|
||||||
|
SOL Prices package/Tauri 0.2.12-pre.9
|
||||||
|
Wallet package/Tauri 0.2.12-pre.9
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hardening Price Desk
|
||||||
|
|
||||||
|
`MarketPriceRuntime::refresh_many` conserve le dispatch générique existant mais rejette désormais avant parsing des IDs opaques une sélection :
|
||||||
|
|
||||||
|
```text
|
||||||
|
vide
|
||||||
|
ou
|
||||||
|
> 64 provider IDs
|
||||||
|
```
|
||||||
|
|
||||||
|
La borne applicative est volontairement indépendante de tout provider concret. La valeur `64` correspond au plafond V1 déjà défendu par `MarketPriceService`; le Desk peut rester plus strict qu'une évolution future du service tant qu'une révision explicite de l'IPC n'a pas été faite.
|
||||||
|
|
||||||
|
Les doublons, IDs inconnus et conflits `in_flight` restent validés comme avant. Aucun scheduler, sleep, fallback, consensus, provider branch ou réseau frontend n'est ajouté.
|
||||||
|
|
||||||
|
## Smoke live de composition
|
||||||
|
|
||||||
|
Ajout du test opt-in :
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-app-solprices-desk/tests/market_price_composition_live_smoke.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Commande opérateur :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-app-solprices-desk --test market_price_composition_live_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Le smoke ne réaudite pas les wire adapters. Il prouve seulement le chemin applicatif attendu :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cfg.composite.ksp-app-solprices-desk / public_keyless
|
||||||
|
-> ConfigDocumentEngine
|
||||||
|
-> ResolvedOffchainTransportConfig
|
||||||
|
-> MarketPriceService registry = 8
|
||||||
|
-> refresh_all
|
||||||
|
-> au moins une observation SOL/USD live
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun secret n'est requis par ce profil.
|
||||||
|
|
||||||
|
## Canaris finaux renforcés
|
||||||
|
|
||||||
|
```text
|
||||||
|
SOL Prices package.json == tauri.conf.json == CARGO_PKG_VERSION
|
||||||
|
Wallet package.json == tauri.conf.json == CARGO_PKG_VERSION
|
||||||
|
Wallet frontendDist reste le dist Wallet dédié
|
||||||
|
Price Desk capabilities restent core + tracing uniquement
|
||||||
|
Price Desk frontend reste sans fetch/persistence/scheduler
|
||||||
|
Wallet src reste sans type provider concret
|
||||||
|
Wallet moyenne/équivalent restent sans f64/f32
|
||||||
|
Wallet frontend reste sans calcul flottant prix
|
||||||
|
resources Config restent bornées au registry packagé
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers ajoutés
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-app-solprices-desk/tests/market_price_composition_live_smoke.rs
|
||||||
|
deltas/0.2.12/pre.009.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-app-solprices-desk/package.json
|
||||||
|
crates/ksp-app-solprices-desk/tauri.conf.json
|
||||||
|
crates/ksp-app-solprices-desk/src/market_price_runtime.rs
|
||||||
|
crates/ksp-app-solprices-desk/unit_tests/market_price_runtime.rs
|
||||||
|
crates/ksp-app-solprices-desk/tests/desktop_contract.rs
|
||||||
|
crates/ksp-app-solprices-desk/tests/desktop_security.rs
|
||||||
|
crates/ksp-app-wallet-desk/package.json
|
||||||
|
crates/ksp-app-wallet-desk/tauri.conf.json
|
||||||
|
crates/ksp-app-wallet-desk/tests/desktop_contract.rs
|
||||||
|
crates/ksp-app-wallet-desk/tests/release_compliance.rs
|
||||||
|
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
|
||||||
|
nouveau provider
|
||||||
|
modification wire/provider adapters
|
||||||
|
nouvelle commande prix Wallet
|
||||||
|
panneau provider détaillé Wallet
|
||||||
|
auto-refresh/polling/scheduler
|
||||||
|
fallback ou provider canonique
|
||||||
|
historique/OHLCV/chart
|
||||||
|
Store/worker prix
|
||||||
|
réconciliation README/USAGE finale
|
||||||
|
CHANGELOG/ROADMAP/prompt de release suivante
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validations exécutées dans le sandbox de préparation
|
||||||
|
|
||||||
|
```text
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
|
||||||
|
validation JSON package/tauri PASS
|
||||||
|
contrôles statiques versions/frontières PASS
|
||||||
|
cargo fmt/check/clippy/test/live/tauri build NOT RUN — cargo indisponible dans le sandbox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gate opérateur attendu
|
||||||
|
|
||||||
|
Exécuter dans cet ordre :
|
||||||
|
|
||||||
|
```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 -p ksp-app-wallet-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)
|
||||||
|
(cd crates/ksp-app-wallet-desk && cargo tauri build)
|
||||||
|
```
|
||||||
|
|
||||||
|
Les deux `cargo tauri build` sont volontairement les dernières opérations lourdes conformément à `KSP-APP-034`.
|
||||||
|
|
||||||
|
## Critère de fermeture
|
||||||
|
|
||||||
|
`pre.009` est fermée lorsque le gate workspace, le smoke live de composition et les deux builds Tauri production sont verts. À ce stade, `pre.010` peut rester strictement documentaire/mécanique avant `rel.001`.
|
||||||
@@ -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: 17 -->
|
<!-- version: 18 -->
|
||||||
|
|
||||||
# Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk
|
# Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk
|
||||||
|
|
||||||
@@ -250,9 +250,12 @@ Le périmètre Wallet Desk est volontairement réduit après validation complèt
|
|||||||
Wallet Desk existing shell
|
Wallet Desk existing shell
|
||||||
-> Dashboard / Wallet courant
|
-> Dashboard / Wallet courant
|
||||||
-> Balance SOL existante
|
-> Balance SOL existante
|
||||||
-> une seule case “SOL/USD moyen”
|
-> “SOL/USD moyen”
|
||||||
-> valeur moyenne dérivée du refresh courant
|
-> valeur moyenne dérivée du refresh courant
|
||||||
-> N.A. si aucune observation exploitable
|
-> N.A. si aucune observation exploitable
|
||||||
|
-> “Équivalent USD”
|
||||||
|
-> balance SOL × moyenne du refresh courant, calcul exact côté Rust
|
||||||
|
-> N.A. si le prix auxiliaire est indisponible
|
||||||
-> bouton Refresh balance existant
|
-> bouton Refresh balance existant
|
||||||
-> getBalance On-chain
|
-> getBalance On-chain
|
||||||
-> refresh_all Off-chain des providers éligibles
|
-> refresh_all Off-chain des providers éligibles
|
||||||
@@ -262,7 +265,7 @@ Wallet Desk existing shell
|
|||||||
|
|
||||||
Aucun inventaire provider, aucune availability détaillée et aucun bouton prix supplémentaire ne sont dupliqués dans Wallet Desk. Les fonctions avancées restent la responsabilité de `ksp-app-solprices-desk`. Le prix auxiliaire suit le lifecycle du refresh de balance existant et n'ajoute aucun nouveau droit VIEW/OWNER.
|
Aucun inventaire provider, aucune availability détaillée et aucun bouton prix supplémentaire ne sont dupliqués dans Wallet Desk. Les fonctions avancées restent la responsabilité de `ksp-app-solprices-desk`. Le prix auxiliaire suit le lifecycle du refresh de balance existant et n'ajoute aucun nouveau droit VIEW/OWNER.
|
||||||
|
|
||||||
**Valorisation USD du solde : toujours hors scope `0.2.12`.** La moyenne est seulement affichée comme information SOL/USD ; aucun calcul `balance SOL × prix` n'est introduit.
|
**Équivalent USD retenu par décision opérateur.** Il reste une projection auxiliaire strictement dérivée du refresh courant : calcul côté Rust sans `f64`, aucun prix canonique/fallback et aucune dépendance supplémentaire du frontend aux providers.
|
||||||
|
|
||||||
## 9. DTO map retenue
|
## 9. DTO map retenue
|
||||||
|
|
||||||
@@ -342,8 +345,8 @@ refresh_wallet_balance
|
|||||||
-> en parallèle : MarketPriceService::refresh_all
|
-> en parallèle : MarketPriceService::refresh_all
|
||||||
-> ne garder que les observations réussies du refresh courant
|
-> ne garder que les observations réussies du refresh courant
|
||||||
-> moyenne arithmétique backend sans f64, arrondie à 8 décimales maximum
|
-> moyenne arithmétique backend sans f64, arrondie à 8 décimales maximum
|
||||||
-> WalletBalanceDto { ..., sol_usd_average: Option<String> }
|
-> WalletBalanceDto { ..., sol_usd_average: Option<String>, sol_usd_equivalent: Option<String> }
|
||||||
-> une seule case UI “SOL/USD moyen” ou “N.A.”
|
-> UI compacte “SOL/USD moyen” + “Équivalent USD”, ou “N.A.”
|
||||||
```
|
```
|
||||||
|
|
||||||
La branche prix est **auxiliaire/best-effort** : un runtime Off-chain indisponible, zéro observation ou un échec structurel prix ne rend pas `getBalance` invalide. La balance SOL reste autoritative et la projection prix devient `None`.
|
La branche prix est **auxiliaire/best-effort** : un runtime Off-chain indisponible, zéro observation ou un échec structurel prix ne rend pas `getBalance` invalide. La balance SOL reste autoritative et la projection prix devient `None`.
|
||||||
@@ -444,7 +447,7 @@ Canari obligatoire : `ksp-app-solprices-desk` référence son propre `package.js
|
|||||||
| TS-RS | bindings exportés par tests; prix exact en String |
|
| TS-RS | bindings exportés par tests; prix exact en String |
|
||||||
| workspace | fmt + audits + check + clippy + test |
|
| workspace | fmt + audits + check + clippy + test |
|
||||||
| SOL Prices Desk dev | parcours splash -> table -> row/many/all sur composition réelle |
|
| SOL Prices Desk dev | parcours splash -> table -> row/many/all sur composition réelle |
|
||||||
| Wallet Desk dev | refresh balance + une case moyenne SOL/USD/N.A. + non-régression Wallet |
|
| Wallet Desk dev | refresh balance + moyenne SOL/USD + équivalent USD/N.A. + non-régression Wallet |
|
||||||
| live composition | un smoke keyless applicatif opt-in suffit; ne réaudite pas les 8 wires |
|
| 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 |
|
| production build | `cargo tauri build` crate-local pour SOL Prices Desk puis Wallet Desk |
|
||||||
|
|
||||||
@@ -459,7 +462,7 @@ OHLCV/historique/chart
|
|||||||
SSE/WebSocket prix
|
SSE/WebSocket prix
|
||||||
consensus/fallback automatique
|
consensus/fallback automatique
|
||||||
provider canonique
|
provider canonique
|
||||||
valorisation USD du solde Wallet
|
panneau providers détaillé ou commandes prix dédiées dans Wallet Desk
|
||||||
auto-refresh/polling périodique
|
auto-refresh/polling périodique
|
||||||
Store/worker/job prix
|
Store/worker/job prix
|
||||||
éditeur Config dans Price Desk
|
éditeur Config dans Price Desk
|
||||||
@@ -555,7 +558,7 @@ Finalisation de la table responsive sans changer le contrat de dispatch : résum
|
|||||||
|
|
||||||
### `pre.008` — Intégration Wallet minimale + recalibrage de clôture
|
### `pre.008` — Intégration Wallet minimale + recalibrage de clôture
|
||||||
|
|
||||||
**Statut : réalisé ; corrigé par `pre.008-fix.001`, `pre.008-fix.002` puis `pre.008-fix.003`, gate opérateur final à confirmer.**
|
**Statut : réalisé ; corrigé par `pre.008-fix.001`, `pre.008-fix.002` puis `pre.008-fix.003`, gate opérateur final PASS.**
|
||||||
|
|
||||||
Absorption de l'ancien couloir Wallet `pre.009`–`pre.011` dans une seule tranche : ajout `offchain_transport/public_keyless` au composite Wallet, runtime Off-chain auxiliaire, `refresh_all` lors de `refresh_wallet_balance`, moyenne SOL/USD backend sans `f64` et projection compacte dans Wallet Desk. La correction `fix.002` complète le besoin opérateur réellement attendu : `WalletBalanceDto` expose également un équivalent USD exact calculé côté Rust à partir des lamports et de la moyenne du refresh courant ; Dashboard et Details affichent le prix moyen et l'équivalent ou `N.A.`. Aucun panneau provider, aucune command prix Wallet et aucun provider ID frontend ne sont ajoutés. La tranche réconcilie également le forecast avec cette réduction de scope.
|
Absorption de l'ancien couloir Wallet `pre.009`–`pre.011` dans une seule tranche : ajout `offchain_transport/public_keyless` au composite Wallet, runtime Off-chain auxiliaire, `refresh_all` lors de `refresh_wallet_balance`, moyenne SOL/USD backend sans `f64` et projection compacte dans Wallet Desk. La correction `fix.002` complète le besoin opérateur réellement attendu : `WalletBalanceDto` expose également un équivalent USD exact calculé côté Rust à partir des lamports et de la moyenne du refresh courant ; Dashboard et Details affichent le prix moyen et l'équivalent ou `N.A.`. Aucun panneau provider, aucune command prix Wallet et aucun provider ID frontend ne sont ajoutés. La tranche réconcilie également le forecast avec cette réduction de scope.
|
||||||
|
|
||||||
@@ -573,15 +576,15 @@ Correction du dernier écart fonctionnel de la tranche : le refresh produisait b
|
|||||||
|
|
||||||
#### `pre.008-fix.003` — Correction du littéral de canari version dynamique
|
#### `pre.008-fix.003` — Correction du littéral de canari version dynamique
|
||||||
|
|
||||||
**Statut : implémenté ; gate opérateur à confirmer.**
|
**Statut : réalisé ; gate opérateur Cargo/workspace intégralement PASS.**
|
||||||
|
|
||||||
Le gate de `pre.008-fix.002` confirme le fonctionnement runtime et visuel attendu : Dashboard et Details affichent la moyenne SOL/USD, l'équivalent USD et la version `0.2.12-pre.8.fix.2`. `cargo fmt`, les audits KSP et `cargo check --workspace` passent. Clippy `--all-targets` s'arrête uniquement sur le canari `desktop_contract.rs` : la raw string `r#"..."#` se ferme prématurément sur le fragment `"#appVersionBadge"`. Le fix remplace cette assertion par une chaîne Rust standard correctement échappée, sans modifier le runtime, le frontend ou le calcul prix.
|
Le gate de `pre.008-fix.002` confirme le fonctionnement runtime et visuel attendu : Dashboard et Details affichent la moyenne SOL/USD, l'équivalent USD et la version `0.2.12-pre.8.fix.2`. `cargo fmt`, les audits KSP et `cargo check --workspace` passent. Clippy `--all-targets` s'arrête uniquement sur le canari `desktop_contract.rs` : la raw string `r#"..."#` se ferme prématurément sur le fragment `"#appVersionBadge"`. Le fix remplace cette assertion par une chaîne Rust standard correctement échappée, sans modifier le runtime, le frontend ou le calcul prix.
|
||||||
|
|
||||||
### `pre.009` — Hardening transversal + gate technique/live final
|
### `pre.009` — Hardening transversal + gate technique/live final
|
||||||
|
|
||||||
**Statut : planifié.**
|
**Statut : implémenté ; gate opérateur live/build à confirmer.**
|
||||||
|
|
||||||
Fusion des anciens hardenings `pre.008`/`pre.012` et du gate `pre.013` : canaris batch hostile/capabilities/resources, non-régression des deux Desks, workspace complet, smoke live keyless de composition, et `cargo tauri build` final des deux applications modifiées. Aucun nouveau comportement métier n'est ouvert.
|
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.
|
||||||
|
|
||||||
### `pre.010` — Réconciliation documentaire + préparation de publication
|
### `pre.010` — Réconciliation documentaire + préparation de publication
|
||||||
|
|
||||||
|
|||||||
@@ -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: 16 -->
|
<!-- version: 17 -->
|
||||||
|
|
||||||
# Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk
|
# Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk
|
||||||
|
|
||||||
@@ -39,8 +39,8 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
| threat model desktop | PASS | plan 019 section 16 |
|
| threat model desktop | PASS | plan 019 section 16 |
|
||||||
| Wallet integration map | PASS | plan 019 section 12 |
|
| Wallet integration map | PASS | plan 019 section 12 |
|
||||||
| auto-refresh | OUT | hors scope confirmé |
|
| auto-refresh | OUT | hors scope confirmé |
|
||||||
| valorisation USD du solde | OUT | aucun prix canonique; hors scope confirmé |
|
| équivalent USD du solde | PASS | demandé opérateur; calcul backend exact depuis moyenne du refresh |
|
||||||
| forecast souple recalibré | PASS | 15 prereleases + rel; plan 019 section 19 |
|
| forecast souple recalibré | PASS | clôture condensée jusqu’à `pre.010` + `rel.001` |
|
||||||
| scope clôturable | PASS | pas de redécoupage requis avant `pre.002` |
|
| scope clôturable | PASS | pas de redécoupage requis avant `pre.002` |
|
||||||
| code/scaffold fonctionnel ajouté en `pre.001` | OUT | interdit par le gate |
|
| code/scaffold fonctionnel ajouté en `pre.001` | OUT | interdit par le gate |
|
||||||
|
|
||||||
@@ -58,9 +58,9 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
| refresh selected/many | `MarketPriceService::refresh_many` | PASS |
|
| refresh selected/many | `MarketPriceService::refresh_many` | PASS |
|
||||||
| refresh all | `MarketPriceService::refresh_all` | PASS |
|
| refresh all | `MarketPriceService::refresh_all` | PASS |
|
||||||
| Diagnostics | profils/counts sûrs seulement | PASS |
|
| Diagnostics | profils/counts sûrs seulement | PASS |
|
||||||
| Wallet prix moyen | une case `SOL/USD moyen` / `N.A.` | PASS |
|
| Wallet prix moyen | `SOL/USD moyen` / `N.A.` | PASS |
|
||||||
| auto-refresh | aucun scheduler/polling | OUT |
|
| auto-refresh | aucun scheduler/polling | OUT |
|
||||||
| Wallet USD valuation | aucune multiplication balance × prix | OUT |
|
| Wallet équivalent USD | calcul Rust exact / `N.A.` | PASS |
|
||||||
|
|
||||||
## 4. DTO/command matrix
|
## 4. DTO/command matrix
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
| `MarketPriceRuntimeStatusDto` | profiles/counts sans secret | PASS |
|
| `MarketPriceRuntimeStatusDto` | profiles/counts sans secret | PASS |
|
||||||
| `MarketPriceProviderRowDto` | ID/display/pair/semantics/auth/availability/price/timestamps/retry | PASS |
|
| `MarketPriceProviderRowDto` | ID/display/pair/semantics/auth/availability/price/timestamps/retry | PASS |
|
||||||
| single refresh direct | provider_id opaque seulement | PASS |
|
| single refresh direct | provider_id opaque seulement | PASS |
|
||||||
| `MarketPriceRefreshManyRequestDto` | liste d’IDs opaques ; borne hostile à durcir en `pre.009` | PASS |
|
| `MarketPriceRefreshManyRequestDto` | liste d’IDs opaques ; garde app `1..=64` avant parsing | PASS |
|
||||||
| `MarketPriceRefreshResultDto` | rows/outcome classifiés | PASS |
|
| `MarketPriceRefreshResultDto` | rows/outcome classifiés | PASS |
|
||||||
| runtime/list/refresh/many/all commands | aucun URL/header/API key/body | 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 |
|
| TS-RS exports | bindings générés non versionnés | PASS |
|
||||||
@@ -78,20 +78,20 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
|
|
||||||
## 5. Config/composite matrix
|
## 5. Config/composite matrix
|
||||||
|
|
||||||
| Contrat | Valeur attendue | Statut |
|
| Contrat | Valeur attendue | Statut |
|
||||||
|---------------------------------------|--------------------------------------------------------------|---------|
|
|---------------------------------------|--------------------------------------------------------------|--------|
|
||||||
| Price Desk composite file | `config/composite.ksp-app-solprices-desk.json` | PASS |
|
| Price Desk composite file | `config/composite.ksp-app-solprices-desk.json` | PASS |
|
||||||
| Price Desk file_id | `cfg.composite.ksp-app-solprices-desk` | PASS |
|
| Price Desk file_id | `cfg.composite.ksp-app-solprices-desk` | PASS |
|
||||||
| schema | `schema.composite` existant | PASS |
|
| schema | `schema.composite` existant | PASS |
|
||||||
| components | `logging`, `offchain_transport` | PASS |
|
| components | `logging`, `offchain_transport` | PASS |
|
||||||
| default profile | `public_keyless` | PASS |
|
| default profile | `public_keyless` | PASS |
|
||||||
| optional profile | `all_free` | PASS |
|
| optional profile | `all_free` | PASS |
|
||||||
| test profile | `tests` -> offchain `public_keyless` | PASS |
|
| test profile | `tests` -> offchain `public_keyless` | PASS |
|
||||||
| Wallet composite | ajoute offchain `public_keyless` à devnet/temporary/tests | PENDING |
|
| Wallet composite | ajoute offchain `public_keyless` à devnet/temporary/tests | PASS |
|
||||||
| registry/resource count | 11 après nouveau composite | PASS |
|
| registry/resource count | 11 après nouveau composite | PASS |
|
||||||
| registry + resources atomiques | Config + Config Desk + Wallet Desk + Price Desk même tranche | PASS |
|
| registry + resources atomiques | Config + Config Desk + Wallet Desk + Price Desk même tranche | PASS |
|
||||||
| nouveau schema Config | inutile | OUT |
|
| nouveau schema Config | inutile | OUT |
|
||||||
| modification `std.offchain_transport` | pas de lacune identifiée | OUT |
|
| modification `std.offchain_transport` | pas de lacune identifiée | OUT |
|
||||||
|
|
||||||
## 6. Provider-agnostic boundary matrix
|
## 6. Provider-agnostic boundary matrix
|
||||||
|
|
||||||
@@ -109,22 +109,22 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
|
|
||||||
## 7. Security matrix
|
## 7. Security matrix
|
||||||
|
|
||||||
| Risque/canari | Attendu | Statut |
|
| Risque/canari | Attendu | Statut |
|
||||||
|--------------------------------|-------------------------------------------------|---------|
|
|--------------------------------|-------------------------------------------------------|--------|
|
||||||
| URL arbitraire depuis frontend | impossible par contrat command | PASS |
|
| URL arbitraire depuis frontend | impossible par contrat command | PASS |
|
||||||
| extraction API key/header | aucune projection/log | PASS |
|
| extraction API key/header | aucune projection/log | PASS |
|
||||||
| provider_id inconnu | erreur KSP sûre | PASS |
|
| provider_id inconnu | erreur KSP sûre | PASS |
|
||||||
| batch duplicate | rejet avant dispatch | PASS |
|
| batch duplicate | rejet avant dispatch | PASS |
|
||||||
| batch oversized | borne hostile applicative à durcir en `pre.009` | PENDING |
|
| batch oversized | garde app `1..=64` avant parsing/dispatch | PASS |
|
||||||
| refresh spam | limites/cooldown Off-chain toujours actifs | PASS |
|
| refresh spam | limites/cooldown Off-chain toujours actifs | PASS |
|
||||||
| stale observation | timestamps/état distingués | PASS |
|
| stale observation | timestamps/état distingués | PASS |
|
||||||
| double-click race | in-flight/order contrôlés | PASS |
|
| double-click race | in-flight/order contrôlés | PASS |
|
||||||
| close pendant refresh | aucune persistance/sûreté frontend requise | PENDING |
|
| close pendant refresh | état uniquement mémoire ; aucune persistance frontend | PASS |
|
||||||
| CWD/resource confusion | canaris propres à chaque app | PENDING |
|
| CWD/resource confusion | frontendDist/cwd/ports/resources canarisés par app | PASS |
|
||||||
| Price Desk capabilities | `core:default`, `tracing:default` uniquement | PASS |
|
| Price Desk capabilities | `core:default`, `tracing:default` uniquement | PASS |
|
||||||
| plugin dialog Price Desk | absent | PASS |
|
| plugin dialog Price Desk | absent | PASS |
|
||||||
| frontend sensitive logging | action/ID/count/code seulement | PASS |
|
| frontend sensitive logging | action/ID/count/code seulement | PASS |
|
||||||
| Wallet VIEW/OWNER/secrets | non-régression | PENDING |
|
| Wallet VIEW/OWNER/secrets | suite Wallet + compliance inchangées | PASS |
|
||||||
|
|
||||||
## 8. Wallet integration matrix
|
## 8. Wallet integration matrix
|
||||||
|
|
||||||
@@ -134,16 +134,16 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
| Config component | Wallet composite -> `cfg.std.offchain_transport/public_keyless` | PASS |
|
| Config component | Wallet composite -> `cfg.std.offchain_transport/public_keyless` | PASS |
|
||||||
| runtime | Config -> `ResolvedOffchainTransportConfig` -> `MarketPriceService` | PASS |
|
| runtime | Config -> `ResolvedOffchainTransportConfig` -> `MarketPriceService` | PASS |
|
||||||
| command | `refresh_wallet_balance` existante, aucun input prix/provider | PASS |
|
| command | `refresh_wallet_balance` existante, aucun input prix/provider | PASS |
|
||||||
| DTO | `WalletBalanceDto.sol_usd_average: Option<String>` | PASS |
|
| DTO | moyenne + équivalent USD en `Option<String>` exacts | PASS |
|
||||||
| moyenne | observations réussies du refresh courant, backend sans `f64`, 8 déc. max | 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 |
|
| UI | résumé compact `SOL/USD moyen` + `Équivalent USD` / `N.A.` | PASS |
|
||||||
| balance HTTP On-chain | `getBalance` inchangé et toujours autoritatif | 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 |
|
| dégradation prix | échec/absence prix -> `N.A.` sans faire échouer la balance | PASS |
|
||||||
| WalletSession VIEW/OWNER | inchangée | PASS |
|
| WalletSession VIEW/OWNER | inchangée | PASS |
|
||||||
| Wallet secret projections | aucune nouvelle | PASS |
|
| Wallet secret projections | aucune nouvelle | PASS |
|
||||||
| provider ID frontend | aucun | PASS |
|
| provider ID frontend | aucun | PASS |
|
||||||
| command prix Wallet | aucune | PASS |
|
| command prix Wallet | aucune | PASS |
|
||||||
| USD balance multiplication | hors scope | OUT |
|
| USD balance multiplication | calcul Rust exact depuis lamports + moyenne du refresh courant | PASS |
|
||||||
|
|
||||||
## 9. Tauri/package matrix
|
## 9. Tauri/package matrix
|
||||||
|
|
||||||
@@ -158,6 +158,7 @@ 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 |
|
||||||
| Tauri production build Price Desk | crate-local PASS attendu | PENDING |
|
| Tauri production build Price Desk | crate-local PASS attendu | PENDING |
|
||||||
| Tauri production build Wallet Desk | crate-local PASS attendu | PENDING |
|
| Tauri production build Wallet Desk | crate-local PASS attendu | PENDING |
|
||||||
|
|
||||||
@@ -171,8 +172,8 @@ NOT RUN commande non exécutée dans le contexte indiqué
|
|||||||
| `cargo check --workspace` | PENDING |
|
| `cargo check --workspace` | PENDING |
|
||||||
| `cargo clippy --workspace --all-targets` | PENDING |
|
| `cargo clippy --workspace --all-targets` | PENDING |
|
||||||
| `cargo test --workspace` | PENDING |
|
| `cargo test --workspace` | PENDING |
|
||||||
| Price Desk functional dev path | PENDING |
|
| Price Desk functional dev path | PASS |
|
||||||
| Wallet Desk functional price path | PENDING |
|
| Wallet Desk functional price path | PASS |
|
||||||
| keyless app-composition live smoke | PENDING |
|
| keyless app-composition live smoke | PENDING |
|
||||||
| Price Desk `cargo tauri build` | PENDING |
|
| Price Desk `cargo tauri build` | PENDING |
|
||||||
| Wallet Desk `cargo tauri build` | PENDING |
|
| Wallet Desk `cargo tauri build` | PENDING |
|
||||||
@@ -726,3 +727,70 @@ cargo test -p ksp-app-wallet-desk
|
|||||||
cargo test --workspace
|
cargo test --workspace
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 28. Gate `0.2.12-pre.009` — hardening transversal et gate final
|
||||||
|
|
||||||
|
Le gate opérateur de `pre.008-fix.003` ferme définitivement la tranche Wallet condensée :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all PASS
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
|
||||||
|
cargo check --workspace PASS
|
||||||
|
cargo clippy --workspace --all-targets PASS
|
||||||
|
cargo test -p ksp-app-wallet-desk PASS
|
||||||
|
cargo test --workspace PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
Le parcours fonctionnel avait déjà confirmé sous `fix.002` puis `fix.003` la moyenne SOL/USD, l'équivalent USD, la version dynamique et le refresh balance réel.
|
||||||
|
|
||||||
|
`pre.009` ajoute les hardenings finaux suivants sans ouvrir de nouvelle fonctionnalité :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Price Desk batch IPC garde 1..=64 avant parsing des provider IDs
|
||||||
|
batch vide rejet KSP sûr
|
||||||
|
batch hostile 65 IDs rejet KSP sûr avant parsing provider
|
||||||
|
Price Desk manual refresh aucun scheduler/fetch/browser persistence
|
||||||
|
Price Desk package metadata npm/Tauri == CARGO_PKG_VERSION
|
||||||
|
Wallet package metadata npm/Tauri == CARGO_PKG_VERSION
|
||||||
|
Wallet frontendDist chemin Wallet dédié canarisé
|
||||||
|
Wallet provider-neutrality aucun type provider concret dans src/
|
||||||
|
Wallet exactness aucun f64/f32 backend, aucun calcul flottant frontend
|
||||||
|
keyless live composition nouveau smoke opt-in SOL Prices Desk
|
||||||
|
```
|
||||||
|
|
||||||
|
Le smoke live dédié est :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-app-solprices-desk --test market_price_composition_live_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Validations sandbox après matérialisation de la tranche :
|
||||||
|
|
||||||
|
```text
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md ... deltas PASS
|
||||||
|
JSON package/tauri des deux apps modifiées PASS
|
||||||
|
contrôles statiques versions/resources/frontières PASS
|
||||||
|
cargo fmt/check/clippy/test/live/tauri build NOT RUN — cargo indisponible
|
||||||
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Gate opérateur final à exécuter, dans cet ordre :
|
||||||
|
|
||||||
|
```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 -p ksp-app-wallet-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)
|
||||||
|
(cd crates/ksp-app-wallet-desk && cargo tauri build)
|
||||||
|
```
|
||||||
|
|
||||||
|
Conformément à `KSP-APP-034`, les deux `cargo tauri build` restent les dernières opérations lourdes.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user