Compare placed-structure side-buffer name corpus
This commit is contained in:
parent
c173623692
commit
564b8b6641
3 changed files with 410 additions and 3 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue