Summarize peer-site payload ladders
This commit is contained in:
parent
aa4147fcf2
commit
26848f96e6
2 changed files with 228 additions and 0 deletions
|
|
@ -3555,6 +3555,23 @@ pub struct SmpPeriodicCompanyServiceTraceEntry {
|
||||||
pub branches: Vec<SmpServiceTraceBranchStatus>,
|
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)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct SmpPeriodicCompanyServiceTraceReport {
|
pub struct SmpPeriodicCompanyServiceTraceReport {
|
||||||
pub profile_family: String,
|
pub profile_family: String,
|
||||||
|
|
@ -3577,6 +3594,12 @@ pub struct SmpPeriodicCompanyServiceTraceReport {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub peer_site_selector_candidate_helper_linkage: Vec<String>,
|
pub peer_site_selector_candidate_helper_linkage: Vec<String>,
|
||||||
#[serde(default)]
|
#[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>,
|
pub peer_site_restore_input_fields: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub peer_site_runtime_input_fields: Vec<String>,
|
pub peer_site_runtime_input_fields: Vec<String>,
|
||||||
|
|
@ -4174,6 +4197,97 @@ pub fn inspect_save_periodic_company_service_trace_file(
|
||||||
Ok(trace)
|
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(
|
fn build_periodic_company_service_trace_report(
|
||||||
analysis: &SmpSaveCompanyChairmanAnalysisReport,
|
analysis: &SmpSaveCompanyChairmanAnalysisReport,
|
||||||
) -> SmpPeriodicCompanyServiceTraceReport {
|
) -> SmpPeriodicCompanyServiceTraceReport {
|
||||||
|
|
@ -4198,6 +4312,10 @@ fn build_periodic_company_service_trace_report(
|
||||||
"0x0040d1e1 -> 0x0045c3c0 consumes the same owner family's [site+0x246] child lane"
|
"0x0040d1e1 -> 0x0045c3c0 consumes the same owner family's [site+0x246] child lane"
|
||||||
.to_string(),
|
.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![
|
let peer_site_restore_input_fields = vec![
|
||||||
"[site+0x3cc] saved placed-structure id feeding 0x62b2fc".to_string(),
|
"[site+0x3cc] saved placed-structure id feeding 0x62b2fc".to_string(),
|
||||||
"[site+0x3d0] saved companion-region id from [placed+0x173] feeding 0x62b268".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(
|
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(),
|
"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(
|
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(),
|
"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_selector_lane,
|
||||||
peer_site_selector_candidate_class_identity_status,
|
peer_site_selector_candidate_class_identity_status,
|
||||||
peer_site_selector_candidate_helper_linkage,
|
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_restore_input_fields,
|
||||||
peer_site_runtime_input_fields,
|
peer_site_runtime_input_fields,
|
||||||
peer_site_runtime_reconstruction_status,
|
peer_site_runtime_reconstruction_status,
|
||||||
|
|
@ -27094,6 +27225,76 @@ mod tests {
|
||||||
fn builds_periodic_company_service_trace_report_with_candidate_consumers() {
|
fn builds_periodic_company_service_trace_report_with_candidate_consumers() {
|
||||||
let mut analysis = empty_analysis_report();
|
let mut analysis = empty_analysis_report();
|
||||||
analysis.selected_company_id = Some(7);
|
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
|
analysis
|
||||||
.company_entries
|
.company_entries
|
||||||
.push(SmpSaveCompanyRecordAnalysisEntry {
|
.push(SmpSaveCompanyRecordAnalysisEntry {
|
||||||
|
|
@ -27154,6 +27355,24 @@ mod tests {
|
||||||
"grounded_direct_local_helper_strip"
|
"grounded_direct_local_helper_strip"
|
||||||
);
|
);
|
||||||
assert_eq!(trace.peer_site_selector_candidate_helper_linkage.len(), 4);
|
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_restore_input_fields.len(), 4);
|
||||||
assert_eq!(trace.peer_site_runtime_input_fields.len(), 3);
|
assert_eq!(trace.peer_site_runtime_input_fields.len(), 3);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,10 @@ Working rule:
|
||||||
three-arg wrapper `0x00530640`
|
three-arg wrapper `0x00530640`
|
||||||
- `0x00490a79` is one chooser-side caller of `0x00455b70`, feeding literal selector
|
- `0x00490a79` is one chooser-side caller of `0x00455b70`, feeding literal selector
|
||||||
`0x005cfd74` with fallback seed `0x005c87a8`
|
`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-
|
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
|
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
|
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
|
`grounded_direct_local_helper_strip`, and helper linkage
|
||||||
`0x0040ceab -> 0x0045c150` / `0x0040d1a1 -> 0x0045c310` /
|
`0x0040ceab -> 0x0045c150` / `0x0040d1a1 -> 0x0045c310` /
|
||||||
`0x0040cd70 seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268`
|
`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
|
- 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:
|
- use the new structured restore/runtime field split in the same trace:
|
||||||
restore subset
|
restore subset
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue