use serde::{Deserialize, Serialize}; use crate::{CalendarPoint, RuntimeState}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RuntimeSummary { pub calendar: CalendarPoint, pub calendar_projection_source: Option, pub calendar_projection_is_placeholder: bool, pub world_flag_count: usize, pub world_restore_selected_year_profile_lane: Option, pub world_restore_campaign_scenario_enabled: Option, pub world_restore_sandbox_enabled: Option, pub world_restore_seed_tuple_written_from_raw_lane: Option, pub world_restore_absolute_counter_requires_shell_context: Option, pub world_restore_absolute_counter_reconstructible_from_save: Option, pub world_restore_disable_cargo_economy_special_condition_slot: Option, pub world_restore_disable_cargo_economy_special_condition_reconstructible_from_save: Option, pub world_restore_disable_cargo_economy_special_condition_write_side_grounded: Option, pub world_restore_disable_cargo_economy_special_condition_enabled: Option, pub world_restore_use_bio_accelerator_cars_enabled: Option, pub world_restore_use_wartime_cargos_enabled: Option, pub world_restore_disable_train_crashes_enabled: Option, pub world_restore_disable_train_crashes_and_breakdowns_enabled: Option, pub world_restore_ai_ignore_territories_at_startup_enabled: Option, pub world_restore_economic_status_code: Option, pub world_restore_absolute_counter_restore_kind: Option, pub world_restore_absolute_counter_adjustment_context: Option, pub metadata_count: usize, pub company_count: usize, pub active_company_count: usize, pub player_count: usize, pub train_count: usize, pub active_train_count: usize, pub retired_train_count: usize, pub territory_count: usize, pub company_territory_track_count: usize, pub packed_event_collection_present: bool, pub packed_event_record_count: usize, pub packed_event_decoded_record_count: usize, pub packed_event_imported_runtime_record_count: usize, pub packed_event_parity_only_record_count: usize, pub packed_event_unsupported_record_count: usize, pub packed_event_blocked_missing_company_context_count: usize, pub packed_event_blocked_missing_selection_context_count: usize, pub packed_event_blocked_missing_company_role_context_count: usize, pub packed_event_blocked_missing_player_context_count: usize, pub packed_event_blocked_missing_player_selection_context_count: usize, pub packed_event_blocked_missing_player_role_context_count: usize, pub packed_event_blocked_missing_condition_context_count: usize, pub packed_event_blocked_missing_player_condition_context_count: usize, pub packed_event_blocked_company_condition_scope_disabled_count: usize, pub packed_event_blocked_player_condition_scope_count: usize, pub packed_event_blocked_territory_condition_scope_count: usize, pub packed_event_blocked_missing_territory_context_count: usize, pub packed_event_blocked_named_territory_binding_count: usize, pub packed_event_blocked_unmapped_ordinary_condition_count: usize, pub packed_event_blocked_unmapped_world_condition_count: usize, pub packed_event_blocked_missing_compact_control_count: usize, pub packed_event_blocked_unmapped_real_descriptor_count: usize, pub packed_event_blocked_unmapped_world_descriptor_count: usize, pub packed_event_blocked_territory_access_variant_count: usize, pub packed_event_blocked_territory_access_scope_count: usize, pub packed_event_blocked_missing_train_context_count: usize, pub packed_event_blocked_missing_train_territory_context_count: usize, pub packed_event_blocked_confiscation_variant_count: usize, pub packed_event_blocked_retire_train_variant_count: usize, pub packed_event_blocked_retire_train_scope_count: usize, pub packed_event_blocked_structural_only_count: usize, pub event_runtime_record_count: usize, pub candidate_availability_count: usize, pub zero_candidate_availability_count: usize, pub special_condition_count: usize, pub enabled_special_condition_count: usize, pub save_profile_kind: Option, pub save_profile_family: Option, pub save_profile_map_path: Option, pub save_profile_display_name: Option, pub save_profile_selected_year_profile_lane: Option, pub save_profile_sandbox_enabled: Option, pub save_profile_campaign_scenario_enabled: Option, pub save_profile_staged_profile_copy_on_restore: Option, pub total_event_record_service_count: u64, pub periodic_boundary_call_count: u64, pub total_trigger_dispatch_count: u64, pub dirty_rerun_count: u64, pub total_company_cash: i64, } impl RuntimeSummary { pub fn from_state(state: &RuntimeState) -> Self { Self { calendar: state.calendar, calendar_projection_source: state.metadata.get("save_slice.calendar_source").cloned(), calendar_projection_is_placeholder: state .metadata .get("save_slice.calendar_source") .is_some_and(|value| value == "default-1830-placeholder"), world_flag_count: state.world_flags.len(), world_restore_selected_year_profile_lane: state .world_restore .selected_year_profile_lane, world_restore_campaign_scenario_enabled: state.world_restore.campaign_scenario_enabled, world_restore_sandbox_enabled: state.world_restore.sandbox_enabled, world_restore_seed_tuple_written_from_raw_lane: state .world_restore .seed_tuple_written_from_raw_lane, world_restore_absolute_counter_requires_shell_context: state .world_restore .absolute_counter_requires_shell_context, world_restore_absolute_counter_reconstructible_from_save: state .world_restore .absolute_counter_reconstructible_from_save, world_restore_disable_cargo_economy_special_condition_slot: state .world_restore .disable_cargo_economy_special_condition_slot, world_restore_disable_cargo_economy_special_condition_reconstructible_from_save: state .world_restore .disable_cargo_economy_special_condition_reconstructible_from_save, world_restore_disable_cargo_economy_special_condition_write_side_grounded: state .world_restore .disable_cargo_economy_special_condition_write_side_grounded, world_restore_disable_cargo_economy_special_condition_enabled: state .world_restore .disable_cargo_economy_special_condition_enabled, world_restore_use_bio_accelerator_cars_enabled: state .world_restore .use_bio_accelerator_cars_enabled, world_restore_use_wartime_cargos_enabled: state .world_restore .use_wartime_cargos_enabled, world_restore_disable_train_crashes_enabled: state .world_restore .disable_train_crashes_enabled, world_restore_disable_train_crashes_and_breakdowns_enabled: state .world_restore .disable_train_crashes_and_breakdowns_enabled, world_restore_ai_ignore_territories_at_startup_enabled: state .world_restore .ai_ignore_territories_at_startup_enabled, world_restore_economic_status_code: state.world_restore.economic_status_code, world_restore_absolute_counter_restore_kind: state .world_restore .absolute_counter_restore_kind .clone(), world_restore_absolute_counter_adjustment_context: state .world_restore .absolute_counter_adjustment_context .clone(), metadata_count: state.metadata.len(), company_count: state.companies.len(), active_company_count: state .companies .iter() .filter(|company| company.active) .count(), player_count: state.players.len(), train_count: state.trains.len(), active_train_count: state.trains.iter().filter(|train| train.active).count(), retired_train_count: state.trains.iter().filter(|train| train.retired).count(), territory_count: state.territories.len(), company_territory_track_count: state.company_territory_track_piece_counts.len(), packed_event_collection_present: state.packed_event_collection.is_some(), packed_event_record_count: state .packed_event_collection .as_ref() .map(|summary| summary.live_record_count) .unwrap_or(0), packed_event_decoded_record_count: state .packed_event_collection .as_ref() .map(|summary| summary.decoded_record_count) .unwrap_or(0), packed_event_imported_runtime_record_count: state .packed_event_collection .as_ref() .map(|summary| summary.imported_runtime_record_count) .unwrap_or(0), packed_event_parity_only_record_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| record.decode_status == "parity_only") .count() }) .unwrap_or(0), packed_event_unsupported_record_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| record.decode_status == "unsupported_framing") .count() }) .unwrap_or(0), packed_event_blocked_missing_company_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_company_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_selection_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_selection_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_company_role_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_company_role_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_player_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_player_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_player_selection_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_player_selection_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_player_role_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_player_role_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_condition_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_condition_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_player_condition_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_player_condition_context") }) .count() }) .unwrap_or(0), packed_event_blocked_company_condition_scope_disabled_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_company_condition_scope_disabled") }) .count() }) .unwrap_or(0), packed_event_blocked_player_condition_scope_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_player_condition_scope") }) .count() }) .unwrap_or(0), packed_event_blocked_territory_condition_scope_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_territory_condition_scope") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_territory_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_territory_context") }) .count() }) .unwrap_or(0), packed_event_blocked_named_territory_binding_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_named_territory_binding") }) .count() }) .unwrap_or(0), packed_event_blocked_unmapped_ordinary_condition_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_unmapped_ordinary_condition") }) .count() }) .unwrap_or(0), packed_event_blocked_unmapped_world_condition_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_unmapped_world_condition") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_compact_control_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_compact_control") }) .count() }) .unwrap_or(0), packed_event_blocked_unmapped_real_descriptor_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_unmapped_real_descriptor") }) .count() }) .unwrap_or(0), packed_event_blocked_unmapped_world_descriptor_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_unmapped_world_descriptor") }) .count() }) .unwrap_or(0), packed_event_blocked_territory_access_variant_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_territory_access_variant") }) .count() }) .unwrap_or(0), packed_event_blocked_territory_access_scope_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_territory_access_scope") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_train_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_train_context") }) .count() }) .unwrap_or(0), packed_event_blocked_missing_train_territory_context_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_missing_train_territory_context") }) .count() }) .unwrap_or(0), packed_event_blocked_confiscation_variant_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_confiscation_variant") }) .count() }) .unwrap_or(0), packed_event_blocked_retire_train_variant_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_retire_train_variant") }) .count() }) .unwrap_or(0), packed_event_blocked_retire_train_scope_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_retire_train_scope") }) .count() }) .unwrap_or(0), packed_event_blocked_structural_only_count: state .packed_event_collection .as_ref() .map(|summary| { summary .records .iter() .filter(|record| { record.import_outcome.as_deref() == Some("blocked_structural_only") }) .count() }) .unwrap_or(0), event_runtime_record_count: state.event_runtime_records.len(), candidate_availability_count: state.candidate_availability.len(), zero_candidate_availability_count: state .candidate_availability .values() .filter(|value| **value == 0) .count(), special_condition_count: state.special_conditions.len(), enabled_special_condition_count: state .special_conditions .values() .filter(|value| **value != 0) .count(), save_profile_kind: state.save_profile.profile_kind.clone(), save_profile_family: state.save_profile.profile_family.clone(), save_profile_map_path: state.save_profile.map_path.clone(), save_profile_display_name: state.save_profile.display_name.clone(), save_profile_selected_year_profile_lane: state.save_profile.selected_year_profile_lane, save_profile_sandbox_enabled: state.save_profile.sandbox_enabled, save_profile_campaign_scenario_enabled: state.save_profile.campaign_scenario_enabled, save_profile_staged_profile_copy_on_restore: state .save_profile .staged_profile_copy_on_restore, total_event_record_service_count: state.service_state.total_event_record_services, periodic_boundary_call_count: state.service_state.periodic_boundary_calls, total_trigger_dispatch_count: state .service_state .trigger_dispatch_counts .values() .sum(), dirty_rerun_count: state.service_state.dirty_rerun_count, total_company_cash: state .companies .iter() .map(|company| company.current_cash) .sum(), } } } #[cfg(test)] mod tests { use std::collections::BTreeMap; use crate::{ CalendarPoint, RuntimeCompany, RuntimeCompanyControllerKind, RuntimePackedEventCollectionSummary, RuntimePackedEventRecordSummary, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState, RuntimeTrackPieceCounts, RuntimeWorldRestoreState, }; use super::RuntimeSummary; #[test] fn counts_structural_only_and_missing_context_frontiers() { let state = RuntimeState { calendar: CalendarPoint { year: 1830, month_slot: 0, phase_slot: 0, tick_slot: 0, }, world_flags: BTreeMap::new(), save_profile: RuntimeSaveProfileState::default(), world_restore: RuntimeWorldRestoreState::default(), metadata: BTreeMap::new(), companies: Vec::new(), selected_company_id: None, players: Vec::new(), selected_player_id: None, trains: Vec::new(), territories: Vec::new(), company_territory_track_piece_counts: Vec::new(), company_territory_access: Vec::new(), packed_event_collection: Some(RuntimePackedEventCollectionSummary { source_kind: "packed-event-runtime-collection".to_string(), mechanism_family: "classic-save-rehydrate-v1".to_string(), mechanism_confidence: "grounded".to_string(), container_profile_family: Some("rt3-classic-save-container-v1".to_string()), packed_state_version: 0x3e9, packed_state_version_hex: "0x000003e9".to_string(), live_id_bound: 11, live_record_count: 5, live_entry_ids: vec![3, 7, 9, 10, 11], decoded_record_count: 5, imported_runtime_record_count: 0, records: vec![ RuntimePackedEventRecordSummary { record_index: 0, live_entry_id: 3, payload_offset: Some(0x7202), payload_len: Some(96), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: None, active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_missing_compact_control".to_string()), notes: Vec::new(), }, RuntimePackedEventRecordSummary { record_index: 1, live_entry_id: 7, payload_offset: Some(0x7262), payload_len: Some(48), decode_status: "parity_only".to_string(), payload_family: "synthetic_harness".to_string(), trigger_kind: Some(7), active: Some(true), marks_collection_dirty: Some(false), one_shot: Some(false), compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_missing_company_context".to_string()), notes: Vec::new(), }, RuntimePackedEventRecordSummary { record_index: 2, live_entry_id: 9, payload_offset: Some(0x7292), payload_len: Some(48), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: Some(7), active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some( "blocked_company_condition_scope_disabled".to_string(), ), notes: Vec::new(), }, RuntimePackedEventRecordSummary { record_index: 3, live_entry_id: 10, payload_offset: Some(0x72c2), payload_len: Some(48), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: Some(7), active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_player_condition_scope".to_string()), notes: Vec::new(), }, RuntimePackedEventRecordSummary { record_index: 4, live_entry_id: 11, payload_offset: Some(0x72f2), payload_len: Some(48), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: Some(7), active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_territory_condition_scope".to_string()), notes: Vec::new(), }, ], }), event_runtime_records: Vec::new(), candidate_availability: BTreeMap::new(), special_conditions: BTreeMap::new(), service_state: RuntimeServiceState::default(), }; let summary = RuntimeSummary::from_state(&state); assert_eq!( summary.packed_event_blocked_missing_compact_control_count, 1 ); assert_eq!( summary.packed_event_blocked_unmapped_real_descriptor_count, 0 ); assert_eq!(summary.packed_event_blocked_structural_only_count, 0); assert_eq!( summary.packed_event_blocked_missing_company_context_count, 1 ); assert_eq!( summary.packed_event_blocked_missing_selection_context_count, 0 ); assert_eq!( summary.packed_event_blocked_missing_company_role_context_count, 0 ); assert_eq!( summary.packed_event_blocked_missing_condition_context_count, 0 ); assert_eq!( summary.packed_event_blocked_company_condition_scope_disabled_count, 1 ); assert_eq!(summary.packed_event_blocked_player_condition_scope_count, 1); assert_eq!( summary.packed_event_blocked_territory_condition_scope_count, 1 ); } #[test] fn counts_active_companies_separately_from_total_companies() { let state = RuntimeState { calendar: CalendarPoint { year: 1830, month_slot: 0, phase_slot: 0, tick_slot: 0, }, world_flags: BTreeMap::new(), save_profile: RuntimeSaveProfileState::default(), world_restore: RuntimeWorldRestoreState::default(), metadata: BTreeMap::new(), companies: vec![ RuntimeCompany { company_id: 1, current_cash: 10, debt: 0, credit_rating_score: None, prime_rate: None, track_piece_counts: RuntimeTrackPieceCounts::default(), active: true, available_track_laying_capacity: None, controller_kind: RuntimeCompanyControllerKind::Human, }, RuntimeCompany { company_id: 2, current_cash: 20, debt: 0, credit_rating_score: None, prime_rate: None, track_piece_counts: RuntimeTrackPieceCounts::default(), active: false, available_track_laying_capacity: Some(7), controller_kind: RuntimeCompanyControllerKind::Ai, }, ], selected_company_id: None, players: Vec::new(), selected_player_id: None, trains: Vec::new(), territories: Vec::new(), company_territory_track_piece_counts: Vec::new(), company_territory_access: Vec::new(), packed_event_collection: None, event_runtime_records: Vec::new(), candidate_availability: BTreeMap::new(), special_conditions: BTreeMap::new(), service_state: RuntimeServiceState::default(), }; let summary = RuntimeSummary::from_state(&state); assert_eq!(summary.company_count, 2); assert_eq!(summary.active_company_count, 1); } #[test] fn counts_world_frontier_buckets_separately() { let state = RuntimeState { calendar: CalendarPoint { year: 1830, month_slot: 0, phase_slot: 0, tick_slot: 0, }, world_flags: BTreeMap::new(), save_profile: RuntimeSaveProfileState::default(), world_restore: RuntimeWorldRestoreState::default(), metadata: BTreeMap::new(), companies: Vec::new(), selected_company_id: None, players: Vec::new(), selected_player_id: None, trains: Vec::new(), territories: Vec::new(), company_territory_track_piece_counts: Vec::new(), company_territory_access: Vec::new(), packed_event_collection: Some(RuntimePackedEventCollectionSummary { source_kind: "packed-event-runtime-collection".to_string(), mechanism_family: "classic-save-rehydrate-v1".to_string(), mechanism_confidence: "grounded".to_string(), container_profile_family: Some("rt3-classic-save-container-v1".to_string()), packed_state_version: 0x3e9, packed_state_version_hex: "0x000003e9".to_string(), live_id_bound: 2, live_record_count: 2, live_entry_ids: vec![21, 22], decoded_record_count: 2, imported_runtime_record_count: 0, records: vec![ RuntimePackedEventRecordSummary { record_index: 0, live_entry_id: 21, payload_offset: Some(0x7202), payload_len: Some(96), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: Some(7), active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 0, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![1, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_unmapped_world_descriptor".to_string()), notes: Vec::new(), }, RuntimePackedEventRecordSummary { record_index: 1, live_entry_id: 22, payload_offset: Some(0x7242), payload_len: Some(96), decode_status: "parity_only".to_string(), payload_family: "real_packed_v1".to_string(), trigger_kind: Some(7), active: None, marks_collection_dirty: None, one_shot: None, compact_control: None, text_bands: Vec::new(), standalone_condition_row_count: 1, standalone_condition_rows: Vec::new(), negative_sentinel_scope: None, grouped_effect_row_counts: vec![0, 0, 0, 0], grouped_effect_rows: Vec::new(), grouped_company_targets: Vec::new(), decoded_conditions: Vec::new(), decoded_actions: Vec::new(), executable_import_ready: false, import_outcome: Some("blocked_unmapped_world_condition".to_string()), notes: Vec::new(), }, ], }), event_runtime_records: Vec::new(), candidate_availability: BTreeMap::new(), special_conditions: BTreeMap::new(), service_state: RuntimeServiceState::default(), }; let summary = RuntimeSummary::from_state(&state); assert_eq!( summary.packed_event_blocked_unmapped_world_descriptor_count, 1 ); assert_eq!( summary.packed_event_blocked_unmapped_world_condition_count, 1 ); } }