Rehost world time state from calendar stepping
This commit is contained in:
parent
ef2c317b6b
commit
4623a05156
3 changed files with 182 additions and 1 deletions
|
|
@ -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(
|
pub fn runtime_pack_packed_calendar_tuple_to_absolute_counter(
|
||||||
tuple: RuntimePackedCalendarTuple,
|
tuple: RuntimePackedCalendarTuple,
|
||||||
) -> Option<u32> {
|
) -> 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]
|
#[test]
|
||||||
fn derives_company_unassigned_share_pool_from_market_state_and_holdings() {
|
fn derives_company_unassigned_share_pool_from_market_state_and_holdings() {
|
||||||
let state = RuntimeState {
|
let state = RuntimeState {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use crate::runtime::{
|
||||||
runtime_round_f64_to_i64,
|
runtime_round_f64_to_i64,
|
||||||
};
|
};
|
||||||
use crate::{
|
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,
|
RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN, RuntimeCargoClass, RuntimeCargoPriceTarget,
|
||||||
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanTarget,
|
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanTarget,
|
||||||
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
|
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
|
||||||
|
|
@ -191,6 +191,7 @@ fn step_once(
|
||||||
boundary_events: &mut Vec<BoundaryEvent>,
|
boundary_events: &mut Vec<BoundaryEvent>,
|
||||||
service_events: &mut Vec<ServiceEvent>,
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let prior_calendar = state.calendar;
|
||||||
let boundary = state.calendar.step_forward();
|
let boundary = state.calendar.step_forward();
|
||||||
if boundary != BoundaryEventKind::Tick {
|
if boundary != BoundaryEventKind::Tick {
|
||||||
boundary_events.push(BoundaryEvent {
|
boundary_events.push(BoundaryEvent {
|
||||||
|
|
@ -199,8 +200,10 @@ fn step_once(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if boundary == BoundaryEventKind::YearRollover {
|
if boundary == BoundaryEventKind::YearRollover {
|
||||||
|
service_sync_world_restore_time_from_calendar(state, prior_calendar);
|
||||||
service_periodic_boundary(state, service_events)?;
|
service_periodic_boundary(state, service_events)?;
|
||||||
}
|
}
|
||||||
|
service_sync_world_restore_time_from_calendar(state, state.calendar);
|
||||||
Ok(())
|
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(
|
fn service_periodic_boundary(
|
||||||
state: &mut RuntimeState,
|
state: &mut RuntimeState,
|
||||||
service_events: &mut Vec<ServiceEvent>,
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
|
|
@ -2922,6 +2950,24 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(result.steps_executed, 5);
|
assert_eq!(result.steps_executed, 5);
|
||||||
assert_eq!(state.calendar.tick_slot, 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]
|
#[test]
|
||||||
|
|
@ -2974,6 +3020,24 @@ mod tests {
|
||||||
.get("world.periodic_rollover_service_fired"),
|
.get("world.periodic_rollover_service_fired"),
|
||||||
Some(&true)
|
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!(
|
assert!(
|
||||||
result
|
result
|
||||||
.service_events
|
.service_events
|
||||||
|
|
|
||||||
51
docs/rehost-queue.md
Normal file
51
docs/rehost-queue.md
Normal 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.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue