Run periodic boundary service on year rollover
This commit is contained in:
parent
6572e3b852
commit
ef2c317b6b
4 changed files with 97 additions and 8 deletions
|
|
@ -117,6 +117,9 @@ dividend, company stat-post, outstanding-share, issue-calendar, and live bond-sl
|
||||||
of stopping at reader-only diagnostics. That same service state now also persists the last emitted
|
of stopping at reader-only diagnostics. That same service state now also persists the last emitted
|
||||||
annual-finance news events as structured runtime records carrying company id, exact selector label,
|
annual-finance news events as structured runtime records carrying company id, exact selector label,
|
||||||
action label, and the grounded debt/share payload totals used by the shell news layer.
|
action label, and the grounded debt/share payload totals used by the shell news layer.
|
||||||
|
Calendar stepping now also starts to use that same seam directly: `StepCount` and `AdvanceTo`
|
||||||
|
invoke the periodic-boundary service automatically on year rollover, so shellless calendar advance
|
||||||
|
can drive the annual finance stack instead of requiring a separate manual service command.
|
||||||
Those bankruptcy branches now follow the grounded owner semantics too: they stamp the bankruptcy
|
Those bankruptcy branches now follow the grounded owner semantics too: they stamp the bankruptcy
|
||||||
year and halve live bond principals in place instead of treating bankruptcy as a liquidation path.
|
year and halve live bond principals in place instead of treating bankruptcy as a liquidation path.
|
||||||
The same save-native live bond-slot surface now also carries per-slot maturity years all the way
|
The same save-native live bond-slot surface now also carries per-slot maturity years all the way
|
||||||
|
|
|
||||||
|
|
@ -122,10 +122,15 @@ pub fn execute_step_command(
|
||||||
let mut boundary_events = Vec::new();
|
let mut boundary_events = Vec::new();
|
||||||
let mut service_events = Vec::new();
|
let mut service_events = Vec::new();
|
||||||
let steps_executed = match command {
|
let steps_executed = match command {
|
||||||
StepCommand::AdvanceTo { calendar } => {
|
StepCommand::AdvanceTo { calendar } => advance_to_target_calendar_point(
|
||||||
advance_to_target_calendar_point(state, *calendar, &mut boundary_events)?
|
state,
|
||||||
|
*calendar,
|
||||||
|
&mut boundary_events,
|
||||||
|
&mut service_events,
|
||||||
|
)?,
|
||||||
|
StepCommand::StepCount { steps } => {
|
||||||
|
step_count(state, *steps, &mut boundary_events, &mut service_events)?
|
||||||
}
|
}
|
||||||
StepCommand::StepCount { steps } => step_count(state, *steps, &mut boundary_events),
|
|
||||||
StepCommand::ServiceTriggerKind { trigger_kind } => {
|
StepCommand::ServiceTriggerKind { trigger_kind } => {
|
||||||
service_trigger_kind(state, *trigger_kind, &mut service_events)?;
|
service_trigger_kind(state, *trigger_kind, &mut service_events)?;
|
||||||
0
|
0
|
||||||
|
|
@ -151,6 +156,7 @@ fn advance_to_target_calendar_point(
|
||||||
state: &mut RuntimeState,
|
state: &mut RuntimeState,
|
||||||
target: crate::CalendarPoint,
|
target: crate::CalendarPoint,
|
||||||
boundary_events: &mut Vec<BoundaryEvent>,
|
boundary_events: &mut Vec<BoundaryEvent>,
|
||||||
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
) -> Result<u64, String> {
|
) -> Result<u64, String> {
|
||||||
target.validate()?;
|
target.validate()?;
|
||||||
if target < state.calendar {
|
if target < state.calendar {
|
||||||
|
|
@ -162,7 +168,7 @@ fn advance_to_target_calendar_point(
|
||||||
|
|
||||||
let mut steps = 0_u64;
|
let mut steps = 0_u64;
|
||||||
while state.calendar < target {
|
while state.calendar < target {
|
||||||
step_once(state, boundary_events);
|
step_once(state, boundary_events, service_events)?;
|
||||||
steps += 1;
|
steps += 1;
|
||||||
}
|
}
|
||||||
Ok(steps)
|
Ok(steps)
|
||||||
|
|
@ -172,14 +178,19 @@ fn step_count(
|
||||||
state: &mut RuntimeState,
|
state: &mut RuntimeState,
|
||||||
steps: u32,
|
steps: u32,
|
||||||
boundary_events: &mut Vec<BoundaryEvent>,
|
boundary_events: &mut Vec<BoundaryEvent>,
|
||||||
) -> u64 {
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
|
) -> Result<u64, String> {
|
||||||
for _ in 0..steps {
|
for _ in 0..steps {
|
||||||
step_once(state, boundary_events);
|
step_once(state, boundary_events, service_events)?;
|
||||||
}
|
}
|
||||||
steps.into()
|
Ok(steps.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_once(state: &mut RuntimeState, boundary_events: &mut Vec<BoundaryEvent>) {
|
fn step_once(
|
||||||
|
state: &mut RuntimeState,
|
||||||
|
boundary_events: &mut Vec<BoundaryEvent>,
|
||||||
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
|
) -> Result<(), String> {
|
||||||
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 {
|
||||||
|
|
@ -187,6 +198,10 @@ fn step_once(state: &mut RuntimeState, boundary_events: &mut Vec<BoundaryEvent>)
|
||||||
calendar: state.calendar,
|
calendar: state.calendar,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if boundary == BoundaryEventKind::YearRollover {
|
||||||
|
service_periodic_boundary(state, service_events)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn boundary_kind_label(boundary: BoundaryEventKind) -> &'static str {
|
fn boundary_kind_label(boundary: BoundaryEventKind) -> &'static str {
|
||||||
|
|
@ -2909,6 +2924,70 @@ mod tests {
|
||||||
assert_eq!(state.calendar.tick_slot, 5);
|
assert_eq!(state.calendar.tick_slot, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn year_rollover_step_runs_periodic_boundary_services() {
|
||||||
|
let mut state = RuntimeState {
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1830,
|
||||||
|
month_slot: crate::MONTH_SLOTS_PER_YEAR - 1,
|
||||||
|
phase_slot: crate::PHASE_SLOTS_PER_MONTH - 1,
|
||||||
|
tick_slot: crate::TICKS_PER_PHASE - 1,
|
||||||
|
},
|
||||||
|
event_runtime_records: vec![RuntimeEventRecord {
|
||||||
|
record_id: 77,
|
||||||
|
trigger_kind: 1,
|
||||||
|
active: true,
|
||||||
|
service_count: 0,
|
||||||
|
marks_collection_dirty: false,
|
||||||
|
one_shot: false,
|
||||||
|
has_fired: false,
|
||||||
|
conditions: Vec::new(),
|
||||||
|
effects: vec![RuntimeEffect::SetWorldFlag {
|
||||||
|
key: "world.periodic_rollover_service_fired".to_string(),
|
||||||
|
value: true,
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
..state()
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_step_command(&mut state, &StepCommand::StepCount { steps: 1 })
|
||||||
|
.expect("year rollover step should run periodic boundary services");
|
||||||
|
|
||||||
|
assert_eq!(result.steps_executed, 1);
|
||||||
|
assert_eq!(
|
||||||
|
result.boundary_events,
|
||||||
|
vec![BoundaryEvent {
|
||||||
|
kind: "year_rollover".to_string(),
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1831,
|
||||||
|
month_slot: 0,
|
||||||
|
phase_slot: 0,
|
||||||
|
tick_slot: 0,
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
assert_eq!(state.service_state.periodic_boundary_calls, 1);
|
||||||
|
assert_eq!(state.service_state.total_event_record_services, 1);
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.world_flags
|
||||||
|
.get("world.periodic_rollover_service_fired"),
|
||||||
|
Some(&true)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result
|
||||||
|
.service_events
|
||||||
|
.iter()
|
||||||
|
.any(|event| event.trigger_kind == Some(1))
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result
|
||||||
|
.service_events
|
||||||
|
.iter()
|
||||||
|
.any(|event| event.kind == "annual_finance_policy")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rejects_backward_target() {
|
fn rejects_backward_target() {
|
||||||
let mut state = state();
|
let mut state = state();
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,9 @@ The highest-value next passes are now:
|
||||||
onto the exact debt headline selectors `2882..2886`
|
onto the exact debt headline selectors `2882..2886`
|
||||||
while persisting the last emitted annual-finance news events as structured runtime-owned records
|
while persisting the last emitted annual-finance news events as structured runtime-owned records
|
||||||
carrying company id, selector label, action label, and the grounded debt/share payload totals
|
carrying company id, selector label, action label, and the grounded debt/share payload totals
|
||||||
|
- shellless calendar advance now also drives that annual seam directly: `StepCount` and `AdvanceTo`
|
||||||
|
invoke periodic-boundary service automatically on year rollover instead of requiring a second
|
||||||
|
manual service pass to make the annual finance stack run
|
||||||
- the project rule on the remaining closure work is now explicit too: when one runtime-facing field
|
- 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
|
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
|
instead of guessing another derived leaf field from neighboring raw offsets
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,10 @@ the runtime selects one annual-finance action per active company and already com
|
||||||
creditor-pressure-bankruptcy, deep-distress-bankruptcy, dividend-adjustment, stock-repurchase,
|
creditor-pressure-bankruptcy, deep-distress-bankruptcy, dividend-adjustment, stock-repurchase,
|
||||||
stock-issue, and bond-issue branches directly into owned dividend, company stat-post,
|
stock-issue, and bond-issue branches directly into owned dividend, company stat-post,
|
||||||
outstanding-share, issue-calendar, live bond-slot, and company activity state.
|
outstanding-share, issue-calendar, live bond-slot, and company activity state.
|
||||||
|
Shellless calendar advance now also starts to consume that service seam directly: `StepCount` and
|
||||||
|
`AdvanceTo` invoke periodic-boundary service automatically on year rollover, so annual finance
|
||||||
|
state can advance as the runtime clock advances instead of only through an explicit manual service
|
||||||
|
command.
|
||||||
The bankruptcy branches now follow the grounded owner semantics too: they stamp the bankruptcy
|
The bankruptcy branches now follow the grounded owner semantics too: they stamp the bankruptcy
|
||||||
year and halve live bond principals in place instead of collapsing into a liquidation-only path.
|
year and halve live bond principals in place instead of collapsing into a liquidation-only path.
|
||||||
The same owned live bond-slot surface now also carries maturity years through save import,
|
The same owned live bond-slot surface now also carries maturity years through save import,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue