Rehost world time state from calendar stepping

This commit is contained in:
Jan Petykiewicz 2026-04-18 06:27:00 -07:00
commit 4623a05156
3 changed files with 182 additions and 1 deletions

View file

@ -4133,6 +4133,45 @@ pub fn runtime_decode_packed_calendar_tuple(
}
}
pub fn runtime_encode_packed_calendar_tuple(tuple: RuntimePackedCalendarTuple) -> (u32, u32) {
let year_bytes = tuple.year_word.to_le_bytes();
let word_0 = u32::from_le_bytes([
year_bytes[0],
year_bytes[1],
tuple.month_1_based,
tuple.week_1_based,
]);
let word_1 = u32::from_le_bytes([
tuple.day_1_based,
tuple.hour_0_based,
tuple.quarter_day_1_based,
tuple.minute_0_based,
]);
(word_0, word_1)
}
pub fn runtime_derive_packed_calendar_tuple_from_calendar_point(
calendar: CalendarPoint,
) -> Option<RuntimePackedCalendarTuple> {
let year_word = u16::try_from(calendar.year).ok()?;
let month_1_based = u8::try_from(calendar.month_slot.checked_add(1)?).ok()?;
let day_1_based = u8::try_from(calendar.phase_slot.checked_add(1)?).ok()?;
let week_1_based = u8::try_from(calendar.phase_slot / 7 + 1).ok()?;
let total_minutes = calendar.tick_slot.checked_mul(1440)? / crate::TICKS_PER_PHASE;
let hour_0_based = u8::try_from(total_minutes / 60).ok()?;
let minute_0_based = u8::try_from(total_minutes % 60).ok()?;
let quarter_day_1_based = u8::try_from((u32::from(hour_0_based) / 6) + 1).ok()?;
Some(RuntimePackedCalendarTuple {
year_word,
month_1_based,
week_1_based,
day_1_based,
hour_0_based,
quarter_day_1_based,
minute_0_based,
})
}
pub fn runtime_pack_packed_calendar_tuple_to_absolute_counter(
tuple: RuntimePackedCalendarTuple,
) -> Option<u32> {
@ -7888,6 +7927,33 @@ mod tests {
);
}
#[test]
fn derives_and_encodes_packed_calendar_tuple_from_runtime_calendar() {
let tuple = runtime_derive_packed_calendar_tuple_from_calendar_point(CalendarPoint {
year: 1830,
month_slot: 11,
phase_slot: 27,
tick_slot: 179,
})
.expect("runtime calendar tuple");
assert_eq!(
tuple,
RuntimePackedCalendarTuple {
year_word: 1830,
month_1_based: 12,
week_1_based: 4,
day_1_based: 28,
hour_0_based: 23,
quarter_day_1_based: 4,
minute_0_based: 52,
}
);
assert_eq!(
runtime_encode_packed_calendar_tuple(tuple),
(0x040c_0726, 0x3404_171c)
);
}
#[test]
fn derives_company_unassigned_share_pool_from_market_state_and_holdings() {
let state = RuntimeState {

View file

@ -9,7 +9,7 @@ use crate::runtime::{
runtime_round_f64_to_i64,
};
use crate::{
RUNTIME_COMPANY_STAT_SLOT_COUNT, RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
CalendarPoint, RUNTIME_COMPANY_STAT_SLOT_COUNT, RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN, RuntimeCargoClass, RuntimeCargoPriceTarget,
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanTarget,
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
@ -191,6 +191,7 @@ fn step_once(
boundary_events: &mut Vec<BoundaryEvent>,
service_events: &mut Vec<ServiceEvent>,
) -> Result<(), String> {
let prior_calendar = state.calendar;
let boundary = state.calendar.step_forward();
if boundary != BoundaryEventKind::Tick {
boundary_events.push(BoundaryEvent {
@ -199,8 +200,10 @@ fn step_once(
});
}
if boundary == BoundaryEventKind::YearRollover {
service_sync_world_restore_time_from_calendar(state, prior_calendar);
service_periodic_boundary(state, service_events)?;
}
service_sync_world_restore_time_from_calendar(state, state.calendar);
Ok(())
}
@ -213,6 +216,31 @@ fn boundary_kind_label(boundary: BoundaryEventKind) -> &'static str {
}
}
fn service_sync_world_restore_time_from_calendar(
state: &mut RuntimeState,
calendar: CalendarPoint,
) {
if let Ok(year_word) = u16::try_from(calendar.year) {
state.world_restore.packed_year_word_raw_u16 = Some(year_word);
}
if let Ok(partial_year_progress) = u8::try_from(calendar.month_slot.saturating_add(1)) {
state.world_restore.partial_year_progress_raw_u8 = Some(partial_year_progress);
}
if let Some(tuple) =
crate::runtime::runtime_derive_packed_calendar_tuple_from_calendar_point(calendar)
{
let (word_0, word_1) = crate::runtime::runtime_encode_packed_calendar_tuple(tuple);
state.world_restore.current_calendar_tuple_word_raw_u32 = Some(word_0);
state.world_restore.current_calendar_tuple_word_2_raw_u32 = Some(word_1);
if let Some(absolute_counter) =
crate::runtime::runtime_pack_packed_calendar_tuple_to_absolute_counter(tuple)
{
state.world_restore.absolute_counter_raw_u32 = Some(absolute_counter);
state.world_restore.absolute_counter_mirror_raw_u32 = Some(absolute_counter);
}
}
}
fn service_periodic_boundary(
state: &mut RuntimeState,
service_events: &mut Vec<ServiceEvent>,
@ -2922,6 +2950,24 @@ mod tests {
assert_eq!(result.steps_executed, 5);
assert_eq!(state.calendar.tick_slot, 5);
assert_eq!(state.world_restore.packed_year_word_raw_u16, Some(1830));
assert_eq!(state.world_restore.partial_year_progress_raw_u8, Some(1));
assert_eq!(
state.world_restore.current_calendar_tuple_word_raw_u32,
Some(0x0101_0726)
);
assert_eq!(
state.world_restore.current_calendar_tuple_word_2_raw_u32,
Some(0x2801_0001)
);
assert_eq!(
state.world_restore.absolute_counter_raw_u32,
Some(885_427_240)
);
assert_eq!(
state.world_restore.absolute_counter_mirror_raw_u32,
Some(885_427_240)
);
}
#[test]
@ -2974,6 +3020,24 @@ mod tests {
.get("world.periodic_rollover_service_fired"),
Some(&true)
);
assert_eq!(state.world_restore.packed_year_word_raw_u16, Some(1831));
assert_eq!(state.world_restore.partial_year_progress_raw_u8, Some(1));
assert_eq!(
state.world_restore.current_calendar_tuple_word_raw_u32,
Some(0x0101_0727)
);
assert_eq!(
state.world_restore.current_calendar_tuple_word_2_raw_u32,
Some(0x0001_0001)
);
assert_eq!(
state.world_restore.absolute_counter_raw_u32,
Some(885_911_040)
);
assert_eq!(
state.world_restore.absolute_counter_mirror_raw_u32,
Some(885_911_040)
);
assert!(
result
.service_events

51
docs/rehost-queue.md Normal file
View file

@ -0,0 +1,51 @@
# Rehost Queue
Working rule:
- Do not stop after commits.
- After each commit, check this queue and continue.
- Only stop if the queue is empty, you hit a real blocker, or you need approval.
- Before any final response, state which stop condition is true. If none is true, continue.
## Next
- Rehost world time owner-state progression from `CalendarPoint` into `world_restore`:
sync `packed_year_word_raw_u16`, `partial_year_progress_raw_u8`, packed calendar tuple words,
and absolute counter so shellless stepping advances the same finance/economy reader inputs used
by periodic service.
- Make automatic year-rollover periodic service run against a consistent end-of-year world-time
snapshot, then refresh into the new-year snapshot after service commits.
- Rehost the next shellless periodic-boundary world work under
`simulation_service_periodic_boundary_work`, starting with any bounded non-dialog queue/state
family that can execute without shell ownership.
## In Progress
- Widen shellless simulation from explicit service commands toward “advance the runtime clock and
the simulation-owned services advance with it.”
## Queued
- Rehost additional periodic finance/service branches that still depend on frozen world restore
fields instead of advanced runtime-owned time state.
- Reduce remaining company/chairman save-native gaps that still block standalone simulation
quality, especially controller-kind closure and any deeper finance/state fields that still rely
on conservative defaults.
- Rehost bounded live economy owner state beyond selector/catalog/override surfaces when a
concrete non-shell-owned seam is grounded.
- Keep tightening shell-owned parity families only when that directly supports later rehosting.
## Blocked
- Full shell/dialog ownership remains intentionally out of scope.
- Any candidate slice that requires guessing rather than rehosting owning state or real
reader/setter families stays blocked until a better owner seam is grounded.
## Recently Done
- Automatic year-rollover calendar stepping now invokes periodic-boundary service.
- Company cash, confiscation, and major governance effects now write through owner state instead of
drifting from market/cache readers.
- Company credit rating, prime rate, book value per share, investor confidence, and management
attitude now refresh from grounded owner-state readers.
- Annual finance service persists structured news events and grounded debt/share flow totals.