From 1c28f3155fa9162f7c7841546d3d3b1cc0d397ef Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Wed, 16 Sep 2026 11:38:02 +0200 Subject: [PATCH] 0.3.15-pre.012-fix.001 --- Cargo.toml | 4 +- .../src/app_state.rs | 33 +++---- .../tests/desktop_contract.rs | 5 +- .../unit_tests/route_runtime.rs | 13 ++- deltas/0.3.15/pre.012-fix.001.md | 86 +++++++++++++++++++ ...032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md | 11 ++- 6 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 deltas/0.3.15/pre.012-fix.001.md diff --git a/Cargo.toml b/Cargo.toml index bf57feb..8fe87e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 622 +# version: 623 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-raw-transaction-ingest-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-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-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.15-pre.12" +version = "0.3.15-pre.12.fix.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs b/crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs index 55ce620..a2e09e7 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs -// version: 8 +// version: 9 //! Shared backend state owned by the Raw Transaction Ingest Desk Tauri application. @@ -121,22 +121,23 @@ impl crate::AppState { if let std::result::Result::Err(error) = admission { return std::result::Result::Err(error); } - let generation = self.inventory_generation.lock(); - let generation = match generation { - std::result::Result::Ok(value) => value, - std::result::Result::Err(_) => { - return std::result::Result::Err(ksp_core_lib::Error::new( - crate::ERROR_CODE_APP_STATE_LOCK_FAILED, - "Raw Transaction Ingest Desk route inventory generation lock is poisoned", - )); - }, + let prepared = { + let generation = self.inventory_generation.lock(); + let generation = match generation { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => { + return std::result::Result::Err(ksp_core_lib::Error::new( + crate::ERROR_CODE_APP_STATE_LOCK_FAILED, + "Raw Transaction Ingest Desk route inventory generation lock is poisoned", + )); + }, + }; + let prepared = crate::prepare_route_start(&self.config_management, *generation, request); + match prepared { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + } }; - let prepared = crate::prepare_route_start(&self.config_management, *generation, request); - let prepared = match prepared { - std::result::Result::Ok(value) => value, - std::result::Result::Err(error) => return std::result::Result::Err(error), - }; - std::mem::drop(generation); return crate::start_route_runtime(std::sync::Arc::clone(&self.route_runtime), prepared).await; } diff --git a/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs b/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs index 9847776..7024755 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs -// version: 10 +// version: 11 //! Desktop scaffold contract canaries for Raw Transaction Ingest Desk. @@ -303,7 +303,8 @@ fn pre_012_window_shutdown_and_start_stop_races_are_bounded_backend_owned() { assert!(runtime.contains(required), "missing pre.012 route-race marker {required}"); } let app_state = read_text(app_root().join("src/app_state.rs").as_path()); + assert!(app_state.contains("let prepared = {")); assert!(app_state.contains("let generation = self.inventory_generation.lock()")); - assert!(app_state.contains("std::mem::drop(generation)")); + assert!(!app_state.contains("std::mem::drop(generation)")); assert!(app_state.contains("self.route_runtime.ensure_start_admission_open()")); } diff --git a/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs b/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs index 1a5c4f4..800e4a7 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs -// version: 4 +// version: 5 #[test] fn pre_009_multi_route_runtime_starts_without_workers_or_shared_store_material() { @@ -130,3 +130,14 @@ fn pre_012_application_shutdown_is_one_shot_and_marks_starting_routes_before_act assert!(matches!(inner.routes.first(), std::option::Option::Some(super::RouteRuntimeSlot::Starting { stop_requested: true, .. }))); } } + +#[test] +fn pre_012_fix_001_start_route_future_is_send_for_tauri_command() { + fn assert_send_future<'a>( + state: &'a crate::AppState, + request: &'a crate::RawIngestRouteStartRequestDto, + ) -> impl std::future::Future> + std::marker::Send + 'a { + return state.start_route(request); + } + let _assertion = assert_send_future; +} diff --git a/deltas/0.3.15/pre.012-fix.001.md b/deltas/0.3.15/pre.012-fix.001.md new file mode 100644 index 0000000..f203355 --- /dev/null +++ b/deltas/0.3.15/pre.012-fix.001.md @@ -0,0 +1,86 @@ + + + +# Delta `0.3.15-pre.012-fix.001` + +## Base + +```text +base archive : ksp-general-0.3.15-pre.012.zip +base SHA-256 : 627a1152e3c5d97517dfbe7de630ca47dc52fd2c3b7683a325b52cfea7291331 +base version : 0.3.15-pre.12 +``` + +## Motif du fix + +Le gate opérateur du 16 septembre 2026 a révélé un défaut de compilation dans la nouvelle protection stale-inventory de `pre.012`. `AppState::start_route` gardait un `std::sync::MutexGuard` dans la portée du futur jusqu'au `await` de `start_route_runtime`. Tauri exige un futur `Send` pour une commande async ; le Desk échouait donc à compiler avec : + +```text +future returned by `start_route` is not `Send` +std::sync::MutexGuard<'_, u32> is not `Send` +``` + +Les audits Rust/Markdown étaient propres et les tests Worker continuaient de passer, mais `cargo check`, Clippy, les tests Desk/workspace et `cargo tauri dev` étaient bloqués par cette erreur. + +## Correction + +La préparation Start synchrone est maintenant enfermée dans une portée lexicale : + +```text +let prepared = { + lock generation + revalidate + reconstruct Config/Transport + return prepared value +}; +await start_route_runtime(...) +``` + +Le guard de génération est ainsi détruit structurellement avant le premier `await`. La protection stale-inventory de `pre.012` est conservée : aucune nouvelle génération ne peut être publiée entre le contrôle et la reconstruction synchrones. + +Un canari de compilation impose désormais `Future + Send` au futur `AppState::start_route`, et le canari desktop vérifie la portée lexicale au lieu d'accepter `std::mem::drop(generation)` comme preuve suffisante. + +## Version + +```text +workspace.package.version : 0.3.15-pre.12.fix.1 +root Cargo header counter : 623 +``` + +## Frontières + +Aucun changement de comportement pour : + +```text +Start / Stop / shutdown +Config / Transport / Store +Worker / Common RAW +monitoring frontend +acquisition / replay / repair +IPC security contract +``` + +## Validation d'assemblage + +Exécuté dans l'environnement d'assemblage : contrôles statiques ciblés du diff, inventaire du delta, intégrité ZIP et reconstruction byte-exact à partir de `pre.012`. + +Cargo/rustfmt ne sont pas disponibles dans cet environnement. Les gates Cargo de ce fix restent à confirmer par l'opérateur. + +## Inventaire exact du delta + +Ajout : + +```text +deltas/0.3.15/pre.012-fix.001.md +``` + +Modifications : + +```text +Cargo.toml +crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs +crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs +crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_runtime.rs +docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md +``` + +Suppressions : aucune. diff --git a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md index ff57005..f78e47b 100644 --- a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md +++ b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md @@ -1,5 +1,5 @@ - + # Validation v0.3.15 — Raw Transaction Ingest Desk @@ -794,4 +794,13 @@ pre_012_race_shutdown_and_ipc_hardening_adds_no_production_module_or_lower_layer ``` Non-claims : `pre.012` ne modifie ni Config, ni Transport, ni Store, ni `ksp-worker-raw-transaction-ingest-lib`, ni Common RAW. Il n'ajoute aucune orchestration Backfill, aucun scheduler, aucune route et aucune nouvelle donnée frontend. `pre.013` reste propriétaire de la fermeture completeness/security cross-layer. +### `pre.012-fix.001` — future Tauri Start `Send` + +Le gate opérateur de `pre.012` a arrêté la tranche sur un défaut de compilation déterministe dans `AppState::start_route` : le `std::sync::MutexGuard` de `inventory_generation` restait considéré vivant au franchissement du `await` final, malgré `std::mem::drop(generation)`. Le futur exposé par la commande Tauri `start_route` ne satisfaisait donc plus la borne `Send` imposée par `tauri::ipc::ResultFutureTag::future`. Les audits Rust/Markdown étaient propres et les suites Worker indépendantes restaient vertes, mais `cargo check`, Clippy, les tests Desk/workspace et `cargo tauri dev` ne pouvaient pas compiler le Desk. + +Le fix ne change aucune sémantique Start/Stop. Lock + revalidation/préparation synchrones sont désormais enfermés dans une portée lexicale `let prepared = { ... };`. Le `MutexGuard` est donc détruit structurellement à la fin du bloc avant tout `await`. Le contrat stale-inventory de `pre.012` reste inchangé : la génération demeure verrouillée pendant toute la reconstruction synchrone, mais aucun guard non-`Send` ne traverse une suspension asynchrone. + +Un canari de compilation `pre_012_fix_001_start_route_future_is_send_for_tauri_command` impose explicitement le type `Future<...> + Send` au futur retourné par `AppState::start_route`. Le canari desktop vérifie également la portée lexicale et interdit le retour au simple `std::mem::drop(generation)` comme preuve de lifetime. + +Non-claims : aucune modification de route, Config, Transport, Store, Worker, Common RAW, monitoring, shutdown ou sécurité IPC.