Add compact dispatch count summary command

This commit is contained in:
Jan Petykiewicz 2026-04-19 02:36:41 -07:00
commit a9906f8bad
2 changed files with 102 additions and 26 deletions

View file

@ -131,6 +131,9 @@ enum Command {
RuntimeInspectCompactEventDispatchCluster {
root_path: PathBuf,
},
RuntimeInspectCompactEventDispatchClusterCounts {
root_path: PathBuf,
},
RuntimeSummarizeSaveLoad {
smp_path: PathBuf,
},
@ -305,6 +308,12 @@ struct RuntimeCompactEventDispatchClusterOutput {
report: RuntimeCompactEventDispatchClusterReport,
}
#[derive(Debug, Serialize)]
struct RuntimeCompactEventDispatchClusterCountsOutput {
root_path: String,
report: RuntimeCompactEventDispatchClusterCountsReport,
}
#[derive(Debug, Serialize)]
struct RuntimeCompactEventDispatchClusterReport {
maps_scanned: usize,
@ -324,6 +333,21 @@ struct RuntimeCompactEventDispatchClusterReport {
BTreeMap<u32, Vec<RuntimeCompactEventDispatchClusterOccurrence>>,
}
#[derive(Debug, Serialize)]
struct RuntimeCompactEventDispatchClusterCountsReport {
maps_scanned: usize,
maps_with_event_runtime_collection: usize,
maps_with_dispatch_strip_records: usize,
dispatch_strip_record_count: usize,
dispatch_strip_records_with_trigger_kind: usize,
dispatch_strip_records_missing_trigger_kind: usize,
dispatch_strip_payload_families: BTreeMap<String, usize>,
dispatch_descriptor_occurrence_counts: BTreeMap<String, usize>,
dispatch_descriptor_map_counts: BTreeMap<String, usize>,
unknown_descriptor_ids: Vec<u32>,
unknown_descriptor_special_condition_label_matches: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
struct RuntimeCompactEventDispatchClusterOccurrence {
path: String,
@ -991,6 +1015,9 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
Command::RuntimeInspectCompactEventDispatchCluster { root_path } => {
run_runtime_inspect_compact_event_dispatch_cluster(&root_path)?;
}
Command::RuntimeInspectCompactEventDispatchClusterCounts { root_path } => {
run_runtime_inspect_compact_event_dispatch_cluster_counts(&root_path)?;
}
Command::RuntimeSummarizeSaveLoad { smp_path } => {
run_runtime_summarize_save_load(&smp_path)?;
}
@ -1224,6 +1251,14 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
root_path: PathBuf::from(root_path),
})
}
[command, subcommand, root_path]
if command == "runtime"
&& subcommand == "inspect-compact-event-dispatch-cluster-counts" =>
{
Ok(Command::RuntimeInspectCompactEventDispatchClusterCounts {
root_path: PathBuf::from(root_path),
})
}
[command, subcommand, path]
if command == "runtime" && subcommand == "summarize-save-load" =>
{
@ -1508,7 +1543,7 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
})
}
_ => Err(
"usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-candidate-table <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime import-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]"
"usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-candidate-table <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime inspect-compact-event-dispatch-cluster-counts <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime import-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]"
.into(),
),
}
@ -1716,6 +1751,45 @@ fn run_runtime_inspect_smp(smp_path: &Path) -> Result<(), Box<dyn std::error::Er
fn run_runtime_inspect_compact_event_dispatch_cluster(
root_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
let report = build_runtime_compact_event_dispatch_cluster_report(root_path)?;
let output = RuntimeCompactEventDispatchClusterOutput {
root_path: root_path.display().to_string(),
report,
};
println!("{}", serde_json::to_string_pretty(&output)?);
Ok(())
}
fn run_runtime_inspect_compact_event_dispatch_cluster_counts(
root_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
let report = build_runtime_compact_event_dispatch_cluster_report(root_path)?;
let output = RuntimeCompactEventDispatchClusterCountsOutput {
root_path: root_path.display().to_string(),
report: RuntimeCompactEventDispatchClusterCountsReport {
maps_scanned: report.maps_scanned,
maps_with_event_runtime_collection: report.maps_with_event_runtime_collection,
maps_with_dispatch_strip_records: report.maps_with_dispatch_strip_records,
dispatch_strip_record_count: report.dispatch_strip_record_count,
dispatch_strip_records_with_trigger_kind: report
.dispatch_strip_records_with_trigger_kind,
dispatch_strip_records_missing_trigger_kind: report
.dispatch_strip_records_missing_trigger_kind,
dispatch_strip_payload_families: report.dispatch_strip_payload_families,
dispatch_descriptor_occurrence_counts: report.dispatch_descriptor_occurrence_counts,
dispatch_descriptor_map_counts: report.dispatch_descriptor_map_counts,
unknown_descriptor_ids: report.unknown_descriptor_ids,
unknown_descriptor_special_condition_label_matches: report
.unknown_descriptor_special_condition_label_matches,
},
};
println!("{}", serde_json::to_string_pretty(&output)?);
Ok(())
}
fn build_runtime_compact_event_dispatch_cluster_report(
root_path: &Path,
) -> Result<RuntimeCompactEventDispatchClusterReport, Box<dyn std::error::Error>> {
let mut input_paths = Vec::new();
collect_compact_event_dispatch_cluster_input_paths(root_path, &mut input_paths)?;
input_paths.sort();
@ -1838,26 +1912,21 @@ fn run_runtime_inspect_compact_event_dispatch_cluster(
})
.collect::<Vec<_>>();
let report = RuntimeCompactEventDispatchClusterOutput {
root_path: root_path.display().to_string(),
report: RuntimeCompactEventDispatchClusterReport {
maps_scanned: input_paths.len(),
maps_with_event_runtime_collection,
maps_with_dispatch_strip_records,
dispatch_strip_record_count,
dispatch_strip_records_with_trigger_kind,
dispatch_strip_records_missing_trigger_kind,
dispatch_strip_payload_families,
dispatch_descriptor_occurrence_counts,
dispatch_descriptor_map_counts,
dispatch_descriptor_occurrences,
unknown_descriptor_ids,
unknown_descriptor_special_condition_label_matches,
unknown_descriptor_occurrences,
},
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
Ok(RuntimeCompactEventDispatchClusterReport {
maps_scanned: input_paths.len(),
maps_with_event_runtime_collection,
maps_with_dispatch_strip_records,
dispatch_strip_record_count,
dispatch_strip_records_with_trigger_kind,
dispatch_strip_records_missing_trigger_kind,
dispatch_strip_payload_families,
dispatch_descriptor_occurrence_counts,
dispatch_descriptor_map_counts,
dispatch_descriptor_occurrences,
unknown_descriptor_ids,
unknown_descriptor_special_condition_label_matches,
unknown_descriptor_occurrences,
})
}
fn run_runtime_summarize_save_load(smp_path: &Path) -> Result<(), Box<dyn std::error::Error>> {

View file

@ -268,11 +268,18 @@ Working rule:
mutation-capable rows in those sampled maps.
- the widened compact-cluster probe now makes that same gap first-class too:
`runtime inspect-compact-event-dispatch-cluster <map-or-dir>` now reports all dispatch-strip
descriptor occurrences, their `trigger_kind`, and payload family instead of only unknown
descriptor ids. On `Texas Tea.gmp`, the widened report now shows `548 Add Building Port01`,
`8 Economic Status`, and `43 Company Variable 1` all arriving on
`real_packed_nondirect_compact_v1` rows with `trigger_kind = null`, so the next pass can work
from a checked probe rather than ad hoc `inspect-smp` scrapes.
descriptor occurrences, their `trigger_kind`, payload family, and the aggregated
`dispatch_descriptor_occurrence_counts` / `dispatch_descriptor_map_counts` summaries instead of
only unknown descriptor ids. On `Texas Tea.gmp`, the widened report now shows
`548 Add Building Port01`, `8 Economic Status`, and `43 Company Variable 1` all arriving on
`real_packed_nondirect_compact_v1` rows with `trigger_kind = null`, while the count summary
reports `Company Variable 1 = 4` occurrences and the other two once each, so the next pass can
work from a checked scalable probe rather than ad hoc `inspect-smp` scrapes.
- the scalable summary sibling is grounded too:
`runtime inspect-compact-event-dispatch-cluster-counts <map-or-dir>` reuses the same analysis
but emits only the corpus-level count fields, so the next broader map-install pass no longer
needs to wade through every occurrence payload just to compare descriptor or trigger-kind
coverage.
- cross-map probing now gives a better static-analysis lead too:
`British Isles.gmp` shows no current `0x00431b20` dispatch-strip rows, `Germany.gmp` stays on
`Game Variable 1` plus `Company Variable 3..4`, while `Texas Tea.gmp` adds `Economic Status`