0.3.15-pre.012-fix.001
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 623
|
# version: 624
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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"]
|
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]
|
[workspace.package]
|
||||||
version = "0.3.15-pre.12.fix.1"
|
version = "0.3.15-pre.12.fix.2"
|
||||||
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-raw-transaction-ingest-desk/src/route_runtime.rs
|
// file: crates/ksp-app-raw-transaction-ingest-desk/src/route_runtime.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
|
|
||||||
//! Multi-route Store and independent Worker lifecycle owned by Raw Transaction Ingest Desk.
|
//! Multi-route Store and independent Worker lifecycle owned by Raw Transaction Ingest Desk.
|
||||||
|
|
||||||
@@ -544,12 +544,35 @@ impl crate::RouteRuntimeLaunch {
|
|||||||
/// Waits for this Worker terminal state, removes only its route and closes Store only after the final same-network route terminates.
|
/// Waits for this Worker terminal state, removes only its route and closes Store only after the final same-network route terminates.
|
||||||
pub(crate) async fn monitor(self) {
|
pub(crate) async fn monitor(self) {
|
||||||
let terminal = self.handle.wait_terminal().await;
|
let terminal = self.handle.wait_terminal().await;
|
||||||
|
let snapshot = self.handle.snapshot_source().current();
|
||||||
|
let worker = snapshot.worker_snapshot();
|
||||||
|
let snapshot_fault = worker.state().fault_code();
|
||||||
|
let snapshot_fault_domain = snapshot_fault.map_or("none", |code| return code.domain());
|
||||||
|
let snapshot_fault_code = snapshot_fault.map_or("none", |code| return code.code());
|
||||||
let terminal_state = match terminal {
|
let terminal_state = match terminal {
|
||||||
std::result::Result::Ok(state) => {
|
std::result::Result::Ok(state) => {
|
||||||
ksp_logging_lib::info!(
|
ksp_logging_lib::info!(
|
||||||
target: crate::TRACING_TARGET,
|
target: crate::TRACING_TARGET,
|
||||||
domain = crate::TRACING_DOMAIN_ROUTE_RUNTIME,
|
domain = crate::TRACING_DOMAIN_ROUTE_RUNTIME,
|
||||||
|
profile_id = self.acknowledgement.profile_id.as_str(),
|
||||||
|
network = self.acknowledgement.network.as_str(),
|
||||||
|
route_id = self.acknowledgement.route_id.as_str(),
|
||||||
|
commitment = self.acknowledgement.commitment.as_str(),
|
||||||
worker_state = state.code(),
|
worker_state = state.code(),
|
||||||
|
worker_health = worker.health().code(),
|
||||||
|
worker_activity = worker.activity().code(),
|
||||||
|
fault_domain = snapshot_fault_domain,
|
||||||
|
fault_code = snapshot_fault_code,
|
||||||
|
source_failure_total = snapshot.source_failure_total(),
|
||||||
|
store_failure_total = snapshot.store_failure_total(),
|
||||||
|
content_conflict_total = snapshot.content_conflict_total(),
|
||||||
|
source_active = snapshot.source_active(),
|
||||||
|
source_reconnecting = snapshot.source_reconnecting(),
|
||||||
|
source_failed = snapshot.source_failed(),
|
||||||
|
open_gap_count = snapshot.open_gap_count(),
|
||||||
|
continuity_has_open_gaps = snapshot.continuity_has_open_gaps(),
|
||||||
|
future_target_coverage = snapshot.future_target_coverage(),
|
||||||
|
failed_source_losses_reconciled = snapshot.failed_source_losses_reconciled(),
|
||||||
"Raw Transaction Ingest Desk route Worker reached terminal state"
|
"Raw Transaction Ingest Desk route Worker reached terminal state"
|
||||||
);
|
);
|
||||||
project_worker_state(state)
|
project_worker_state(state)
|
||||||
@@ -558,8 +581,18 @@ impl crate::RouteRuntimeLaunch {
|
|||||||
ksp_logging_lib::warn!(
|
ksp_logging_lib::warn!(
|
||||||
target: crate::TRACING_TARGET,
|
target: crate::TRACING_TARGET,
|
||||||
domain = crate::TRACING_DOMAIN_ROUTE_RUNTIME,
|
domain = crate::TRACING_DOMAIN_ROUTE_RUNTIME,
|
||||||
|
profile_id = self.acknowledgement.profile_id.as_str(),
|
||||||
|
network = self.acknowledgement.network.as_str(),
|
||||||
|
route_id = self.acknowledgement.route_id.as_str(),
|
||||||
|
commitment = self.acknowledgement.commitment.as_str(),
|
||||||
error_domain = error.code().domain(),
|
error_domain = error.code().domain(),
|
||||||
error_code = error.code().code(),
|
error_code = error.code().code(),
|
||||||
|
worker_health = worker.health().code(),
|
||||||
|
snapshot_fault_domain = snapshot_fault_domain,
|
||||||
|
snapshot_fault_code = snapshot_fault_code,
|
||||||
|
source_failure_total = snapshot.source_failure_total(),
|
||||||
|
store_failure_total = snapshot.store_failure_total(),
|
||||||
|
content_conflict_total = snapshot.content_conflict_total(),
|
||||||
"Raw Transaction Ingest Desk terminal Worker wait failed"
|
"Raw Transaction Ingest Desk terminal Worker wait failed"
|
||||||
);
|
);
|
||||||
crate::RawIngestRouteState::Faulted
|
crate::RawIngestRouteState::Faulted
|
||||||
@@ -567,7 +600,6 @@ impl crate::RouteRuntimeLaunch {
|
|||||||
};
|
};
|
||||||
let mut terminal = self.acknowledgement;
|
let mut terminal = self.acknowledgement;
|
||||||
terminal.state = terminal_state;
|
terminal.state = terminal_state;
|
||||||
let snapshot = self.handle.snapshot_source().current();
|
|
||||||
let monitoring = crate::project_route_monitoring(&terminal, &snapshot);
|
let monitoring = crate::project_route_monitoring(&terminal, &snapshot);
|
||||||
let monitoring = match monitoring {
|
let monitoring = match monitoring {
|
||||||
std::result::Result::Ok(value) => std::option::Option::Some(value),
|
std::result::Result::Ok(value) => std::option::Option::Some(value),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs
|
// file: crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs
|
||||||
// version: 11
|
// version: 12
|
||||||
|
|
||||||
//! Desktop scaffold contract canaries for Raw Transaction Ingest Desk.
|
//! Desktop scaffold contract canaries for Raw Transaction Ingest Desk.
|
||||||
|
|
||||||
@@ -308,3 +308,42 @@ fn pre_012_window_shutdown_and_start_stop_races_are_bounded_backend_owned() {
|
|||||||
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()"));
|
assert!(app_state.contains("self.route_runtime.ensure_start_admission_open()"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_012_fix_002_terminal_fault_logging_keeps_safe_route_identity_and_worker_cause_counters() {
|
||||||
|
let runtime = read_text(app_root().join("src/route_runtime.rs").as_path());
|
||||||
|
let start = runtime.find("pub(crate) async fn monitor(self)");
|
||||||
|
let start = match start {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => {
|
||||||
|
assert!(false, "missing RouteRuntimeLaunch::monitor");
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let remainder = &runtime[start..];
|
||||||
|
let end = remainder.find("/// Starts one exact route Worker");
|
||||||
|
let end = match end {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => {
|
||||||
|
assert!(false, "missing route runtime monitor end marker");
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let monitor = &remainder[..end];
|
||||||
|
for required in [
|
||||||
|
"worker_health = worker.health().code()",
|
||||||
|
"fault_domain = snapshot_fault_domain",
|
||||||
|
"fault_code = snapshot_fault_code",
|
||||||
|
"source_failure_total = snapshot.source_failure_total()",
|
||||||
|
"store_failure_total = snapshot.store_failure_total()",
|
||||||
|
"content_conflict_total = snapshot.content_conflict_total()",
|
||||||
|
"open_gap_count = snapshot.open_gap_count()",
|
||||||
|
"future_target_coverage = snapshot.future_target_coverage()",
|
||||||
|
"failed_source_losses_reconciled = snapshot.failed_source_losses_reconciled()",
|
||||||
|
] {
|
||||||
|
assert!(monitor.contains(required), "missing pre.012-fix.002 terminal diagnostic marker {required}");
|
||||||
|
}
|
||||||
|
for forbidden in ["endpoint_url", "connection_uri", "api_key", "source_key", "worker_id", "signature", "canonical_bytes", "wire_bytes"] {
|
||||||
|
assert!(!monitor.contains(forbidden), "terminal diagnostic surface exposes forbidden marker {forbidden}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
71
deltas/0.3.15/pre.012-fix.002.md
Normal file
71
deltas/0.3.15/pre.012-fix.002.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<!-- file: deltas/0.3.15/pre.012-fix.002.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.3.15-pre.012-fix.002`
|
||||||
|
|
||||||
|
## Base
|
||||||
|
|
||||||
|
```text
|
||||||
|
base archive : ksp-general-0.3.15-pre.012-fix.001.zip
|
||||||
|
base SHA-256 : c6b9925fe0c04b10d43283291c29c4576df9e052ab242fdc8bcd80114b784753
|
||||||
|
base version : 0.3.15-pre.12.fix.1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Motif du fix
|
||||||
|
|
||||||
|
Le gate opérateur de `pre.012-fix.001` est propre côté compilation/tests, mais le live Mainnet montre `yellowstone-hydrated` devenant terminal `faulted` pendant que `http-block-polling` reste productif. Le log terminal du Desk ne conservait que le lifecycle final et ne permettait pas de distinguer de façon sûre un `source_failed`, un `store_failure`, un `content_conflict` ou un défaut interne de projection/continuité.
|
||||||
|
|
||||||
|
## Correction
|
||||||
|
|
||||||
|
`RouteRuntimeLaunch::monitor` lit désormais le snapshot terminal déjà détenu par le Worker avant cleanup et journalise seulement des informations source-neutres et bornées : identité logique route, lifecycle/health/activity, `fault_domain`/`fault_code`, compteurs source/Store/conflit, cardinalités source/gap et indicateurs de continuité.
|
||||||
|
|
||||||
|
Aucune décision métier n'est modifiée. Un Worker `Faulted` reste fail-closed ; ce fix rend sa cause observable avant de décider d'un éventuel correctif comportemental.
|
||||||
|
|
||||||
|
## Version
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version : 0.3.15-pre.12.fix.2
|
||||||
|
root Cargo header counter : 624
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontières
|
||||||
|
|
||||||
|
Aucun changement de comportement pour :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Config / Transport / Store
|
||||||
|
Worker / Common RAW
|
||||||
|
acquisition / replay / repair
|
||||||
|
Start / Stop / shutdown
|
||||||
|
monitoring IPC / frontend
|
||||||
|
politique health / fault
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sécurité
|
||||||
|
|
||||||
|
Le diagnostic terminal interdit toujours endpoint URL/URI, credentials, API keys, source keys, WorkerId, signatures, canonical/wire bytes et payloads RAW.
|
||||||
|
|
||||||
|
## Validation d'assemblage
|
||||||
|
|
||||||
|
Exécuté dans l'environnement d'assemblage : audits statiques Rust/Markdown disponibles, canari de surface terminale, inventaire du delta, intégrité ZIP et reconstruction byte-exact.
|
||||||
|
|
||||||
|
Cargo/rustfmt ne sont pas disponibles dans cet environnement ; les gates Cargo restent à confirmer par l'opérateur.
|
||||||
|
|
||||||
|
## Inventaire exact du delta
|
||||||
|
|
||||||
|
Ajout :
|
||||||
|
|
||||||
|
```text
|
||||||
|
deltas/0.3.15/pre.012-fix.002.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Modifications :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-app-raw-transaction-ingest-desk/src/route_runtime.rs
|
||||||
|
crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_contract.rs
|
||||||
|
docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppressions : aucune.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md -->
|
<!-- file: docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md -->
|
||||||
<!-- version: 23 -->
|
<!-- version: 24 -->
|
||||||
|
|
||||||
# Validation v0.3.15 — Raw Transaction Ingest Desk
|
# Validation v0.3.15 — Raw Transaction Ingest Desk
|
||||||
|
|
||||||
@@ -804,3 +804,10 @@ Un canari de compilation `pre_012_fix_001_start_route_future_is_send_for_tauri_c
|
|||||||
|
|
||||||
Non-claims : aucune modification de route, Config, Transport, Store, Worker, Common RAW, monitoring, shutdown ou sécurité IPC.
|
Non-claims : aucune modification de route, Config, Transport, Store, Worker, Common RAW, monitoring, shutdown ou sécurité IPC.
|
||||||
|
|
||||||
|
### `pre.012-fix.002` — fault terminal diagnostiquable sans payload sensible
|
||||||
|
|
||||||
|
Le gate opérateur de `pre.012-fix.001` compile et teste proprement le Desk, y compris le canari `Future + Send`. Le live Mainnet révèle toutefois un Worker Yellowstone devenant terminal `faulted` alors que le Worker HTTP Block Polling continue à produire des `getBlock` HTTP 200. Aucun `WARN` source/Transport n'est émis avant le terminal, et le log Desk historique ne conservait que `worker_state="faulted"`; le `fault_domain`/`fault_code` déjà présents dans le snapshot Worker et dans le DTO monitoring étaient donc perdus côté logs opérateur.
|
||||||
|
|
||||||
|
Le fix ajoute uniquement une projection de diagnostic terminale source-neutre et bornée dans `RouteRuntimeLaunch::monitor`. Le log terminal porte désormais l'identité logique sûre de route, `worker_state`, `worker_health`, `worker_activity`, `fault_domain`, `fault_code`, les compteurs `source_failure_total`, `store_failure_total`, `content_conflict_total`, les cardinalités source/gap et les booléens de continuité. Aucun endpoint, credential, source key, WorkerId, signature, payload ou octet RAW n'est journalisé.
|
||||||
|
|
||||||
|
Ce fix ne change volontairement aucune politique fail-closed : il ne transforme pas un `Faulted` en succès et ne suppose pas que l'incident observé est un conflit Store ou une panne source. Le prochain live doit permettre de classer exactement la cause avant toute correction comportementale.
|
||||||
|
|||||||
Reference in New Issue
Block a user