diff --git a/README.md b/README.md index cc992d2..6c2a73e 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,9 @@ market reader now exposes outstanding shares, assigned shares, public float, rou price, salary lanes, bonus amount, and issue-calendar words from the owned annual-finance state instead of leaving that logic spread across summary helpers. The same annual-finance state now also derives elapsed years since founding, last dividend, and last bankruptcy from the runtime calendar, -which lines up directly with the grounded annual finance-policy gates in the atlas. A checked-in +which lines up directly with the grounded annual finance-policy gates in the atlas. Live bond-slot +count is now carried through the same owned company market and annual-finance state too, which +matches the stock-capital branch gate that requires at least two live bonds. A checked-in The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we should prefer rehosting the owning source state or the real reader/setter family rather than guessing one more derived leaf field from nearby offsets. A checked-in diff --git a/crates/rrt-fixtures/src/schema.rs b/crates/rrt-fixtures/src/schema.rs index 32997f8..fc52439 100644 --- a/crates/rrt-fixtures/src/schema.rs +++ b/crates/rrt-fixtures/src/schema.rs @@ -92,6 +92,8 @@ pub struct ExpectedRuntimeSummary { #[serde(default)] pub selected_company_outstanding_shares: Option, #[serde(default)] + pub selected_company_bond_count: Option, + #[serde(default)] pub selected_company_assigned_share_pool: Option, #[serde(default)] pub selected_company_unassigned_share_pool: Option, @@ -609,6 +611,14 @@ impl ExpectedRuntimeSummary { )); } } + if let Some(value) = self.selected_company_bond_count { + if actual.selected_company_bond_count != Some(value) { + mismatches.push(format!( + "selected_company_bond_count mismatch: expected {value}, got {:?}", + actual.selected_company_bond_count + )); + } + } if let Some(value) = self.selected_company_assigned_share_pool { if actual.selected_company_assigned_share_pool != Some(value) { mismatches.push(format!( diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index 8cf50d9..a3a3994 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -5041,6 +5041,7 @@ mod tests { merger_cooldown_year: Some(1838), market_state: Some(crate::RuntimeCompanyMarketState { outstanding_shares: 20_000, + bond_count: 2, mutable_support_scalar_raw_u32: 0x3f99999a, young_company_support_scalar_raw_u32: 0x42700000, support_progress_word: 12, @@ -5087,6 +5088,7 @@ mod tests { merger_cooldown_year: None, market_state: Some(crate::RuntimeCompanyMarketState { outstanding_shares: 18_000, + bond_count: 1, mutable_support_scalar_raw_u32: 0x3f4ccccd, young_company_support_scalar_raw_u32: 0x42580000, support_progress_word: 9, @@ -6376,6 +6378,7 @@ mod tests { 42, crate::RuntimeCompanyMarketState { outstanding_shares: 30_000, + bond_count: 3, mutable_support_scalar_raw_u32: 0x3f19999a, young_company_support_scalar_raw_u32: 0x42580000, support_progress_word: 8, diff --git a/crates/rrt-runtime/src/runtime.rs b/crates/rrt-runtime/src/runtime.rs index 93e155e..02249f2 100644 --- a/crates/rrt-runtime/src/runtime.rs +++ b/crates/rrt-runtime/src/runtime.rs @@ -53,6 +53,8 @@ pub struct RuntimeCompanyMarketState { #[serde(default)] pub outstanding_shares: u32, #[serde(default)] + pub bond_count: u8, + #[serde(default)] pub mutable_support_scalar_raw_u32: u32, #[serde(default)] pub young_company_support_scalar_raw_u32: u32, @@ -96,6 +98,7 @@ pub struct RuntimeCompanyMarketState { pub struct RuntimeCompanyAnnualFinanceState { pub company_id: u32, pub outstanding_shares: u32, + pub bond_count: u8, pub assigned_share_pool: u32, pub unassigned_share_pool: u32, #[serde(default)] @@ -352,6 +355,7 @@ pub enum RuntimeCompanyMetric { #[serde(rename_all = "snake_case")] pub enum RuntimeCompanyMarketMetric { OutstandingShares, + BondCount, AssignedSharePool, UnassignedSharePool, CachedSharePrice, @@ -1923,6 +1927,7 @@ pub fn runtime_company_annual_finance_state( Some(RuntimeCompanyAnnualFinanceState { company_id, outstanding_shares: market_state.outstanding_shares, + bond_count: market_state.bond_count, assigned_share_pool, unassigned_share_pool, cached_share_price: rounded_cached_share_price_i64(market_state.cached_share_price_raw_u32), @@ -1953,6 +1958,7 @@ pub fn runtime_company_market_value( RuntimeCompanyMarketMetric::OutstandingShares => { Some(annual_finance_state.outstanding_shares as i64) } + RuntimeCompanyMarketMetric::BondCount => Some(annual_finance_state.bond_count as i64), RuntimeCompanyMarketMetric::AssignedSharePool => { Some(annual_finance_state.assigned_share_pool as i64) } @@ -4222,6 +4228,7 @@ mod tests { 4, RuntimeCompanyMarketState { outstanding_shares: 20_000, + bond_count: 3, cached_share_price_raw_u32: 0x42200000, chairman_salary_baseline: 24, chairman_salary_current: 30, @@ -4247,6 +4254,7 @@ mod tests { Some(RuntimeCompanyAnnualFinanceState { company_id: 4, outstanding_shares: 20_000, + bond_count: 3, assigned_share_pool: 15_500, unassigned_share_pool: 4_500, cached_share_price: Some(40), @@ -4344,6 +4352,7 @@ mod tests { 7, RuntimeCompanyMarketState { outstanding_shares: 20_000, + bond_count: 2, cached_share_price_raw_u32: 0x42200000, chairman_salary_baseline: 18, chairman_salary_current: 27, @@ -4365,6 +4374,10 @@ mod tests { runtime_company_market_value(&state, 7, RuntimeCompanyMarketMetric::OutstandingShares), Some(20_000) ); + assert_eq!( + runtime_company_market_value(&state, 7, RuntimeCompanyMarketMetric::BondCount), + Some(2) + ); assert_eq!( runtime_company_market_value(&state, 7, RuntimeCompanyMarketMetric::AssignedSharePool), Some(12_000) diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index 867d458..98da2b9 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -3581,6 +3581,7 @@ fn parse_save_company_roster_probe( record_offset + SAVE_COMPANY_RECORD_OUTSTANDING_SHARES_OFFSET, )?; let debt = parse_save_company_total_debt(bytes, record_offset)?; + let bond_count = read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)?; let available_track_laying_capacity = parse_save_company_available_track_laying_capacity(bytes, record_offset)?; let mutable_support_scalar_raw_u32 = read_u32_at( @@ -3694,6 +3695,7 @@ fn parse_save_company_roster_probe( merger_cooldown_year, market_state: Some(RuntimeCompanyMarketState { outstanding_shares, + bond_count, mutable_support_scalar_raw_u32, young_company_support_scalar_raw_u32, support_progress_word, diff --git a/crates/rrt-runtime/src/summary.rs b/crates/rrt-runtime/src/summary.rs index 8242ec5..3d282e1 100644 --- a/crates/rrt-runtime/src/summary.rs +++ b/crates/rrt-runtime/src/summary.rs @@ -50,6 +50,7 @@ pub struct RuntimeSummary { pub active_company_count: usize, pub company_market_state_owner_count: usize, pub selected_company_outstanding_shares: Option, + pub selected_company_bond_count: Option, pub selected_company_assigned_share_pool: Option, pub selected_company_unassigned_share_pool: Option, pub selected_company_cached_share_price: Option, @@ -258,6 +259,8 @@ impl RuntimeSummary { company_market_state_owner_count: state.service_state.company_market_state.len(), selected_company_outstanding_shares: selected_company_market_state .map(|market_state| market_state.outstanding_shares), + selected_company_bond_count: selected_company_market_state + .map(|market_state| market_state.bond_count), selected_company_assigned_share_pool: selected_company_annual_finance_state .as_ref() .map(|finance_state| finance_state.assigned_share_pool), @@ -1956,6 +1959,7 @@ mod tests { 1, crate::RuntimeCompanyMarketState { outstanding_shares: 20_000, + bond_count: 2, mutable_support_scalar_raw_u32: 0x3f800000, young_company_support_scalar_raw_u32: 0x42340000, support_progress_word: 12, @@ -2023,6 +2027,7 @@ mod tests { let summary = RuntimeSummary::from_state(&state); assert_eq!(summary.company_market_state_owner_count, 1); assert_eq!(summary.selected_company_outstanding_shares, Some(20_000)); + assert_eq!(summary.selected_company_bond_count, Some(2)); assert_eq!(summary.selected_company_assigned_share_pool, Some(5_000)); assert_eq!(summary.selected_company_unassigned_share_pool, Some(15_000)); assert_eq!(summary.selected_company_cached_share_price, Some(40)); diff --git a/docs/README.md b/docs/README.md index 2e9e61f..e0aeb73 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,7 +126,8 @@ The highest-value next passes are now: closure can target a broader owned restore-state window; the same annual-finance state now also feeds a shared company market reader for stock-capital, salary, bonus, and issue-calendar values, and now derives elapsed years since founding, last dividend, and last bankruptcy for later annual - finance-policy rehosting + finance-policy rehosting; live bond-slot count now travels through that same owned annual-finance + state for the stock-capital branch gate - the project rule on the remaining closure work is now explicit too: when one runtime-facing field is still ambiguous, prefer rehosting the owning source state or real reader/setter family first instead of guessing another derived leaf field from neighboring raw offsets diff --git a/docs/runtime-rehost-plan.md b/docs/runtime-rehost-plan.md index b59fb9c..0e550fa 100644 --- a/docs/runtime-rehost-plan.md +++ b/docs/runtime-rehost-plan.md @@ -216,7 +216,9 @@ now also drives a shared company market reader seam for stock-capital, salary, b issue-calendar values, which is a better base for shellless finance simulation than summary-only helpers. That same owned annual-finance state now also derives elapsed years since founding, last dividend, and last bankruptcy from the runtime calendar, which lines up directly with the grounded -annual finance-policy gates in the atlas. +annual finance-policy gates in the atlas. Live bond-slot count now also flows through that same +owned company market and annual-finance state, matching the stock-capital branch gate that needs +at least two live bonds. ## Why This Boundary