Compare placed-structure side-buffer name corpus

This commit is contained in:
Jan Petykiewicz 2026-04-18 12:09:08 -07:00
commit 564b8b6641
3 changed files with 410 additions and 3 deletions

View file

@ -119,6 +119,8 @@ pub use smp::{
SmpSaveAnchorRunBlock, SmpSaveBootstrapBlock, SmpSaveChairmanRecordAnalysisEntry, SmpSaveAnchorRunBlock, SmpSaveBootstrapBlock, SmpSaveChairmanRecordAnalysisEntry,
SmpSaveCompanyChairmanAnalysisReport, SmpSaveCompanyRecordAnalysisEntry, SmpSaveDwordCandidate, SmpSaveCompanyChairmanAnalysisReport, SmpSaveCompanyRecordAnalysisEntry, SmpSaveDwordCandidate,
SmpSaveLoadCandidateTableSummary, SmpSaveLoadSummary, SmpSaveLoadCandidateTableSummary, SmpSaveLoadSummary,
SmpSavePlacedStructureDynamicSideBufferAlignmentProbe,
SmpSavePlacedStructureDynamicSideBufferNamePairSummary,
SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary, SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary,
SmpSavePlacedStructureDynamicSideBufferProbe, SmpSaveScalarCandidate, SmpSavePlacedStructureDynamicSideBufferProbe, SmpSaveScalarCandidate,
SmpSaveTaggedCollectionHeaderProbe, SmpSaveWorldEconomicTuningProbe, SmpSaveTaggedCollectionHeaderProbe, SmpSaveWorldEconomicTuningProbe,

View file

@ -1796,8 +1796,10 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
pub prefix_separator_byte_hex: String, pub prefix_separator_byte_hex: String,
pub first_embedded_name_tag_relative_offset: usize, pub first_embedded_name_tag_relative_offset: usize,
pub embedded_name_tag_count: usize, pub embedded_name_tag_count: usize,
pub decoded_embedded_name_row_count: usize,
pub unique_compact_prefix_pattern_count: usize, pub unique_compact_prefix_pattern_count: usize,
pub prefix_leading_dword_matching_embedded_profile_tag_count: usize, pub prefix_leading_dword_matching_embedded_profile_tag_count: usize,
pub unique_embedded_name_pair_count: usize,
#[serde(default)] #[serde(default)]
pub first_embedded_primary_name: Option<String>, pub first_embedded_primary_name: Option<String>,
#[serde(default)] #[serde(default)]
@ -1807,6 +1809,8 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
#[serde(default)] #[serde(default)]
pub compact_prefix_pattern_summaries: pub compact_prefix_pattern_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary>, Vec<SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary>,
#[serde(default)]
pub name_pair_summaries: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
pub evidence: Vec<String>, pub evidence: Vec<String>,
} }
@ -1846,6 +1850,39 @@ pub struct SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary {
pub first_secondary_name: Option<String>, pub first_secondary_name: Option<String>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
pub primary_name: String,
pub secondary_name: String,
pub count: usize,
pub first_name_tag_relative_offset: usize,
pub unique_compact_prefix_pattern_count: usize,
pub dominant_prefix_leading_dword: u32,
pub dominant_prefix_leading_dword_hex: String,
pub dominant_prefix_trailing_word: u16,
pub dominant_prefix_trailing_word_hex: String,
pub dominant_prefix_separator_byte: u8,
pub dominant_prefix_separator_byte_hex: String,
pub dominant_prefix_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
pub unique_side_buffer_name_pair_count: usize,
pub unique_triplet_name_pair_count: usize,
pub overlapping_name_pair_count: usize,
pub side_buffer_row_count: usize,
pub side_buffer_rows_with_matching_triplet_name_pair_count: usize,
pub side_buffer_rows_without_matching_triplet_name_pair_count: usize,
pub triplet_name_pairs_without_side_buffer_match_count: usize,
#[serde(default)]
pub matched_name_pair_samples: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
#[serde(default)]
pub unmatched_side_buffer_name_pair_samples:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105SaveNameTableProbe { pub struct SmpRt3105SaveNameTableProbe {
pub profile_family: String, pub profile_family: String,
@ -2794,6 +2831,9 @@ pub struct SmpSaveCompanyChairmanAnalysisReport {
#[serde(default)] #[serde(default)]
pub placed_structure_dynamic_side_buffer: Option<SmpSavePlacedStructureDynamicSideBufferProbe>, pub placed_structure_dynamic_side_buffer: Option<SmpSavePlacedStructureDynamicSideBufferProbe>,
#[serde(default)] #[serde(default)]
pub placed_structure_dynamic_side_buffer_alignment:
Option<SmpSavePlacedStructureDynamicSideBufferAlignmentProbe>,
#[serde(default)]
pub unclassified_tagged_collection_headers: Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>, pub unclassified_tagged_collection_headers: Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>,
#[serde(default)] #[serde(default)]
pub company_entries: Vec<SmpSaveCompanyRecordAnalysisEntry>, pub company_entries: Vec<SmpSaveCompanyRecordAnalysisEntry>,
@ -3616,6 +3656,12 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
report.container_profile.as_ref(), report.container_profile.as_ref(),
) )
}); });
let placed_structure_dynamic_side_buffer_alignment = placed_structure_dynamic_side_buffer
.as_ref()
.zip(placed_structure_record_triplets.as_ref())
.map(|(side_buffer, triplets)| {
summarize_placed_structure_dynamic_side_buffer_alignment(side_buffer, triplets)
});
let unclassified_tagged_collection_headers = report let unclassified_tagged_collection_headers = report
.save_unclassified_tagged_collection_header_probes .save_unclassified_tagged_collection_header_probes
.clone(); .clone();
@ -3979,8 +4025,10 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() { if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() {
let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first(); let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first();
notes.push(format!( 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{}.", "Placed-structure analysis now also exports the separate 0x38a5 dynamic side-buffer owner seam with {} embedded name rows, {} decoded rows across {} unique name pairs, {} unique compact prefix patterns, {} rows whose leading dword matches 0x55f3, and dominant compact pattern={}/{}/{} x{}.",
side_buffer.embedded_name_tag_count, side_buffer.embedded_name_tag_count,
side_buffer.decoded_embedded_name_row_count,
side_buffer.unique_embedded_name_pair_count,
side_buffer.unique_compact_prefix_pattern_count, side_buffer.unique_compact_prefix_pattern_count,
side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count, side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count,
dominant_pattern dominant_pattern
@ -3995,6 +4043,16 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
dominant_pattern.map(|pattern| pattern.count).unwrap_or_default() dominant_pattern.map(|pattern| pattern.count).unwrap_or_default()
)); ));
} }
if let Some(alignment) = placed_structure_dynamic_side_buffer_alignment.as_ref() {
notes.push(format!(
"Placed-structure analysis now also compares the 0x38a5 side-buffer against the grounded 0x36b1 triplet corpus: {} of {} decoded side-buffer rows reuse {} overlapping placed-structure name pairs, leaving {} unmatched side-buffer rows and {} triplet-only name pairs.",
alignment.side_buffer_rows_with_matching_triplet_name_pair_count,
alignment.side_buffer_row_count,
alignment.overlapping_name_pair_count,
alignment.side_buffer_rows_without_matching_triplet_name_pair_count,
alignment.triplet_name_pairs_without_side_buffer_match_count
));
}
if let Some(candidate) = unclassified_tagged_collection_headers.first() { if let Some(candidate) = unclassified_tagged_collection_headers.first() {
notes.push(format!( 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}.", "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}.",
@ -4057,6 +4115,7 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
.clone(), .clone(),
placed_structure_record_triplets, placed_structure_record_triplets,
placed_structure_dynamic_side_buffer, placed_structure_dynamic_side_buffer,
placed_structure_dynamic_side_buffer_alignment,
unclassified_tagged_collection_headers, unclassified_tagged_collection_headers,
company_entries, company_entries,
chairman_entries, chairman_entries,
@ -10689,6 +10748,13 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
other_primary_name_count: usize, other_primary_name_count: usize,
} }
#[derive(Default)]
struct NamePairAccumulator {
count: usize,
first_name_tag_relative_offset: usize,
prefix_counts: BTreeMap<(u32, u16, u8), usize>,
}
if file_extension_hint != Some("gms") { if file_extension_hint != Some("gms") {
return None; return None;
} }
@ -10858,6 +10924,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut compact_prefix_pattern_map = let mut compact_prefix_pattern_map =
BTreeMap::<(u32, u16, u8), PrefixPatternAccumulator>::new(); BTreeMap::<(u32, u16, u8), PrefixPatternAccumulator>::new();
let mut name_pair_map = BTreeMap::<(String, String), NamePairAccumulator>::new();
for row in &embedded_name_rows { for row in &embedded_name_rows {
let entry = compact_prefix_pattern_map let entry = compact_prefix_pattern_map
.entry(( .entry((
@ -10883,6 +10950,25 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
entry.other_primary_name_count += 1; entry.other_primary_name_count += 1;
} }
} }
if let (Some(primary_name), Some(secondary_name)) =
(row.primary_name.as_ref(), row.secondary_name.as_ref())
{
let entry = name_pair_map
.entry((primary_name.clone(), secondary_name.clone()))
.or_insert_with(|| NamePairAccumulator {
first_name_tag_relative_offset: row.name_tag_relative_offset,
..Default::default()
});
entry.count += 1;
*entry
.prefix_counts
.entry((
row.prefix_leading_dword,
row.prefix_trailing_word,
row.prefix_separator_byte,
))
.or_default() += 1;
}
} }
let prefix_leading_dword_matching_embedded_profile_tag_count = embedded_name_rows let prefix_leading_dword_matching_embedded_profile_tag_count = embedded_name_rows
.iter() .iter()
@ -10928,7 +11014,61 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
.then_with(|| left.prefix_trailing_word.cmp(&right.prefix_trailing_word)) .then_with(|| left.prefix_trailing_word.cmp(&right.prefix_trailing_word))
.then_with(|| left.prefix_separator_byte.cmp(&right.prefix_separator_byte)) .then_with(|| left.prefix_separator_byte.cmp(&right.prefix_separator_byte))
}); });
let mut name_pair_summaries = name_pair_map
.into_iter()
.filter_map(|((primary_name, secondary_name), accumulator)| {
let dominant_prefix = accumulator.prefix_counts.iter().max_by(
|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
},
)?;
let (
dominant_prefix_leading_dword,
dominant_prefix_trailing_word,
dominant_prefix_separator_byte,
) = *dominant_prefix.0;
let dominant_prefix_count = *dominant_prefix.1;
Some(SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name,
secondary_name,
count: accumulator.count,
first_name_tag_relative_offset: accumulator.first_name_tag_relative_offset,
unique_compact_prefix_pattern_count: accumulator.prefix_counts.len(),
dominant_prefix_leading_dword,
dominant_prefix_leading_dword_hex: format!(
"0x{dominant_prefix_leading_dword:08x}"
),
dominant_prefix_trailing_word,
dominant_prefix_trailing_word_hex: format!(
"0x{dominant_prefix_trailing_word:04x}"
),
dominant_prefix_separator_byte,
dominant_prefix_separator_byte_hex: format!(
"0x{dominant_prefix_separator_byte:02x}"
),
dominant_prefix_count,
})
})
.collect::<Vec<_>>();
name_pair_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.primary_name.cmp(&right.primary_name))
.then_with(|| left.secondary_name.cmp(&right.secondary_name))
});
let unique_embedded_name_pair_count = name_pair_summaries.len();
let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned(); let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
let decoded_embedded_name_row_count = embedded_name_rows
.iter()
.filter(|row| row.primary_name.is_some() && row.secondary_name.is_some())
.count();
return Some(SmpSavePlacedStructureDynamicSideBufferProbe { return Some(SmpSavePlacedStructureDynamicSideBufferProbe {
profile_family: profile.profile_family.clone(), profile_family: profile.profile_family.clone(),
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(), source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
@ -10951,12 +11091,15 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"), prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
first_embedded_name_tag_relative_offset, first_embedded_name_tag_relative_offset,
embedded_name_tag_count: embedded_name_tag_offsets.len(), embedded_name_tag_count: embedded_name_tag_offsets.len(),
decoded_embedded_name_row_count,
unique_compact_prefix_pattern_count: compact_prefix_pattern_summaries.len(), unique_compact_prefix_pattern_count: compact_prefix_pattern_summaries.len(),
prefix_leading_dword_matching_embedded_profile_tag_count, prefix_leading_dword_matching_embedded_profile_tag_count,
unique_embedded_name_pair_count,
first_embedded_primary_name: Some(first_embedded_primary_name.clone()), first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()), first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
embedded_name_row_samples, embedded_name_row_samples,
compact_prefix_pattern_summaries, compact_prefix_pattern_summaries,
name_pair_summaries,
evidence: vec![ evidence: vec![
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(), "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(), "records payload begins with a compact 6-byte prefix plus one separator byte before the first embedded 0x55f1 name row".to_string(),
@ -10973,6 +11116,10 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
embedded_name_rows.len(), embedded_name_rows.len(),
u32::from(SAVE_REGION_RECORD_PROFILE_TAG) u32::from(SAVE_REGION_RECORD_PROFILE_TAG)
), ),
format!(
"{decoded_embedded_name_row_count} decoded embedded name rows collapse into {} unique placed-structure name pairs",
unique_embedded_name_pair_count
),
dominant_compact_prefix_pattern dominant_compact_prefix_pattern
.map(|pattern| { .map(|pattern| {
format!( format!(
@ -10996,6 +11143,83 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
None None
} }
fn summarize_placed_structure_dynamic_side_buffer_alignment(
side_buffer: &SmpSavePlacedStructureDynamicSideBufferProbe,
triplets: &SmpSavePlacedStructureRecordTripletProbe,
) -> SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
let triplet_name_pairs = triplets
.entries
.iter()
.map(|entry| (entry.primary_name.clone(), entry.secondary_name.clone()))
.collect::<BTreeSet<_>>();
let matched_name_pair_samples = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.take(5)
.cloned()
.collect::<Vec<_>>();
let unmatched_side_buffer_name_pair_samples = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
!triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.take(5)
.cloned()
.collect::<Vec<_>>();
let side_buffer_rows_with_matching_triplet_name_pair_count = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.map(|summary| summary.count)
.sum::<usize>();
let unique_side_buffer_name_pair_count = side_buffer.name_pair_summaries.len();
let overlapping_name_pair_count = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.count();
SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
unique_side_buffer_name_pair_count,
unique_triplet_name_pair_count: triplet_name_pairs.len(),
overlapping_name_pair_count,
side_buffer_row_count: side_buffer.decoded_embedded_name_row_count,
side_buffer_rows_with_matching_triplet_name_pair_count,
side_buffer_rows_without_matching_triplet_name_pair_count: side_buffer
.decoded_embedded_name_row_count
.saturating_sub(side_buffer_rows_with_matching_triplet_name_pair_count),
triplet_name_pairs_without_side_buffer_match_count: triplet_name_pairs
.len()
.saturating_sub(overlapping_name_pair_count),
matched_name_pair_samples,
unmatched_side_buffer_name_pair_samples,
evidence: vec![
"placed-structure dynamic side-buffer alignment compares decoded 0x38a5 embedded name pairs against the grounded 0x36b1 triplet name-pair corpus".to_string(),
format!(
"{} of {} decoded side-buffer rows currently reuse name pairs already present in the placed-structure triplet owner seam",
side_buffer_rows_with_matching_triplet_name_pair_count,
side_buffer.decoded_embedded_name_row_count
),
format!(
"{} of {} unique side-buffer name pairs overlap the grounded triplet name-pair corpus",
overlapping_name_pair_count,
unique_side_buffer_name_pair_count
),
],
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct IndexedCollectionHeaderSummary { struct IndexedCollectionHeaderSummary {
metadata_tag_offset: usize, metadata_tag_offset: usize,
@ -18923,11 +19147,13 @@ mod tests {
assert_eq!(probe.prefix_separator_byte_hex, "0xff"); assert_eq!(probe.prefix_separator_byte_hex, "0xff");
assert_eq!(probe.first_embedded_name_tag_relative_offset, 7); assert_eq!(probe.first_embedded_name_tag_relative_offset, 7);
assert_eq!(probe.embedded_name_tag_count, 1); assert_eq!(probe.embedded_name_tag_count, 1);
assert_eq!(probe.decoded_embedded_name_row_count, 1);
assert_eq!(probe.unique_compact_prefix_pattern_count, 1); assert_eq!(probe.unique_compact_prefix_pattern_count, 1);
assert_eq!( assert_eq!(
probe.prefix_leading_dword_matching_embedded_profile_tag_count, probe.prefix_leading_dword_matching_embedded_profile_tag_count,
0 0
); );
assert_eq!(probe.unique_embedded_name_pair_count, 1);
assert_eq!( assert_eq!(
probe.first_embedded_primary_name.as_deref(), probe.first_embedded_primary_name.as_deref(),
Some("TrackCapST_Cap.3dp") Some("TrackCapST_Cap.3dp")
@ -18950,6 +19176,12 @@ mod tests {
probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count, probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count,
0 0
); );
assert_eq!(probe.name_pair_summaries.len(), 1);
assert_eq!(probe.name_pair_summaries[0].count, 1);
assert_eq!(
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
"0x0005d368"
);
} }
#[test] #[test]
@ -19005,11 +19237,13 @@ mod tests {
.expect("placed-structure dynamic side-buffer probe should parse"); .expect("placed-structure dynamic side-buffer probe should parse");
assert_eq!(probe.embedded_name_tag_count, 3); assert_eq!(probe.embedded_name_tag_count, 3);
assert_eq!(probe.decoded_embedded_name_row_count, 3);
assert_eq!(probe.unique_compact_prefix_pattern_count, 2); assert_eq!(probe.unique_compact_prefix_pattern_count, 2);
assert_eq!( assert_eq!(
probe.prefix_leading_dword_matching_embedded_profile_tag_count, probe.prefix_leading_dword_matching_embedded_profile_tag_count,
2 2
); );
assert_eq!(probe.unique_embedded_name_pair_count, 2);
assert_eq!(probe.compact_prefix_pattern_summaries.len(), 2); assert_eq!(probe.compact_prefix_pattern_summaries.len(), 2);
assert_eq!( assert_eq!(
probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex, probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
@ -19033,6 +19267,170 @@ mod tests {
"0xff0000ff" "0xff0000ff"
); );
assert_eq!(probe.compact_prefix_pattern_summaries[1].count, 1); assert_eq!(probe.compact_prefix_pattern_summaries[1].count, 1);
assert_eq!(probe.name_pair_summaries.len(), 2);
assert_eq!(probe.name_pair_summaries[0].count, 2);
assert_eq!(
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
"0x000055f3"
);
assert_eq!(probe.name_pair_summaries[1].count, 1);
}
#[test]
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
semantic_family: "scenario-save-placed-structure-dynamic-side-buffer-records"
.to_string(),
metadata_tag_offset: 0,
records_tag_offset: 0,
close_tag_offset: 0,
records_span_len: 0,
direct_record_stride: 6,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 1000,
live_id_bound_hex: "0x000003e8".to_string(),
live_record_count: 10,
live_record_count_hex: "0x0000000a".to_string(),
prefix_leading_dword: 0,
prefix_leading_dword_hex: "0x00000000".to_string(),
prefix_trailing_word: 1,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
first_embedded_name_tag_relative_offset: 7,
embedded_name_tag_count: 3,
decoded_embedded_name_row_count: 3,
unique_compact_prefix_pattern_count: 2,
prefix_leading_dword_matching_embedded_profile_tag_count: 2,
unique_embedded_name_pair_count: 2,
first_embedded_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
first_embedded_secondary_name: Some("Infrastructure".to_string()),
embedded_name_row_samples: vec![],
compact_prefix_pattern_summaries: vec![],
name_pair_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name: "TunnelSTBrick_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
count: 2,
first_name_tag_relative_offset: 7,
unique_compact_prefix_pattern_count: 1,
dominant_prefix_leading_dword: 0x55f3,
dominant_prefix_leading_dword_hex: "0x000055f3".to_string(),
dominant_prefix_trailing_word: 1,
dominant_prefix_trailing_word_hex: "0x0001".to_string(),
dominant_prefix_separator_byte: 0xff,
dominant_prefix_separator_byte_hex: "0xff".to_string(),
dominant_prefix_count: 2,
},
SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name: "BridgeSTWood_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
count: 1,
first_name_tag_relative_offset: 27,
unique_compact_prefix_pattern_count: 1,
dominant_prefix_leading_dword: 0xff000000,
dominant_prefix_leading_dword_hex: "0xff000000".to_string(),
dominant_prefix_trailing_word: 1,
dominant_prefix_trailing_word_hex: "0x0001".to_string(),
dominant_prefix_separator_byte: 0xff,
dominant_prefix_separator_byte_hex: "0xff".to_string(),
dominant_prefix_count: 1,
},
],
evidence: vec![],
};
let triplets = SmpSavePlacedStructureRecordTripletProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-record-triplets".to_string(),
semantic_family: "scenario-save-placed-structure-record-triplets".to_string(),
records_tag_offset: 0,
close_tag_offset: 0,
record_count: 2,
entries: vec![
SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: 0,
primary_name: "TunnelSTBrick_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0,
profile_chunk_len: 0,
policy_f32_lane_0: 0.0,
policy_f32_lane_1: 0.0,
policy_f32_lane_2: 0.0,
policy_f32_lane_3: 0.0,
policy_f32_lane_4: 0.0,
policy_reserved_dword: 0,
policy_trailing_word: 0,
policy_trailing_word_hex: "0x0000".to_string(),
profile_open_marker: 0,
profile_open_marker_hex: "0x00000000".to_string(),
profile_repeated_primary_name: "TunnelSTBrick_Section.3dp".to_string(),
profile_repeated_secondary_name: "Infrastructure".to_string(),
profile_payload_dword: 0,
profile_payload_dword_hex: "0x00000000".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0,
profile_close_marker_hex: "0x00000000".to_string(),
},
SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: 1,
primary_name: "TrackCapST_Cap.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0,
profile_chunk_len: 0,
policy_f32_lane_0: 0.0,
policy_f32_lane_1: 0.0,
policy_f32_lane_2: 0.0,
policy_f32_lane_3: 0.0,
policy_f32_lane_4: 0.0,
policy_reserved_dword: 0,
policy_trailing_word: 0,
policy_trailing_word_hex: "0x0000".to_string(),
profile_open_marker: 0,
profile_open_marker_hex: "0x00000000".to_string(),
profile_repeated_primary_name: "TrackCapST_Cap.3dp".to_string(),
profile_repeated_secondary_name: "Infrastructure".to_string(),
profile_payload_dword: 0,
profile_payload_dword_hex: "0x00000000".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0,
profile_close_marker_hex: "0x00000000".to_string(),
},
],
evidence: vec![],
};
let alignment =
summarize_placed_structure_dynamic_side_buffer_alignment(&side_buffer, &triplets);
assert_eq!(alignment.unique_side_buffer_name_pair_count, 2);
assert_eq!(alignment.unique_triplet_name_pair_count, 2);
assert_eq!(alignment.overlapping_name_pair_count, 1);
assert_eq!(
alignment.side_buffer_rows_with_matching_triplet_name_pair_count,
2
);
assert_eq!(
alignment.side_buffer_rows_without_matching_triplet_name_pair_count,
1
);
assert_eq!(
alignment.triplet_name_pairs_without_side_buffer_match_count,
1
);
assert_eq!(alignment.matched_name_pair_samples.len(), 1);
assert_eq!(alignment.unmatched_side_buffer_name_pair_samples.len(), 1);
} }
#[test] #[test]

View file

@ -26,8 +26,9 @@ Working rule:
name rows now make it the grounded placed-structure dynamic side-buffer owner; the remaining name rows now make it the grounded placed-structure dynamic side-buffer owner; the remaining
blocker is semantic closure of the compact prefix regimes now summarized in real saves as seven 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 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 subset, especially now that the side-buffer name-pair corpus is proven disjoint from the
`0x000055f3/0x0001/0xff` group that matches the embedded profile tag directly. grounded `0x36b1` triplet name-pair corpus on `q.gms`; the next pass should treat `0x38a5` as
a separate infrastructure-asset owner seam, not a compact alias over the triplet records.
- Extend shellless clock advancement so more periodic-company service branches consume owned - Extend shellless clock advancement so more periodic-company service branches consume owned
runtime time state directly instead of only the explicit periodic service command. 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 - Keep widening selected-year world-owner state only when a full owning reader/rebuild family is
@ -110,6 +111,12 @@ Working rule:
rows, the `0xff0000ff/0x0001/0xff` and `0xf3010100/0x0055/0x00` groups concentrating cap-like 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 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. leading dword matches the embedded placed-structure profile tag directly.
- The save-company/chairman analysis path now also compares that grounded `0x38a5` side-buffer
name-pair corpus against the grounded `0x36b1` triplet name-pair corpus directly; on `q.gms`
the overlap is currently zero (`0/138` decoded side-buffer rows and `0/5` unique side-buffer
name pairs match the 56-triplet corpus), which shifts the remaining placed-structure work away
from “prove these are aliases” toward “find how the separate infrastructure-asset owner seam is
consumed by city-connection / linked-transit service.”
- The placed-structure tagged save stream now also exposes repeated `0x55f1/0x55f2/0x55f3` - 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` 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 footer carrying one raw `u32` payload lane plus one live `i32` status lane, so the remaining