v0.1.0-pre.076

This commit is contained in:
2026-08-01 16:23:15 +02:00
parent f4331cf48a
commit d7284ab71e
27 changed files with 2273 additions and 2020 deletions

View File

@@ -1,5 +1,5 @@
// file: kb-app-demo-desktop/src/demo_decode_replay.rs
// version: 33
// version: 37
//! Tauri commands and UI payloads for contextual instruction decode replay.
@@ -357,7 +357,289 @@ impl std::ops::Drop for crate::DemoDecodeReplayRunGuard<'_> {
}
}
pub(crate) fn register_active_campaign(
/// Returns available decoders and default replay bounds.
pub(crate) fn demo_decode_replay_options(
state: tauri::State<'_, crate::AppState>,
) -> crate::DemoDecodeReplayOptionsPayload {
let decoders = available_decoders();
let decoder_options = decoders
.iter()
.map(|decoder| {
let identity = decoder.identity();
return crate::DemoDecodeReplayDecoderOption {
name: identity.name,
version: identity.version,
program_ids: decoder
.surfaces()
.iter()
.map(|surface| return surface.program_id.to_string())
.collect(),
};
})
.collect::<std::vec::Vec<_>>();
let materializers = available_materializers();
let materializer_names = materializers
.iter()
.map(|materializer| {
let identity = materializer.identity();
return format!("{}@{}", identity.name, identity.version);
})
.collect::<std::vec::Vec<_>>();
let programs = kb_program_ids::registered_program_ids()
.iter()
.map(|entry| {
return crate::DemoDecodeReplayProgramOption {
code: entry.code().to_string(),
program_id: entry.program_id().to_string(),
};
})
.collect();
let running = state.demo_decode_replay_running().load(std::sync::atomic::Ordering::Acquire);
tracing::debug!(
target: crate::TRACING_TARGET,
action = "load_options",
pipeline_version = kb_pipeline::DECODE_PIPELINE_VERSION,
decoder_count = decoder_options.len(),
materializer_names = ?materializer_names,
default_limit = 100_u32,
default_max_concurrent_inputs = 4_u32,
running,
"return contextual decode replay options"
);
return crate::DemoDecodeReplayOptionsPayload {
pipeline_version: kb_pipeline::DECODE_PIPELINE_VERSION.to_string(),
decoders: decoder_options,
materializer_names,
programs,
default_limit: 100,
default_max_concurrent_inputs: 4,
running,
};
}
/// Executes one bounded contextual decode and optional materialization campaign.
pub(crate) async fn demo_decode_replay_execute(
app_handle: tauri::AppHandle,
state: tauri::State<'_, crate::AppState>,
request: crate::DemoDecodeReplayRequest,
) -> std::result::Result<crate::DemoDecodeReplaySummaryPayload, std::string::String> {
let campaign_id = kb_pipeline::new_decode_campaign_id();
tracing::debug!(
target: crate::TRACING_TARGET,
action = "execute",
campaign_id = %campaign_id,
instruction_state = %request.instruction_state,
signature_line_count = optional_line_count(&request.signatures_text),
program_id = ?request.program_id,
instruction_paths_text = ?request.instruction_paths_text,
decoder_names = ?request.decoder_names,
limit = request.limit,
max_concurrent_inputs = request.max_concurrent_inputs,
all_compatible = request.all_compatible,
force_replay = request.force_replay,
force_replay_all_matching = request.force_replay_all_matching,
materialize_after_decode = request.materialize_after_decode,
"received contextual decode replay command"
);
let acquire_result = state.demo_decode_replay_running().compare_exchange(
false,
true,
std::sync::atomic::Ordering::AcqRel,
std::sync::atomic::Ordering::Acquire,
);
if acquire_result.is_err() {
tracing::warn!(target: crate::TRACING_TARGET, action = "execute", campaign_id = %campaign_id, accepted = false, reason = "already_running", "reject contextual decode replay command");
return std::result::Result::Err(
"a contextual decode replay campaign is already running".to_string(),
);
}
let _run_guard = crate::DemoDecodeReplayRunGuard {
running: state.demo_decode_replay_running(),
campaign_id: state.demo_decode_replay_campaign_id(),
};
let register_result =
register_active_campaign(state.demo_decode_replay_campaign_id(), campaign_id.as_str());
if let std::result::Result::Err(error) = register_result {
tracing::error!(target: crate::TRACING_TARGET, action = "register_campaign", campaign_id = %campaign_id, error = %error, "cannot lock active contextual decode campaign slot");
return std::result::Result::Err(error);
}
state
.demo_decode_replay_cancel_requested()
.store(false, std::sync::atomic::Ordering::Release);
let pipeline_request_result = build_pipeline_request(request, campaign_id.clone());
let pipeline_request = match pipeline_request_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
tracing::error!(target: crate::TRACING_TARGET, action = "build_request", campaign_id = %campaign_id, error = %error, "cannot build contextual decode replay request");
return std::result::Result::Err(error);
},
};
tracing::debug!(
target: crate::TRACING_TARGET,
action = "execute_pipeline",
campaign_id = %pipeline_request.campaign_id,
signature_count = pipeline_request.selection.signatures.len(),
signature_sample = ?text_sample(pipeline_request.selection.signatures.as_slice(), 5),
processing_states = ?pipeline_request.selection.processing_states,
min_slot = ?pipeline_request.selection.min_slot,
max_slot = ?pipeline_request.selection.max_slot,
program_ids = ?pipeline_request.selection.program_ids,
instruction_paths = ?pipeline_request.selection.instruction_paths,
incomplete_signatures = pipeline_request.selection.incomplete_signatures,
limit = pipeline_request.selection.limit,
decoder_names = ?pipeline_request.decoder_names,
dispatch_policy = ?pipeline_request.dispatch_policy,
max_concurrent_inputs = pipeline_request.max_concurrent_inputs,
force_replay = pipeline_request.force_replay,
force_replay_all_matching = pipeline_request.force_replay_all_matching,
materialize_after_decode = pipeline_request.materialize_after_decode,
"start contextual decode replay pipeline"
);
let store_result = crate::connect_postgres_store(state.active_profile()).await;
let store = match store_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
tracing::error!(target: crate::TRACING_TARGET, action = "connect_store", campaign_id = %pipeline_request.campaign_id, error = %error, "cannot connect contextual decode replay store");
return std::result::Result::Err(error);
},
};
let decoders = available_decoders();
let materializers = available_materializers();
let observer = crate::DemoDecodeReplayObserver {
app_handle,
campaign_id: pipeline_request.campaign_id.clone(),
cancel_requested: state.demo_decode_replay_cancel_requested(),
};
let summary_result = kb_pipeline::execute_decode_replay(
&store,
&pipeline_request,
decoders.as_slice(),
materializers.as_slice(),
&observer,
)
.await;
let summary = match summary_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
tracing::error!(target: crate::TRACING_TARGET, action = "execute_pipeline", campaign_id = %pipeline_request.campaign_id, error = %error, "contextual decode replay pipeline failed");
return std::result::Result::Err(error.to_string());
},
};
tracing::debug!(
target: crate::TRACING_TARGET,
action = "execute_pipeline",
campaign_id = %summary.campaign_id,
selected = summary.selected,
started = summary.started,
completed = summary.completed,
unmatched = summary.unmatched,
not_started = summary.not_started,
failed_inputs = summary.failed_inputs,
processing_error_inputs = summary.processing_error_inputs,
cancelled = summary.cancelled,
processors = ?summary.processors,
"contextual decode replay command completed"
);
return std::result::Result::Ok(summary_payload(summary));
}
/// Requests cooperative cancellation of the current decode replay campaign.
pub(crate) fn demo_decode_replay_cancel(state: tauri::State<'_, crate::AppState>) -> bool {
let running = state.demo_decode_replay_running().load(std::sync::atomic::Ordering::Acquire);
state
.demo_decode_replay_cancel_requested()
.store(true, std::sync::atomic::Ordering::Release);
let campaign_lock_result = state.demo_decode_replay_campaign_id().lock();
let campaign_id = match campaign_lock_result {
std::result::Result::Ok(active_campaign_id) => active_campaign_id.clone(),
std::result::Result::Err(_) => std::option::Option::None,
};
tracing::debug!(target: crate::TRACING_TARGET, action = "cancel", campaign_id = ?campaign_id, running, cancellation_requested = true, "contextual decode replay cancellation command handled");
return running;
}
/// Loads read-only decode, materialization, ledger and coverage diagnostics.
pub(crate) async fn demo_decode_replay_diagnostics(
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::DemoDecodeDiagnosticsPayload, std::string::String> {
tracing::debug!(target: crate::TRACING_TARGET, action = "load_diagnostics", coverage_limit = 500_u32, "load contextual decode replay diagnostics");
let store_result = crate::connect_postgres_store(state.active_profile()).await;
let store = match store_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let table_result = store.known_table_diagnostics().await;
let all_tables = match table_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
let selected_tables: std::vec::Vec<crate::DemoSqlTableSnapshot> = all_tables
.iter()
.filter(|table| {
return table.table_name.starts_with("kb_sol_decode_")
|| table.table_name.starts_with("kb_sol_mat_")
|| table.table_name == "kb_sol_ops_processing_ledger";
})
.map(crate::table_snapshot_from_pg)
.collect();
let coverage_result = kb_store::DecodePipelineStore::list_decode_coverage_summary(
&store,
std::option::Option::None,
std::option::Option::None,
500,
)
.await;
let coverage = match coverage_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
tracing::debug!(target: crate::TRACING_TARGET, action = "load_diagnostics", table_count = selected_tables.len(), coverage_count = coverage.len(), "contextual decode replay diagnostics loaded");
return std::result::Result::Ok(crate::DemoDecodeDiagnosticsPayload {
tables: selected_tables,
coverage: coverage.into_iter().map(coverage_payload).collect(),
});
}
/// Loads a bounded journal of committed SPL Memo transaction annotations.
pub(crate) async fn demo_decode_replay_annotations(
state: tauri::State<'_, crate::AppState>,
request: crate::DemoTransactionAnnotationRequest,
) -> std::result::Result<std::vec::Vec<crate::DemoTransactionAnnotationRow>, std::string::String> {
let filter_result = kb_store::MaterializedEventFilter::new(
std::option::Option::Some("materializer.transaction.annotations".to_string()),
std::option::Option::Some("transaction_annotation".to_string()),
request.signature_contains,
request.limit,
);
let filter = match filter_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
tracing::debug!(target: crate::TRACING_TARGET, action = "load_transaction_annotations", signature_contains = ?filter.signature_contains, limit = filter.limit, "load bounded committed transaction annotation journal");
let store_result = crate::connect_postgres_store(state.active_profile()).await;
let store = match store_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let rows_result =
kb_store::DecodePipelineStore::list_materialized_events(&store, &filter).await;
let rows = match rows_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
let mut output = std::vec::Vec::with_capacity(rows.len());
for row in rows {
let mapped = annotation_payload(row);
match mapped {
std::result::Result::Ok(value) => output.push(value),
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
}
tracing::debug!(target: crate::TRACING_TARGET, action = "load_transaction_annotations", row_count = output.len(), "bounded committed transaction annotation journal loaded");
return std::result::Result::Ok(output);
}
fn register_active_campaign(
campaign_slot: &std::sync::Mutex<std::option::Option<std::string::String>>,
campaign_id: &str,
) -> std::result::Result<(), std::string::String> {
@@ -374,8 +656,7 @@ pub(crate) fn register_active_campaign(
return std::result::Result::Ok(());
}
pub(crate) fn available_materializers()
-> std::vec::Vec<std::sync::Arc<dyn kb_lib::MtApiEventMaterializer>> {
fn available_materializers() -> std::vec::Vec<std::sync::Arc<dyn kb_lib::MtApiEventMaterializer>> {
return std::vec![
std::sync::Arc::new(kb_lib::MtAdminMaterializer),
std::sync::Arc::new(kb_lib::MtComplianceAuditMaterializer),
@@ -388,8 +669,7 @@ pub(crate) fn available_materializers()
];
}
pub(crate) fn available_decoders()
-> std::vec::Vec<std::sync::Arc<dyn kb_lib::DcApiInstructionDecoder>> {
fn available_decoders() -> std::vec::Vec<std::sync::Arc<dyn kb_lib::DcApiInstructionDecoder>> {
return std::vec![
std::sync::Arc::new(kb_lib::DcSolanaCoreDecoder),
std::sync::Arc::new(kb_lib::DcMetadataMetaplexTokenMetadataDecoder),
@@ -401,7 +681,7 @@ pub(crate) fn available_decoders()
];
}
pub(crate) fn build_demo_decode_replay_pipeline_request(
fn build_pipeline_request(
request: crate::DemoDecodeReplayRequest,
campaign_id: std::string::String,
) -> std::result::Result<kb_pipeline::DecodeReplayRequest, std::string::String> {
@@ -474,7 +754,7 @@ pub(crate) fn build_demo_decode_replay_pipeline_request(
return std::result::Result::Ok(pipeline_request);
}
pub(crate) fn optional_line_count(value: &std::option::Option<std::string::String>) -> usize {
fn optional_line_count(value: &std::option::Option<std::string::String>) -> usize {
return match value {
std::option::Option::Some(text) => {
text.lines().filter(|line| return !line.trim().is_empty()).count()
@@ -483,7 +763,7 @@ pub(crate) fn optional_line_count(value: &std::option::Option<std::string::Strin
};
}
pub(crate) fn text_sample(values: &[std::string::String], limit: usize) -> std::vec::Vec<&str> {
fn text_sample(values: &[std::string::String], limit: usize) -> std::vec::Vec<&str> {
return values.iter().take(limit).map(std::string::String::as_str).collect();
}
@@ -538,7 +818,7 @@ fn split_lines(text: std::option::Option<&str>) -> std::vec::Vec<std::string::St
return output;
}
pub(crate) fn demo_decode_replay_summary_payload(
fn summary_payload(
summary: kb_pipeline::DecodeReplaySummary,
) -> crate::DemoDecodeReplaySummaryPayload {
return crate::DemoDecodeReplaySummaryPayload {
@@ -576,7 +856,7 @@ pub(crate) fn demo_decode_replay_summary_payload(
};
}
pub(crate) fn coverage_payload(
fn coverage_payload(
value: kb_store::DecodeCoverageSummaryRow,
) -> crate::DemoDecodeCoverageSummaryPayload {
return crate::DemoDecodeCoverageSummaryPayload {
@@ -597,7 +877,7 @@ pub(crate) fn coverage_payload(
};
}
pub(crate) fn annotation_payload(
fn annotation_payload(
row: kb_store::MaterializedEventQueryRow,
) -> std::result::Result<crate::DemoTransactionAnnotationRow, std::string::String> {
if row.processor_name != "materializer.transaction.annotations"
@@ -742,7 +1022,7 @@ mod tests {
#[test]
fn native_memo_token_2022_elgamal_classic_token_and_ata_decoders_are_registered() {
let decoders = crate::available_decoders();
let decoders = super::available_decoders();
assert_eq!(decoders.len(), 7);
let mut names = decoders
.iter()
@@ -764,7 +1044,7 @@ mod tests {
#[test]
fn runtime_materializer_registry_is_complete_for_current_instructional_surfaces() {
let materializers = crate::available_materializers();
let materializers = super::available_materializers();
assert_eq!(materializers.len(), 8);
let names = materializers
.iter()
@@ -798,7 +1078,7 @@ mod tests {
),
] {
let observation = ata_observation(entry);
let owners = crate::available_materializers()
let owners = super::available_materializers()
.iter()
.filter(|materializer| return materializer.accepts_observation(&observation))
.map(|materializer| return materializer.identity().name)
@@ -836,7 +1116,7 @@ mod tests {
#[test]
fn force_replay_requires_signatures_or_all_matching_authorization() {
let result = crate::build_demo_decode_replay_pipeline_request(
let result = super::build_pipeline_request(
request(std::option::Option::None, true, false, false),
"decode-test".to_string(),
);
@@ -845,7 +1125,7 @@ mod tests {
#[test]
fn force_replay_all_matching_is_forwarded() {
let result = crate::build_demo_decode_replay_pipeline_request(
let result = super::build_pipeline_request(
request(std::option::Option::None, true, true, false),
"decode-test".to_string(),
);
@@ -880,7 +1160,7 @@ mod tests {
#[test]
fn register_active_campaign_sets_slot_without_exposing_guard() {
let campaign_id = std::sync::Mutex::new(std::option::Option::None);
let result = crate::register_active_campaign(&campaign_id, "decode-test");
let result = super::register_active_campaign(&campaign_id, "decode-test");
assert!(result.is_ok());
let lock_result = campaign_id.lock();
let active_campaign_id = match lock_result {
@@ -894,10 +1174,7 @@ mod tests {
fn incomplete_signature_state_uses_actionable_states_and_expansion() {
let mut request = request(std::option::Option::None, false, false, true);
request.instruction_state = "incomplete_signatures".to_string();
let result = crate::build_demo_decode_replay_pipeline_request(
request,
"decode-incomplete".to_string(),
);
let result = super::build_pipeline_request(request, "decode-incomplete".to_string());
let pipeline_request = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("request mapping failed: {error}"),
@@ -944,7 +1221,7 @@ mod tests {
created_at: "created".to_string(),
updated_at: "updated".to_string(),
};
let result = crate::annotation_payload(row);
let result = super::annotation_payload(row);
let mapped = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("annotation mapping failed: {error}"),
@@ -971,6 +1248,6 @@ mod tests {
created_at: "created".to_string(),
updated_at: "updated".to_string(),
};
assert!(crate::annotation_payload(row).is_err());
assert!(super::annotation_payload(row).is_err());
}
}