From 6593a53ca76773b4ac36ef3c1a374df38d002715 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 18 Apr 2026 21:11:40 -0700 Subject: [PATCH] Rehost company route-anchor cache tuple --- crates/rrt-runtime/src/import.rs | 6 ++ crates/rrt-runtime/src/runtime.rs | 4 + crates/rrt-runtime/src/smp.rs | 128 ++++++++++++++++++++++-------- crates/rrt-runtime/src/summary.rs | 24 ++++++ docs/rehost-queue.md | 6 +- 5 files changed, 134 insertions(+), 34 deletions(-) diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index de73bba..a17846d 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -5393,6 +5393,8 @@ mod tests { prior_issue_calendar_word_2: 5, city_connection_latch: true, linked_transit_latch: false, + linked_transit_route_anchor_entry_id: Some(77), + linked_transit_route_anchor_fallback_counts: vec![3, 5, 8], stat_band_root_0cfb_candidates: Vec::new(), stat_band_root_0d7f_candidates: Vec::new(), stat_band_root_1c47_candidates: Vec::new(), @@ -5453,6 +5455,8 @@ mod tests { prior_issue_calendar_word_2: 3, city_connection_latch: false, linked_transit_latch: true, + linked_transit_route_anchor_entry_id: Some(41), + linked_transit_route_anchor_fallback_counts: vec![13, 21, 34], stat_band_root_0cfb_candidates: Vec::new(), stat_band_root_0d7f_candidates: Vec::new(), stat_band_root_1c47_candidates: Vec::new(), @@ -6994,6 +6998,8 @@ mod tests { prior_issue_calendar_word_2: 4, city_connection_latch: false, linked_transit_latch: true, + linked_transit_route_anchor_entry_id: Some(91), + linked_transit_route_anchor_fallback_counts: vec![2, 4, 6], stat_band_root_0cfb_candidates: Vec::new(), stat_band_root_0d7f_candidates: Vec::new(), stat_band_root_1c47_candidates: Vec::new(), diff --git a/crates/rrt-runtime/src/runtime.rs b/crates/rrt-runtime/src/runtime.rs index 2fce68f..7b269f5 100644 --- a/crates/rrt-runtime/src/runtime.rs +++ b/crates/rrt-runtime/src/runtime.rs @@ -100,6 +100,10 @@ pub struct RuntimeCompanyMarketState { #[serde(default)] pub linked_transit_latch: bool, #[serde(default)] + pub linked_transit_route_anchor_entry_id: Option, + #[serde(default)] + pub linked_transit_route_anchor_fallback_counts: Vec, + #[serde(default)] pub stat_band_root_0cfb_candidates: Vec, #[serde(default)] pub stat_band_root_0d7f_candidates: Vec, diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index 1dd70e5..fb57feb 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -3454,6 +3454,10 @@ pub struct SmpSaveCompanyRecordAnalysisEntry { pub preferred_locomotive_engine_type_raw_hex: String, pub city_connection_latch: bool, pub linked_transit_latch: bool, + #[serde(default)] + pub linked_transit_route_anchor_entry_id: Option, + #[serde(default)] + pub linked_transit_route_anchor_fallback_counts: Vec, pub merger_cooldown_year: u32, pub takeover_cooldown_year: u32, #[serde(default)] @@ -4547,16 +4551,16 @@ fn build_periodic_company_service_trace_report( ]; let near_city_acquisition_company_input_fields = vec![ "company stat-family reader 0x2329/0x0d through 0x0042a5d0".to_string(), - "cached linked-transit route-anchor entry id [company+0x0d35] through 0x00401860" + "save-native linked-transit route-anchor entry id [company+0x0d35] through 0x00401860" .to_string(), - "linked-transit route-anchor fallback counts [company+0x7664/+0x7668/+0x766c] through 0x00401860" + "save-native linked-transit route-anchor fallback counts [company+0x7664/+0x7668/+0x766c] through 0x00401860" .to_string(), "current chairman profile byte [profile+0x291] through 0x00426ef0".to_string(), "company byte [company+0x5b] and indexed lane [company+0x67 + 12*0x0042a0e0()]".to_string(), "company-root argument [company+0x00] passed into 0x0040d540 and 0x00455f60".to_string(), ]; let near_city_acquisition_shellless_readiness_status = - "peer_inputs_grounded_company_route_anchor_and_site_restore_gaps_remaining".to_string(); + "peer_and_company_inputs_grounded_site_restore_gaps_remaining".to_string(); let near_city_acquisition_runtime_backed_input_families = vec![ "peer-site restore subset [site+0x3cc/+0x3d0] plus tagged 0x5dc1 [owner+0x23e/+0x242]" .to_string(), @@ -4565,13 +4569,14 @@ fn build_periodic_company_service_trace_report( "linked-site post-load replay republishing world-cell owner and linked-site chains through 0x0042bbf0/0x0042bbb0 and 0x0042c9f0/0x0042c9a0" .to_string(), "company stat-family lane 0x2329/0x0d already rehosted in runtime company state".to_string(), + "company market state now carries the save-native linked-transit route-anchor tuple [company+0x0d35] and [company+0x7664/+0x7668/+0x766c]" + .to_string(), "chairman personality byte [profile+0x291] already reconstructed from raw save chairman rows" .to_string(), "company-root pointer and linked chairman/company save-native roster identity already imported" .to_string(), ]; let near_city_acquisition_remaining_owner_gaps = vec![ - "runtime-owned company projection for cached linked-transit route-anchor entry id [company+0x0d35] and its fallback count lanes [company+0x7664/+0x7668/+0x766c] consumed through 0x00401860".to_string(), "save-native projection of placed-structure owner field [site+0x276] for the acquisition-side owner-present gate".to_string(), "save payload or restore owner for [site+0x2a4] winning placed-structure id lane before 0x004269b0 commits the chosen site".to_string(), "save payload or restore owner for [site+0x310/+0x338/+0x360] cached tri-lane sampled by 0x0040cac0; current binary scan finds no direct placed-structure runtime writer".to_string(), @@ -4813,7 +4818,7 @@ fn build_periodic_company_service_trace_report( "Direct disassembly now narrows the acquisition-side sibling substantially: 0x004014b0 gates on the periodic outer owner, then scans the live placed-structure collection at 0x0062b26c, rejects sites whose owner field [site+0x276] is already nonzero, filters candidates through the subtype-4 predicate 0x0040d360, scores surviving sites against company linkage/age/proximity through 0x0040d540 and 0x0040cac0, and then commits the winning site through 0x004269b0 before the shared news lane 0x004554e0 formats the headline.".to_string(), ); notes.push( - "The shellless acquisition frontier is narrower now too: the peer-site selector/linked-peer seam is grounded enough to plan around, and the company/chairman side already sits on existing runtime-backed stat-family and save-native roster inputs. The remaining blocker is placed-structure-side restore or rebuild ownership for [site+0x276], [site+0x2a4], and the cached tri-lane [site+0x310/+0x338/+0x360], plus the save-native projection of the subtype gate consumed through 0x0040d360.".to_string(), + "The shellless acquisition frontier is narrower now too: the peer-site selector/linked-peer seam is grounded enough to plan around, and the company/chairman side now includes the save-native route-anchor tuple used by 0x00401860 on top of the existing runtime-backed stat-family and roster inputs. The remaining blocker is placed-structure-side restore or rebuild ownership for [site+0x276], [site+0x2a4], and the cached tri-lane [site+0x310/+0x338/+0x360], plus the save-native projection of the subtype gate consumed through 0x0040d360.".to_string(), ); notes.push( "Direct disassembly now tightens the remaining placed-structure lanes too: 0x0040cac0 is only the raw tri-lane delta reader over [site+0x310/+0x338/+0x360]; 0x0040d360 is only the exact subtype test [candidate+0x32] == 4; and the current binary write scan finds no direct placed-structure runtime writer for either [site+0x2a4] or [site+0x310/+0x338/+0x360], which now makes both lanes look payload/restore-owned rather than service-produced.".to_string(), @@ -6938,6 +6943,15 @@ pub fn inspect_save_company_and_chairman_analysis_bytes( &bytes, record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET, )? != 0; + let linked_transit_route_anchor_entry_id = parse_nonzero_u32( + &bytes, + record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_ENTRY_ID_OFFSET, + )?; + let linked_transit_route_anchor_fallback_counts = + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_FALLBACK_COUNT_OFFSETS + .iter() + .map(|relative_offset| read_u32_at(&bytes, record_offset + *relative_offset)) + .collect::>>()?; let merger_cooldown_year = read_u32_at( &bytes, record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET, @@ -7007,6 +7021,8 @@ pub fn inspect_save_company_and_chairman_analysis_bytes( ), city_connection_latch, linked_transit_latch, + linked_transit_route_anchor_entry_id, + linked_transit_route_anchor_fallback_counts, merger_cooldown_year, takeover_cooldown_year, scalar_dword_candidates, @@ -7830,12 +7846,15 @@ const SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET: usize = 0x289; const SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET: usize = 0x0d2d; const SAVE_COMPANY_RECORD_PREFERRED_LOCOMOTIVE_ENGINE_TYPE_OFFSET: usize = 0x0d17; const SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET: usize = 0x0d18; +const SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_ENTRY_ID_OFFSET: usize = 0x0d35; const SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET: usize = 0x0d07; const SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET: usize = 0x0d59; const SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET: usize = 0x0d56; const SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET: usize = 0x0d19; const SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET: usize = 0x0d7b; const SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET: usize = 0x7680; +const SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_FALLBACK_COUNT_OFFSETS: [usize; 3] = + [0x7664, 0x7668, 0x766c]; const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET: usize = 0x0cfb; const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET: usize = 0x0d7f; const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET: usize = 0x1c47; @@ -8037,6 +8056,15 @@ fn parse_save_company_roster_probe( bytes, record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET, )? != 0; + let linked_transit_route_anchor_entry_id = parse_nonzero_u32( + bytes, + record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_ENTRY_ID_OFFSET, + )?; + let linked_transit_route_anchor_fallback_counts = + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_FALLBACK_COUNT_OFFSETS + .iter() + .map(|relative_offset| read_u32_at(bytes, record_offset + *relative_offset)) + .collect::>>()?; let merger_cooldown_year = parse_nonzero_u32( bytes, record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET, @@ -8143,6 +8171,8 @@ fn parse_save_company_roster_probe( prior_issue_calendar_word_2, city_connection_latch, linked_transit_latch, + linked_transit_route_anchor_entry_id, + linked_transit_route_anchor_fallback_counts, stat_band_root_0cfb_candidates: stat_band_root_0cfb_candidates .iter() .map(runtime_company_stat_band_candidate_from_save) @@ -25987,6 +26017,8 @@ mod tests { preferred_locomotive_engine_type_raw_u8, city_connection_latch, linked_transit_latch, + linked_transit_route_anchor_entry_id, + linked_transit_route_anchor_fallback_counts, ), ) in [ ( @@ -26016,6 +26048,8 @@ mod tests { 2u8, true, false, + Some(77u32), + [3u32, 5u32, 8u32], ), ( "Company Two", @@ -26044,6 +26078,8 @@ mod tests { 1u8, false, true, + Some(41u32), + [13u32, 21u32, 34u32], ), ] .into_iter() @@ -26142,6 +26178,24 @@ mod tests { u8::from(city_connection_latch); bytes[record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET] = u8::from(linked_transit_latch); + if let Some(anchor_entry_id) = linked_transit_route_anchor_entry_id { + bytes[record_offset + + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_ENTRY_ID_OFFSET + ..record_offset + + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_ENTRY_ID_OFFSET + + 4] + .copy_from_slice(&anchor_entry_id.to_le_bytes()); + } + for (fallback_index, relative_offset) in + SAVE_COMPANY_RECORD_LINKED_TRANSIT_ROUTE_ANCHOR_FALLBACK_COUNT_OFFSETS + .into_iter() + .enumerate() + { + bytes[record_offset + relative_offset..record_offset + relative_offset + 4] + .copy_from_slice( + &linked_transit_route_anchor_fallback_counts[fallback_index].to_le_bytes(), + ); + } let current_cash: f64 = if index == 0 { 125_000.0 } else { -25_000.0 }; let current_cash_slot_offset = record_offset + SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET @@ -26236,6 +26290,11 @@ mod tests { assert_eq!(market_state.current_issue_calendar_word_2, 8); assert_eq!(market_state.prior_issue_calendar_word, 6); assert_eq!(market_state.prior_issue_calendar_word_2, 7); + assert_eq!(market_state.linked_transit_route_anchor_entry_id, Some(77)); + assert_eq!( + market_state.linked_transit_route_anchor_fallback_counts, + vec![3, 5, 8] + ); assert_eq!( roster.entries[0].preferred_locomotive_engine_type_raw_u8, Some(2) @@ -26287,6 +26346,14 @@ mod tests { assert_eq!(second_market_state.current_issue_calendar_word_2, 4); assert_eq!(second_market_state.prior_issue_calendar_word, 2); assert_eq!(second_market_state.prior_issue_calendar_word_2, 3); + assert_eq!( + second_market_state.linked_transit_route_anchor_entry_id, + Some(41) + ); + assert_eq!( + second_market_state.linked_transit_route_anchor_fallback_counts, + vec![13, 21, 34] + ); assert_eq!( roster.entries[1].preferred_locomotive_engine_type_raw_u8, Some(1) @@ -27551,15 +27618,13 @@ mod tests { trace.candidate_consumer_hypotheses[3] .evidence .iter() - .any(|line| line.contains("0x00444887") - && line.contains("0x00421510")) + .any(|line| line.contains("0x00444887") && line.contains("0x00421510")) ); assert!( trace.candidate_consumer_hypotheses[3] .evidence .iter() - .any(|line| line.contains("0x00444b90") - && line.contains("0x00420560")) + .any(|line| line.contains("0x00444b90") && line.contains("0x00420560")) ); assert_eq!( trace.candidate_consumer_hypotheses[4].status, @@ -27587,22 +27652,19 @@ mod tests { trace.candidate_consumer_hypotheses[4] .evidence .iter() - .any(|line| line.contains("0x00446d40") - && line.contains("0x004384d0")) + .any(|line| line.contains("0x00446d40") && line.contains("0x004384d0")) ); assert!( trace.candidate_consumer_hypotheses[4] .evidence .iter() - .any(|line| line.contains("0x004133b0") - && line.contains("0x00480710")) + .any(|line| line.contains("0x004133b0") && line.contains("0x00480710")) ); assert!( trace.candidate_consumer_hypotheses[4] .evidence .iter() - .any(|line| line.contains("0x00421c20") - && line.contains("0x004235c0")) + .any(|line| line.contains("0x00421c20") && line.contains("0x004235c0")) ); assert!( trace.candidate_consumer_hypotheses[1] @@ -27743,6 +27805,8 @@ mod tests { preferred_locomotive_engine_type_raw_hex: "0x02".to_string(), city_connection_latch: true, linked_transit_latch: false, + linked_transit_route_anchor_entry_id: Some(77), + linked_transit_route_anchor_fallback_counts: vec![3, 5, 8], merger_cooldown_year: 0, takeover_cooldown_year: 0, scalar_dword_candidates: Vec::new(), @@ -27827,15 +27891,15 @@ mod tests { assert_eq!(trace.near_city_acquisition_company_input_fields.len(), 6); assert_eq!( trace.near_city_acquisition_shellless_readiness_status, - "peer_inputs_grounded_company_route_anchor_and_site_restore_gaps_remaining" + "peer_and_company_inputs_grounded_site_restore_gaps_remaining" ); assert_eq!( trace .near_city_acquisition_runtime_backed_input_families .len(), - 6 + 7 ); - assert_eq!(trace.near_city_acquisition_remaining_owner_gaps.len(), 5); + assert_eq!(trace.near_city_acquisition_remaining_owner_gaps.len(), 4); assert_eq!(trace.near_city_acquisition_region_lane_statuses.len(), 4); assert!(trace.atlas_candidate_consumers.iter().any(|line| { line.contains("0x00420030 / 0x00420280") @@ -27875,8 +27939,14 @@ mod tests { trace .near_city_acquisition_company_input_fields .iter() + .any(|line| line.contains("[company+0x0d35]") && line.contains("0x00401860")) + ); + assert!( + trace + .near_city_acquisition_runtime_backed_input_families + .iter() .any(|line| line.contains("[company+0x0d35]") - && line.contains("0x00401860")) + && line.contains("[company+0x7664/+0x7668/+0x766c]")) ); assert!( trace @@ -27893,13 +27963,6 @@ mod tests { .iter() .any(|line| line.contains("0x2329/0x0d")) ); - assert!( - trace - .near_city_acquisition_remaining_owner_gaps - .iter() - .any(|line| line.contains("[company+0x0d35]") - && line.contains("[company+0x7664/+0x7668/+0x766c]")) - ); assert!( trace .near_city_acquisition_remaining_owner_gaps @@ -27914,11 +27977,14 @@ mod tests { && line.contains("placed-structure runtime writer")) ); assert!( - trace.peer_site_runtime_reconstruction_steps.iter().any(|line| { - line.contains("[cell+0xd4]") - && line.contains("[cell+0xd6]") - && line.contains("0x0042bbf0/0x0042bbb0") - }) + trace + .peer_site_runtime_reconstruction_steps + .iter() + .any(|line| { + line.contains("[cell+0xd4]") + && line.contains("[cell+0xd6]") + && line.contains("0x0042bbf0/0x0042bbb0") + }) ); assert!(trace.next_owner_questions.iter().any(|line| { line.contains("0x004160aa") diff --git a/crates/rrt-runtime/src/summary.rs b/crates/rrt-runtime/src/summary.rs index a85f16c..05e5ed1 100644 --- a/crates/rrt-runtime/src/summary.rs +++ b/crates/rrt-runtime/src/summary.rs @@ -128,6 +128,10 @@ pub struct RuntimeSummary { pub selected_company_periodic_side_latch_preferred_locomotive_engine_type_raw_u8: Option, pub selected_company_periodic_side_latch_city_connection_latch: Option, pub selected_company_periodic_side_latch_linked_transit_latch: Option, + #[serde(default)] + pub selected_company_linked_transit_route_anchor_entry_id: Option, + #[serde(default)] + pub selected_company_linked_transit_route_anchor_fallback_counts: Vec, pub selected_company_periodic_service_base_route_preference_raw_u8: Option, pub selected_company_periodic_service_effective_route_preference_raw_u8: Option, pub selected_company_periodic_service_electric_route_preference_override_active: Option, @@ -660,6 +664,16 @@ impl RuntimeSummary { selected_company_periodic_side_latch_linked_transit_latch: selected_company_periodic_side_latch_state .map(|latch_state| latch_state.linked_transit_latch), + selected_company_linked_transit_route_anchor_entry_id: selected_company_market_state + .and_then(|market_state| market_state.linked_transit_route_anchor_entry_id), + selected_company_linked_transit_route_anchor_fallback_counts: + selected_company_market_state + .map(|market_state| { + market_state + .linked_transit_route_anchor_fallback_counts + .clone() + }) + .unwrap_or_default(), selected_company_periodic_service_base_route_preference_raw_u8: selected_company_periodic_service_state .as_ref() @@ -2983,6 +2997,8 @@ mod tests { prior_issue_calendar_word_2: 5, city_connection_latch: true, linked_transit_latch: false, + linked_transit_route_anchor_entry_id: Some(77), + linked_transit_route_anchor_fallback_counts: vec![3, 5, 8], stat_band_root_0cfb_candidates: vec![ crate::RuntimeCompanyStatBandCandidate { label: "stat_band_0cfb_word_1".to_string(), @@ -3098,6 +3114,14 @@ mod tests { summary.selected_company_periodic_side_latch_linked_transit_latch, Some(false) ); + assert_eq!( + summary.selected_company_linked_transit_route_anchor_entry_id, + Some(77) + ); + assert_eq!( + summary.selected_company_linked_transit_route_anchor_fallback_counts, + vec![3, 5, 8] + ); assert_eq!( summary.selected_company_periodic_service_base_route_preference_raw_u8, Some(2) diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index dcd588b..d92abb4 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -39,6 +39,8 @@ Working rule: - the company-side half of that gate is now explicit too: `0x00401860` validates or rebuilds the cached linked-transit route-anchor entry id `[company+0x0d35]` from the live route-entry collection using fallback count lanes `[company+0x7664/+0x7668/+0x766c]` + - those four company lanes are now threaded into save-native company market state, so the + route-anchor side of the acquisition gate is no longer just a trace-only blocker - `0x0040d360` is the subtype-`4` predicate over the current placed-structure subject's candidate byte `[candidate+0x32]` - `0x0040d540` scores site/company proximity with pending-bonus context @@ -72,9 +74,7 @@ Working rule: - the winning site id is staged in `[site+0x2a4]` before `0x004269b0` commits the acquisition - That leaves the acquisition blocker set tighter than before: - peer-site and linked-site replay seams are grounded enough for planning - - remaining non-hook gaps are the company cached route-anchor lane - `[company+0x0d35]` plus fallback counts `[company+0x7664/+0x7668/+0x766c]`, and the - placed-structure save/rebuild lanes `[site+0x276]`, `[site+0x2a4]`, + - remaining non-hook gaps are the placed-structure save/rebuild lanes `[site+0x276]`, `[site+0x2a4]`, `[site+0x310/+0x338/+0x360]`, and subtype byte `[candidate+0x32] == 4` - direct disassembly now shows the generic base constructor `0x0052edf0` clearing base state through `0x0052ecd0` and then writing `[this+0x04]` from caller arg `1`