diff --git a/README.md b/README.md index 4c7b959..f6c617e 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,9 @@ through checked-in metadata into keyed `world_flags`, while the wider locomotive scalar bands are now split more cleanly: the boolean `0/1` availability subset can import through an overlay-backed `RuntimeState.locomotive_catalog` into `RuntimeState.named_locomotive_availability`, while non-boolean availability payloads plus the -locomotive-cost/cargo-production/territory-access-cost families remain recovered-but-parity-only. +locomotive-cost/cargo-production/territory-access-cost families now surface as recovered, +metadata-rich parity rows with checked-in slot labels and locomotive ids where grounded, but they +still remain non-executable. The runtime still carries the save-owned named locomotive availability table directly too: checked-in save-slice documents can populate `RuntimeState.named_locomotive_availability`, and imported runtime effects can mutate that map through the ordinary event-service path without diff --git a/crates/rrt-cli/src/main.rs b/crates/rrt-cli/src/main.rs index f053520..8602605 100644 --- a/crates/rrt-cli/src/main.rs +++ b/crates/rrt-cli/src/main.rs @@ -4463,6 +4463,9 @@ mod tests { let overlay_locomotive_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( "../../fixtures/runtime/packed-event-locomotive-availability-overlay-fixture.json", ); + let scalar_band_parity_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( + "../../fixtures/runtime/packed-event-world-scalar-band-parity-save-slice-fixture.json", + ); run_runtime_summarize_fixture(&parity_fixture) .expect("save-slice-backed parity fixture should summarize"); @@ -4487,6 +4490,8 @@ mod tests { ); run_runtime_summarize_fixture(&overlay_locomotive_fixture) .expect("overlay-backed locomotive availability fixture should summarize"); + run_runtime_summarize_fixture(&scalar_band_parity_fixture) + .expect("save-slice-backed recovered scalar-band parity fixture should summarize"); } #[test] diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index 5b67f4f..4abb1e2 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -3070,11 +3070,19 @@ mod tests { descriptor_id: u32, value: i32, ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { + let recovered_locomotive_id = match descriptor_id { + 352..=451 => Some(descriptor_id - 351), + 475..=500 => Some(descriptor_id - 374), + _ => None, + }; + let descriptor_label = recovered_locomotive_id + .map(|loco_id| format!("Locomotive {loco_id} Cost")) + .unwrap_or_else(|| "Locomotive Cost".to_string()); crate::SmpLoadedPackedEventGroupedEffectRowSummary { group_index: 0, row_index: 0, descriptor_id, - descriptor_label: Some("Unknown Loco Cost".to_string()), + descriptor_label: Some(descriptor_label.clone()), target_mask_bits: Some(0x08), parameter_family: Some("locomotive_cost_scalar".to_string()), opcode: 3, @@ -3087,12 +3095,65 @@ mod tests { value_word_0x16: 0, row_shape: "scalar_assignment".to_string(), semantic_family: Some("scalar_assignment".to_string()), - semantic_preview: Some(format!("Set Unknown Loco Cost to {value}")), - recovered_locomotive_id: match descriptor_id { - 352..=451 => Some(descriptor_id - 351), - 475..=500 => Some(descriptor_id - 374), - _ => None, - }, + semantic_preview: Some(format!("Set {descriptor_label} to {value}")), + recovered_locomotive_id, + locomotive_name: None, + notes: vec![], + } + } + + fn real_cargo_production_row( + descriptor_id: u32, + value: i32, + ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { + let slot = descriptor_id.saturating_sub(229); + let descriptor_label = format!("Cargo Production Slot {slot}"); + crate::SmpLoadedPackedEventGroupedEffectRowSummary { + group_index: 0, + row_index: 0, + descriptor_id, + descriptor_label: Some(descriptor_label.clone()), + target_mask_bits: Some(0x08), + parameter_family: Some("cargo_production_scalar".to_string()), + opcode: 3, + raw_scalar_value: value, + value_byte_0x09: 0, + value_dword_0x0d: 0, + value_byte_0x11: 0, + value_byte_0x12: 0, + value_word_0x14: 0, + value_word_0x16: 0, + row_shape: "scalar_assignment".to_string(), + semantic_family: Some("scalar_assignment".to_string()), + semantic_preview: Some(format!("Set {descriptor_label} to {value}")), + recovered_locomotive_id: None, + locomotive_name: None, + notes: vec![], + } + } + + fn real_territory_access_cost_row( + value: i32, + ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { + crate::SmpLoadedPackedEventGroupedEffectRowSummary { + group_index: 0, + row_index: 0, + descriptor_id: 453, + descriptor_label: Some("Territory Access Cost".to_string()), + target_mask_bits: Some(0x08), + parameter_family: Some("territory_access_cost_scalar".to_string()), + opcode: 3, + raw_scalar_value: value, + value_byte_0x09: 0, + value_dword_0x0d: 0, + value_byte_0x11: 0, + value_byte_0x12: 0, + value_word_0x14: 0, + value_word_0x16: 0, + row_shape: "scalar_assignment".to_string(), + semantic_family: Some("scalar_assignment".to_string()), + semantic_preview: Some(format!("Set Territory Access Cost to {value}")), + recovered_locomotive_id: None, locomotive_name: None, notes: vec![], } @@ -5155,6 +5216,152 @@ mod tests { ); } + #[test] + fn keeps_recovered_cargo_production_rows_parity_only() { + let save_slice = SmpLoadedSaveSlice { + file_extension_hint: Some("gms".to_string()), + container_profile_family: Some("rt3-classic-save-container-v1".to_string()), + mechanism_family: "classic-save-rehydrate-v1".to_string(), + mechanism_confidence: "grounded".to_string(), + trailer_family: None, + bridge_family: None, + profile: None, + candidate_availability_table: None, + named_locomotive_availability_table: None, + special_conditions_table: None, + event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary { + 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()), + metadata_tag_offset: 0x7100, + records_tag_offset: 0x7200, + close_tag_offset: 0x7600, + packed_state_version: 0x3e9, + packed_state_version_hex: "0x000003e9".to_string(), + live_id_bound: 35, + live_record_count: 1, + live_entry_ids: vec![35], + decoded_record_count: 1, + imported_runtime_record_count: 0, + records: vec![crate::SmpLoadedPackedEventRecordSummary { + record_index: 0, + live_entry_id: 35, + 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: Some(false), + compact_control: Some(real_compact_control()), + text_bands: vec![], + standalone_condition_row_count: 0, + standalone_condition_rows: vec![], + negative_sentinel_scope: None, + grouped_effect_row_counts: vec![1, 0, 0, 0], + grouped_effect_rows: vec![real_cargo_production_row(230, 125)], + decoded_conditions: Vec::new(), + decoded_actions: vec![], + executable_import_ready: false, + notes: vec!["cargo production rows remain metadata-only".to_string()], + }], + }), + notes: vec![], + }; + + let import = project_save_slice_to_runtime_state_import( + &save_slice, + "packed-events-cargo-production-frontier", + None, + ) + .expect("save slice should project"); + + assert!(import.state.event_runtime_records.is_empty()); + assert_eq!( + import + .state + .packed_event_collection + .as_ref() + .and_then(|summary| summary.records[0].import_outcome.as_deref()), + Some("blocked_unmapped_world_descriptor") + ); + } + + #[test] + fn keeps_recovered_territory_access_cost_rows_parity_only() { + let save_slice = SmpLoadedSaveSlice { + file_extension_hint: Some("gms".to_string()), + container_profile_family: Some("rt3-classic-save-container-v1".to_string()), + mechanism_family: "classic-save-rehydrate-v1".to_string(), + mechanism_confidence: "grounded".to_string(), + trailer_family: None, + bridge_family: None, + profile: None, + candidate_availability_table: None, + named_locomotive_availability_table: None, + special_conditions_table: None, + event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary { + 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()), + metadata_tag_offset: 0x7100, + records_tag_offset: 0x7200, + close_tag_offset: 0x7600, + packed_state_version: 0x3e9, + packed_state_version_hex: "0x000003e9".to_string(), + live_id_bound: 36, + live_record_count: 1, + live_entry_ids: vec![36], + decoded_record_count: 1, + imported_runtime_record_count: 0, + records: vec![crate::SmpLoadedPackedEventRecordSummary { + record_index: 0, + live_entry_id: 36, + 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: Some(false), + compact_control: Some(real_compact_control()), + text_bands: vec![], + standalone_condition_row_count: 0, + standalone_condition_rows: vec![], + negative_sentinel_scope: None, + grouped_effect_row_counts: vec![1, 0, 0, 0], + grouped_effect_rows: vec![real_territory_access_cost_row(750000)], + decoded_conditions: Vec::new(), + decoded_actions: vec![], + executable_import_ready: false, + notes: vec!["territory access cost rows remain metadata-only".to_string()], + }], + }), + notes: vec![], + }; + + let import = project_save_slice_to_runtime_state_import( + &save_slice, + "packed-events-territory-access-cost-frontier", + None, + ) + .expect("save slice should project"); + + assert!(import.state.event_runtime_records.is_empty()); + assert_eq!( + import + .state + .packed_event_collection + .as_ref() + .and_then(|summary| summary.records[0].import_outcome.as_deref()), + Some("blocked_unmapped_world_descriptor") + ); + } + #[test] fn overlays_real_company_cash_descriptor_into_executable_runtime_record() { let base_state = RuntimeState { diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index f8629c4..052ffcb 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -1,5 +1,7 @@ +use std::collections::BTreeMap; use std::fs; use std::path::Path; +use std::sync::OnceLock; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -2684,6 +2686,11 @@ fn parse_real_grouped_effect_row_summary( "locomotive availability descriptor maps to live locomotive id {loco_id}" )); } + if let Some(loco_id) = recovered_locomotive_cost_loco_id(descriptor_id) { + notes.push(format!( + "locomotive cost descriptor maps to live locomotive id {loco_id}" + )); + } Some(SmpLoadedPackedEventGroupedEffectRowSummary { group_index, @@ -2711,7 +2718,8 @@ fn parse_real_grouped_effect_row_summary( value_word_0x14, value_word_0x16, )), - recovered_locomotive_id: recovered_locomotive_availability_loco_id(descriptor_id), + recovered_locomotive_id: recovered_locomotive_availability_loco_id(descriptor_id) + .or_else(|| recovered_locomotive_cost_loco_id(descriptor_id)), locomotive_name, notes, }) @@ -2823,16 +2831,16 @@ fn real_grouped_effect_descriptor_metadata( fn recovered_cargo_production_descriptor_metadata( descriptor_id: u32, ) -> Option { - (230..=240) - .contains(&descriptor_id) - .then_some(RealGroupedEffectDescriptorMetadata { + recovered_cargo_production_label(descriptor_id).map(|label| { + RealGroupedEffectDescriptorMetadata { descriptor_id, - label: "Unknown Cargo Production", + label, target_mask_bits: 0x08, - parameter_family: "unknown_cargo_production_scalar", + parameter_family: "cargo_production_scalar", runtime_key: None, executable_in_runtime: false, - }) + } + }) } fn recovered_locomotive_availability_descriptor_metadata( @@ -2872,31 +2880,66 @@ fn recovered_locomotive_availability_loco_id(descriptor_id: u32) -> Option None } +fn recovered_cargo_production_label(descriptor_id: u32) -> Option<&'static str> { + static LABELS: OnceLock> = OnceLock::new(); + LABELS + .get_or_init(|| { + (230..=240) + .enumerate() + .map(|(slot_index, descriptor_id)| { + let label = Box::leak( + format!("Cargo Production Slot {}", slot_index + 1).into_boxed_str(), + ) as &'static str; + (descriptor_id, label) + }) + .collect() + }) + .get(&descriptor_id) + .copied() +} + +fn recovered_locomotive_cost_loco_id(descriptor_id: u32) -> Option { + if (352..=451).contains(&descriptor_id) { + return Some(descriptor_id - 351); + } + if (475..=500).contains(&descriptor_id) { + return Some(descriptor_id - 374); + } + None +} + +fn recovered_locomotive_cost_label(descriptor_id: u32) -> Option<&'static str> { + static LABELS: OnceLock> = OnceLock::new(); + LABELS + .get_or_init(|| { + (352..=451) + .chain(475..=500) + .filter_map(|descriptor_id| { + recovered_locomotive_cost_loco_id(descriptor_id).map(|loco_id| { + let label = Box::leak(format!("Locomotive {loco_id} Cost").into_boxed_str()) + as &'static str; + (descriptor_id, label) + }) + }) + .collect() + }) + .get(&descriptor_id) + .copied() +} + fn recovered_locomotive_cost_descriptor_metadata( descriptor_id: u32, ) -> Option { - (352..=451) - .contains(&descriptor_id) - .then_some(RealGroupedEffectDescriptorMetadata { + recovered_locomotive_cost_label(descriptor_id).map(|label| { + RealGroupedEffectDescriptorMetadata { descriptor_id, - label: "Unknown Loco Cost", + label, target_mask_bits: 0x08, parameter_family: "locomotive_cost_scalar", runtime_key: None, executable_in_runtime: false, - }) - .or_else(|| { - (475..=500) - .contains(&descriptor_id) - .then_some(RealGroupedEffectDescriptorMetadata { - descriptor_id, - label: "Unknown Loco Cost", - target_mask_bits: 0x08, - parameter_family: "locomotive_cost_scalar", - runtime_key: None, - executable_in_runtime: false, - }) - }) + } + }) } fn recovered_territory_access_cost_descriptor_metadata( @@ -2904,7 +2947,7 @@ fn recovered_territory_access_cost_descriptor_metadata( ) -> Option { (descriptor_id == 453).then_some(RealGroupedEffectDescriptorMetadata { descriptor_id, - label: "Territory access cost", + label: "Territory Access Cost", target_mask_bits: 0x08, parameter_family: "territory_access_cost_scalar", runtime_key: None, @@ -9292,6 +9335,81 @@ mod tests { ); } + #[test] + fn looks_up_recovered_cargo_production_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(230).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Cargo Production Slot 1"); + assert_eq!(metadata.target_mask_bits, 0x08); + assert_eq!(metadata.parameter_family, "cargo_production_scalar"); + assert_eq!(metadata.runtime_key, None); + assert!(!metadata.executable_in_runtime); + } + + #[test] + fn looks_up_recovered_lower_band_locomotive_cost_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(352).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Locomotive 1 Cost"); + assert_eq!(metadata.target_mask_bits, 0x08); + assert_eq!(metadata.parameter_family, "locomotive_cost_scalar"); + assert_eq!(metadata.runtime_key, None); + assert_eq!(recovered_locomotive_cost_loco_id(352), Some(1)); + assert!(!metadata.executable_in_runtime); + } + + #[test] + fn looks_up_recovered_upper_band_locomotive_cost_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(475).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Locomotive 101 Cost"); + assert_eq!(metadata.parameter_family, "locomotive_cost_scalar"); + assert_eq!(recovered_locomotive_cost_loco_id(475), Some(101)); + assert!(!metadata.executable_in_runtime); + } + + #[test] + fn looks_up_recovered_territory_access_cost_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(453).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Territory Access Cost"); + assert_eq!(metadata.target_mask_bits, 0x08); + assert_eq!(metadata.parameter_family, "territory_access_cost_scalar"); + assert_eq!(metadata.runtime_key, None); + assert!(!metadata.executable_in_runtime); + } + + #[test] + fn parses_recovered_locomotive_cost_row_with_structured_locomotive_id() { + let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec { + descriptor_id: 352, + raw_scalar_value: 250000, + opcode: 3, + value_byte_0x09: 0, + value_dword_0x0d: 0, + value_byte_0x11: 0, + value_byte_0x12: 0, + value_word_0x14: 0, + value_word_0x16: 0, + locomotive_name: None, + }); + + let row = parse_real_grouped_effect_row_summary(&row_bytes, 0, 0, None) + .expect("row should parse"); + + assert_eq!(row.descriptor_id, 352); + assert_eq!(row.descriptor_label.as_deref(), Some("Locomotive 1 Cost")); + assert_eq!(row.recovered_locomotive_id, Some(1)); + assert_eq!( + row.parameter_family.as_deref(), + Some("locomotive_cost_scalar") + ); + } + #[test] fn looks_up_recovered_locomotive_policy_descriptor_metadata() { let metadata = diff --git a/docs/README.md b/docs/README.md index cc99fbe..5a49b70 100644 --- a/docs/README.md +++ b/docs/README.md @@ -125,8 +125,9 @@ The highest-value next passes are now: `blocked_unmapped_world_descriptor` frontier - the next recovered locomotives-page descriptor batch is partially executable too: descriptors `454..456` (`All Steam/Diesel/Electric Locos Avail.`) now lower through checked-in - metadata into keyed `world_flags`, while the wider locomotive availability/cost scalar bands - remain recovered-but-parity-only until per-locomotive identity is grounded + metadata into keyed `world_flags`, while the wider locomotive availability/cost scalar bands now + split cleanly between executable boolean availability rows and recovered metadata-rich parity + rows for the remaining cargo-production, locomotive-cost, and territory-access-cost families - the runtime now also carries both the save-owned named locomotive availability table and an overlay-backed locomotive catalog context: checked-in save-slice documents can populate `RuntimeState.named_locomotive_availability`, and boolean `0/1` availability descriptors can diff --git a/docs/runtime-rehost-plan.md b/docs/runtime-rehost-plan.md index 90fd199..ba673cd 100644 --- a/docs/runtime-rehost-plan.md +++ b/docs/runtime-rehost-plan.md @@ -88,12 +88,15 @@ Implemented today: through the ordinary event-service path without requiring Trainbuy or live locomotive-pool parity - the boolean `0/1` subset of the recovered locomotives-page availability bands can now import through an overlay-backed `RuntimeState.locomotive_catalog`; non-boolean availability payloads - and the adjacent locomotive-cost/cargo-production/access-cost families remain parity-only + and the adjacent locomotive-cost/cargo-production/access-cost families now surface as recovered + metadata-rich parity rows with checked-in slot labels and locomotive ids where grounded, but + execution for those scalar families remains deferred That means the next implementation work is breadth, not bootstrap. The recommended next slice is -broader real grouped-descriptor and ordinary condition-id coverage beyond the current access, -whole-game toggle, train, player, numeric-threshold, named locomotive availability, and -overlay-resolved locomotive availability batches. +honest landing surfaces for one or more of those recovered scalar families, plus broader real +grouped-descriptor and ordinary condition-id coverage beyond the current access, whole-game +toggle, train, player, numeric-threshold, named locomotive availability, and overlay-resolved +locomotive availability batches. Richer runtime ownership should still be added only where a later descriptor or condition family needs more than the current event-owned roster. diff --git a/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice-fixture.json b/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice-fixture.json new file mode 100644 index 0000000..b10a463 --- /dev/null +++ b/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice-fixture.json @@ -0,0 +1,97 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-scalar-band-parity-save-slice-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture backed by a tracked save-slice document that pins recovered scalar-band world descriptors as parity-only." + }, + "state_save_slice_path": "packed-event-world-scalar-band-parity-save-slice.json", + "commands": [ + { + "kind": "step_count", + "steps": 1 + } + ], + "expected_summary": { + "calendar": { + "year": 1830, + "month_slot": 0, + "phase_slot": 0, + "tick_slot": 1 + }, + "calendar_projection_is_placeholder": true, + "packed_event_collection_present": true, + "packed_event_record_count": 3, + "packed_event_decoded_record_count": 3, + "packed_event_imported_runtime_record_count": 0, + "packed_event_parity_only_record_count": 3, + "packed_event_unsupported_record_count": 0, + "packed_event_blocked_missing_condition_context_count": 0, + "packed_event_blocked_territory_condition_scope_count": 0, + "packed_event_blocked_missing_compact_control_count": 0, + "packed_event_blocked_unmapped_real_descriptor_count": 0, + "packed_event_blocked_unmapped_world_descriptor_count": 3, + "packed_event_blocked_structural_only_count": 0, + "event_runtime_record_count": 0, + "total_company_cash": 0 + }, + "expected_state_fragment": { + "metadata": { + "save_slice.import_projection": "partial-runtime-restore-v1" + }, + "packed_event_collection": { + "live_entry_ids": [11, 12, 13], + "records": [ + { + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "import_outcome": "blocked_unmapped_world_descriptor", + "grouped_effect_rows": [ + { + "descriptor_id": 230, + "descriptor_label": "Cargo Production Slot 1", + "target_mask_bits": 8, + "parameter_family": "cargo_production_scalar", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Cargo Production Slot 1 to 125", + "row_shape": "scalar_assignment" + } + ] + }, + { + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "import_outcome": "blocked_unmapped_world_descriptor", + "grouped_effect_rows": [ + { + "descriptor_id": 352, + "descriptor_label": "Locomotive 1 Cost", + "target_mask_bits": 8, + "parameter_family": "locomotive_cost_scalar", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Locomotive 1 Cost to 250000", + "recovered_locomotive_id": 1, + "row_shape": "scalar_assignment" + } + ] + }, + { + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "import_outcome": "blocked_unmapped_world_descriptor", + "grouped_effect_rows": [ + { + "descriptor_id": 453, + "descriptor_label": "Territory Access Cost", + "target_mask_bits": 8, + "parameter_family": "territory_access_cost_scalar", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Territory Access Cost to 750000", + "row_shape": "scalar_assignment" + } + ] + } + ] + } + } +} diff --git a/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice.json b/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice.json new file mode 100644 index 0000000..54594c8 --- /dev/null +++ b/fixtures/runtime/packed-event-world-scalar-band-parity-save-slice.json @@ -0,0 +1,213 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-scalar-band-parity-save-slice", + "source": { + "description": "Tracked save-slice document pinning recovered locomotives-page scalar families that are still parity-only.", + "original_save_filename": "captured-world-scalar-band-parity.gms", + "original_save_sha256": "world-scalar-band-parity-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "covers recovered cargo production, locomotive cost, and territory access cost families without claiming executable runtime semantics" + ] + }, + "save_slice": { + "file_extension_hint": "gms", + "container_profile_family": "rt3-classic-save-container-v1", + "mechanism_family": "classic-save-rehydrate-v1", + "mechanism_confidence": "grounded", + "trailer_family": null, + "bridge_family": null, + "profile": null, + "candidate_availability_table": null, + "named_locomotive_availability_table": null, + "special_conditions_table": null, + "event_runtime_collection": { + "source_kind": "packed-event-runtime-collection", + "mechanism_family": "classic-save-rehydrate-v1", + "mechanism_confidence": "grounded", + "container_profile_family": "rt3-classic-save-container-v1", + "metadata_tag_offset": 29696, + "records_tag_offset": 29952, + "close_tag_offset": 30720, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 13, + "live_record_count": 3, + "live_entry_ids": [11, 12, 13], + "decoded_record_count": 3, + "imported_runtime_record_count": 0, + "records": [ + { + "record_index": 0, + "live_entry_id": 11, + "payload_offset": 29984, + "payload_len": 96, + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "trigger_kind": 6, + "one_shot": false, + "compact_control": { + "mode_byte_0x7ef": 6, + "primary_selector_0x7f0": 0, + "grouped_mode_0x7f4": 2, + "one_shot_header_0x7f5": 0, + "modifier_flag_0x7f9": 0, + "modifier_flag_0x7fa": 0, + "grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0], + "grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0], + "summary_toggle_0x800": 1, + "grouped_territory_selectors_0x80f": [-1, -1, -1, -1] + }, + "text_bands": [], + "standalone_condition_row_count": 0, + "standalone_condition_rows": [], + "grouped_effect_row_counts": [1, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 230, + "descriptor_label": "Cargo Production Slot 1", + "target_mask_bits": 8, + "parameter_family": "cargo_production_scalar", + "opcode": 3, + "raw_scalar_value": 125, + "value_byte_0x09": 0, + "value_dword_0x0d": 0, + "value_byte_0x11": 0, + "value_byte_0x12": 0, + "value_word_0x14": 0, + "value_word_0x16": 0, + "row_shape": "scalar_assignment", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Cargo Production Slot 1 to 125", + "recovered_locomotive_id": null, + "locomotive_name": null, + "notes": [] + } + ], + "decoded_actions": [], + "executable_import_ready": false, + "notes": [ + "recovered cargo production metadata is now checked in, but no runtime landing surface exists yet" + ] + }, + { + "record_index": 1, + "live_entry_id": 12, + "payload_offset": 30096, + "payload_len": 96, + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "trigger_kind": 6, + "one_shot": false, + "compact_control": { + "mode_byte_0x7ef": 6, + "primary_selector_0x7f0": 0, + "grouped_mode_0x7f4": 2, + "one_shot_header_0x7f5": 0, + "modifier_flag_0x7f9": 0, + "modifier_flag_0x7fa": 0, + "grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0], + "grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0], + "summary_toggle_0x800": 1, + "grouped_territory_selectors_0x80f": [-1, -1, -1, -1] + }, + "text_bands": [], + "standalone_condition_row_count": 0, + "standalone_condition_rows": [], + "grouped_effect_row_counts": [1, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 352, + "descriptor_label": "Locomotive 1 Cost", + "target_mask_bits": 8, + "parameter_family": "locomotive_cost_scalar", + "opcode": 3, + "raw_scalar_value": 250000, + "value_byte_0x09": 0, + "value_dword_0x0d": 0, + "value_byte_0x11": 0, + "value_byte_0x12": 0, + "value_word_0x14": 0, + "value_word_0x16": 0, + "row_shape": "scalar_assignment", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Locomotive 1 Cost to 250000", + "recovered_locomotive_id": 1, + "locomotive_name": null, + "notes": [ + "locomotive cost descriptor maps to live locomotive id 1" + ] + } + ], + "decoded_actions": [], + "executable_import_ready": false, + "notes": [ + "recovered locomotive cost metadata is now checked in, but execution is still deferred" + ] + }, + { + "record_index": 2, + "live_entry_id": 13, + "payload_offset": 30208, + "payload_len": 96, + "decode_status": "parity_only", + "payload_family": "real_packed_v1", + "trigger_kind": 6, + "one_shot": false, + "compact_control": { + "mode_byte_0x7ef": 6, + "primary_selector_0x7f0": 0, + "grouped_mode_0x7f4": 2, + "one_shot_header_0x7f5": 0, + "modifier_flag_0x7f9": 0, + "modifier_flag_0x7fa": 0, + "grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0], + "grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0], + "summary_toggle_0x800": 1, + "grouped_territory_selectors_0x80f": [-1, -1, -1, -1] + }, + "text_bands": [], + "standalone_condition_row_count": 0, + "standalone_condition_rows": [], + "grouped_effect_row_counts": [1, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 453, + "descriptor_label": "Territory Access Cost", + "target_mask_bits": 8, + "parameter_family": "territory_access_cost_scalar", + "opcode": 3, + "raw_scalar_value": 750000, + "value_byte_0x09": 0, + "value_dword_0x0d": 0, + "value_byte_0x11": 0, + "value_byte_0x12": 0, + "value_word_0x14": 0, + "value_word_0x16": 0, + "row_shape": "scalar_assignment", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Territory Access Cost to 750000", + "recovered_locomotive_id": null, + "locomotive_name": null, + "notes": [] + } + ], + "decoded_actions": [], + "executable_import_ready": false, + "notes": [ + "recovered territory access cost metadata is now checked in, but execution is still deferred" + ] + } + ] + }, + "notes": [ + "world scalar parity sample" + ] + } +}