diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index ebb4dc1..f72e926 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -9432,6 +9432,26 @@ fn parse_event_runtime_collection_summary_with_tag_width( .collect::>(); trigger_kinds_present.sort_unstable(); trigger_kinds_present.dedup(); + let mut mutation_candidate_record_indexes = records + .iter() + .filter(|record| { + record.grouped_effect_rows.iter().any(|row| { + opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(row.opcode) + }) + }) + .map(|record| record.record_index) + .collect::>(); + mutation_candidate_record_indexes.sort_unstable(); + mutation_candidate_record_indexes.dedup(); + let mut mutation_candidate_opcodes = records + .iter() + .flat_map(|record| record.grouped_effect_rows.iter().map(|row| row.opcode)) + .filter(|opcode| { + opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(*opcode) + }) + .collect::>(); + mutation_candidate_opcodes.sort_unstable(); + mutation_candidate_opcodes.dedup(); let mut control_lane_notes = Vec::new(); if nondirect_compact_record_count != 0 && nondirect_compact_record_count == nondirect_compact_records_missing_trigger_kind @@ -9446,6 +9466,16 @@ fn parse_event_runtime_collection_summary_with_tag_width( trigger_kinds_present )); } + if !mutation_candidate_record_indexes.is_empty() { + control_lane_notes.push(format!( + "records with grouped opcodes already in the 0x00431b20 mutation strip = {:?}", + mutation_candidate_record_indexes + )); + control_lane_notes.push(format!( + "0x00431b20 mutation-strip opcodes present in decoded grouped rows = {:?}", + mutation_candidate_opcodes + )); + } return Some(SmpLoadedEventRuntimeCollectionSummary { source_kind, @@ -9480,6 +9510,10 @@ fn parse_event_runtime_collection_summary_with_tag_width( None } +fn opcode_reaches_world_apply_compact_runtime_effect_dispatch_strip(opcode: u8) -> bool { + matches!(opcode, 0x04..=0x08 | 0x0d | 0x10..=0x13 | 0x16) +} + fn try_parse_nondirect_event_runtime_record_summaries( records_payload: &[u8], records_payload_offset: usize, @@ -22145,6 +22179,14 @@ mod tests { assert!(summary.control_lane_notes.iter().any(|line| { line.contains("all compact non-direct rows currently decode row bodies only") })); + assert!(summary.control_lane_notes.iter().any(|line| { + line.contains( + "records with grouped opcodes already in the 0x00431b20 mutation strip = [0]", + ) + })); + assert!(summary.control_lane_notes.iter().any(|line| { + line.contains("0x00431b20 mutation-strip opcodes present in decoded grouped rows = [4]") + })); let record = summary .records .first() diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index 092f446..4dbb38b 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -252,6 +252,11 @@ Working rule: `control_lane_notes`; real `War Effort.gmp` output currently shows `24/24` compact non-direct rows still missing decoded trigger kind, which narrows the next owner question to the non-row-body control lane rather than the compact row framing itself + - the same probe now narrows the candidate runtime-effect set too: + it reports which decoded records already carry grouped opcodes in the grounded + `0x00431b20` mutation strip; real `War Effort.gmp` currently narrows that to record indexes + `[1, 9, 12, 13, 14, 15, 16, 17, 22]`, all through opcode `4`, so the next pass can focus on + that smaller subset instead of the full 24-row compact collection - the concrete owner strip above that bundle is grounded now too: `0x00433060` is the direct non-direct serializer loop that writes `0x4e99/0x4e9a/0x4e9b`, calls `0x00430d70` per live collection row, and sits beside the sibling `0x00433130` size/load