Summarize peer-site payload ladders

This commit is contained in:
Jan Petykiewicz 2026-04-18 20:10:29 -07:00
commit 26848f96e6
2 changed files with 228 additions and 0 deletions

View file

@ -3555,6 +3555,23 @@ pub struct SmpPeriodicCompanyServiceTraceEntry {
pub branches: Vec<SmpServiceTraceBranchStatus>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureProfilePayloadSummaryEntry {
pub profile_payload_dword_hex: String,
pub profile_status_kind: String,
pub count: usize,
#[serde(default)]
pub sample_primary_names: Vec<String>,
#[serde(default)]
pub sample_secondary_names: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureProfilePayloadDeltaSummaryEntry {
pub delta_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPeriodicCompanyServiceTraceReport {
pub profile_family: String,
@ -3577,6 +3594,12 @@ pub struct SmpPeriodicCompanyServiceTraceReport {
#[serde(default)]
pub peer_site_selector_candidate_helper_linkage: Vec<String>,
#[serde(default)]
pub peer_site_selector_candidate_saved_payload_summaries:
Vec<SmpSavePlacedStructureProfilePayloadSummaryEntry>,
#[serde(default)]
pub peer_site_selector_candidate_saved_payload_delta_summaries:
Vec<SmpSavePlacedStructureProfilePayloadDeltaSummaryEntry>,
#[serde(default)]
pub peer_site_restore_input_fields: Vec<String>,
#[serde(default)]
pub peer_site_runtime_input_fields: Vec<String>,
@ -4174,6 +4197,97 @@ pub fn inspect_save_periodic_company_service_trace_file(
Ok(trace)
}
fn summarize_peer_site_selector_candidate_saved_payloads(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> Vec<SmpSavePlacedStructureProfilePayloadSummaryEntry> {
let Some(triplets) = analysis.placed_structure_record_triplets.as_ref() else {
return Vec::new();
};
let mut grouped =
BTreeMap::<(String, String), (usize, BTreeSet<String>, BTreeSet<String>)>::new();
for entry in &triplets.entries {
let grouped_entry = grouped
.entry((
entry.profile_payload_dword_hex.clone(),
entry.profile_status_kind.clone(),
))
.or_insert_with(|| (0, BTreeSet::new(), BTreeSet::new()));
grouped_entry.0 += 1;
if grouped_entry.1.len() < 4 {
grouped_entry.1.insert(entry.primary_name.clone());
}
if grouped_entry.2.len() < 4 {
grouped_entry.2.insert(entry.secondary_name.clone());
}
}
let mut summaries = grouped
.into_iter()
.map(
|(
(profile_payload_dword_hex, profile_status_kind),
(count, primary_names, secondary_names),
)| {
SmpSavePlacedStructureProfilePayloadSummaryEntry {
profile_payload_dword_hex,
profile_status_kind,
count,
sample_primary_names: primary_names.into_iter().collect(),
sample_secondary_names: secondary_names.into_iter().collect(),
}
},
)
.collect::<Vec<_>>();
summaries.sort_by(|left, right| {
right
.count
.cmp(&left.count)
.then_with(|| {
left.profile_payload_dword_hex
.cmp(&right.profile_payload_dword_hex)
})
.then_with(|| left.profile_status_kind.cmp(&right.profile_status_kind))
});
summaries.truncate(8);
summaries
}
fn summarize_peer_site_selector_candidate_saved_payload_deltas(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> Vec<SmpSavePlacedStructureProfilePayloadDeltaSummaryEntry> {
let Some(triplets) = analysis.placed_structure_record_triplets.as_ref() else {
return Vec::new();
};
let mut payload_values = triplets
.entries
.iter()
.map(|entry| entry.profile_payload_dword)
.collect::<Vec<_>>();
payload_values.sort_unstable();
payload_values.dedup();
let mut delta_counts = BTreeMap::<u32, usize>::new();
for window in payload_values.windows(2) {
let delta = window[1].wrapping_sub(window[0]);
*delta_counts.entry(delta).or_insert(0) += 1;
}
let mut summaries = delta_counts
.into_iter()
.map(
|(delta, count)| SmpSavePlacedStructureProfilePayloadDeltaSummaryEntry {
delta_hex: format!("0x{delta:08x}"),
count,
},
)
.collect::<Vec<_>>();
summaries.sort_by(|left, right| {
right
.count
.cmp(&left.count)
.then_with(|| left.delta_hex.cmp(&right.delta_hex))
});
summaries.truncate(6);
summaries
}
fn build_periodic_company_service_trace_report(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> SmpPeriodicCompanyServiceTraceReport {
@ -4198,6 +4312,10 @@ fn build_periodic_company_service_trace_report(
"0x0040d1e1 -> 0x0045c3c0 consumes the same owner family's [site+0x246] child lane"
.to_string(),
];
let peer_site_selector_candidate_saved_payload_summaries =
summarize_peer_site_selector_candidate_saved_payloads(analysis);
let peer_site_selector_candidate_saved_payload_delta_summaries =
summarize_peer_site_selector_candidate_saved_payload_deltas(analysis);
let peer_site_restore_input_fields = vec![
"[site+0x3cc] saved placed-structure id feeding 0x62b2fc".to_string(),
"[site+0x3d0] saved companion-region id from [placed+0x173] feeding 0x62b268".to_string(),
@ -4504,6 +4622,17 @@ fn build_periodic_company_service_trace_report(
notes.push(
"Direct disassembly now closes the negative persistence side too: the direct 0x36b1 per-record callbacks serialize the shared base scalar triplets rooted at [this+0x206/+0x20a/+0x20e] plus the subordinate payload callback strip, while the 0x4a9d/0x4a3a/0x4a3b side-buffer owner only persists route-entry lists, three byte arrays, five proximity buckets, and the sampled-cell list. That means neither checked-in save owner seam currently persists the core peer-site identity fields [site+0x04], [site+0x2a8], or [peer+0x08] directly.".to_string(),
);
if !peer_site_selector_candidate_saved_payload_summaries.is_empty() {
notes.push(format!(
"The periodic-company trace now also carries a compact save-side summary of the tagged 0x5dc1 placed-structure profile payload/status pairs already parsed from the 0x36b1 triplet seam; dominant current pair is {} / {} x{}, and dominant adjacent payload delta is {:?}.",
peer_site_selector_candidate_saved_payload_summaries[0].profile_payload_dword_hex,
peer_site_selector_candidate_saved_payload_summaries[0].profile_status_kind,
peer_site_selector_candidate_saved_payload_summaries[0].count,
peer_site_selector_candidate_saved_payload_delta_summaries
.first()
.map(|entry| entry.delta_hex.as_str())
));
}
notes.push(
"The replay strip is tighter now too. 0x00444690 is the current late world bring-up caller of 0x004133b0, that outer owner drains queued site ids through 0x0040e450 and then sweeps every live placed structure through 0x0040ee10, and 0x0040ee10 itself reaches 0x0040edf6 -> 0x00480710 plus the later 0x0040e360 follow-on. A separate runtime path at 0x004160aa also re-enters 0x0040ee10 later. So [peer+0x08] replay is no longer the open question, and [site+0x04] is no longer an owner mystery either: the local linked-site helper strip seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268, reaches the save-backed 0x0045c150 / 0x0045c310 owner directly, that owner fills [owner+0x23e/+0x242] from tagged payload 0x5dc1, and 0x0045c36e then feeds [owner+0x23e] through 0x00456100 -> 0x00455b70 -> 0x0052edf0 into [site+0x04]. The remaining non-hook target is now the smaller shellless-simulation question: which subset of those persisted site/peer fields is actually sufficient to run 0x004014b0 and its city-connection sibling without shell state.".to_string(),
);
@ -4521,6 +4650,8 @@ fn build_periodic_company_service_trace_report(
peer_site_selector_candidate_selector_lane,
peer_site_selector_candidate_class_identity_status,
peer_site_selector_candidate_helper_linkage,
peer_site_selector_candidate_saved_payload_summaries,
peer_site_selector_candidate_saved_payload_delta_summaries,
peer_site_restore_input_fields,
peer_site_runtime_input_fields,
peer_site_runtime_reconstruction_status,
@ -27094,6 +27225,76 @@ mod tests {
fn builds_periodic_company_service_trace_report_with_candidate_consumers() {
let mut analysis = empty_analysis_report();
analysis.selected_company_id = Some(7);
analysis.placed_structure_record_triplets =
Some(SmpSavePlacedStructureRecordTripletProbe {
profile_family: analysis.profile_family.clone(),
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: "StationA".to_string(),
secondary_name: "StationSetA".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0x1a,
profile_chunk_len: 0x20,
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: 0x0101,
policy_trailing_word_hex: "0x0101".to_string(),
profile_open_marker: 0x5dc1,
profile_open_marker_hex: "0x00005dc1".to_string(),
profile_repeated_primary_name: "StationA".to_string(),
profile_repeated_secondary_name: "StationSetA".to_string(),
profile_payload_dword: 0x0e373880,
profile_payload_dword_hex: "0x0e373880".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0x5dc2,
profile_close_marker_hex: "0x00005dc2".to_string(),
},
SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: 1,
primary_name: "StationB".to_string(),
secondary_name: "StationSetB".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0x1a,
profile_chunk_len: 0x20,
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: 0x0101,
policy_trailing_word_hex: "0x0101".to_string(),
profile_open_marker: 0x5dc1,
profile_open_marker_hex: "0x00005dc1".to_string(),
profile_repeated_primary_name: "StationB".to_string(),
profile_repeated_secondary_name: "StationSetB".to_string(),
profile_payload_dword: 0x0e373500,
profile_payload_dword_hex: "0x0e373500".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0x5dc2,
profile_close_marker_hex: "0x00005dc2".to_string(),
},
],
evidence: Vec::new(),
});
analysis
.company_entries
.push(SmpSaveCompanyRecordAnalysisEntry {
@ -27154,6 +27355,24 @@ mod tests {
"grounded_direct_local_helper_strip"
);
assert_eq!(trace.peer_site_selector_candidate_helper_linkage.len(), 4);
assert_eq!(
trace
.peer_site_selector_candidate_saved_payload_summaries
.len(),
2
);
assert_eq!(
trace.peer_site_selector_candidate_saved_payload_summaries[0].profile_payload_dword_hex,
"0x0e373500"
);
assert_eq!(
trace.peer_site_selector_candidate_saved_payload_summaries[0].count,
1
);
assert_eq!(
trace.peer_site_selector_candidate_saved_payload_delta_summaries[0].delta_hex,
"0x00000380"
);
assert_eq!(trace.peer_site_restore_input_fields.len(), 4);
assert_eq!(trace.peer_site_runtime_input_fields.len(), 3);
assert_eq!(

View file

@ -88,6 +88,10 @@ Working rule:
three-arg wrapper `0x00530640`
- `0x00490a79` is one chooser-side caller of `0x00455b70`, feeding literal selector
`0x005cfd74` with fallback seed `0x005c87a8`
- the periodic-company trace now also surfaces the save-side `0x5dc1` payload/status summaries
already parsed from the `0x36b1` triplet seam; on grounded `p.gms` the payload dword lane is
almost entirely unique while the status kind stays `unset`, and the dominant adjacent payload
delta is `0x00000780` across `1908` steps
So the next owner question is no longer “what does the acquisition branch do?” or “which post-
load owner replays linked-site refresh?” but “which concrete `0x00455b70` caller family applies
to the live site rows, and which persisted lane becomes the selector bundle that ultimately
@ -113,6 +117,11 @@ Working rule:
`grounded_direct_local_helper_strip`, and helper linkage
`0x0040ceab -> 0x0045c150` / `0x0040d1a1 -> 0x0045c310` /
`0x0040cd70 seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268`
- use the new `0x5dc1` payload/status summary in the same trace as negative evidence too:
the current `profile_payload_dword` lane behaves like a monotone ladder (`dominant adjacent
delta 0x780`) rather than a compact selector family, so the next peer-site slice should treat
that raw dword as a likely allocator/offset lane until a stronger selector interpretation
appears
- treat the peer-site selector seam itself as grounded enough for planning purposes
- use the new structured restore/runtime field split in the same trace:
restore subset