Probe infrastructure payload 0x55f1 triplets

This commit is contained in:
Jan Petykiewicz 2026-04-18 13:50:07 -07:00
commit ae67719ac6
3 changed files with 104 additions and 11 deletions

View file

@ -1838,6 +1838,7 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
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 decoded_embedded_name_row_count: usize,
pub decoded_embedded_name_row_with_tertiary_name_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, pub unique_embedded_name_pair_count: usize,
@ -1846,6 +1847,8 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
#[serde(default)] #[serde(default)]
pub first_embedded_secondary_name: Option<String>, pub first_embedded_secondary_name: Option<String>,
#[serde(default)] #[serde(default)]
pub first_embedded_tertiary_name: Option<String>,
#[serde(default)]
pub embedded_name_row_samples: Vec<SmpSavePlacedStructureDynamicSideBufferSampleEntry>, pub embedded_name_row_samples: Vec<SmpSavePlacedStructureDynamicSideBufferSampleEntry>,
#[serde(default)] #[serde(default)]
pub compact_prefix_pattern_summaries: pub compact_prefix_pattern_summaries:
@ -1869,6 +1872,8 @@ pub struct SmpSavePlacedStructureDynamicSideBufferSampleEntry {
pub primary_name: Option<String>, pub primary_name: Option<String>,
#[serde(default)] #[serde(default)]
pub secondary_name: Option<String>, pub secondary_name: Option<String>,
#[serde(default)]
pub tertiary_name: Option<String>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -3960,6 +3965,13 @@ fn build_infrastructure_asset_trace_report(
"direct disassembly now also shows 0x005181f0/0x00518260 treating the same 12-byte rows as a live-entry directory: dword +0 is the payload pointer, dword +4 is previous live id, and dword +8 is next live id, with collection head/tail caches alongside them".to_string(), "direct disassembly now also shows 0x005181f0/0x00518260 treating the same 12-byte rows as a live-entry directory: dword +0 is the payload pointer, dword +4 is previous live id, and dword +8 is next live id, with collection head/tail caches alongside them".to_string(),
"direct disassembly now also shows 0x00493be0 iterating live-entry ordinals through 0x00518380(ordinal, 0), converting each ordinal to a live id, then resolving that live id through 0x00518140 before handing the resulting payload pointer to 0x0048dcf0".to_string(), "direct disassembly now also shows 0x00493be0 iterating live-entry ordinals through 0x00518380(ordinal, 0), converting each ordinal to a live id, then resolving that live id through 0x00518140 before handing the resulting payload pointer to 0x0048dcf0".to_string(),
"direct disassembly now shows 0x00518680 loading the non-direct collection header, tombstone bitset, and live-id-bound-scaled 12-byte tables for the non-direct path before 0x00493be0 starts iterating".to_string(), "direct disassembly now shows 0x00518680 loading the non-direct collection header, tombstone bitset, and live-id-bound-scaled 12-byte tables for the non-direct path before 0x00493be0 starts iterating".to_string(),
"direct disassembly now also shows the shared child payload callback 0x00455fc0 opening 0x55f1, parsing three len-prefixed strings through 0x531380, opening 0x55f2, seeding the child through 0x455b70, dispatching slot +0x48, and then opening 0x55f3".to_string(),
format!(
"current save-side probe reports {} embedded 0x55f1 rows with a third decoded string",
side_buffer
.map(|probe| probe.decoded_embedded_name_row_with_tertiary_name_count)
.unwrap_or_default()
),
"local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string(), "local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string(),
"direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string(), "direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string(),
"direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string(), "direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string(),
@ -3968,6 +3980,7 @@ fn build_infrastructure_asset_trace_report(
blockers: vec![ blockers: vec![
"how the payload streams reached through 0x00518380 -> 0x00518140 align with the embedded 0x55f1 name-pair groups and compact-prefix regimes surfaced by the save-side probe".to_string(), "how the payload streams reached through 0x00518380 -> 0x00518140 align with the embedded 0x55f1 name-pair groups and compact-prefix regimes surfaced by the save-side probe".to_string(),
"which tagged values inside each payload stream correspond to the child count, optional primary-child ordinal, and the per-child shared tagged callback sequence consumed by 0x0048dcf0".to_string(), "which tagged values inside each payload stream correspond to the child count, optional primary-child ordinal, and the per-child shared tagged callback sequence consumed by 0x0048dcf0".to_string(),
"whether the third 0x55f1 string parsed by 0x00455fc0 is absent on grounded saves, stored under a different framing than the current probe, or only populated on a narrower infrastructure subset".to_string(),
"which restored child fields or grouped rows retain the 0x38a5 embedded name-pair semantics before route/local-runtime follow-ons take over".to_string(), "which restored child fields or grouped rows retain the 0x38a5 embedded name-pair semantics before route/local-runtime follow-ons take over".to_string(),
], ],
}, },
@ -4436,7 +4449,7 @@ pub fn load_save_slice_from_report(
if let Some(probe) = &placed_structure_dynamic_side_buffer_probe { if let Some(probe) = &placed_structure_dynamic_side_buffer_probe {
let dominant_pattern = probe.compact_prefix_pattern_summaries.first(); let dominant_pattern = probe.compact_prefix_pattern_summaries.first();
notes.push(format!( notes.push(format!(
"Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, owner-shared 0x38a6 dword={} at relative offset 0x{:x}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}, embedded 0x55f1 row count={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, dominant compact pattern={}/{}/{} x{}.", "Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, owner-shared 0x38a6 dword={} at relative offset 0x{:x}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}/{:?}, embedded 0x55f1 row count={}, rows with tertiary 0x55f1 string={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, dominant compact pattern={}/{}/{} x{}.",
probe.live_record_count, probe.live_record_count,
probe.owner_shared_dword_hex, probe.owner_shared_dword_hex,
probe.owner_shared_dword_relative_offset, probe.owner_shared_dword_relative_offset,
@ -4445,7 +4458,9 @@ pub fn load_save_slice_from_report(
probe.prefix_separator_byte_hex, probe.prefix_separator_byte_hex,
probe.first_embedded_primary_name.as_deref(), probe.first_embedded_primary_name.as_deref(),
probe.first_embedded_secondary_name.as_deref(), probe.first_embedded_secondary_name.as_deref(),
probe.first_embedded_tertiary_name.as_deref(),
probe.embedded_name_tag_count, probe.embedded_name_tag_count,
probe.decoded_embedded_name_row_with_tertiary_name_count,
probe.unique_compact_prefix_pattern_count, probe.unique_compact_prefix_pattern_count,
probe.prefix_leading_dword_matching_embedded_profile_tag_count, probe.prefix_leading_dword_matching_embedded_profile_tag_count,
dominant_pattern dominant_pattern
@ -4932,10 +4947,11 @@ 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, {} decoded rows across {} unique name pairs, {} 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, {} rows with a tertiary 0x55f1 string, {} 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.decoded_embedded_name_row_count,
side_buffer.unique_embedded_name_pair_count, side_buffer.unique_embedded_name_pair_count,
side_buffer.decoded_embedded_name_row_with_tertiary_name_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
@ -11725,6 +11741,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
prefix_separator_byte: u8, prefix_separator_byte: u8,
primary_name: Option<String>, primary_name: Option<String>,
secondary_name: Option<String>, secondary_name: Option<String>,
tertiary_name: Option<String>,
} }
#[derive(Default)] #[derive(Default)]
@ -11851,13 +11868,16 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
else { else {
continue; continue;
}; };
if let Some(names) = parse_save_len_prefixed_ascii_name_pair(name_payload) { if let Some(names) = parse_save_len_prefixed_ascii_name_triplet(name_payload) {
parsed_embedded_names = Some(names); parsed_embedded_names = Some(names);
break; break;
} }
} }
let Some((first_embedded_primary_name, first_embedded_secondary_name)) = let Some((
parsed_embedded_names first_embedded_primary_name,
first_embedded_secondary_name,
first_embedded_tertiary_name,
)) = parsed_embedded_names
else { else {
continue; continue;
}; };
@ -11879,12 +11899,13 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
else { else {
continue; continue;
}; };
if let Some(names) = parse_save_len_prefixed_ascii_name_pair(name_payload) { if let Some(names) = parse_save_len_prefixed_ascii_name_triplet(name_payload) {
parsed_names = Some(names); parsed_names = Some(names);
break; break;
} }
} }
let (primary_name, secondary_name) = parsed_names.unwrap_or_default(); let (primary_name, secondary_name, tertiary_name) =
parsed_names.unwrap_or_default();
Some(EmbeddedNameRow { Some(EmbeddedNameRow {
name_tag_relative_offset, name_tag_relative_offset,
prefix_leading_dword, prefix_leading_dword,
@ -11892,6 +11913,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
prefix_separator_byte, prefix_separator_byte,
primary_name: (!primary_name.is_empty()).then_some(primary_name), primary_name: (!primary_name.is_empty()).then_some(primary_name),
secondary_name: (!secondary_name.is_empty()).then_some(secondary_name), secondary_name: (!secondary_name.is_empty()).then_some(secondary_name),
tertiary_name,
}) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -11911,6 +11933,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
prefix_separator_byte_hex: format!("0x{:02x}", row.prefix_separator_byte), prefix_separator_byte_hex: format!("0x{:02x}", row.prefix_separator_byte),
primary_name: row.primary_name.clone(), primary_name: row.primary_name.clone(),
secondary_name: row.secondary_name.clone(), secondary_name: row.secondary_name.clone(),
tertiary_name: row.tertiary_name.clone(),
}, },
) )
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -12061,6 +12084,14 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
.iter() .iter()
.filter(|row| row.primary_name.is_some() && row.secondary_name.is_some()) .filter(|row| row.primary_name.is_some() && row.secondary_name.is_some())
.count(); .count();
let decoded_embedded_name_row_with_tertiary_name_count = embedded_name_rows
.iter()
.filter(|row| {
row.primary_name.is_some()
&& row.secondary_name.is_some()
&& row.tertiary_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(),
@ -12089,11 +12120,13 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
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, decoded_embedded_name_row_count,
decoded_embedded_name_row_with_tertiary_name_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, 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()),
first_embedded_tertiary_name: first_embedded_tertiary_name.clone(),
embedded_name_row_samples, embedded_name_row_samples,
compact_prefix_pattern_summaries, compact_prefix_pattern_summaries,
name_pair_summaries, name_pair_summaries,
@ -12105,9 +12138,10 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
"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(),
"first embedded 0x55f1 row decodes with placed-structure-style dual names, which makes this the strongest current candidate for the separate placed-structure dynamic side-buffer owner seam".to_string(), "first embedded 0x55f1 row decodes with placed-structure-style dual names, which makes this the strongest current candidate for the separate placed-structure dynamic side-buffer owner seam".to_string(),
format!( format!(
"grounded first embedded names are {:?}/{:?} with {} embedded 0x55f1 name rows in the tagged records span", "grounded first embedded names are {:?}/{:?}/{:?} with {} embedded 0x55f1 name rows in the tagged records span",
Some(first_embedded_primary_name), Some(first_embedded_primary_name),
Some(first_embedded_secondary_name), Some(first_embedded_secondary_name),
first_embedded_tertiary_name,
embedded_name_tag_offsets.len() embedded_name_tag_offsets.len()
), ),
format!( format!(
@ -12117,8 +12151,10 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
u32::from(SAVE_REGION_RECORD_PROFILE_TAG) u32::from(SAVE_REGION_RECORD_PROFILE_TAG)
), ),
format!( format!(
"{decoded_embedded_name_row_count} decoded embedded name rows collapse into {} unique placed-structure name pairs", "{decoded_embedded_name_row_count} decoded embedded name rows collapse into {} unique placed-structure name pairs; {} rows also expose a third embedded 0x55f1 string",
unique_embedded_name_pair_count unique_embedded_name_pair_count
,
decoded_embedded_name_row_with_tertiary_name_count
), ),
dominant_compact_prefix_pattern dominant_compact_prefix_pattern
.map(|pattern| { .map(|pattern| {
@ -12511,6 +12547,13 @@ fn parse_save_len_prefixed_ascii_name(bytes: &[u8]) -> Option<String> {
} }
fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, String)> { fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, String)> {
let (first, second, _) = parse_save_len_prefixed_ascii_name_triplet(bytes)?;
Some((first, second))
}
fn parse_save_len_prefixed_ascii_name_triplet(
bytes: &[u8],
) -> Option<(String, String, Option<String>)> {
let first_len = *bytes.first()? as usize; let first_len = *bytes.first()? as usize;
let first_end = 1 + first_len; let first_end = 1 + first_len;
let first = std::str::from_utf8(bytes.get(1..first_end)?) let first = std::str::from_utf8(bytes.get(1..first_end)?)
@ -12530,7 +12573,24 @@ fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, Stri
if first.is_empty() || second.is_empty() { if first.is_empty() || second.is_empty() {
return None; return None;
} }
Some((first, second)) let mut third_len_offset = second_start + second_len;
while matches!(bytes.get(third_len_offset), Some(0)) {
third_len_offset += 1;
}
let third = bytes
.get(third_len_offset)
.copied()
.filter(|len| *len != 0)
.and_then(|third_len| {
let third_len = third_len as usize;
let third_start = third_len_offset + 1;
let text = std::str::from_utf8(bytes.get(third_start..third_start + third_len)?)
.ok()?
.trim_end_matches('\0')
.to_string();
(!text.is_empty()).then_some(text)
});
Some((first, second, third))
} }
fn parse_save_fixed_ascii_name(bytes: &[u8]) -> Option<String> { fn parse_save_fixed_ascii_name(bytes: &[u8]) -> Option<String> {
@ -20205,6 +20265,7 @@ mod tests {
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.decoded_embedded_name_row_count, 1);
assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
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,
@ -20219,6 +20280,7 @@ mod tests {
probe.first_embedded_secondary_name.as_deref(), probe.first_embedded_secondary_name.as_deref(),
Some("Infrastructure") Some("Infrastructure")
); );
assert_eq!(probe.first_embedded_tertiary_name.as_deref(), None);
assert_eq!(probe.compact_prefix_pattern_summaries.len(), 1); assert_eq!(probe.compact_prefix_pattern_summaries.len(), 1);
assert_eq!( assert_eq!(
probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex, probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
@ -20295,6 +20357,7 @@ mod tests {
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.decoded_embedded_name_row_count, 3);
assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
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,
@ -20333,6 +20396,19 @@ mod tests {
assert_eq!(probe.name_pair_summaries[1].count, 1); assert_eq!(probe.name_pair_summaries[1].count, 1);
} }
#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_optional_third_name() {
let bytes = [
5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5,
b'T', b'h', b'i', b'r', b'd',
];
let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
.expect("triplet parser should decode three len-prefixed ascii names");
assert_eq!(parsed.0, "First");
assert_eq!(parsed.1, "Second");
assert_eq!(parsed.2.as_deref(), Some("Third"));
}
#[test] #[test]
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() { fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe { let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
@ -20363,11 +20439,13 @@ mod tests {
first_embedded_name_tag_relative_offset: 7, first_embedded_name_tag_relative_offset: 7,
embedded_name_tag_count: 3, embedded_name_tag_count: 3,
decoded_embedded_name_row_count: 3, decoded_embedded_name_row_count: 3,
decoded_embedded_name_row_with_tertiary_name_count: 0,
unique_compact_prefix_pattern_count: 2, unique_compact_prefix_pattern_count: 2,
prefix_leading_dword_matching_embedded_profile_tag_count: 2, prefix_leading_dword_matching_embedded_profile_tag_count: 2,
unique_embedded_name_pair_count: 2, unique_embedded_name_pair_count: 2,
first_embedded_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()), first_embedded_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
first_embedded_secondary_name: Some("Infrastructure".to_string()), first_embedded_secondary_name: Some("Infrastructure".to_string()),
first_embedded_tertiary_name: None,
embedded_name_row_samples: vec![], embedded_name_row_samples: vec![],
compact_prefix_pattern_summaries: vec![], compact_prefix_pattern_summaries: vec![],
name_pair_summaries: vec![ name_pair_summaries: vec![
@ -22015,11 +22093,13 @@ mod tests {
first_embedded_name_tag_relative_offset: 0x20, first_embedded_name_tag_relative_offset: 0x20,
embedded_name_tag_count: 138, embedded_name_tag_count: 138,
decoded_embedded_name_row_count: 138, decoded_embedded_name_row_count: 138,
decoded_embedded_name_row_with_tertiary_name_count: 0,
unique_compact_prefix_pattern_count: 7, unique_compact_prefix_pattern_count: 7,
prefix_leading_dword_matching_embedded_profile_tag_count: 17, prefix_leading_dword_matching_embedded_profile_tag_count: 17,
unique_embedded_name_pair_count: 5, unique_embedded_name_pair_count: 5,
first_embedded_primary_name: Some("TrackCapST_Cap.3dp".to_string()), first_embedded_primary_name: Some("TrackCapST_Cap.3dp".to_string()),
first_embedded_secondary_name: Some("Infrastructure".to_string()), first_embedded_secondary_name: Some("Infrastructure".to_string()),
first_embedded_tertiary_name: None,
embedded_name_row_samples: Vec::new(), embedded_name_row_samples: Vec::new(),
compact_prefix_pattern_summaries: Vec::new(), compact_prefix_pattern_summaries: Vec::new(),
name_pair_summaries: vec![SmpSavePlacedStructureDynamicSideBufferNamePairSummary { name_pair_summaries: vec![SmpSavePlacedStructureDynamicSideBufferNamePairSummary {

View file

@ -2933,6 +2933,13 @@ The low helper strip beneath that shared family is tighter now too: `0x0052ecd0`
next unknowns are no longer inside that row layout itself; they are in the payload streams those next unknowns are no longer inside that row layout itself; they are in the payload streams those
rows point at, and how those streams align with the save-side `0x55f1` name-pair groups and rows point at, and how those streams align with the save-side `0x55f1` name-pair groups and
compact prefix regimes. compact prefix regimes.
The shared child payload callback is tighter now too: `0x00455fc0` zeroes the route-entry and
cached bridge bands, opens `0x55f1`, parses three len-prefixed strings through `0x00531380`,
opens `0x55f2`, seeds the child through `0x00455b70`, dispatches slot `+0x48`, runs the local
follow-on `0x0052ebd0`, and then opens `0x55f3`. The widened save-side probe currently still
sees only two embedded `0x55f1` strings on grounded `q.gms`, so the remaining payload question is
whether that third parsed string is absent on ordinary saves, hidden behind different framing, or
only populated on a narrower infrastructure subset.
The child loader family is explicit now too: local `.rdata` at `0x005cfd00` proves the The child loader family is explicit now too: local `.rdata` at `0x005cfd00` proves the
`Infrastructure` child vtable uses the shared tagged callback strip directly, with `Infrastructure` child vtable uses the shared tagged callback strip directly, with
`+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining `+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining

View file

@ -65,7 +65,13 @@ Working rule:
`(payload pointer, previous live id, next live id)`, so the next infrastructure question is only `(payload pointer, previous live id, next live id)`, so the next infrastructure question is only
how those payload streams align with the embedded `0x55f1` name-pair groups and compact-prefix how those payload streams align with the embedded `0x55f1` name-pair groups and compact-prefix
regimes, and which tagged values inside each payload stream become the child count, optional regimes, and which tagged values inside each payload stream become the child count, optional
primary-child ordinal, and per-child callback sequence that `0x0048dcf0` consumes. primary-child ordinal, and per-child callback sequence that `0x0048dcf0` consumes. Direct
disassembly now also shows the shared child payload callback `0x00455fc0` opening
`0x55f1 -> 0x55f2 -> 0x55f3`, parsing three `0x55f1` strings through `0x00531380`, seeding the
child through `0x00455b70`, and then dispatching slot `+0x48`; the widened save-side probe
currently sees `0` third `0x55f1` strings on grounded `q.gms`, so the next pass should ask
whether that third string is genuinely absent on ordinary saves or stored under different
framing than the current embedded-row scan.
- The child loader identity is closed now too: local `.rdata` at `0x005cfd00` proves the - The child loader identity is closed now too: local `.rdata` at `0x005cfd00` proves the
`Infrastructure` child vtable uses the shared tagged callback strip directly, with `Infrastructure` child vtable uses the shared tagged callback strip directly, with
`+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining `+0x40 = 0x00455fc0`, `+0x48 = 0x00455870`, and `+0x4c = 0x00455930`. So the remaining