v0.2.6-pre.003-fix.002

This commit is contained in:
2026-08-20 21:33:46 +02:00
parent 0e72914237
commit 3fa4ab251a
13 changed files with 652 additions and 81 deletions

View File

@@ -6,7 +6,7 @@ resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
[workspace.package]
version = "0.2.6-pre.3.fix.1"
version = "0.2.6-pre.3.fix.2"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md -->
<!-- version: 60 -->
<!-- version: 61 -->
# Roadmap KSP
@@ -50,7 +50,7 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
- [X] `0.2.3` — HTTP Transactions stable : 11/11 wrappers typés publiés, classification `8 Read / 2 WriteSubmission / 1 Simulation`, no-resend ambigu prouvé pour les write submissions, `KSP-TRANSPORT-007` réaudité conforme sur les 37 wrappers HTTP courants, graphes Cargo et deux smokes Devnet validés ; `0.2.4` reprend les 15 Blocks/Economics restants.
- [X] `0.2.4` — HTTP Blocks + Economics stable : 15/15 wrappers `V0_2_4` publiés, surface typed complète à 52/52 méthodes courantes, 14/14 historiques conservées, réaudit SIMD/inventaire final et `KSP-TRANSPORT-007` global validés ; deux smokes Devnet passés avant publication.
- [X] `0.2.5` — Wallet foundation stable : `.kspwallet` V1, VIEW/OWNER indépendants, Argon2id/XChaCha20-Poly1305, autorité Ed25519 OWNER, persistence no-clobber, signature, administration/rotations/révocation VIEW forte, import/export Solana CLI JSON + Base58, canaris adversariaux, interop externe et documentation durable publiés. La clôture `pre.010-fix.001``fix.003` ajoute `ed25519-dalek 3.0.0` direct, normalise le Rust workspace et installe laudit structurel Python complémentaire à rustfmt/Clippy. `Pubkey` reste via `ksp-core-lib`, la keypair reste encapsulée dans Wallet et Config/Transport/ExecutionPolicy/Store/Tauri restent hors Wallet.
- [ ] `0.2.6` — Introduire `ksp-app-wallet-desk` utilisant Config composite + Wallet + transport HTTP. `pre.001` fixe le sizing et le gabarit ; `pre.002` matérialise la crate Tauri et son shell splash/main avec Config + Logging bootstrap, ports `1432/1433`, Bootstrap, Font Awesome, DataTables/Select, SimpleBar, resize-observer-polyfill, TS-RS et bridge frontend Logging. `pre.003` matérialise `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, `ResolvedWalletConfig`, `wallets_directory` global + `wallets_subdirectory` par profil et la préparation automatique des répertoires côté application avec logs debug/error. `pre.003-fix.001` corrige les canaris Config révélés par les tests workspace, rend le composite explicite sur un profil Logging `wallet_desk_dev` et active la visibilité trace des interactions frontend Wallet Desk sans exposer les valeurs de contrôles. Les tranches suivantes ajoutent inventory, lifecycle VIEW/OWNER, secrets `KSP_SECRET_WALLET_PASS_*`, identité autorisée + `getBalance`, puis administration/import/export, avec une dernière tranche prévue pour README/USAGE/docs/validation, prompt `0.2.7` et build Tauri final.
- [ ] `0.2.6` — Introduire `ksp-app-wallet-desk` utilisant Config composite + Wallet + transport HTTP. `pre.001` fixe le sizing et le gabarit ; `pre.002` matérialise la crate Tauri et son shell splash/main avec Config + Logging bootstrap, ports `1432/1433`, Bootstrap, Font Awesome, DataTables/Select, SimpleBar, resize-observer-polyfill, TS-RS et bridge frontend Logging. `pre.003` matérialise `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, `ResolvedWalletConfig`, `wallets_directory` global + `wallets_subdirectory` par profil et la préparation automatique des répertoires côté application avec logs debug/error. `pre.003-fix.001` corrige les premiers canaris Config et active la trace des interactions frontend sans valeur de contrôle. `pre.003-fix.002` corrige le scanner `.env.example` sur les fragments didentifiants Rust, généralise `std.logging` avec les profils console-only, `file_info`, `superdev` et `supertrace`, et sélectionne temporairement `supertrace` dans le composite Wallet Desk. Les tranches suivantes ajoutent inventory, lifecycle VIEW/OWNER, secrets `KSP_SECRET_WALLET_PASS_*`, identité autorisée + `getBalance`, puis administration/import/export, avec une dernière tranche prévue pour README/USAGE/docs/validation, prompt `0.2.7` et build Tauri final.
- [ ] `0.2.7` — Étendre `ksp-onchain-transport-lib` au WebSocket Solana standard complet ; permettre plusieurs sessions sur une même URL sans imposer encore un pool automatique complexe.
- [ ] `0.2.8` — Ajouter Helius LaserStream WebSocket comme extension du moteur WebSocket standard, sans duplication de client.
- [ ] `0.2.9` — Ajouter une première fondation Yellowstone gRPC standard/provider-neutral ; dimensionner la surface exacte à `pre.001` selon la documentation normative actuelle.

View File

@@ -8,7 +8,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",
@@ -28,7 +28,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",
@@ -48,7 +48,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",

View File

@@ -8,7 +8,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",
@@ -28,7 +28,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",
@@ -48,7 +48,7 @@
{
"component_id": "logging",
"file_id": "cfg.std.logging",
"profile_id": "wallet_desk_dev"
"profile_id": "supertrace"
},
{
"component_id": "transport",

View File

@@ -3,6 +3,156 @@
"logs_directory": "${KSP_LOGS_DIRECTORY:-logs}",
"default_profile": "local_dev",
"profiles": [
{
"profile_id": "console_error",
"default_filter": "error",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "error",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [],
"target_filters": []
},
{
"profile_id": "console_warn",
"default_filter": "warn",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "warn",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [],
"target_filters": []
},
{
"profile_id": "console_info",
"default_filter": "info",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "info",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [],
"target_filters": []
},
{
"profile_id": "console_debug",
"default_filter": "debug",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "debug",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [],
"target_filters": []
},
{
"profile_id": "console_trace",
"default_filter": "trace",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "trace",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [],
"target_filters": []
},
{
"profile_id": "file_info",
"default_filter": "info",
"span_events": "new_and_close",
"console": {
"enabled": false,
"output": "stderr",
"ansi": false,
"format": "compact",
"filter": {
"level": "off",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [
{
"output_id": "file.all.info",
"enabled": true,
"path": "info/ksp-info.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "info",
"targets": [
"*"
],
"domains": [
"*"
]
}
}
],
"target_filters": []
},
{
"profile_id": "local_dev",
"default_filter": "warn",
@@ -95,8 +245,8 @@
]
},
{
"profile_id": "wallet_desk_dev",
"default_filter": "info",
"profile_id": "superdev",
"default_filter": "debug",
"span_events": "new_and_close",
"console": {
"enabled": true,
@@ -104,9 +254,9 @@
"ansi": true,
"format": "compact",
"filter": {
"level": "trace",
"level": "debug",
"targets": [
"ksp-app-wallet-desk"
"*"
],
"domains": [
"*"
@@ -115,16 +265,16 @@
},
"files": [
{
"output_id": "file.all.info",
"output_id": "file.ksp_app_config_desk.debug",
"enabled": true,
"path": "info/ksp-info.log",
"path": "targets/debug/ksp-app-config-desk.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "info",
"level": "debug",
"targets": [
"*"
"ksp-app-config-desk"
],
"domains": [
"*"
@@ -132,14 +282,14 @@
}
},
{
"output_id": "file.wallet_desk.trace",
"output_id": "file.ksp_app_wallet_desk.debug",
"enabled": true,
"path": "wallet-desk/ksp-app-wallet-desk.log",
"path": "targets/debug/ksp-app-wallet-desk.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"level": "debug",
"targets": [
"ksp-app-wallet-desk"
],
@@ -149,14 +299,65 @@
}
},
{
"output_id": "file.onchain_transport.info",
"output_id": "file.ksp_config_lib.debug",
"enabled": true,
"path": "transport/onchain/ksp-onchain-transport.log",
"path": "targets/debug/ksp-config-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "info",
"level": "debug",
"targets": [
"ksp-config-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_core_lib.debug",
"enabled": true,
"path": "targets/debug/ksp-core-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "debug",
"targets": [
"ksp-core-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_logging_lib.debug",
"enabled": true,
"path": "targets/debug/ksp-logging-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "debug",
"targets": [
"ksp-logging-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_onchain_transport_lib.debug",
"enabled": true,
"path": "targets/debug/ksp-onchain-transport-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "debug",
"targets": [
"ksp-onchain-transport-lib"
],
@@ -166,45 +367,166 @@
}
},
{
"output_id": "file.config.error",
"output_id": "file.ksp_wallet_lib.debug",
"enabled": true,
"path": "config/ksp-config-errors.jsonl",
"path": "targets/debug/ksp-wallet-lib.log",
"rotation": "daily",
"format": "json",
"format": "human",
"ansi": false,
"filter": {
"level": "error",
"level": "debug",
"targets": [
"ksp-wallet-lib"
],
"domains": [
"*"
]
}
}
],
"target_filters": []
},
{
"profile_id": "supertrace",
"default_filter": "trace",
"span_events": "new_and_close",
"console": {
"enabled": true,
"output": "stderr",
"ansi": true,
"format": "compact",
"filter": {
"level": "debug",
"targets": [
"*"
],
"domains": [
"*"
]
}
},
"files": [
{
"output_id": "file.ksp_app_config_desk.trace",
"enabled": true,
"path": "targets/trace/ksp-app-config-desk.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-app-config-desk"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_app_wallet_desk.trace",
"enabled": true,
"path": "targets/trace/ksp-app-wallet-desk.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-app-wallet-desk"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_config_lib.trace",
"enabled": true,
"path": "targets/trace/ksp-config-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-config-lib"
],
"domains": [
"config"
"*"
]
}
},
{
"output_id": "file.ksp_core_lib.trace",
"enabled": true,
"path": "targets/trace/ksp-core-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-core-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_logging_lib.trace",
"enabled": true,
"path": "targets/trace/ksp-logging-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-logging-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_onchain_transport_lib.trace",
"enabled": true,
"path": "targets/trace/ksp-onchain-transport-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-onchain-transport-lib"
],
"domains": [
"*"
]
}
},
{
"output_id": "file.ksp_wallet_lib.trace",
"enabled": true,
"path": "targets/trace/ksp-wallet-lib.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"filter": {
"level": "trace",
"targets": [
"ksp-wallet-lib"
],
"domains": [
"*"
]
}
}
],
"target_filters": [
{
"target_prefix": "ksp-app-config-desk",
"level": "info"
},
{
"target_prefix": "ksp-app-wallet-desk",
"level": "trace"
},
{
"target_prefix": "ksp-config-lib",
"level": "info"
},
{
"target_prefix": "ksp-logging-lib",
"level": "info"
},
{
"target_prefix": "ksp-onchain-transport-lib",
"level": "info"
}
]
"target_filters": []
}
]
}

