Implement governance issue packed event conditions

This commit is contained in:
Jan Petykiewicz 2026-04-16 17:30:42 -07:00
commit 5c2156bcbf
10 changed files with 1048 additions and 13 deletions

View file

@ -4523,6 +4523,18 @@ mod tests {
.join(
"../../fixtures/runtime/packed-event-company-governance-condition-save-slice-fixture.json",
);
let investor_confidence_condition_save_fixture = PathBuf::from(env!(
"CARGO_MANIFEST_DIR"
))
.join(
"../../fixtures/runtime/packed-event-investor-confidence-condition-save-slice-fixture.json",
);
let management_attitude_condition_save_fixture = PathBuf::from(env!(
"CARGO_MANIFEST_DIR"
))
.join(
"../../fixtures/runtime/packed-event-management-attitude-condition-save-slice-fixture.json",
);
run_runtime_summarize_fixture(&parity_fixture)
.expect("save-slice-backed parity fixture should summarize");
@ -4590,6 +4602,10 @@ mod tests {
.expect("overlay-backed company governance condition fixture should summarize");
run_runtime_summarize_fixture(&company_governance_condition_save_fixture)
.expect("save-slice-backed company governance condition fixture should summarize");
run_runtime_summarize_fixture(&investor_confidence_condition_save_fixture)
.expect("save-slice-backed investor-confidence condition fixture should summarize");
run_runtime_summarize_fixture(&management_attitude_condition_save_fixture)
.expect("save-slice-backed management-attitude condition fixture should summarize");
}
#[test]

View file

@ -9661,6 +9661,262 @@ mod tests {
);
}
#[test]
fn imports_investor_confidence_condition_from_save_slice_company_context() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: Some(save_company_roster()),
chairman_profile_table: Some(save_chairman_profile_table()),
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
metadata_tag_offset: 0x7100,
records_tag_offset: 0x7200,
close_tag_offset: 0x7600,
packed_state_version: 0x3e9,
packed_state_version_hex: "0x000003e9".to_string(),
live_id_bound: 73,
live_record_count: 1,
live_entry_ids: vec![73],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 73,
payload_offset: Some(0x7202),
payload_len: Some(136),
decode_status: "parity_only".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: Some(7),
active: None,
marks_collection_dirty: None,
one_shot: Some(false),
compact_control: Some(real_compact_control()),
text_bands: vec![],
standalone_condition_row_count: 1,
standalone_condition_rows: vec![
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: 2366,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&37_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Investor Confidence".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Investor Confidence == 37".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
},
],
negative_sentinel_scope: Some(company_negative_sentinel_scope(
RuntimeCompanyConditionTestScope::SelectedCompanyOnly,
)),
grouped_effect_row_counts: vec![1, 0, 0, 0],
grouped_effect_rows: vec![real_world_flag_row(
110,
"Disable Stock Buying and Selling",
true,
)],
decoded_conditions: vec![RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: crate::RuntimeCompanyMetric::InvestorConfidence,
comparator: RuntimeConditionComparator::Eq,
value: 37,
}],
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
key: "world.investor_confidence_condition_imported".to_string(),
value: true,
}],
executable_import_ready: true,
notes: vec![
"investor confidence condition gates a world-side effect".to_string(),
],
}],
}),
notes: vec![],
};
let mut import = project_save_slice_to_runtime_state_import(
&save_slice,
"company-investor-confidence-condition",
None,
)
.expect("save-slice import should project");
assert_eq!(import.state.event_runtime_records.len(), 1);
assert_eq!(
import.state.event_runtime_records[0].conditions,
vec![RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::SelectedCompany,
metric: crate::RuntimeCompanyMetric::InvestorConfidence,
comparator: RuntimeConditionComparator::Eq,
value: 37,
}]
);
crate::execute_step_command(
&mut import.state,
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("investor-confidence trigger should execute");
assert_eq!(
import
.state
.world_flags
.get("world.investor_confidence_condition_imported"),
Some(&true)
);
}
#[test]
fn imports_management_attitude_condition_from_save_slice_company_context() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: Some(save_company_roster()),
chairman_profile_table: Some(save_chairman_profile_table()),
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
metadata_tag_offset: 0x7100,
records_tag_offset: 0x7200,
close_tag_offset: 0x7600,
packed_state_version: 0x3e9,
packed_state_version_hex: "0x000003e9".to_string(),
live_id_bound: 74,
live_record_count: 1,
live_entry_ids: vec![74],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 74,
payload_offset: Some(0x7202),
payload_len: Some(136),
decode_status: "parity_only".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: Some(7),
active: None,
marks_collection_dirty: None,
one_shot: Some(false),
compact_control: Some(real_compact_control()),
text_bands: vec![],
standalone_condition_row_count: 1,
standalone_condition_rows: vec![
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: 2369,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&58_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Management Attitude".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Management Attitude == 58".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
},
],
negative_sentinel_scope: Some(company_negative_sentinel_scope(
RuntimeCompanyConditionTestScope::SelectedCompanyOnly,
)),
grouped_effect_row_counts: vec![1, 0, 0, 0],
grouped_effect_rows: vec![real_world_flag_row(
110,
"Disable Stock Buying and Selling",
true,
)],
decoded_conditions: vec![RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: crate::RuntimeCompanyMetric::ManagementAttitude,
comparator: RuntimeConditionComparator::Eq,
value: 58,
}],
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
key: "world.management_attitude_condition_imported".to_string(),
value: true,
}],
executable_import_ready: true,
notes: vec![
"management attitude condition gates a world-side effect".to_string(),
],
}],
}),
notes: vec![],
};
let mut import = project_save_slice_to_runtime_state_import(
&save_slice,
"company-management-attitude-condition",
None,
)
.expect("save-slice import should project");
assert_eq!(import.state.event_runtime_records.len(), 1);
assert_eq!(
import.state.event_runtime_records[0].conditions,
vec![RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::SelectedCompany,
metric: crate::RuntimeCompanyMetric::ManagementAttitude,
comparator: RuntimeConditionComparator::Eq,
value: 58,
}]
);
crate::execute_step_command(
&mut import.state,
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("management-attitude trigger should execute");
assert_eq!(
import
.state
.world_flags
.get("world.management_attitude_condition_imported"),
Some(&true)
);
}
#[test]
fn overlays_recovered_world_toggle_batch_into_executable_runtime_record() {
let base_state = state();

View file

@ -350,6 +350,10 @@ const REAL_CHAIRMAN_CASH_CONDITION_ID: i32 = 2218;
const REAL_CHAIRMAN_HOLDINGS_TOTAL_CONDITION_ID: i32 = 2239;
const REAL_CHAIRMAN_NET_WORTH_CONDITION_ID: i32 = 2240;
const REAL_CHAIRMAN_PURCHASING_POWER_CONDITION_ID: i32 = 1247;
const REAL_INVESTOR_CONFIDENCE_CONDITION_ID: i32 = 2366;
const REAL_CREDIT_RATING_CONDITION_ID: i32 = 2367;
const REAL_PRIME_RATE_CONDITION_ID: i32 = 2368;
const REAL_MANAGEMENT_ATTITUDE_CONDITION_ID: i32 = 2369;
const REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID: i32 = 2620;
const REAL_CARGO_PRODUCTION_CONDITION_TEMPLATE_ID: i32 = 200;
const REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID: i32 = 2422;
@ -361,7 +365,7 @@ const REAL_OTHER_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2421;
const REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID: i32 = 2547;
const REAL_TERRITORY_ACCESS_COST_CONDITION_ID: i32 = 1516;
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 38] = [
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 40] = [
RealOrdinaryConditionMetadata {
raw_condition_id: 1802,
label: "Current Cash",
@ -405,19 +409,33 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 38] = [
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2366,
raw_condition_id: REAL_INVESTOR_CONFIDENCE_CONDITION_ID,
label: "Investor Confidence",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::InvestorConfidence,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CREDIT_RATING_CONDITION_ID,
label: "Credit Rating",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::CreditRating,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2368,
raw_condition_id: REAL_PRIME_RATE_CONDITION_ID,
label: "Prime Rate",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::PrimeRate,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_MANAGEMENT_ATTITUDE_CONDITION_ID,
label: "Management Attitude",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::ManagementAttitude,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID,
label: "Book Value Per Share",
@ -10559,6 +10577,24 @@ mod tests {
.expect("chairman purchasing-power condition metadata should exist");
assert_eq!(purchasing_power.label, "Purchasing Power");
let investor_confidence =
real_ordinary_condition_metadata(REAL_INVESTOR_CONFIDENCE_CONDITION_ID)
.expect("investor-confidence condition metadata should exist");
assert_eq!(investor_confidence.label, "Investor Confidence");
let credit_rating = real_ordinary_condition_metadata(REAL_CREDIT_RATING_CONDITION_ID)
.expect("credit-rating condition metadata should exist");
assert_eq!(credit_rating.label, "Credit Rating");
let prime_rate = real_ordinary_condition_metadata(REAL_PRIME_RATE_CONDITION_ID)
.expect("prime-rate condition metadata should exist");
assert_eq!(prime_rate.label, "Prime Rate");
let management_attitude =
real_ordinary_condition_metadata(REAL_MANAGEMENT_ATTITUDE_CONDITION_ID)
.expect("management-attitude condition metadata should exist");
assert_eq!(management_attitude.label, "Management Attitude");
let book_value = real_ordinary_condition_metadata(REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID)
.expect("book value condition metadata should exist");
assert_eq!(book_value.label, "Book Value Per Share");
@ -10636,6 +10672,72 @@ mod tests {
);
}
#[test]
fn decodes_investor_confidence_condition_to_company_metric() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_INVESTOR_CONFIDENCE_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&37_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Investor Confidence".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Investor Confidence == 37".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: RuntimeCompanyMetric::InvestorConfidence,
comparator: RuntimeConditionComparator::Eq,
value: 37,
})
);
}
#[test]
fn decodes_management_attitude_condition_to_company_metric() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_MANAGEMENT_ATTITUDE_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&58_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Management Attitude".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Management Attitude == 58".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: RuntimeCompanyMetric::ManagementAttitude,
comparator: RuntimeConditionComparator::Eq,
value: 58,
})
);
}
#[test]
fn looks_up_checked_in_world_flag_descriptor_metadata() {
let metadata =