v0.3.7-pre.004
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 419
|
# version: 420
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-app-backfill-desk", "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-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
members = ["crates/ksp-app-backfill-desk", "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-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.3.7-pre.3.fix.1"
|
version = "0.3.7-pre.4"
|
||||||
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,5 +1,5 @@
|
|||||||
# file: crates/ksp-app-backfill-desk/Cargo.toml
|
# file: crates/ksp-app-backfill-desk/Cargo.toml
|
||||||
# version: 1
|
# version: 2
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "ksp-app-backfill-desk"
|
name = "ksp-app-backfill-desk"
|
||||||
@@ -27,6 +27,7 @@ fs2.workspace = true
|
|||||||
ksp-config-lib = { path = "../ksp-config-lib" }
|
ksp-config-lib = { path = "../ksp-config-lib" }
|
||||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||||
ksp-logging-lib = { path = "../ksp-logging-lib" }
|
ksp-logging-lib = { path = "../ksp-logging-lib" }
|
||||||
|
ksp-onchain-transport-lib = { path = "../ksp-onchain-transport-lib" }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
tauri.workspace = true
|
tauri.workspace = true
|
||||||
tauri-plugin-tracing.workspace = true
|
tauri-plugin-tracing.workspace = true
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/app_state.rs
|
// file: crates/ksp-app-backfill-desk/src/app_state.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Shared backend state owned by the Backfill Desk Tauri application.
|
//! Shared backend state owned by the Backfill Desk Tauri application.
|
||||||
|
|
||||||
@@ -9,6 +9,8 @@ pub(crate) struct AppState {
|
|||||||
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
|
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
|
||||||
splash_settings: crate::SplashSettings,
|
splash_settings: crate::SplashSettings,
|
||||||
splash_sequence_started: std::sync::atomic::AtomicBool,
|
splash_sequence_started: std::sync::atomic::AtomicBool,
|
||||||
|
transport_runtime: std::option::Option<crate::TransportRuntime>,
|
||||||
|
transport_startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::AppState {
|
impl crate::AppState {
|
||||||
@@ -29,6 +31,21 @@ impl crate::AppState {
|
|||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
|
let transport_startup = crate::initialize_transport(&config_management);
|
||||||
|
let (transport_runtime, transport_startup_diagnostic) = match transport_startup {
|
||||||
|
std::result::Result::Ok(value) => (std::option::Option::Some(value), std::option::Option::None),
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
let diagnostic = crate::CommandErrorDto::from_error(&error);
|
||||||
|
ksp_logging_lib::warn!(
|
||||||
|
target: crate::TRACING_TARGET,
|
||||||
|
domain = crate::TRACING_DOMAIN_TRANSPORT,
|
||||||
|
error_domain = diagnostic.domain.as_str(),
|
||||||
|
error_code = diagnostic.code.as_str(),
|
||||||
|
"Backfill Desk Transport readiness is unavailable; keeping desktop shell available"
|
||||||
|
);
|
||||||
|
(std::option::Option::None, std::option::Option::Some(diagnostic))
|
||||||
|
},
|
||||||
|
};
|
||||||
let splash_settings = crate::SplashSettings::load();
|
let splash_settings = crate::SplashSettings::load();
|
||||||
let splash_settings = match splash_settings {
|
let splash_settings = match splash_settings {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
@@ -65,6 +82,8 @@ impl crate::AppState {
|
|||||||
}),
|
}),
|
||||||
splash_settings,
|
splash_settings,
|
||||||
splash_sequence_started: std::sync::atomic::AtomicBool::new(false),
|
splash_sequence_started: std::sync::atomic::AtomicBool::new(false),
|
||||||
|
transport_runtime,
|
||||||
|
transport_startup_diagnostic,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,11 +116,25 @@ impl crate::AppState {
|
|||||||
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||||
config_document_count: document_count,
|
config_document_count: document_count,
|
||||||
fallback_logging_active: runtime.fallback_active,
|
fallback_logging_active: runtime.fallback_active,
|
||||||
shell_phase: "pre.002-desktop-scaffold".to_owned(),
|
shell_phase: "pre.004-transport-readiness".to_owned(),
|
||||||
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the safe Transport-readiness subset of Backfill Desk options.
|
||||||
|
pub(crate) fn backfill_options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
|
||||||
|
let runtime = self.transport_runtime.as_ref();
|
||||||
|
return match runtime {
|
||||||
|
std::option::Option::Some(value) => value.options(),
|
||||||
|
std::option::Option::None => std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
||||||
|
compatible_roles: std::vec::Vec::new(),
|
||||||
|
configured_networks: std::vec::Vec::new(),
|
||||||
|
transport_diagnostic: self.transport_startup_diagnostic.clone(),
|
||||||
|
transport_ready: false,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the resolved splash timings captured during application bootstrap.
|
/// Returns the resolved splash timings captured during application bootstrap.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {
|
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/constants.rs
|
// file: crates/ksp-app-backfill-desk/src/constants.rs
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! Application-owned tracing targets and domains.
|
//! Application-owned tracing targets and domains.
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ pub(crate) const TRACING_DOMAIN_BOOTSTRAP: &str = "backfill.bootstrap";
|
|||||||
pub(crate) const TRACING_DOMAIN_FRONTEND: &str = "frontend";
|
pub(crate) const TRACING_DOMAIN_FRONTEND: &str = "frontend";
|
||||||
/// Structured domain used by the Backfill Desk shell.
|
/// Structured domain used by the Backfill Desk shell.
|
||||||
pub(crate) const TRACING_DOMAIN_SHELL: &str = "backfill.shell";
|
pub(crate) const TRACING_DOMAIN_SHELL: &str = "backfill.shell";
|
||||||
|
/// Structured domain used by Transport readiness and role inventory operations.
|
||||||
|
pub(crate) const TRACING_DOMAIN_TRANSPORT: &str = "backfill.transport";
|
||||||
/// Structured domain used by Tauri window lifecycle operations.
|
/// Structured domain used by Tauri window lifecycle operations.
|
||||||
pub(crate) const TRACING_DOMAIN_WINDOWS: &str = "desktop.window";
|
pub(crate) const TRACING_DOMAIN_WINDOWS: &str = "desktop.window";
|
||||||
/// Owning target for backend events emitted by Backfill Desk.
|
/// Owning target for backend events emitted by Backfill Desk.
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/dto_common.rs
|
// file: crates/ksp-app-backfill-desk/src/dto_common.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Common Tauri DTOs shared by the Backfill Desk shell.
|
//! Common Tauri DTOs shared by the Backfill Desk shell.
|
||||||
|
|
||||||
use ts_rs::TS; // rust-rules: trait-import
|
use ts_rs::TS; // rust-rules: trait-import
|
||||||
|
|
||||||
|
/// Safe Transport-readiness subset of the Backfill Desk options contract.
|
||||||
|
///
|
||||||
|
/// Campaign scopes, commitments and backend-owned bounds are added in the dedicated request/DTO slice. Endpoint URLs, provider identities and credentials
|
||||||
|
/// are intentionally absent.
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_backfill_desk/dto_common/BackfillDeskOptionsDto.ts")]
|
||||||
|
pub(crate) struct BackfillDeskOptionsDto {
|
||||||
|
/// Logical roles that can route both RPC methods required by the Backfill runtime.
|
||||||
|
pub(crate) compatible_roles: std::vec::Vec<String>,
|
||||||
|
/// Distinct enabled HTTP cluster labels selected by the active Transport profile.
|
||||||
|
pub(crate) configured_networks: std::vec::Vec<String>,
|
||||||
|
/// Safe startup diagnostic when Transport configuration could not be resolved or constructed.
|
||||||
|
pub(crate) transport_diagnostic: std::option::Option<CommandErrorDto>,
|
||||||
|
/// Whether Transport currently has one coherent network and at least one compatible available role.
|
||||||
|
pub(crate) transport_ready: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Safe command error projection that never serializes arbitrary KSP error context or source values.
|
/// Safe command error projection that never serializes arbitrary KSP error context or source values.
|
||||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/errors.rs
|
// file: crates/ksp-app-backfill-desk/src/errors.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Application-local error codes for Backfill Desk composition and desktop runtime surfaces.
|
//! Application-local error codes for Backfill Desk composition and desktop runtime surfaces.
|
||||||
|
|
||||||
@@ -8,17 +8,13 @@ pub(crate) const ERROR_CODE_APP_STATE_INVALID: ksp_core_lib::ErrorCode = ksp_cor
|
|||||||
/// Shared Backfill Desk runtime state cannot be locked safely.
|
/// Shared Backfill Desk runtime state cannot be locked safely.
|
||||||
pub(crate) const ERROR_CODE_APP_STATE_LOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "app_state_lock_failed");
|
pub(crate) const ERROR_CODE_APP_STATE_LOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "app_state_lock_failed");
|
||||||
/// Backfill Desk composite configuration is missing or references an unexpected document.
|
/// Backfill Desk composite configuration is missing or references an unexpected document.
|
||||||
pub(crate) const ERROR_CODE_CONFIG_COMPOSITE_INVALID: ksp_core_lib::ErrorCode =
|
pub(crate) const ERROR_CODE_CONFIG_COMPOSITE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "config_composite_invalid");
|
||||||
ksp_core_lib::ErrorCode::new("backfill_desk", "config_composite_invalid");
|
|
||||||
/// Frontend logging requested an unsupported level.
|
/// Frontend logging requested an unsupported level.
|
||||||
pub(crate) const ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID: ksp_core_lib::ErrorCode =
|
pub(crate) const ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_level_invalid");
|
||||||
ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_level_invalid");
|
|
||||||
/// Frontend logging requested a target outside the application whitelist.
|
/// Frontend logging requested a target outside the application whitelist.
|
||||||
pub(crate) const ERROR_CODE_FRONTEND_LOG_TARGET_INVALID: ksp_core_lib::ErrorCode =
|
pub(crate) const ERROR_CODE_FRONTEND_LOG_TARGET_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_target_invalid");
|
||||||
ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_target_invalid");
|
|
||||||
/// Backfill Desk could not install the managed Logging runtime or its safe fallback.
|
/// Backfill Desk could not install the managed Logging runtime or its safe fallback.
|
||||||
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode =
|
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "logging_bootstrap_failed");
|
||||||
ksp_core_lib::ErrorCode::new("backfill_desk", "logging_bootstrap_failed");
|
|
||||||
/// Splash readiness was invoked from a window other than the splash window.
|
/// Splash readiness was invoked from a window other than the splash window.
|
||||||
pub(crate) const ERROR_CODE_SPLASH_ORIGIN_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "splash_origin_invalid");
|
pub(crate) const ERROR_CODE_SPLASH_ORIGIN_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "splash_origin_invalid");
|
||||||
/// A KSP desk splash environment duration is malformed or exceeds its safety bound.
|
/// A KSP desk splash environment duration is malformed or exceeds its safety bound.
|
||||||
@@ -30,3 +26,5 @@ pub(crate) const ERROR_CODE_TAURI_WINDOW_MISSING: ksp_core_lib::ErrorCode = ksp_
|
|||||||
/// A Tauri window show/focus/destroy/event operation failed.
|
/// A Tauri window show/focus/destroy/event operation failed.
|
||||||
pub(crate) const ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED: ksp_core_lib::ErrorCode =
|
pub(crate) const ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED: ksp_core_lib::ErrorCode =
|
||||||
ksp_core_lib::ErrorCode::new("backfill_desk", "tauri_window_operation_failed");
|
ksp_core_lib::ErrorCode::new("backfill_desk", "tauri_window_operation_failed");
|
||||||
|
/// Backfill Desk cannot derive a safe Transport readiness contract from the Transport registry.
|
||||||
|
pub(crate) const ERROR_CODE_TRANSPORT_READINESS_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "transport_readiness_invalid");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/lib.rs
|
// file: crates/ksp-app-backfill-desk/src/lib.rs
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! Tauri desktop application scaffold for controlling and inspecting KSP RAW backfill jobs.
|
//! Tauri desktop application scaffold for controlling and inspecting KSP RAW backfill jobs.
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ mod frontend_logging;
|
|||||||
mod logging_runtime;
|
mod logging_runtime;
|
||||||
mod splash;
|
mod splash;
|
||||||
mod tauri;
|
mod tauri;
|
||||||
|
mod transport_runtime;
|
||||||
mod tw_main;
|
mod tw_main;
|
||||||
mod tw_splash;
|
mod tw_splash;
|
||||||
|
|
||||||
@@ -46,6 +47,8 @@ pub(crate) use self::constants::TRACING_DOMAIN_BOOTSTRAP;
|
|||||||
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
|
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
|
||||||
/// Structured domain used by the Backfill Desk shell.
|
/// Structured domain used by the Backfill Desk shell.
|
||||||
pub(crate) use self::constants::TRACING_DOMAIN_SHELL;
|
pub(crate) use self::constants::TRACING_DOMAIN_SHELL;
|
||||||
|
/// Structured domain used by Transport readiness and role inventory operations.
|
||||||
|
pub(crate) use self::constants::TRACING_DOMAIN_TRANSPORT;
|
||||||
/// Structured domain used by Tauri window lifecycle operations.
|
/// Structured domain used by Tauri window lifecycle operations.
|
||||||
pub(crate) use self::constants::TRACING_DOMAIN_WINDOWS;
|
pub(crate) use self::constants::TRACING_DOMAIN_WINDOWS;
|
||||||
/// Owning target for backend events emitted by Backfill Desk.
|
/// Owning target for backend events emitted by Backfill Desk.
|
||||||
@@ -56,6 +59,8 @@ pub(crate) use self::constants::TRACING_TARGET_FRONTEND;
|
|||||||
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_MAIN;
|
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_MAIN;
|
||||||
/// Owning target for splash-window frontend events.
|
/// Owning target for splash-window frontend events.
|
||||||
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_SPLASH;
|
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_SPLASH;
|
||||||
|
/// Safe Transport-readiness subset of the Backfill Desk options contract.
|
||||||
|
pub(crate) use self::dto_common::BackfillDeskOptionsDto;
|
||||||
/// Safe command error projection exposed to Tauri commands.
|
/// Safe command error projection exposed to Tauri commands.
|
||||||
pub(crate) use self::dto_common::CommandErrorDto;
|
pub(crate) use self::dto_common::CommandErrorDto;
|
||||||
/// Safe scaffold/runtime snapshot exposed to the shell.
|
/// Safe scaffold/runtime snapshot exposed to the shell.
|
||||||
@@ -82,6 +87,8 @@ pub(crate) use self::errors::ERROR_CODE_TAURI_RUNTIME_FAILED;
|
|||||||
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_MISSING;
|
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_MISSING;
|
||||||
/// A Tauri window show/focus/destroy/event operation failed.
|
/// A Tauri window show/focus/destroy/event operation failed.
|
||||||
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED;
|
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED;
|
||||||
|
/// Backfill Desk cannot derive a safe Transport readiness contract.
|
||||||
|
pub(crate) use self::errors::ERROR_CODE_TRANSPORT_READINESS_INVALID;
|
||||||
/// Log payload sent by Backfill Desk frontend scripts.
|
/// Log payload sent by Backfill Desk frontend scripts.
|
||||||
pub(crate) use self::frontend_logging::FrontendLogPayloadDto;
|
pub(crate) use self::frontend_logging::FrontendLogPayloadDto;
|
||||||
/// Emits one validated frontend event through the KSP Logging facade.
|
/// Emits one validated frontend event through the KSP Logging facade.
|
||||||
@@ -92,6 +99,10 @@ pub(crate) use self::logging_runtime::launch_identity;
|
|||||||
pub(crate) use self::splash::SplashOrderDto;
|
pub(crate) use self::splash::SplashOrderDto;
|
||||||
/// Runtime timings used by the common desk splash lifecycle.
|
/// Runtime timings used by the common desk splash lifecycle.
|
||||||
pub(crate) use self::splash::SplashSettings;
|
pub(crate) use self::splash::SplashSettings;
|
||||||
|
/// Safe and executable Transport runtime retained by application state.
|
||||||
|
pub(crate) use self::transport_runtime::TransportRuntime;
|
||||||
|
/// Initializes the composite-selected HTTP Transport runtime.
|
||||||
|
pub(crate) use self::transport_runtime::initialize_transport;
|
||||||
/// Resolves the required main window or returns a typed error.
|
/// Resolves the required main window or returns a typed error.
|
||||||
pub(crate) use self::tw_main::require_main_window;
|
pub(crate) use self::tw_main::require_main_window;
|
||||||
/// Shows and focuses the main Backfill Desk window.
|
/// Shows and focuses the main Backfill Desk window.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/tauri.rs
|
// file: crates/ksp-app-backfill-desk/src/tauri.rs
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! Tauri runtime assembly for the KSP Backfill desktop application.
|
//! Tauri runtime assembly for the KSP Backfill desktop application.
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<taur
|
|||||||
|
|
||||||
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for async command dispatch.
|
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for async command dispatch.
|
||||||
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||||
return builder.invoke_handler(tauri::generate_handler![emit_frontend_log, get_runtime_status, splash_frontend_ready]);
|
return builder.invoke_handler(tauri::generate_handler![backfill_options, emit_frontend_log, get_runtime_status, splash_frontend_ready]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||||
@@ -102,6 +102,15 @@ fn project_command_error(command: &'static str, domain: &'static str, error: &ks
|
|||||||
return crate::CommandErrorDto::from_error(error);
|
return crate::CommandErrorDto::from_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn backfill_options(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::BackfillDeskOptionsDto, crate::CommandErrorDto> {
|
||||||
|
let result = state.backfill_options();
|
||||||
|
return match result {
|
||||||
|
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||||
|
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_options", crate::TRACING_DOMAIN_TRANSPORT, &error)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn emit_frontend_log(payload: crate::FrontendLogPayloadDto) -> std::result::Result<(), crate::CommandErrorDto> {
|
fn emit_frontend_log(payload: crate::FrontendLogPayloadDto) -> std::result::Result<(), crate::CommandErrorDto> {
|
||||||
let result = crate::emit_frontend_log_event(payload);
|
let result = crate::emit_frontend_log_event(payload);
|
||||||
|
|||||||
148
crates/ksp-app-backfill-desk/src/transport_runtime.rs
Normal file
148
crates/ksp-app-backfill-desk/src/transport_runtime.rs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// file: crates/ksp-app-backfill-desk/src/transport_runtime.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Composite-selected HTTP Transport readiness owned by Backfill Desk.
|
||||||
|
|
||||||
|
/// Safe and executable Transport runtime retained by the application state.
|
||||||
|
pub(crate) struct TransportRuntime {
|
||||||
|
pool: ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
profile_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransportRuntime {
|
||||||
|
/// Returns the composite-selected Transport profile identifier.
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn profile_id(&self) -> &str {
|
||||||
|
return self.profile_id.as_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds the current safe Transport-only projection for the Backfill options surface.
|
||||||
|
pub(crate) fn options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
|
||||||
|
let snapshot = self.pool.snapshot();
|
||||||
|
let configured_networks = configured_networks(&snapshot);
|
||||||
|
let compatible_roles = compatible_backfill_roles(&self.pool, &snapshot);
|
||||||
|
let compatible_roles = match compatible_roles {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let transport_ready = configured_networks.len() == 1 && !compatible_roles.is_empty() && snapshot.available_endpoint_count() > 0;
|
||||||
|
return std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
||||||
|
compatible_roles,
|
||||||
|
configured_networks,
|
||||||
|
transport_diagnostic: std::option::Option::None,
|
||||||
|
transport_ready,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the composite-selected Transport profile and builds the executable HTTP pool.
|
||||||
|
pub(crate) fn initialize_transport(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<TransportRuntime> {
|
||||||
|
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||||
|
let environment = match environment {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let composite = crate::load_backfill_desk_composite(management);
|
||||||
|
let composite = match composite {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_TRANSPORT, ksp_config_lib::FILE_ID_STD_TRANSPORT);
|
||||||
|
let profile = match profile {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let resolved = management.engine().resolve_transport_config_profile(&profile, &environment);
|
||||||
|
let resolved = match resolved {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let profile_id = resolved.profile_id().to_owned();
|
||||||
|
let pool = ksp_onchain_transport_lib::HttpTransportPool::new(resolved.into_settings());
|
||||||
|
let pool = match pool {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let runtime = TransportRuntime { pool, profile_id };
|
||||||
|
let options = runtime.options();
|
||||||
|
let options = match options {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
ksp_logging_lib::debug!(
|
||||||
|
target: crate::TRACING_TARGET,
|
||||||
|
domain = crate::TRACING_DOMAIN_TRANSPORT,
|
||||||
|
transport_profile = runtime.profile_id(),
|
||||||
|
network_count = options.configured_networks.len(),
|
||||||
|
compatible_role_count = options.compatible_roles.len(),
|
||||||
|
transport_ready = options.transport_ready,
|
||||||
|
"initialized Backfill Desk HTTP Transport readiness from composite-managed configuration"
|
||||||
|
);
|
||||||
|
return std::result::Result::Ok(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible_backfill_roles(
|
||||||
|
pool: &ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
|
snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot,
|
||||||
|
) -> ksp_core_lib::Result<std::vec::Vec<String>> {
|
||||||
|
let signatures = required_http_rpc_method("getSignaturesForAddress");
|
||||||
|
let signatures = match signatures {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let transaction = required_http_rpc_method("getTransaction");
|
||||||
|
let transaction = match transaction {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let mut candidates = std::collections::BTreeSet::new();
|
||||||
|
for endpoint in snapshot.endpoints() {
|
||||||
|
if !endpoint.enabled() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for role in endpoint.roles() {
|
||||||
|
if role.enabled() {
|
||||||
|
candidates.insert(role.role().to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut compatible = std::vec::Vec::new();
|
||||||
|
for candidate in candidates {
|
||||||
|
let role = ksp_onchain_transport_lib::HttpRoleName::new(candidate.clone());
|
||||||
|
if pool.select_for_method(&role, signatures).is_ok() && pool.select_for_method(&role, transaction).is_ok() {
|
||||||
|
compatible.push(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::result::Result::Ok(compatible);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configured_networks(snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot) -> std::vec::Vec<String> {
|
||||||
|
let mut values = snapshot
|
||||||
|
.endpoints()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|endpoint| {
|
||||||
|
if endpoint.enabled() {
|
||||||
|
return std::option::Option::Some(endpoint.cluster().to_owned());
|
||||||
|
}
|
||||||
|
return std::option::Option::None;
|
||||||
|
})
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
values.sort();
|
||||||
|
values.dedup();
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn required_http_rpc_method(method: &'static str) -> ksp_core_lib::Result<&'static ksp_onchain_transport_lib::HttpRpcMethodDescriptor> {
|
||||||
|
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method);
|
||||||
|
return match descriptor {
|
||||||
|
std::option::Option::Some(value) => std::result::Result::Ok(value),
|
||||||
|
std::option::Option::None => std::result::Result::Err(
|
||||||
|
ksp_core_lib::Error::new(crate::ERROR_CODE_TRANSPORT_READINESS_INVALID, "Backfill Desk Transport registry is missing a required HTTP RPC method")
|
||||||
|
.with_context("rpc_method", method),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "../unit_tests/transport_runtime.rs"]
|
||||||
|
mod tests;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/config_composition.rs
|
// file: crates/ksp-app-backfill-desk/tests/config_composition.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
//! Config composite contracts for Backfill Desk pre.003.
|
//! Config composite and Transport-readiness contracts for Backfill Desk through pre.004.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
@@ -86,3 +86,73 @@ fn pre_003_named_profiles_keep_transport_and_store_network_selection_paired() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_004_default_composite_builds_http_pool_for_both_backfill_rpc_methods() {
|
||||||
|
let engine = workspace_engine();
|
||||||
|
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
|
||||||
|
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_BACKFILL_DESK);
|
||||||
|
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 Backfill Desk composite should resolve: {composite:?}");
|
||||||
|
let composite = match composite {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let transport = composite.component("transport");
|
||||||
|
assert!(transport.is_some(), "Backfill Desk composite should expose Transport");
|
||||||
|
let transport = match transport {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||||
|
assert!(environment.is_ok(), "Config environment should load for committed public devnet profile");
|
||||||
|
let environment = match environment {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let resolved = engine.resolve_transport_config_profile(transport.resolved(), &environment);
|
||||||
|
assert!(resolved.is_ok(), "composite-selected Transport should map: {resolved:?}");
|
||||||
|
let resolved = match resolved {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(resolved.profile_id(), "devnet_public");
|
||||||
|
assert_eq!(resolved.selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
|
||||||
|
let pool = ksp_onchain_transport_lib::HttpTransportPool::new(resolved.into_settings());
|
||||||
|
assert!(pool.is_ok(), "composite-selected Transport settings should construct an HTTP pool");
|
||||||
|
let pool = match pool {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let snapshot = pool.snapshot();
|
||||||
|
let mut clusters = snapshot
|
||||||
|
.endpoints()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|endpoint| {
|
||||||
|
if endpoint.enabled() {
|
||||||
|
return std::option::Option::Some(endpoint.cluster().to_owned());
|
||||||
|
}
|
||||||
|
return std::option::Option::None;
|
||||||
|
})
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
clusters.sort();
|
||||||
|
clusters.dedup();
|
||||||
|
assert_eq!(clusters, vec!["devnet".to_owned()]);
|
||||||
|
let role = ksp_onchain_transport_lib::HttpRoleName::new("default");
|
||||||
|
for method in ["getSignaturesForAddress", "getTransaction"] {
|
||||||
|
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method);
|
||||||
|
assert!(descriptor.is_some(), "required Transport method {method} should exist");
|
||||||
|
if let std::option::Option::Some(descriptor) = descriptor {
|
||||||
|
let selection = pool.select_for_method(&role, descriptor);
|
||||||
|
assert!(selection.is_ok(), "role default should route {method}: {selection:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs
|
// file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Structural desktop contract checks for the Backfill Desk scaffold.
|
//! Structural desktop contract checks for the Backfill Desk scaffold.
|
||||||
|
|
||||||
@@ -99,13 +99,7 @@ fn pre_002_package_dependencies_match_desk_baseline() {
|
|||||||
fn pre_002_splash_assets_and_styles_match_existing_desk_template() {
|
fn pre_002_splash_assets_and_styles_match_existing_desk_template() {
|
||||||
let root = app_root();
|
let root = app_root();
|
||||||
let reference = workspace_root().join("crates/ksp-app-solprices-desk");
|
let reference = workspace_root().join("crates/ksp-app-solprices-desk");
|
||||||
for relative in [
|
for relative in ["frontend/fonts/DOS_Amazigh.ttf", "frontend/imgs/logo.png", "frontend/imgs/splash.png", "icons/favicon.png", "icons/favicon.ico"] {
|
||||||
"frontend/fonts/DOS_Amazigh.ttf",
|
|
||||||
"frontend/imgs/logo.png",
|
|
||||||
"frontend/imgs/splash.png",
|
|
||||||
"icons/favicon.png",
|
|
||||||
"icons/favicon.ico",
|
|
||||||
] {
|
|
||||||
assert_eq!(read_bytes(root.join(relative).as_path()), read_bytes(reference.join(relative).as_path()), "Desk asset differs: {relative}");
|
assert_eq!(read_bytes(root.join(relative).as_path()), read_bytes(reference.join(relative).as_path()), "Desk asset differs: {relative}");
|
||||||
}
|
}
|
||||||
let splash = read_text(root.join("frontend/splash.html").as_path());
|
let splash = read_text(root.join("frontend/splash.html").as_path());
|
||||||
@@ -113,9 +107,7 @@ fn pre_002_splash_assets_and_styles_match_existing_desk_template() {
|
|||||||
assert!(splash.contains("Backfill Desk"));
|
assert!(splash.contains("Backfill Desk"));
|
||||||
let splash_style = read_text(root.join("frontend/sass/splash.scss").as_path());
|
let splash_style = read_text(root.join("frontend/sass/splash.scss").as_path());
|
||||||
let reference_style = read_text(reference.join("frontend/sass/splash.scss").as_path());
|
let reference_style = read_text(reference.join("frontend/sass/splash.scss").as_path());
|
||||||
let normalized = splash_style
|
let normalized = splash_style.replace("crates/ksp-app-backfill-desk", "crates/ksp-app-solprices-desk").replace("// version: 1", "// version: 2");
|
||||||
.replace("crates/ksp-app-backfill-desk", "crates/ksp-app-solprices-desk")
|
|
||||||
.replace("// version: 1", "// version: 2");
|
|
||||||
assert_eq!(normalized, reference_style);
|
assert_eq!(normalized, reference_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +171,7 @@ fn pre_003_composite_packaging_follows_atomic_config_registry_contract() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_003_bootstrap_uses_composite_logging_without_opening_transport_or_store() {
|
fn pre_003_bootstrap_keeps_logging_composition_separate_from_transport_runtime() {
|
||||||
let root = app_root();
|
let root = app_root();
|
||||||
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
|
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
|
||||||
assert!(bootstrap.contains("FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK"));
|
assert!(bootstrap.contains("FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK"));
|
||||||
@@ -188,6 +180,23 @@ fn pre_003_bootstrap_uses_composite_logging_without_opening_transport_or_store()
|
|||||||
assert!(bootstrap.contains("COMPOSITE_COMPONENT_ID_STORE"));
|
assert!(bootstrap.contains("COMPOSITE_COMPONENT_ID_STORE"));
|
||||||
assert!(bootstrap.contains("LogFilterLevel::Trace"));
|
assert!(bootstrap.contains("LogFilterLevel::Trace"));
|
||||||
for forbidden in ["HttpTransportPool", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
|
for forbidden in ["HttpTransportPool", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
|
||||||
assert!(!bootstrap.contains(forbidden), "pre.003 opens later runtime surface {forbidden}");
|
assert!(!bootstrap.contains(forbidden), "bootstrap.rs absorbs another runtime responsibility: {forbidden}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_004_transport_runtime_builds_pool_and_validates_both_required_rpc_methods() {
|
||||||
|
let root = app_root();
|
||||||
|
let transport = read_text(root.join("src/transport_runtime.rs").as_path());
|
||||||
|
assert!(transport.contains("HttpTransportPool::new"));
|
||||||
|
assert!(transport.contains("getSignaturesForAddress"));
|
||||||
|
assert!(transport.contains("getTransaction"));
|
||||||
|
assert!(transport.contains("select_for_method"));
|
||||||
|
assert!(transport.contains("configured_networks"));
|
||||||
|
assert!(transport.contains("compatible_backfill_roles"));
|
||||||
|
for forbidden in ["provider()", "url()", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
|
||||||
|
assert!(!transport.contains(forbidden), "pre.004 opens or projects forbidden surface {forbidden}");
|
||||||
|
}
|
||||||
|
let tauri = read_text(root.join("src/tauri.rs").as_path());
|
||||||
|
assert!(tauri.contains("backfill_options"));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/desktop_security.rs
|
// file: crates/ksp-app-backfill-desk/tests/desktop_security.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Security and dependency-boundary checks for the Backfill Desk scaffold.
|
//! Security and dependency-boundary checks for the Backfill Desk scaffold.
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ fn read_text(path: &std::path::Path) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_002_capability_surface_is_core_plus_tracing_only() {
|
fn capability_surface_remains_core_plus_tracing_while_transport_is_backend_only() {
|
||||||
let root = app_root();
|
let root = app_root();
|
||||||
let capability = read_text(root.join("capabilities/default.json").as_path());
|
let capability = read_text(root.join("capabilities/default.json").as_path());
|
||||||
assert!(capability.contains("\"core:default\""));
|
assert!(capability.contains("\"core:default\""));
|
||||||
@@ -53,16 +53,9 @@ fn pre_002_capability_surface_is_core_plus_tracing_only() {
|
|||||||
}
|
}
|
||||||
let manifest = read_text(root.join("Cargo.toml").as_path());
|
let manifest = read_text(root.join("Cargo.toml").as_path());
|
||||||
assert!(manifest.contains("tauri-plugin-tracing.workspace = true"));
|
assert!(manifest.contains("tauri-plugin-tracing.workspace = true"));
|
||||||
for forbidden in [
|
assert!(manifest.contains("ksp-onchain-transport-lib = { path = \"../ksp-onchain-transport-lib\" }"));
|
||||||
"ksp-job-backfill-lib",
|
for forbidden in ["ksp-job-backfill-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib", "reqwest", "tokio-postgres"] {
|
||||||
"ksp-onchain-transport-lib",
|
assert!(!manifest.contains(forbidden), "current Backfill Desk opens a forbidden dependency: {forbidden}");
|
||||||
"ksp-store-lib",
|
|
||||||
"ksp-store-api",
|
|
||||||
"ksp-store-postgres-lib",
|
|
||||||
"reqwest",
|
|
||||||
"tokio-postgres",
|
|
||||||
] {
|
|
||||||
assert!(!manifest.contains(forbidden), "pre.002 opens a later-layer dependency: {forbidden}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +88,7 @@ fn pre_002_tauri_commands_remain_centralized() {
|
|||||||
assert_eq!(count, 0, "{} declares a Tauri command outside tauri.rs", path.display());
|
assert_eq!(count, 0, "{} declares a Tauri command outside tauri.rs", path.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(command_count, 3);
|
assert_eq!(command_count, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -121,15 +114,21 @@ fn pre_002_frontend_instrumentation_avoids_business_or_secret_payloads() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_003_keeps_config_only_composition_boundary() {
|
fn pre_004_opens_only_config_logging_and_onchain_transport_dependencies() {
|
||||||
let root = app_root();
|
let root = app_root();
|
||||||
let manifest = read_text(root.join("Cargo.toml").as_path());
|
let manifest = read_text(root.join("Cargo.toml").as_path());
|
||||||
assert!(manifest.contains("ksp-config-lib = { path = \"../ksp-config-lib\" }"));
|
assert!(manifest.contains("ksp-config-lib = { path = \"../ksp-config-lib\" }"));
|
||||||
for forbidden in ["ksp-job-backfill-lib", "ksp-onchain-transport-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib"] {
|
assert!(manifest.contains("ksp-onchain-transport-lib = { path = \"../ksp-onchain-transport-lib\" }"));
|
||||||
assert!(!manifest.contains(forbidden), "pre.003 opens a later-layer dependency: {forbidden}");
|
for forbidden in ["ksp-job-backfill-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib"] {
|
||||||
|
assert!(!manifest.contains(forbidden), "pre.004 opens a later-layer dependency: {forbidden}");
|
||||||
}
|
}
|
||||||
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
|
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
|
||||||
assert!(bootstrap.contains("LogFilterLevel::Trace"));
|
assert!(bootstrap.contains("LogFilterLevel::Trace"));
|
||||||
assert!(!bootstrap.contains("HttpTransportPool"));
|
assert!(!bootstrap.contains("HttpTransportPool"));
|
||||||
assert!(!bootstrap.contains("Store::open"));
|
assert!(!bootstrap.contains("Store::open"));
|
||||||
|
let dto = read_text(root.join("src/dto_common.rs").as_path());
|
||||||
|
assert!(dto.contains("BackfillDeskOptionsDto"));
|
||||||
|
for forbidden in ["pub(crate) provider", "endpoint_url", "pub(crate) url", "pub(crate) credential", "pub(crate) token"] {
|
||||||
|
assert!(!dto.contains(forbidden), "Transport options DTO source contains forbidden field marker {forbidden}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
|
// file: crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
||||||
@@ -12,3 +12,23 @@ fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
|||||||
assert_eq!(dto.code, "failed");
|
assert_eq!(dto.code, "failed");
|
||||||
assert_eq!(dto.message, "safe message");
|
assert_eq!(dto.message, "safe message");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transport_options_projection_contains_only_safe_transport_metadata() {
|
||||||
|
let dto = crate::BackfillDeskOptionsDto {
|
||||||
|
compatible_roles: vec!["default".to_owned()],
|
||||||
|
configured_networks: vec!["devnet".to_owned()],
|
||||||
|
transport_diagnostic: std::option::Option::None,
|
||||||
|
transport_ready: true,
|
||||||
|
};
|
||||||
|
let value = serde_json::to_value(dto);
|
||||||
|
assert!(value.is_ok());
|
||||||
|
if let std::result::Result::Ok(value) = value {
|
||||||
|
let serialized = value.to_string();
|
||||||
|
assert!(serialized.contains("default"));
|
||||||
|
assert!(serialized.contains("devnet"));
|
||||||
|
assert!(!serialized.contains("provider"));
|
||||||
|
assert!(!serialized.contains("url"));
|
||||||
|
assert!(!serialized.contains("endpoint"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
101
crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs
Normal file
101
crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// file: crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
fn endpoint(
|
||||||
|
name: &str,
|
||||||
|
cluster: &str,
|
||||||
|
role_name: &str,
|
||||||
|
request_kinds: std::vec::Vec<ksp_onchain_transport_lib::HttpRequestKind>,
|
||||||
|
) -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpEndpointSettings> {
|
||||||
|
let url = ksp_onchain_transport_lib::HttpEndpointUrl::parse(format!("https://{name}.example.invalid"));
|
||||||
|
let url = match url {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let role = ksp_onchain_transport_lib::HttpEndpointRoleSettings::new(
|
||||||
|
ksp_onchain_transport_lib::HttpRoleName::new(role_name),
|
||||||
|
true,
|
||||||
|
request_kinds,
|
||||||
|
0,
|
||||||
|
ksp_onchain_transport_lib::HttpRoleLimits::new(
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
std::option::Option::None,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return std::result::Result::Ok(ksp_onchain_transport_lib::HttpEndpointSettings::new(
|
||||||
|
name,
|
||||||
|
true,
|
||||||
|
ksp_onchain_transport_lib::HttpProviderName::new("fixture"),
|
||||||
|
ksp_onchain_transport_lib::HttpClusterName::new(cluster),
|
||||||
|
url,
|
||||||
|
std::time::Duration::from_secs(1),
|
||||||
|
std::time::Duration::from_secs(2),
|
||||||
|
std::option::Option::Some(1),
|
||||||
|
vec![role],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pool(endpoints: std::vec::Vec<ksp_onchain_transport_lib::HttpEndpointSettings>) -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpTransportPool> {
|
||||||
|
let settings = ksp_onchain_transport_lib::HttpTransportSettings::new(
|
||||||
|
endpoints,
|
||||||
|
ksp_onchain_transport_lib::HttpRetrySettings::new(0, std::time::Duration::from_millis(10), std::time::Duration::from_millis(10)),
|
||||||
|
);
|
||||||
|
return ksp_onchain_transport_lib::HttpTransportPool::new(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_roles_require_both_backfill_rpc_methods() {
|
||||||
|
let signatures = ksp_onchain_transport_lib::find_http_rpc_method("getSignaturesForAddress");
|
||||||
|
let transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction");
|
||||||
|
assert!(signatures.is_some());
|
||||||
|
assert!(transaction.is_some());
|
||||||
|
let signatures = match signatures {
|
||||||
|
std::option::Option::Some(value) => ksp_onchain_transport_lib::HttpRequestKind::new(value.request_kind()),
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let transaction = match transaction {
|
||||||
|
std::option::Option::Some(value) => ksp_onchain_transport_lib::HttpRequestKind::new(value.request_kind()),
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let complete = endpoint("complete", "devnet", "complete", vec![signatures.clone(), transaction]);
|
||||||
|
let complete = match complete {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let partial = endpoint("partial", "devnet", "partial", vec![signatures]);
|
||||||
|
let partial = match partial {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let runtime_pool = pool(vec![complete, partial]);
|
||||||
|
assert!(runtime_pool.is_ok());
|
||||||
|
let runtime_pool = match runtime_pool {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let snapshot = runtime_pool.snapshot();
|
||||||
|
let roles = super::compatible_backfill_roles(&runtime_pool, &snapshot);
|
||||||
|
assert!(roles.is_ok());
|
||||||
|
if let std::result::Result::Ok(roles) = roles {
|
||||||
|
assert_eq!(roles, vec!["complete".to_owned()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn configured_networks_are_safe_sorted_and_deduplicated() {
|
||||||
|
let one = endpoint("one", "testnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
|
||||||
|
let two = endpoint("two", "devnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
|
||||||
|
let three = endpoint("three", "devnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
|
||||||
|
let (one, two, three) = match (one, two, three) {
|
||||||
|
(std::result::Result::Ok(one), std::result::Result::Ok(two), std::result::Result::Ok(three)) => (one, two, three),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let runtime_pool = pool(vec![one, two, three]);
|
||||||
|
assert!(runtime_pool.is_ok());
|
||||||
|
if let std::result::Result::Ok(runtime_pool) = runtime_pool {
|
||||||
|
let values = super::configured_networks(&runtime_pool.snapshot());
|
||||||
|
assert_eq!(values, vec!["devnet".to_owned(), "testnet".to_owned()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
123
deltas/0.3.7/pre.004.md
Normal file
123
deltas/0.3.7/pre.004.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<!-- file: deltas/0.3.7/pre.004.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.3.7-pre.004` — Transport readiness de Backfill Desk
|
||||||
|
|
||||||
|
## 1. Base requise
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.3.7-pre.003-fix.001
|
||||||
|
workspace.package.version = 0.3.7-pre.3.fix.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Le replay opérateur de `pre.003-fix.001` est propre : audits Rust/Markdown, `cargo check --workspace`, Clippy, suites Config/Config Desk/Wallet Desk/SOL Prices Desk/Backfill Desk et arbres de dépendances Backfill Desk ne rapportent plus d'échec.
|
||||||
|
|
||||||
|
## 2. Objectif
|
||||||
|
|
||||||
|
Ouvrir uniquement la readiness HTTP Transport de Backfill Desk : résoudre le profil Transport sélectionné par le composite, construire `HttpTransportPool`, dériver des métadonnées réseau/rôle sûres, vérifier que chaque rôle exposé sait router `getSignaturesForAddress` et `getTransaction`, puis offrir cette readiness via IPC sans ouvrir Store ni Job Backfill.
|
||||||
|
|
||||||
|
## 3. Implémentation
|
||||||
|
|
||||||
|
- ajouter la dépendance backend `ksp-onchain-transport-lib` à `ksp-app-backfill-desk` ;
|
||||||
|
- créer `transport_runtime.rs`, propriétaire du pool HTTP et de la dérivation de readiness ;
|
||||||
|
- collecter uniquement les labels de cluster des endpoints HTTP activés, sans URL ni provider ;
|
||||||
|
- dédupliquer les rôles logiques à partir des snapshots sûrs Transport ;
|
||||||
|
- ne conserver comme rôles compatibles que ceux pour lesquels `select_for_method()` réussit sur `getSignaturesForAddress` et `getTransaction` ;
|
||||||
|
- considérer Transport ready uniquement avec un réseau distinct, au moins un rôle compatible et au moins un endpoint actuellement disponible ;
|
||||||
|
- conserver le shell ouvrable lorsqu'une erreur Config/Transport empêche la construction du pool, en projetant uniquement un `CommandErrorDto` sûr ;
|
||||||
|
- introduire `BackfillDeskOptionsDto` comme sous-contrat Transport du futur DTO complet et centraliser la commande Tauri `backfill_options` ;
|
||||||
|
- maintenir les capabilities Tauri à `core:default + tracing:default` et le niveau de développement Backfill à `supertrace` / fallback `trace`.
|
||||||
|
|
||||||
|
Le DTO complet avec commitments, scopes et bornes reste réservé à `pre.006`. `pre.004` n'ajoute aucune dépendance Store ou Job.
|
||||||
|
|
||||||
|
## 4. Version
|
||||||
|
|
||||||
|
Cette tranche modifie du code/runtime et ajoute une dépendance fonctionnelle. Conformément à `VER-ID-009` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = 0.3.7-pre.4
|
||||||
|
label = 0.3.7-pre.004
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Fichiers ajoutés
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-app-backfill-desk/src/transport_runtime.rs
|
||||||
|
crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs
|
||||||
|
deltas/0.3.7/pre.004.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Fichiers modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-app-backfill-desk/Cargo.toml
|
||||||
|
crates/ksp-app-backfill-desk/src/app_state.rs
|
||||||
|
crates/ksp-app-backfill-desk/src/constants.rs
|
||||||
|
crates/ksp-app-backfill-desk/src/dto_common.rs
|
||||||
|
crates/ksp-app-backfill-desk/src/errors.rs
|
||||||
|
crates/ksp-app-backfill-desk/src/lib.rs
|
||||||
|
crates/ksp-app-backfill-desk/src/tauri.rs
|
||||||
|
crates/ksp-app-backfill-desk/tests/config_composition.rs
|
||||||
|
crates/ksp-app-backfill-desk/tests/desktop_contract.rs
|
||||||
|
crates/ksp-app-backfill-desk/tests/desktop_security.rs
|
||||||
|
crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
|
||||||
|
docs/plans/028-V0_3_7_BACKFILL_DESK_PLAN.md
|
||||||
|
docs/validation/024-V0_3_7_BACKFILL_DESK.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Fichiers supprimés
|
||||||
|
|
||||||
|
Aucun.
|
||||||
|
|
||||||
|
## 8. Invariants conservés
|
||||||
|
|
||||||
|
- Config reste l'unique propriétaire du choix de profil et des secrets/URLs physiques ;
|
||||||
|
- Transport reste propriétaire du pool, du routage, retry, pacing, rate-limit et choix physique d'endpoint ;
|
||||||
|
- aucun provider, URL, endpoint physique ou credential n'est sérialisé dans `BackfillDeskOptionsDto` ;
|
||||||
|
- aucun rôle `history_backfill` n'est hardcodé ; les rôles proviennent des snapshots Transport ;
|
||||||
|
- aucune dépendance `ksp-store-lib`, `ksp-store-api`, `ksp-store-postgres-lib` ou `ksp-job-backfill-lib` n'est ouverte ;
|
||||||
|
- aucun `Store::open`, `BackfillRequest`, `BackfillJobRuntime` ou checkpoint n'est introduit ;
|
||||||
|
- le frontend garde son gabarit, ses dependencies et son instrumentation de clics/tabs inchangés ;
|
||||||
|
- le tracing de développement reste `supertrace` via Config devnet et `trace` en fallback Backfill Desk.
|
||||||
|
|
||||||
|
## 9. Validations exécutées dans l'environnement d'assemblage
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.3.7
|
||||||
|
```
|
||||||
|
|
||||||
|
Contrôles ciblés supplémentaires :
|
||||||
|
|
||||||
|
- parse du manifeste Cargo modifié ;
|
||||||
|
- vérification de la frontière de dépendances Backfill Desk ;
|
||||||
|
- vérification du composite `devnet -> devnet_public` ;
|
||||||
|
- vérification que `devnet_public`, `mainnet_public` et `publicnode_testnet` utilisent chacun un cluster unique et le rôle logique `default` wildcard ;
|
||||||
|
- vérification que le DTO Transport ne projette aucun champ provider/URL/credential ;
|
||||||
|
- vérification que les capabilities Tauri restent inchangées.
|
||||||
|
|
||||||
|
## 10. Validations non exécutées dans l'environnement d'assemblage
|
||||||
|
|
||||||
|
`cargo` et `rustfmt` ne sont pas disponibles dans cet environnement. Le gate opérateur `pre.004` reste à exécuter :
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.3.7
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
cargo test -p ksp-app-backfill-desk
|
||||||
|
cargo tree -p ksp-app-backfill-desk --edges normal
|
||||||
|
cargo tree -p ksp-app-backfill-desk -e features
|
||||||
|
```
|
||||||
|
|
||||||
|
## 11. Décisions
|
||||||
|
|
||||||
|
`BackfillDeskOptionsDto` est introduit progressivement : `pre.004` possède uniquement la readiness Transport ; `pre.005` ajoutera la cohérence Store/réseau et `pre.006` ajoutera les paramètres de campagne. Cette progression évite d'ajouter `ksp-job-backfill-lib` avant sa tranche dédiée.
|
||||||
|
|
||||||
|
La construction Transport ne rend pas le shell inutilisable lorsqu'elle échoue. L'AppState conserve alors seulement un diagnostic applicatif sûr et `backfill_options` retourne `transport_ready = false`. Une composition HTTP multi-cluster est également non-ready afin de préparer la vérification stricte Store/Transport de `pre.005`.
|
||||||
|
|
||||||
|
## 12. Questions ouvertes
|
||||||
|
|
||||||
|
Aucune.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/028-V0_3_7_BACKFILL_DESK_PLAN.md -->
|
<!-- file: docs/plans/028-V0_3_7_BACKFILL_DESK_PLAN.md -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
|
|
||||||
# Plan v0.3.7 — Backfill Desk
|
# Plan v0.3.7 — Backfill Desk
|
||||||
|
|
||||||
@@ -239,9 +239,11 @@ Ajouter le composite Backfill Desk et l'enregistrer dans Config, mettre à jour
|
|||||||
|
|
||||||
Le gate opérateur de `pre.003` ouvre `pre.003-fix.001` pour quatre corrections strictement locales : ordre `RUST-FMT-104` d'un bloc de constantes, `return` explicite dans un canari Clippy, réconciliation de la fixture composite Backfill avec les profils réellement disponibles dans le corpus de fixtures Config, et correction d'un canari de dépendance qui doit reconnaître la syntaxe `path` utilisée par les crates KSP internes. Le composite de production, son profil `supertrace` et les frontières runtime de `pre.003` restent inchangés.
|
Le gate opérateur de `pre.003` ouvre `pre.003-fix.001` pour quatre corrections strictement locales : ordre `RUST-FMT-104` d'un bloc de constantes, `return` explicite dans un canari Clippy, réconciliation de la fixture composite Backfill avec les profils réellement disponibles dans le corpus de fixtures Config, et correction d'un canari de dépendance qui doit reconnaître la syntaxe `path` utilisée par les crates KSP internes. Le composite de production, son profil `supertrace` et les frontières runtime de `pre.003` restent inchangés.
|
||||||
|
|
||||||
|
Le replay opérateur de `pre.003-fix.001` est ensuite intégralement propre : audits Rust/Markdown, `cargo check`, Clippy, suites Config/Config Desk/Wallet Desk/SOL Prices Desk/Backfill Desk et arbres de dépendances Backfill. Ce gate ouvre `pre.004`.
|
||||||
|
|
||||||
### pre.004 — Transport readiness
|
### pre.004 — Transport readiness
|
||||||
|
|
||||||
Construire `HttpTransportPool`, dériver réseau/role inventory sûr, vérifier support des deux RPC et produire options DTO sans provider/URL.
|
Construire `HttpTransportPool`, dériver l'inventaire sûr des réseaux/rôles, vérifier le support simultané de `getSignaturesForAddress` et `getTransaction`, puis exposer `backfill_options()` sans provider, endpoint physique ni URL. `BackfillDeskOptionsDto` apparaît ici comme sous-contrat Transport seulement (`configured_networks`, rôles compatibles, diagnostic sûr, readiness) ; `pre.006` l'étendra avec commitments, scopes et bornes plutôt que d'ouvrir prématurément `ksp-job-backfill-lib`. Une composition Transport avec plusieurs clusters HTTP actifs ou sans rôle compatible reste non-ready. Une erreur de résolution/construction Transport est conservée comme diagnostic sûr afin que le shell puisse rester ouvrable.
|
||||||
|
|
||||||
### pre.005 — Store readiness
|
### pre.005 — Store readiness
|
||||||
|
|
||||||
@@ -249,7 +251,7 @@ Ouvrir `ksp-store-lib::Store`, vérifier réseau Store/Transport avant run, life
|
|||||||
|
|
||||||
### pre.006 — DTO/request mapping
|
### pre.006 — DTO/request mapping
|
||||||
|
|
||||||
DTO TS-RS app-owned, quatre scopes, commitments, min context slot, bornes backend-owned, signatures hostiles et validation de rôle/réseau.
|
Compléter les DTO TS-RS app-owned commencés par le sous-contrat Transport de `pre.004` : quatre scopes, commitments, min context slot, bornes backend-owned, signatures hostiles et validation de rôle/réseau.
|
||||||
|
|
||||||
### pre.007 — runtime + Start
|
### pre.007 — runtime + Start
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/024-V0_3_7_BACKFILL_DESK.md -->
|
<!-- file: docs/validation/024-V0_3_7_BACKFILL_DESK.md -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
|
|
||||||
# Validation v0.3.7 — Backfill Desk
|
# Validation v0.3.7 — Backfill Desk
|
||||||
|
|
||||||
@@ -92,11 +92,11 @@ Le journal opérateur fourni rapporte `cargo clean`, `cargo fmt`, audits Rust/Ma
|
|||||||
|
|
||||||
## 8. Gates futures
|
## 8. Gates futures
|
||||||
|
|
||||||
- [ ] Package Rust lib + bin conforme.
|
- [X] Package Rust lib + bin conforme.
|
||||||
- [ ] Ports Vite/HMR 1436/1437 stricts.
|
- [X] Ports Vite/HMR 1436/1437 stricts.
|
||||||
- [ ] Splash/main + tracing conformes.
|
- [X] Splash/main + tracing conformes.
|
||||||
- [X] Composite Backfill Desk packagé et valide.
|
- [X] Composite Backfill Desk packagé et valide.
|
||||||
- [ ] Transport readiness et role inventory sûrs.
|
- [X] Transport readiness et role inventory sûrs.
|
||||||
- [ ] Store readiness et cohérence réseau.
|
- [ ] Store readiness et cohérence réseau.
|
||||||
- [ ] Quatre scopes + commitments + bornes mappés.
|
- [ ] Quatre scopes + commitments + bornes mappés.
|
||||||
- [ ] Single active run + Start.
|
- [ ] Single active run + Start.
|
||||||
@@ -196,5 +196,31 @@ cargo test -p ksp-app-backfill-desk FAIL — canari Ca
|
|||||||
### Gate du fix
|
### Gate du fix
|
||||||
|
|
||||||
- [X] audits statiques Rust/Markdown rejoués dans l'environnement d'assemblage ;
|
- [X] audits statiques Rust/Markdown rejoués dans l'environnement d'assemblage ;
|
||||||
- [ ] `cargo fmt --all`, `cargo check --workspace`, Clippy et suites Cargo à rejouer par l'opérateur ; `cargo`/`rustfmt` restent absents du sandbox.
|
- [X] replay opérateur du 2026-09-02 : audits Rust/Markdown propres, `cargo check --workspace` propre, Clippy propre ;
|
||||||
|
- [X] `cargo test -p ksp-config-lib` : 128 tests unitaires + suites ownership/public API, aucun échec ;
|
||||||
|
- [X] `cargo test -p ksp-app-config-desk` : 63 tests unitaires + desktop/security/public API, aucun échec ;
|
||||||
|
- [X] `cargo test -p ksp-app-wallet-desk` et `cargo test -p ksp-app-solprices-desk` : suites ciblées propres ;
|
||||||
|
- [X] `cargo test -p ksp-app-backfill-desk` : 13 unitaires + 2 composition + 7 desktop contract + 5 desktop security + 1 public API, aucun échec ;
|
||||||
|
- [X] arbres `cargo tree` Backfill Desk exécutés sans anomalie rapportée.
|
||||||
|
|
||||||
|
## 12. `pre.004` — Transport readiness
|
||||||
|
|
||||||
|
Backfill Desk dépend désormais directement de `ksp-onchain-transport-lib` au niveau backend uniquement. `initialize_transport()` résout le profil Transport déjà sélectionné par le composite, construit `HttpTransportPool`, dérive les clusters HTTP activés et déduplique les rôles logiques à partir des snapshots sûrs. Chaque rôle candidat doit réussir `select_for_method()` pour `getSignaturesForAddress` **et** `getTransaction` avant d'être exposé comme compatible.
|
||||||
|
|
||||||
|
Le sous-contrat `BackfillDeskOptionsDto` expose uniquement : réseaux configurés, rôles compatibles, readiness Transport et diagnostic applicatif sûr. Il ne contient ni provider, URL, endpoint physique, token, checkpoint, payload RAW ou objet Transport. La commande Tauri `backfill_options` est centralisée dans `tauri.rs`. Les scopes, commitments et bornes restent hors de cette tranche et seront ajoutés en `pre.006`.
|
||||||
|
|
||||||
|
Une seule network distincte et au moins un rôle compatible sont requis pour `transport_ready = true`. Une erreur Config/Transport n'empêche pas le shell de démarrer : elle produit une options projection non-ready avec `CommandErrorDto`, tandis que le pool n'est pas conservé. La cohérence avec le réseau Store reste explicitement réservée à `pre.005`.
|
||||||
|
|
||||||
|
### Gate statique local `pre.004`
|
||||||
|
|
||||||
|
- [X] dépendance `ksp-onchain-transport-lib` ajoutée à Backfill Desk ;
|
||||||
|
- [X] aucune dépendance `ksp-store-lib`, `ksp-store-api`, `ksp-store-postgres-lib` ou `ksp-job-backfill-lib` ajoutée ;
|
||||||
|
- [X] `HttpTransportPool` construit uniquement dans `transport_runtime.rs`, pas dans le bootstrap Config/Logging ;
|
||||||
|
- [X] inventaire des clusters dérivé sans URL/provider ;
|
||||||
|
- [X] rôles candidats dédupliqués et vérifiés sur les deux RPC requis ;
|
||||||
|
- [X] le profil standard `devnet_public` possède un unique cluster `devnet` et le rôle wildcard `default` ;
|
||||||
|
- [X] capabilities Tauri inchangées : `core:default + tracing:default` ;
|
||||||
|
- [X] tracing de développement Backfill inchangé : Config `supertrace`, fallback `trace` ;
|
||||||
|
- [X] audit Rust workspace local propre, zéro candidat d'export ;
|
||||||
|
- [ ] `cargo fmt/check/clippy/test` de `pre.004` à rejouer par l'opérateur ; `cargo`/`rustfmt` restent absents du sandbox.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user