diff --git a/crates/rrt-runtime/src/lib.rs b/crates/rrt-runtime/src/lib.rs index d817794..12c66a4 100644 --- a/crates/rrt-runtime/src/lib.rs +++ b/crates/rrt-runtime/src/lib.rs @@ -118,8 +118,9 @@ pub use smp::{ SmpRuntimePostSpanHeaderCandidate, SmpRuntimePostSpanProbe, SmpRuntimeTrailerBlock, SmpSaveAnchorRunBlock, SmpSaveBootstrapBlock, SmpSaveChairmanRecordAnalysisEntry, SmpSaveCompanyChairmanAnalysisReport, SmpSaveCompanyRecordAnalysisEntry, SmpSaveDwordCandidate, - SmpSavePlacedStructureDynamicSideBufferProbe, - SmpSaveLoadCandidateTableSummary, SmpSaveLoadSummary, SmpSaveScalarCandidate, + SmpSaveLoadCandidateTableSummary, SmpSaveLoadSummary, + SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary, + SmpSavePlacedStructureDynamicSideBufferProbe, SmpSaveScalarCandidate, SmpSaveTaggedCollectionHeaderProbe, SmpSaveWorldEconomicTuningProbe, SmpSaveWorldFinanceNeighborhoodProbe, SmpSaveWorldIssue37Probe, SmpSaveWorldSelectionRoleAnalysis, SmpSaveWorldSelectionRoleAnalysisEntry, diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index b7cd165..84f0bcb 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -1796,12 +1796,17 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe { pub prefix_separator_byte_hex: String, pub first_embedded_name_tag_relative_offset: usize, pub embedded_name_tag_count: usize, + pub unique_compact_prefix_pattern_count: usize, + pub prefix_leading_dword_matching_embedded_profile_tag_count: usize, #[serde(default)] pub first_embedded_primary_name: Option, #[serde(default)] pub first_embedded_secondary_name: Option, #[serde(default)] pub embedded_name_row_samples: Vec, + #[serde(default)] + pub compact_prefix_pattern_summaries: + Vec, pub evidence: Vec, } @@ -1821,6 +1826,26 @@ pub struct SmpSavePlacedStructureDynamicSideBufferSampleEntry { pub secondary_name: Option, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary { + pub prefix_leading_dword: u32, + pub prefix_leading_dword_hex: String, + pub prefix_trailing_word: u16, + pub prefix_trailing_word_hex: String, + pub prefix_separator_byte: u8, + pub prefix_separator_byte_hex: String, + pub count: usize, + pub first_name_tag_relative_offset: usize, + pub prefix_leading_dword_matches_embedded_profile_tag: bool, + pub section_like_primary_name_count: usize, + pub cap_like_primary_name_count: usize, + pub other_primary_name_count: usize, + #[serde(default)] + pub first_primary_name: Option, + #[serde(default)] + pub first_secondary_name: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct SmpRt3105SaveNameTableProbe { pub profile_family: String, @@ -2767,8 +2792,7 @@ pub struct SmpSaveCompanyChairmanAnalysisReport { #[serde(default)] pub placed_structure_record_triplets: Option, #[serde(default)] - pub placed_structure_dynamic_side_buffer: - Option, + pub placed_structure_dynamic_side_buffer: Option, #[serde(default)] pub unclassified_tagged_collection_headers: Vec, #[serde(default)] @@ -3138,10 +3162,12 @@ pub fn inspect_unclassified_save_collection_headers_file( file_extension_hint.as_deref(), container_profile.as_ref(), ); - Ok(filter_unclassified_tagged_collection_header_probes_outside_known_spans( - probes, - &known_header_probes, - )) + Ok( + filter_unclassified_tagged_collection_header_probes_outside_known_spans( + probes, + &known_header_probes, + ), + ) } pub fn inspect_save_placed_structure_dynamic_side_buffer_file( @@ -3333,8 +3359,9 @@ pub fn load_save_slice_from_report( enabled_visible_labels: probe.enabled_visible_labels.clone(), entries: probe.entries.clone(), }); - let placed_structure_dynamic_side_buffer_probe = - report.save_placed_structure_dynamic_side_buffer_probe.clone(); + let placed_structure_dynamic_side_buffer_probe = report + .save_placed_structure_dynamic_side_buffer_probe + .clone(); let mut notes = summary.notes.clone(); if let Some(probe) = &report.save_world_selection_context_probe { notes.push(format!( @@ -3491,15 +3518,28 @@ pub fn load_save_slice_from_report( )); } if let Some(probe) = &placed_structure_dynamic_side_buffer_probe { + let dominant_pattern = probe.compact_prefix_pattern_summaries.first(); notes.push(format!( - "Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}, embedded 0x55f1 row count={}.", + "Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}, embedded 0x55f1 row count={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, dominant compact pattern={}/{}/{} x{}.", probe.live_record_count, probe.prefix_leading_dword_hex, probe.prefix_trailing_word_hex, probe.prefix_separator_byte_hex, probe.first_embedded_primary_name.as_deref(), probe.first_embedded_secondary_name.as_deref(), - probe.embedded_name_tag_count + probe.embedded_name_tag_count, + probe.unique_compact_prefix_pattern_count, + probe.prefix_leading_dword_matching_embedded_profile_tag_count, + dominant_pattern + .map(|pattern| pattern.prefix_leading_dword_hex.as_str()) + .unwrap_or("0x00000000"), + dominant_pattern + .map(|pattern| pattern.prefix_trailing_word_hex.as_str()) + .unwrap_or("0x0000"), + dominant_pattern + .map(|pattern| pattern.prefix_separator_byte_hex.as_str()) + .unwrap_or("0x00"), + dominant_pattern.map(|pattern| pattern.count).unwrap_or_default() )); } if let Some(roster) = &report.save_company_roster_probe { @@ -3936,6 +3976,25 @@ pub fn inspect_save_company_and_chairman_analysis_bytes( triplets.entries.first().map(|entry| entry.profile_status_kind.as_str()) )); } + if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() { + let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first(); + notes.push(format!( + "Placed-structure analysis now also exports the separate 0x38a5 dynamic side-buffer owner seam with {} embedded name rows, {} unique compact prefix patterns, {} rows whose leading dword matches 0x55f3, and dominant compact pattern={}/{}/{} x{}.", + side_buffer.embedded_name_tag_count, + side_buffer.unique_compact_prefix_pattern_count, + side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count, + dominant_pattern + .map(|pattern| pattern.prefix_leading_dword_hex.as_str()) + .unwrap_or("0x00000000"), + dominant_pattern + .map(|pattern| pattern.prefix_trailing_word_hex.as_str()) + .unwrap_or("0x0000"), + dominant_pattern + .map(|pattern| pattern.prefix_separator_byte_hex.as_str()) + .unwrap_or("0x00"), + dominant_pattern.map(|pattern| pattern.count).unwrap_or_default() + )); + } if let Some(candidate) = unclassified_tagged_collection_headers.first() { notes.push(format!( "Generic save-side tagged collection scan also found {} unclassified candidate families; largest current candidate uses tags {}/{}/{} with live_record_count={} stride=0x{:x} records_span_len=0x{:x}.", @@ -10609,6 +10668,27 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( file_extension_hint: Option<&str>, container_profile: Option<&SmpContainerProfile>, ) -> Option { + #[derive(Clone)] + struct EmbeddedNameRow { + name_tag_relative_offset: usize, + prefix_leading_dword: u32, + prefix_trailing_word: u16, + prefix_separator_byte: u8, + primary_name: Option, + secondary_name: Option, + } + + #[derive(Default)] + struct PrefixPatternAccumulator { + count: usize, + first_name_tag_relative_offset: usize, + first_primary_name: Option, + first_secondary_name: Option, + section_like_primary_name_count: usize, + cap_like_primary_name_count: usize, + other_primary_name_count: usize, + } + if file_extension_hint != Some("gms") { return None; } @@ -10630,13 +10710,15 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( let Some(records_tag_offset) = records_offsets .iter() .copied() - .find(|offset| *offset > metadata_tag_offset) else { + .find(|offset| *offset > metadata_tag_offset) + else { continue; }; let Some(close_tag_offset) = close_offsets .iter() .copied() - .find(|offset| *offset > records_tag_offset) else { + .find(|offset| *offset > records_tag_offset) + else { continue; }; let Some(payload) = bytes.get(metadata_tag_offset + 4..records_tag_offset) else { @@ -10647,7 +10729,8 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( } let Some(header_words) = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT) .map(|index| read_u32_at(payload, index * 4)) - .collect::>>() else { + .collect::>>() + else { continue; }; let Some(header_words): Option<[u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT]> = @@ -10683,10 +10766,12 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( }; let embedded_name_tag_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_NAME_TAG); - let Some(&first_embedded_name_tag_relative_offset) = embedded_name_tag_offsets.first() else { + let Some(&first_embedded_name_tag_relative_offset) = embedded_name_tag_offsets.first() + else { continue; }; - let Some(prefix_payload) = records_payload.get(..first_embedded_name_tag_relative_offset) else { + let Some(prefix_payload) = records_payload.get(..first_embedded_name_tag_relative_offset) + else { continue; }; if prefix_payload.len() < 7 { @@ -10704,7 +10789,8 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( let mut parsed_embedded_names = None; for relative_name_offset in [4usize, 6usize] { let Some(name_payload) = records_payload - .get(first_embedded_name_tag_relative_offset + relative_name_offset..) else { + .get(first_embedded_name_tag_relative_offset + relative_name_offset..) + else { continue; }; if let Some(names) = parse_save_len_prefixed_ascii_name_pair(name_payload) { @@ -10717,11 +10803,10 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( else { continue; }; - let embedded_name_row_samples = embedded_name_tag_offsets + let embedded_name_rows = embedded_name_tag_offsets .iter() .copied() - .enumerate() - .filter_map(|(sample_index, name_tag_relative_offset)| { + .filter_map(|name_tag_relative_offset| { let prefix_payload = records_payload.get(..name_tag_relative_offset)?; if prefix_payload.len() < 7 { return None; @@ -10731,8 +10816,9 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( let prefix_separator_byte = *prefix_payload.last()?; let mut parsed_names = None; for relative_name_offset in [4usize, 6usize] { - let Some(name_payload) = records_payload - .get(name_tag_relative_offset + relative_name_offset..) else { + let Some(name_payload) = + records_payload.get(name_tag_relative_offset + relative_name_offset..) + else { continue; }; if let Some(names) = parse_save_len_prefixed_ascii_name_pair(name_payload) { @@ -10741,21 +10827,108 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( } } let (primary_name, secondary_name) = parsed_names.unwrap_or_default(); - Some(SmpSavePlacedStructureDynamicSideBufferSampleEntry { - sample_index, + Some(EmbeddedNameRow { name_tag_relative_offset, prefix_leading_dword, - prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"), prefix_trailing_word, - prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"), prefix_separator_byte, - prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"), primary_name: (!primary_name.is_empty()).then_some(primary_name), secondary_name: (!secondary_name.is_empty()).then_some(secondary_name), }) }) - .take(8) .collect::>(); + let embedded_name_row_samples = embedded_name_rows + .iter() + .take(8) + .enumerate() + .map( + |(sample_index, row)| SmpSavePlacedStructureDynamicSideBufferSampleEntry { + sample_index, + name_tag_relative_offset: row.name_tag_relative_offset, + prefix_leading_dword: row.prefix_leading_dword, + prefix_leading_dword_hex: format!("0x{:08x}", row.prefix_leading_dword), + prefix_trailing_word: row.prefix_trailing_word, + prefix_trailing_word_hex: format!("0x{:04x}", row.prefix_trailing_word), + prefix_separator_byte: row.prefix_separator_byte, + prefix_separator_byte_hex: format!("0x{:02x}", row.prefix_separator_byte), + primary_name: row.primary_name.clone(), + secondary_name: row.secondary_name.clone(), + }, + ) + .collect::>(); + let mut compact_prefix_pattern_map = + BTreeMap::<(u32, u16, u8), PrefixPatternAccumulator>::new(); + for row in &embedded_name_rows { + let entry = compact_prefix_pattern_map + .entry(( + row.prefix_leading_dword, + row.prefix_trailing_word, + row.prefix_separator_byte, + )) + .or_insert_with(|| PrefixPatternAccumulator { + first_name_tag_relative_offset: row.name_tag_relative_offset, + first_primary_name: row.primary_name.clone(), + first_secondary_name: row.secondary_name.clone(), + ..Default::default() + }); + entry.count += 1; + match row.primary_name.as_deref() { + Some(name) if name.ends_with("_Section.3dp") => { + entry.section_like_primary_name_count += 1; + } + Some(name) if name.ends_with("_Cap.3dp") => { + entry.cap_like_primary_name_count += 1; + } + _ => { + entry.other_primary_name_count += 1; + } + } + } + let prefix_leading_dword_matching_embedded_profile_tag_count = embedded_name_rows + .iter() + .filter(|row| row.prefix_leading_dword == u32::from(SAVE_REGION_RECORD_PROFILE_TAG)) + .count(); + let mut compact_prefix_pattern_summaries = compact_prefix_pattern_map + .into_iter() + .map( + |( + (prefix_leading_dword, prefix_trailing_word, prefix_separator_byte), + accumulator, + )| { + SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary { + prefix_leading_dword, + prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"), + prefix_trailing_word, + prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"), + prefix_separator_byte, + prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"), + count: accumulator.count, + first_name_tag_relative_offset: accumulator.first_name_tag_relative_offset, + prefix_leading_dword_matches_embedded_profile_tag: prefix_leading_dword + == u32::from(SAVE_REGION_RECORD_PROFILE_TAG), + section_like_primary_name_count: accumulator + .section_like_primary_name_count, + cap_like_primary_name_count: accumulator.cap_like_primary_name_count, + other_primary_name_count: accumulator.other_primary_name_count, + first_primary_name: accumulator.first_primary_name, + first_secondary_name: accumulator.first_secondary_name, + } + }, + ) + .collect::>(); + compact_prefix_pattern_summaries.sort_by(|left, right| { + right + .count + .cmp(&left.count) + .then_with(|| { + left.first_name_tag_relative_offset + .cmp(&right.first_name_tag_relative_offset) + }) + .then_with(|| left.prefix_leading_dword.cmp(&right.prefix_leading_dword)) + .then_with(|| left.prefix_trailing_word.cmp(&right.prefix_trailing_word)) + .then_with(|| left.prefix_separator_byte.cmp(&right.prefix_separator_byte)) + }); + let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned(); return Some(SmpSavePlacedStructureDynamicSideBufferProbe { profile_family: profile.profile_family.clone(), source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(), @@ -10778,9 +10951,12 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"), first_embedded_name_tag_relative_offset, embedded_name_tag_count: embedded_name_tag_offsets.len(), + unique_compact_prefix_pattern_count: compact_prefix_pattern_summaries.len(), + prefix_leading_dword_matching_embedded_profile_tag_count, first_embedded_primary_name: Some(first_embedded_primary_name.clone()), first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()), embedded_name_row_samples, + compact_prefix_pattern_summaries, evidence: vec![ "exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(), "records payload begins with a compact 6-byte prefix plus one separator byte before the first embedded 0x55f1 name row".to_string(), @@ -10791,6 +10967,29 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe( Some(first_embedded_secondary_name), embedded_name_tag_offsets.len() ), + format!( + "{} of {} embedded name rows use compact leading dword 0x{:08x}, matching the placed-structure embedded profile tag", + prefix_leading_dword_matching_embedded_profile_tag_count, + embedded_name_rows.len(), + u32::from(SAVE_REGION_RECORD_PROFILE_TAG) + ), + dominant_compact_prefix_pattern + .map(|pattern| { + format!( + "dominant compact prefix pattern {} / {} / {} occurs {} times; section-like rows={}, cap-like rows={}, first names={:?}/{:?}", + pattern.prefix_leading_dword_hex, + pattern.prefix_trailing_word_hex, + pattern.prefix_separator_byte_hex, + pattern.count, + pattern.section_like_primary_name_count, + pattern.cap_like_primary_name_count, + pattern.first_primary_name, + pattern.first_secondary_name + ) + }) + .unwrap_or_else(|| { + "no dominant compact prefix pattern summary was available".to_string() + }), ], }); } @@ -11072,13 +11271,10 @@ fn filter_unclassified_tagged_collection_header_probes_outside_known_spans( probes .into_iter() .filter(|probe| { - !known_header_probes - .iter() - .flatten() - .any(|known| { - probe.metadata_tag_offset >= known.metadata_tag_offset - && probe.close_tag_offset <= known.close_tag_offset - }) + !known_header_probes.iter().flatten().any(|known| { + probe.metadata_tag_offset >= known.metadata_tag_offset + && probe.close_tag_offset <= known.close_tag_offset + }) }) .collect() } @@ -18683,8 +18879,7 @@ mod tests { .copy_from_slice(&0x000038a5u32.to_le_bytes()); bytes[records_tag_offset..records_tag_offset + 4] .copy_from_slice(&0x000038a6u32.to_le_bytes()); - bytes[close_tag_offset..close_tag_offset + 4] - .copy_from_slice(&0x000038a7u32.to_le_bytes()); + bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes()); let header_words = [ 0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; @@ -18728,6 +18923,11 @@ mod tests { assert_eq!(probe.prefix_separator_byte_hex, "0xff"); assert_eq!(probe.first_embedded_name_tag_relative_offset, 7); assert_eq!(probe.embedded_name_tag_count, 1); + assert_eq!(probe.unique_compact_prefix_pattern_count, 1); + assert_eq!( + probe.prefix_leading_dword_matching_embedded_profile_tag_count, + 0 + ); assert_eq!( probe.first_embedded_primary_name.as_deref(), Some("TrackCapST_Cap.3dp") @@ -18736,6 +18936,103 @@ mod tests { probe.first_embedded_secondary_name.as_deref(), Some("Infrastructure") ); + assert_eq!(probe.compact_prefix_pattern_summaries.len(), 1); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex, + "0x0005d368" + ); + assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 1); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count, + 1 + ); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count, + 0 + ); + } + + #[test] + fn summarizes_placed_structure_dynamic_side_buffer_compact_prefix_patterns() { + let mut bytes = vec![0u8; 0x600]; + let metadata_tag_offset = 0x40usize; + let records_tag_offset = 0x140usize; + let close_tag_offset = 0x320usize; + bytes[metadata_tag_offset..metadata_tag_offset + 4] + .copy_from_slice(&0x000038a5u32.to_le_bytes()); + bytes[records_tag_offset..records_tag_offset + 4] + .copy_from_slice(&0x000038a6u32.to_le_bytes()); + bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes()); + let header_words = [ + 0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + for (index, word) in header_words.into_iter().enumerate() { + let offset = metadata_tag_offset + 4 + index * 4; + bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes()); + } + let mut cursor = records_tag_offset + 4; + for (leading_dword, primary_name) in [ + (0x000055f3u32, "TunnelSTBrick_Section.3dp"), + (0x000055f3u32, "TunnelSTBrick_Cap.3dp"), + (0xff0000ffu32, "TunnelSTBrick_Cap.3dp"), + ] { + bytes[cursor..cursor + 4].copy_from_slice(&leading_dword.to_le_bytes()); + bytes[cursor + 4..cursor + 6].copy_from_slice(&0x0001u16.to_le_bytes()); + bytes[cursor + 6] = 0xff; + let name_tag_offset = cursor + 7; + bytes[name_tag_offset..name_tag_offset + 2] + .copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes()); + let secondary_name = "Infrastructure"; + bytes[name_tag_offset + 4] = primary_name.len() as u8; + bytes[name_tag_offset + 5..name_tag_offset + 5 + primary_name.len()] + .copy_from_slice(primary_name.as_bytes()); + let second_len_offset = name_tag_offset + 5 + primary_name.len(); + bytes[second_len_offset] = secondary_name.len() as u8; + bytes[second_len_offset + 1..second_len_offset + 1 + secondary_name.len()] + .copy_from_slice(secondary_name.as_bytes()); + cursor = second_len_offset + 1 + secondary_name.len(); + } + + let probe = parse_save_placed_structure_dynamic_side_buffer_probe( + &bytes, + Some("gms"), + Some(&SmpContainerProfile { + profile_family: "rt3-105-save-container-v1".to_string(), + profile_evidence: vec![], + is_known_profile: true, + }), + ) + .expect("placed-structure dynamic side-buffer probe should parse"); + + assert_eq!(probe.embedded_name_tag_count, 3); + assert_eq!(probe.unique_compact_prefix_pattern_count, 2); + assert_eq!( + probe.prefix_leading_dword_matching_embedded_profile_tag_count, + 2 + ); + assert_eq!(probe.compact_prefix_pattern_summaries.len(), 2); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex, + "0x000055f3" + ); + assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 2); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count, + 1 + ); + assert_eq!( + probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count, + 1 + ); + assert!( + probe.compact_prefix_pattern_summaries[0] + .prefix_leading_dword_matches_embedded_profile_tag + ); + assert_eq!( + probe.compact_prefix_pattern_summaries[1].prefix_leading_dword_hex, + "0xff0000ff" + ); + assert_eq!(probe.compact_prefix_pattern_summaries[1].count, 1); } #[test] diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index 721e969..f487106 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -24,8 +24,10 @@ Working rule: separate tagged side-buffer seam candidates, especially the exact `0x38a5/0x38a6/0x38a7` family whose compact `6`-byte header pattern and embedded placed-structure-style `0x55f1` name rows now make it the grounded placed-structure dynamic side-buffer owner; the remaining - blocker is semantic closure of the 6-byte prefix lane and its relation to the embedded - `0x55f1/0x55f2/0x55f3` row subset. + blocker is semantic closure of the compact prefix regimes now summarized in real saves as seven + stable patterns on `q.gms` and their relation to the embedded `0x55f1/0x55f2/0x55f3` row + subset, especially the dominant bridge-section `0xff000000/0x0001/0xff` group and the smaller + `0x000055f3/0x0001/0xff` group that matches the embedded profile tag directly. - Extend shellless clock advancement so more periodic-company service branches consume owned runtime time state directly instead of only the explicit periodic service command. - Keep widening selected-year world-owner state only when a full owning reader/rebuild family is @@ -102,6 +104,12 @@ Working rule: samples include repeated `TunnelSTBrick_*` names under `Infrastructure` with compact leading dwords like `0x000055f3` and `0xff0000ff`, so the next pass can target the semantics of those compact prefix patterns instead of hunting the owner seam itself. +- The `0x38a5` probe now also summarizes all embedded compact prefix regimes instead of just the + first few samples: grounded `q.gms` currently exposes seven stable pattern groups across 138 + embedded rows, with the dominant `0xff000000/0x0001/0xff` group carrying 62 bridge-section + rows, the `0xff0000ff/0x0001/0xff` and `0xf3010100/0x0055/0x00` groups concentrating cap-like + rows, and a smaller `0x000055f3/0x0001/0xff` group carrying 17 tunnel-section / cap rows whose + leading dword matches the embedded placed-structure profile tag directly. - The placed-structure tagged save stream now also exposes repeated `0x55f1/0x55f2/0x55f3` triplets with dual name stems, a fixed five-`f32` policy row, and a compact `0x5dc1...0x5dc2` footer carrying one raw `u32` payload lane plus one live `i32` status lane, so the remaining