View File

@@ -1,7 +1,7 @@
{
"name": "ksp-app-wallet-desk",
"private": true,
"version": "0.2.6-pre.3.fix.1",
"version": "0.2.6-pre.3.fix.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "KSP Wallet Desk",
"version": "0.2.6-pre.3.fix.1",
"version": "0.2.6-pre.3.fix.2",
"identifier": "com.sasedev.ksp-app-wallet-desk",
"build": {
"beforeDevCommand": "npm run dev",

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-wallet-desk/tests/config_composition.rs
// version: 2
// version: 3
//! Config composition contracts introduced for Wallet Desk pre.003.
@@ -29,8 +29,8 @@ fn wallet_desk_composite_selects_logging_transport_and_wallet_by_file_id() {
assert!(composite.is_ok(), "committed Wallet Desk composite should resolve: {composite:?}");
if let std::result::Result::Ok(composite) = composite {
assert_eq!(composite.profile_id(), "devnet");
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "wallet_desk_dev");
assert_wallet_desk_logging_trace_profile(&composite);
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "supertrace");
assert_wallet_desk_supertrace_profile(&composite);
assert_component(&composite, "transport", ksp_config_lib::FILE_ID_STD_TRANSPORT, "devnet_public");
assert_component(&composite, "wallet", ksp_config_lib::FILE_ID_STD_WALLET, "default");
}
@@ -38,12 +38,12 @@ fn wallet_desk_composite_selects_logging_transport_and_wallet_by_file_id() {
}
}
fn assert_wallet_desk_logging_trace_profile(composite: &ksp_config_lib::ResolvedConfigComposite) {
fn assert_wallet_desk_supertrace_profile(composite: &ksp_config_lib::ResolvedConfigComposite) {
let component = composite.component("logging");
assert!(component.is_some(), "missing logging component");
if let std::option::Option::Some(component) = component {
let profile = component.resolved().profile();
assert_eq!(profile.get("default_filter").and_then(serde_json::Value::as_str), std::option::Option::Some("info"));
assert_eq!(profile.get("default_filter").and_then(serde_json::Value::as_str), std::option::Option::Some("trace"));
let console = profile.get("console").and_then(serde_json::Value::as_object);
let console_filter = console
.and_then(|value| {
@@ -55,26 +55,39 @@ fn assert_wallet_desk_logging_trace_profile(composite: &ksp_config_lib::Resolved
return value.get("level");
})
.and_then(serde_json::Value::as_str);
assert_eq!(console_level, std::option::Option::Some("trace"));
let targets = console_filter
assert_eq!(console_level, std::option::Option::Some("debug"));
let console_targets = console_filter
.and_then(|value| {
return value.get("targets");
})
.and_then(serde_json::Value::as_array);
assert!(targets.is_some(), "Wallet Desk console targets should exist");
if let std::option::Option::Some(targets) = targets {
assert!(targets.iter().any(|target| -> bool {
return target.as_str() == std::option::Option::Some("ksp-app-wallet-desk");
}));
assert_eq!(console_targets.and_then(|value| value.first()).and_then(serde_json::Value::as_str), std::option::Option::Some("*"));
let files = profile.get("files").and_then(serde_json::Value::as_array);
assert_eq!(files.map(std::vec::Vec::len), std::option::Option::Some(7));
if let std::option::Option::Some(files) = files {
for target in [
"ksp-app-config-desk",
"ksp-app-wallet-desk",
"ksp-config-lib",
"ksp-core-lib",
"ksp-logging-lib",
"ksp-onchain-transport-lib",
"ksp-wallet-lib",
] {
assert!(
files.iter().any(|file| -> bool {
let filter = file.get("filter");
let level = filter.and_then(|value| value.get("level")).and_then(serde_json::Value::as_str);
let targets = filter.and_then(|value| value.get("targets")).and_then(serde_json::Value::as_array);
return level == std::option::Option::Some("trace")
&& targets.is_some_and(|targets| targets.iter().any(|value| value.as_str() == std::option::Option::Some(target)));
}),
"supertrace should contain one trace file sink for target {target}"
);
}
}
let target_filters = profile.get("target_filters").and_then(serde_json::Value::as_array);
assert!(target_filters.is_some(), "Wallet Desk target filters should exist");
if let std::option::Option::Some(target_filters) = target_filters {
assert!(target_filters.iter().any(|filter| -> bool {
return filter.get("target_prefix").and_then(serde_json::Value::as_str) == std::option::Option::Some("ksp-app-wallet-desk")
&& filter.get("level").and_then(serde_json::Value::as_str) == std::option::Option::Some("trace");
}));
}
assert!(target_filters.is_some_and(std::vec::Vec::is_empty), "supertrace should rely on the global trace takeover instead of per-target overrides");
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/tests/ownership.rs
// version: 4
// version: 5
//! Workspace ownership audits for KSP application configuration boundaries.
@@ -81,6 +81,10 @@ fn collect_environment_names(source: &str, names: &mut std::collections::BTreeSe
index += 1;
continue;
};
if !environment_name_start_boundary(bytes, index) {
index += 1;
continue;
}
let mut end = index + prefix_length;
while end < bytes.len() {
let byte = bytes[end];
@@ -94,6 +98,7 @@ fn collect_environment_names(source: &str, names: &mut std::collections::BTreeSe
if let std::result::Result::Ok(candidate) = candidate
&& candidate.len() > prefix_length
&& !candidate.ends_with('_')
&& environment_name_end_boundary(bytes, end)
&& !is_environment_namespace_label(candidate)
{
names.insert(candidate.to_owned());
@@ -106,6 +111,22 @@ fn is_environment_namespace_label(candidate: &str) -> bool {
return matches!(candidate, "KSP_PUBLIC" | "KSP_SECRET" | "KSPB_PUBLIC" | "KSPB_SECRET");
}
fn environment_name_end_boundary(bytes: &[u8], end: usize) -> bool {
if end >= bytes.len() {
return true;
}
let next = bytes[end];
return !next.is_ascii_alphanumeric() && next != b'_';
}
fn environment_name_start_boundary(bytes: &[u8], index: usize) -> bool {
if index == 0 {
return true;
}
let previous = bytes[index - 1];
return !previous.is_ascii_alphanumeric() && previous != b'_';
}
fn dotenv_example_assignments(source: &str) -> std::collections::BTreeMap<String, usize> {
let mut assignments = std::collections::BTreeMap::<String, usize>::new();
for (line_index, line) in source.lines().enumerate() {
@@ -267,6 +288,8 @@ fn environment_name_scanner_ignores_namespace_labels_but_keeps_concrete_names()
const KSP_SECRET_API_KEY: &str = "KSP_SECRET_API_KEY";
const KSPB_PUBLIC_ENDPOINT: &str = "KSPB_PUBLIC_ENDPOINT";
const KSPB_SECRET_TOKEN: &str = "KSPB_SECRET_TOKEN";
const FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK: &str = "cfg.composite.ksp-app-wallet-desk";
const KSP_PUBLIC_RPC_URL_SUFFIXED: &str = "not-an-env";
"#;
let mut names = std::collections::BTreeSet::<String>::new();
collect_environment_names(source, &mut names);
@@ -278,6 +301,8 @@ fn environment_name_scanner_ignores_namespace_labels_but_keeps_concrete_names()
assert!(names.contains("KSP_SECRET_API_KEY"));
assert!(names.contains("KSPB_PUBLIC_ENDPOINT"));
assert!(names.contains("KSPB_SECRET_TOKEN"));
assert!(!names.contains("KSP_APP_WALLET_DESK"));
assert!(!names.contains("KSP_PUBLIC_RPC_URL_SUFFIXED"));
}
#[test]

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/unit_tests/document.rs
// version: 4
// version: 5
#[test]
fn committed_logging_document_passes_registered_schema_and_semantic_validation() {
@@ -32,6 +32,63 @@ fn committed_logging_document_passes_registered_schema_and_semantic_validation()
}
}
#[test]
fn committed_logging_document_exposes_reusable_operational_profiles() {
let workspace = workspace_root();
let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
let registry = crate::ConfigFileRegistry::defaults();
let file_id = crate::ConfigFileId::new(crate::FILE_ID_STD_LOGGING);
assert!(bootstrap.is_ok(), "workspace Config paths should be valid: {bootstrap:?}");
assert!(registry.is_ok(), "default registry should be valid: {registry:?}");
assert!(file_id.is_ok(), "logging file_id should be valid: {file_id:?}");
if let (std::result::Result::Ok(bootstrap), std::result::Result::Ok(registry), std::result::Result::Ok(file_id)) = (bootstrap, registry, file_id) {
let engine = crate::ConfigDocumentEngine::new(bootstrap, registry);
let document = engine.load_validated_document(&file_id);
assert!(document.is_ok(), "committed std.logging.json should validate: {document:?}");
if let std::result::Result::Ok(document) = document {
let profiles = document.value().get("profiles").and_then(serde_json::Value::as_array);
assert!(profiles.is_some(), "validated Logging document should retain profiles");
if let std::option::Option::Some(profiles) = profiles {
for profile_id in
["console_error", "console_warn", "console_info", "console_debug", "console_trace", "file_info", "local_dev", "superdev", "supertrace"]
{
assert!(
profiles.iter().any(|profile| -> bool {
return profile.get("profile_id").and_then(serde_json::Value::as_str) == std::option::Option::Some(profile_id);
}),
"committed Logging document is missing profile {profile_id}"
);
}
assert_super_profile(profiles, "superdev", "debug");
assert_super_profile(profiles, "supertrace", "trace");
}
}
}
}
fn assert_super_profile(profiles: &[serde_json::Value], profile_id: &str, file_level: &str) {
let profile = profiles.iter().find(|profile| -> bool {
return profile.get("profile_id").and_then(serde_json::Value::as_str) == std::option::Option::Some(profile_id);
});
assert!(profile.is_some(), "missing super Logging profile {profile_id}");
if let std::option::Option::Some(profile) = profile {
let console_level =
profile.get("console").and_then(|value| value.get("filter")).and_then(|value| value.get("level")).and_then(serde_json::Value::as_str);
assert_eq!(console_level, std::option::Option::Some("debug"));
let files = profile.get("files").and_then(serde_json::Value::as_array);
assert_eq!(files.map(std::vec::Vec::len), std::option::Option::Some(7));
if let std::option::Option::Some(files) = files {
assert!(
files.iter().all(|file| -> bool {
return file.get("filter").and_then(|value| value.get("level")).and_then(serde_json::Value::as_str)
== std::option::Option::Some(file_level);
}),
"all {profile_id} file sinks should use level {file_level}"
);
}
}
}
#[test]
fn missing_document_is_reported_with_file_read_error() {
let fixture = fixture_roots("missing-document");

View File

@@ -0,0 +1,132 @@
<!-- file: deltas/0.2.6/pre.003-fix.002.md -->
<!-- version: 1 -->
# Delta `0.2.6-pre.003-fix.002` — canari environnement + profils Logging génériques
## Base requise
```text
0.2.6-pre.003-fix.001 appliquée
workspace.package.version = 0.2.6-pre.3.fix.1
```
La validation opérateur de `pre.003-fix.001` confirme `cargo fmt --all`, laudit structurel, `cargo check --workspace`, `cargo clippy --workspace --all-targets`, `cargo test -p ksp-app-config-desk`, `cargo test -p ksp-app-wallet-desk` ainsi que le comportement Tauri/trace frontend. `cargo test -p ksp-config-lib` et `cargo test --workspace` révèlent toutefois un dernier défaut du canari dinventaire `.env.example` : le scanner interprète le fragment `KSP_APP_WALLET_DESK` de lidentifiant Rust `FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK` comme une variable denvironnement réelle.
## Type de livraison
```text
ksp-general-0.2.6-pre.003-fix.002.zip
```
Le correctif touche tests Rust et configuration runtime Logging. La version technique devient :
```text
workspace.package.version = 0.2.6-pre.3.fix.2
commit = v0.2.6-pre.003-fix.002
```
`ksp-app-wallet-desk/package.json` et `tauri.conf.json` suivent le signal technique `0.2.6-pre.3.fix.2`. Aucune dépendance Cargo ou npm nest ajoutée ou modifiée.
## Correction du scanner `.env.example`
`collect_environment_names` exige désormais une frontière lexicale valide avant et après un nom KSP/KSPB. Un fragment inclus dans un identifiant Rust plus long nest donc plus considéré comme une variable runtime.
Le canari couvre explicitement :
```text
FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK
-X-> KSP_APP_WALLET_DESK
KSP_PUBLIC_RPC_URL_SUFFIXED
-X-> KSP_PUBLIC_RPC_URL_SUFFIXED
"KSP_PUBLIC_RPC_URL"
-> KSP_PUBLIC_RPC_URL
```
Aucune fausse entrée `KSP_APP_WALLET_DESK` nest ajoutée à `.env.example`.
## Profils standard Logging
`config/std.logging.json` conserve `local_dev` pour compatibilité et ajoute une surface générique réutilisable :
```text
console_error
console_warn
console_info
console_debug
console_trace
file_info
superdev
supertrace
```
Les cinq profils `console_*` nactivent que la console au niveau correspondant.
`file_info` désactive la console et écrit tous les targets KSP au niveau `info` dans le sink global `info/ksp-info.log`.
`superdev` utilise :
```text
console = debug
fichiers = debug, un par target KSP racine
```
`supertrace` utilise :
```text
console = debug
fichiers = trace, un par target KSP racine
```
Les targets racines actuellement couvertes sont :
```text
ksp-app-config-desk
ksp-app-wallet-desk
ksp-config-lib
ksp-core-lib
ksp-logging-lib
ksp-onchain-transport-lib
ksp-wallet-lib
```
Les filtres de sortie sont des préfixes : les sous-targets tels que `ksp-app-wallet-desk.frontend.main` sont donc routés dans le fichier du target racine correspondant.
## Composite Wallet Desk
Le profil ad hoc `wallet_desk_dev` est supprimé. Les profils `devnet`, `temporary` et `tests` de `cfg.composite.ksp-app-wallet-desk` sélectionnent temporairement :
```text
logging -> cfg.std.logging / supertrace
```
Ce choix permet de garder la console lisible en `debug` tout en conservant les événements `trace` frontend dans le fichier `targets/trace/ksp-app-wallet-desk.log`. Le niveau Logging reste entièrement piloté par la composition Config et pourra être remplacé plus tard par `superdev`, `console_info` ou un autre profil sans changement du runtime Wallet Desk.
## Canaris
Les tests Config vérifient désormais la présence de la famille de profils Logging et les propriétés structurantes de `superdev`/`supertrace`. Le test de composition Wallet Desk vérifie la sélection `supertrace`, la console `debug` et les sept sinks `trace` par target.
## Validation opérateur requise
Après application :
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-config-lib
cargo test -p ksp-app-config-desk
cargo test -p ksp-app-wallet-desk
cargo test --workspace
KSP_WALLETS_DIRECTORY=var/wallet-desk-pre003 cargo tauri dev -c crates/ksp-app-wallet-desk/tauri.conf.json
```
Pendant le `tauri dev`, les événements frontend `trace` ne sont plus attendus dans la console `supertrace` lorsque leur niveau dépasse `debug`, mais ils doivent être présents dans le fichier de lancement correspondant au target `ksp-app-wallet-desk`. Les événements Rust/frontend `debug` restent visibles en console.
`cargo tauri build -c crates/ksp-app-wallet-desk/tauri.conf.json` reste exclu de ce fix et réservé à la toute dernière validation de `0.2.6`.
## Suite
Après validation de `pre.003-fix.002`, `pre.004` peut brancher linventory réel `.kspwallet` sur la base Config/Logging stabilisée.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
<!-- version: 59 -->
<!-- version: 60 -->
# Séquence des releases fonctionnelles KSP
@@ -430,7 +430,7 @@ Le prompt [`../../prompts/011-V0_2_6_START_PROMPT.md`](../../prompts/011-V0_2_6_
`0.2.6-pre.001` confirme que le registre Config doit être étendu pour `cfg.std.wallet`/`schema.std.wallet` et `cfg.composite.ksp-app-wallet-desk`. `wallets_directory` reste global avec fallback `${KSP_WALLETS_DIRECTORY:-wallets}` et chaque profil peut définir un `wallets_subdirectory` relatif pour isoler tests, temporaires ou futurs scénarios. Wallet Desk prépare/crée le répertoire effectif après résolution Config et journalise le succès en debug ou l'échec en error. Le gabarit Config Desk est réutilisé avec Bootstrap, Font Awesome, DataTables/Select, SimpleBar et `resize-observer-polyfill`. L'inventory reste non récursive `.kspwallet`, sans symlink d'entrée et root-scoped; les handles VIEW/OWNER restent exclusivement côté Rust. L'ouverture accepte un password éphémère saisi ou une tentative explicite de secrets Config `KSP_SECRET_WALLET_PASS_*`, dont ni nom ni valeur ne traversent le frontend. `getBalance` utilise la Pubkey du handle autorisé et les flows OWNER metadata/rotations/revocation/export fichier délèguent à Wallet. La CSP reste `null` par défaut comme dans Config Desk et n'est réauditée qu'en présence d'un besoin WebView concret. Le forecast souple détaillé s'étend jusqu'à `pre.014`, dernière tranche prévue pour README/USAGE/docs/validation, prompt `0.2.7` et build Tauri final; le plan actif est `docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md`.
`0.2.6-pre.002` matérialise le shell Tauri spécialisé. `0.2.6-pre.003` matérialise ensuite la première composition Config propre à Wallet Desk : `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, `ResolvedWalletConfig`, la racine `${KSP_WALLETS_DIRECTORY:-wallets}`, les sous-répertoires de profils `temporary`/`tests`, la préservation de provenance `Composite` dans les adapters Logging/Wallet et la création sûre des répertoires par lapplication. Aucun inventory ou fichier `.kspwallet` nest encore ouvert dans cette tranche. `0.2.6-pre.003-fix.001` corrige ensuite les tests de registry/fixtures devenus obsolètes, sélectionne le profil Logging composite `wallet_desk_dev` avec trace ciblée `ksp-app-wallet-desk`, et instrumente les clics frontend génériques sans sérialiser la valeur des contrôles.
`0.2.6-pre.002` matérialise le shell Tauri spécialisé. `0.2.6-pre.003` matérialise ensuite la première composition Config propre à Wallet Desk : `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, `ResolvedWalletConfig`, la racine `${KSP_WALLETS_DIRECTORY:-wallets}`, les sous-répertoires de profils `temporary`/`tests`, la préservation de provenance `Composite` dans les adapters Logging/Wallet et la création sûre des répertoires par lapplication. Aucun inventory ou fichier `.kspwallet` nest encore ouvert dans cette tranche. `0.2.6-pre.003-fix.001` corrige ensuite les tests de registry/fixtures devenus obsolètes et instrumente les clics frontend génériques sans sérialiser la valeur des contrôles. `0.2.6-pre.003-fix.002` corrige le scanner dinventaire `.env.example` qui interprétait `FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK` comme une variable denvironnement, remplace le profil Logging ad hoc Wallet Desk par les profils génériques console-only/`file_info`/`superdev`/`supertrace`, et sélectionne temporairement `supertrace` dans le composite Wallet Desk.
## `0.2.7` — WebSocket Solana standard

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/013-V0_2_6_WALLET_DESK_PLAN.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Plan `0.2.6` — Wallet Desk
@@ -23,7 +23,7 @@ Les validations opérateur du `2026-08-20` ont ensuite confirmé la base `pre.00
`0.2.6-pre.002` matérialise ensuite la première tranche technique : la crate `ksp-app-wallet-desk` rejoint le workspace avec le shell splash/main du gabarit Config Desk, le bootstrap Config + Logging commun, les ports `1432/1433`, Bootstrap, Font Awesome, DataTables/Select, SimpleBar, `resize-observer-polyfill`, TS-RS et le bridge frontend -> Rust -> `ksp-logging-lib`. Cette tranche ne branche encore ni `std.wallet`, ni inventory filesystem réel, ni `ksp-wallet-lib`, ni Transport : ces responsabilités restent dans les prereleases déjà dimensionnées.
`0.2.6-pre.003` matérialise la composition Config prévue : `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, les profils Wallet `default`/`temporary`/`tests`, `ResolvedWalletConfig` et les adapters qui peuvent consommer un profil déjà sélectionné par composite sans perdre la provenance `Composite`. Wallet Desk valide les composants `logging`/`transport`/`wallet`, crée la racine et le sous-répertoire effectif absents avec logs `debug`, refuse les objets filesystem invalides/symlinks de sous-répertoire avec logs `error`, et expose uniquement les chemins/profils non secrets dans le statut runtime. Aucun inventory `.kspwallet` nest encore effectué. `pre.003-fix.001` corrige les deux régressions de tests révélées par la validation workspace et le warning Clippy, puis sélectionne un profil Logging composite `wallet_desk_dev` qui rend visibles les événements `trace` de `ksp-app-wallet-desk`; les clics frontend sur boutons/navigation/tabs sont instrumentés avec des métadonnées techniques sans valeur de contrôle.
`0.2.6-pre.003` matérialise la composition Config prévue : `cfg.std.wallet`/`schema.std.wallet`, le composite `cfg.composite.ksp-app-wallet-desk`, les profils Wallet `default`/`temporary`/`tests`, `ResolvedWalletConfig` et les adapters qui peuvent consommer un profil déjà sélectionné par composite sans perdre la provenance `Composite`. Wallet Desk valide les composants `logging`/`transport`/`wallet`, crée la racine et le sous-répertoire effectif absents avec logs `debug`, refuse les objets filesystem invalides/symlinks de sous-répertoire avec logs `error`, et expose uniquement les chemins/profils non secrets dans le statut runtime. Aucun inventory `.kspwallet` nest encore effectué. `pre.003-fix.001` corrige les deux régressions de tests révélées par la validation workspace et le warning Clippy, puis rend visibles les événements `trace` frontend. `pre.003-fix.002` corrige ensuite le canari dinventaire `.env.example` qui confondait un fragment didentifiant Rust avec une variable KSP, remplace le profil temporaire `wallet_desk_dev` par une famille Logging réutilisable (`console_*`, `file_info`, `superdev`, `supertrace`) et fait sélectionner temporairement `supertrace` par le composite Wallet Desk afin de conserver la visibilité des actions frontend sans profil spécifique à lapplication.
## 2. Sources relues et hiérarchie appliquée
@@ -169,6 +169,27 @@ wallet_export_cancelled
Ils ne sérialisent jamais aveuglément les request DTOs.
La configuration standard Logging expose aussi des profils opératoires réutilisables :
```text
console_error / console_warn / console_info / console_debug / console_trace
console seule au niveau correspondant
file_info
console désactivée
fichier global info pour tous les targets KSP
superdev
console debug
un fichier debug par target KSP racine
supertrace
console debug
un fichier trace par target KSP racine
```
`local_dev` est conservé pour compatibilité avec Config Desk et les scénarios historiques. Pendant le développement de Wallet Desk, le composite sélectionne explicitement `supertrace`; ce choix reste une donnée de composition et pourra être resserré ultérieurement sans modifier lapplication. Les fichiers par target utilisent des filtres de préfixe, de sorte que les sous-targets frontend (`ksp-app-wallet-desk.frontend.*`) restent routés dans le fichier de leur target racine.
## 5. Audit de la surface publique `ksp-wallet-lib`
La release stable `0.2.5` possède déjà la logique métier nécessaire. Wallet Desk compose et projette ; il ne réimplémente rien.
@@ -367,7 +388,7 @@ Shape de référence :
{
"profile_id": "devnet",
"documents": [
{"component_id": "logging", "file_id": "cfg.std.logging", "profile_id": "wallet_desk_dev"},
{"component_id": "logging", "file_id": "cfg.std.logging", "profile_id": "supertrace"},
{"component_id": "transport", "file_id": "cfg.std.transport", "profile_id": "devnet_public"},
{"component_id": "wallet", "file_id": "cfg.std.wallet", "profile_id": "default"}
]
@@ -375,7 +396,7 @@ Shape de référence :
{
"profile_id": "tests",
"documents": [
{"component_id": "logging", "file_id": "cfg.std.logging", "profile_id": "wallet_desk_dev"},
{"component_id": "logging", "file_id": "cfg.std.logging", "profile_id": "supertrace"},
{"component_id": "transport", "file_id": "cfg.std.transport", "profile_id": "devnet_public"},
{"component_id": "wallet", "file_id": "cfg.std.wallet", "profile_id": "tests"}
]
@@ -1255,13 +1276,14 @@ wallets_subdirectory optionnel, relatif et multi-composants normaux
profils default / temporary / tests
ResolvedWalletConfig avec root/subdirectory/effective path/provenance
resolve_logging_config_profile / resolve_wallet_config_profile pour profils composites
cfg.composite.ksp-app-wallet-desk = logging(wallet_desk_dev) + transport + wallet
cfg.composite.ksp-app-wallet-desk = logging(supertrace) + transport + wallet
.env.example documente KSP_WALLETS_DIRECTORY et le pattern futur KSP_SECRET_WALLET_PASS_*
bootstrap Wallet Desk valide les trois component_id/file_id requis
création automatique du root et du sous-répertoire effectif absents
rejet d'un root non-directory et d'un composant de sous-répertoire symlink/non-directory
debug sur répertoires prêts/créés ; error sur préparation impossible
profil Logging wallet_desk_dev : target ksp-app-wallet-desk à trace, console et fichier dédiés
profils Logging génériques : console_error/warn/info/debug/trace, file_info, superdev et supertrace ; local_dev conservé pour compatibilité
composite Wallet Desk temporairement sur supertrace : console debug + un fichier trace par target KSP racine
trace frontend metadata-only sur clics boutons/navigation/tabs et actions shell
status DTO/UI : profil composite, profils Logging/Wallet, root/subdirectory/effective directory
```