607 lines
19 KiB
Rust
607 lines
19 KiB
Rust
use std::fs;
|
|
|
|
use serde::Deserialize;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct HandoverAsset {
|
|
#[serde(rename = "handoverDate")]
|
|
handover_date: String,
|
|
#[serde(rename = "closedRoadmapPlan")]
|
|
closed_roadmap_plan: String,
|
|
#[serde(rename = "postRoadmapPlan")]
|
|
post_roadmap_plan: String,
|
|
#[serde(rename = "roadmapClosureStatus")]
|
|
roadmap_closure_status: String,
|
|
#[serde(rename = "scopeStatement")]
|
|
scope_statement: String,
|
|
#[serde(rename = "mainlineFamilyStateMatrix")]
|
|
mainline_family_state_matrix: Vec<MainlineFamilyState>,
|
|
#[serde(rename = "boundaryFamilyStateMatrix")]
|
|
boundary_family_state_matrix: Vec<GroupState>,
|
|
#[serde(rename = "deferredFamilyStateMatrix")]
|
|
deferred_family_state_matrix: Vec<GroupState>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct MainlineFamilyState {
|
|
group: String,
|
|
status: String,
|
|
#[serde(rename = "representativeBaseline")]
|
|
representative_baseline: String,
|
|
#[serde(rename = "promotedExpansions")]
|
|
promoted_expansions: u32,
|
|
#[serde(rename = "candidateQueueCount")]
|
|
candidate_queue_count: u32,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct GroupState {
|
|
group: String,
|
|
status: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct SceneExecutionBoard {
|
|
#[serde(rename = "boardDate")]
|
|
board_date: String,
|
|
scope: String,
|
|
#[serde(rename = "sourceAssets")]
|
|
source_assets: SourceAssets,
|
|
#[serde(rename = "statusVocabulary")]
|
|
status_vocabulary: Vec<String>,
|
|
summary: ExecutionBoardSummary,
|
|
scenes: Vec<SceneBoardEntry>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct SourceAssets {
|
|
workbook: String,
|
|
#[serde(rename = "ledgerSnapshot")]
|
|
ledger_snapshot: String,
|
|
#[serde(rename = "ledgerStatusOverlay")]
|
|
ledger_status_overlay: String,
|
|
#[serde(rename = "roadmapExecutionStatus")]
|
|
roadmap_execution_status: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct ExecutionBoardSummary {
|
|
#[serde(rename = "totalScenes")]
|
|
total_scenes: u32,
|
|
#[serde(rename = "statusCounts")]
|
|
status_counts: serde_json::Map<String, serde_json::Value>,
|
|
#[serde(rename = "selectedRealSamples")]
|
|
selected_real_samples: u32,
|
|
#[serde(rename = "executedRealSamples")]
|
|
executed_real_samples: u32,
|
|
#[serde(rename = "pendingRealSamples")]
|
|
pending_real_samples: u32,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct SceneBoardEntry {
|
|
#[serde(rename = "sceneName")]
|
|
scene_name: String,
|
|
#[serde(rename = "snapshotGroupingResult")]
|
|
snapshot_grouping_result: String,
|
|
#[serde(rename = "snapshotFamilyJudgement")]
|
|
snapshot_family_judgement: String,
|
|
#[serde(rename = "hasExplicitValidationConclusion")]
|
|
has_explicit_validation_conclusion: String,
|
|
#[serde(rename = "snapshotValidationStatus")]
|
|
snapshot_validation_status: String,
|
|
#[serde(rename = "snapshotValidationResult")]
|
|
snapshot_validation_result: String,
|
|
#[serde(rename = "snapshotNote")]
|
|
snapshot_note: String,
|
|
#[serde(rename = "currentGroup")]
|
|
current_group: Option<String>,
|
|
#[serde(rename = "currentStatus")]
|
|
current_status: String,
|
|
#[serde(rename = "currentSourceAsset")]
|
|
current_source_asset: Option<String>,
|
|
#[serde(rename = "realSampleRecordId")]
|
|
real_sample_record_id: Option<String>,
|
|
#[serde(rename = "realSampleLayerStatus")]
|
|
real_sample_layer_status: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RealSampleValidationPlan {
|
|
#[serde(rename = "planDate")]
|
|
plan_date: String,
|
|
scope: String,
|
|
criteria: Vec<String>,
|
|
#[serde(rename = "selectedFamilies")]
|
|
selected_families: Vec<SelectedFamily>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct SelectedFamily {
|
|
group: String,
|
|
#[serde(rename = "recordId")]
|
|
record_id: String,
|
|
#[serde(rename = "sceneName")]
|
|
scene_name: String,
|
|
#[serde(rename = "currentBoardStatus")]
|
|
current_board_status: String,
|
|
#[serde(rename = "sourceEvidence")]
|
|
source_evidence: String,
|
|
#[serde(rename = "selectionReason")]
|
|
selection_reason: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RealSampleValidationTemplate {
|
|
#[serde(rename = "templateDate")]
|
|
template_date: String,
|
|
scope: String,
|
|
#[serde(rename = "requiredFields")]
|
|
required_fields: Vec<String>,
|
|
#[serde(rename = "allowedValidationStates")]
|
|
allowed_validation_states: Vec<String>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RealSampleValidationRecords {
|
|
#[serde(rename = "recordDate")]
|
|
record_date: String,
|
|
scope: String,
|
|
records: Vec<RealSampleValidationRecord>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RealSampleValidationRecord {
|
|
#[serde(rename = "recordId")]
|
|
record_id: String,
|
|
group: String,
|
|
#[serde(rename = "sceneName")]
|
|
scene_name: String,
|
|
#[serde(rename = "currentBoardStatus")]
|
|
current_board_status: String,
|
|
#[serde(rename = "validationState")]
|
|
validation_state: String,
|
|
#[serde(rename = "compileSuccess")]
|
|
compile_success: Option<bool>,
|
|
#[serde(rename = "readinessCorrectness")]
|
|
readiness_correctness: Option<bool>,
|
|
#[serde(rename = "dataCorrectness")]
|
|
data_correctness: Option<bool>,
|
|
#[serde(rename = "outputCorrectness")]
|
|
output_correctness: Option<bool>,
|
|
#[serde(rename = "failClosedCorrectness")]
|
|
fail_closed_correctness: Option<bool>,
|
|
result: String,
|
|
#[serde(rename = "mismatchCodes")]
|
|
mismatch_codes: Vec<String>,
|
|
#[serde(rename = "sourceEvidence")]
|
|
source_evidence: Vec<String>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct MismatchTaxonomy {
|
|
#[serde(rename = "taxonomyDate")]
|
|
taxonomy_date: String,
|
|
scope: String,
|
|
codes: Vec<MismatchCode>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct MismatchCode {
|
|
code: String,
|
|
category: String,
|
|
description: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct BoundaryRuntimeEntryRules {
|
|
#[serde(rename = "assetDate")]
|
|
asset_date: String,
|
|
scope: String,
|
|
#[serde(rename = "boundaryReadiness")]
|
|
boundary_readiness: Vec<BoundaryReadiness>,
|
|
#[serde(rename = "deferredFamilyEntryCriteria")]
|
|
deferred_family_entry_criteria: Vec<DeferredFamilyEntryCriteria>,
|
|
#[serde(rename = "runtimeGapMatrix")]
|
|
runtime_gap_matrix: Vec<RuntimeGap>,
|
|
prioritization: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct BoundaryReadiness {
|
|
group: String,
|
|
status: String,
|
|
readiness: String,
|
|
#[serde(rename = "nextEntryCondition")]
|
|
next_entry_condition: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct DeferredFamilyEntryCriteria {
|
|
group: String,
|
|
#[serde(rename = "currentStatus")]
|
|
current_status: String,
|
|
#[serde(rename = "entryCriteria")]
|
|
entry_criteria: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RuntimeGap {
|
|
gap: String,
|
|
category: String,
|
|
status: String,
|
|
blocks: Vec<String>,
|
|
}
|
|
|
|
#[test]
|
|
fn post_roadmap_handover_asset_is_actionable() {
|
|
let handover = load_handover();
|
|
|
|
assert_eq!(handover.handover_date, "2026-04-18");
|
|
assert!(handover.closed_roadmap_plan.ends_with(".md"));
|
|
assert!(handover.post_roadmap_plan.ends_with(".md"));
|
|
assert_eq!(handover.roadmap_closure_status, "completed");
|
|
assert!(handover.scope_statement.contains("roadmap is closed"));
|
|
assert_eq!(handover.mainline_family_state_matrix.len(), 3);
|
|
assert_eq!(handover.boundary_family_state_matrix.len(), 3);
|
|
assert_eq!(handover.deferred_family_state_matrix.len(), 2);
|
|
assert!(!handover.notes.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn post_roadmap_execution_board_stays_minimal_and_validation_oriented() {
|
|
let board = load_execution_board();
|
|
|
|
assert_eq!(board.board_date, "2026-04-19");
|
|
assert_eq!(board.scope, "post-roadmap-minimum-current-execution-board");
|
|
assert!(board.source_assets.workbook.ends_with(".xlsx"));
|
|
assert!(board.source_assets.ledger_snapshot.ends_with(".json"));
|
|
assert!(board.source_assets.ledger_status_overlay.ends_with(".json"));
|
|
assert!(board
|
|
.source_assets
|
|
.roadmap_execution_status
|
|
.ends_with(".json"));
|
|
assert_eq!(board.status_vocabulary.len(), 6);
|
|
assert_eq!(board.summary.total_scenes, 102);
|
|
assert_eq!(board.summary.selected_real_samples, 5);
|
|
assert_eq!(board.summary.executed_real_samples, 5);
|
|
assert_eq!(board.summary.pending_real_samples, 0);
|
|
assert_eq!(
|
|
board
|
|
.summary
|
|
.status_counts
|
|
.get("promoted-baseline")
|
|
.and_then(|value| value.as_u64()),
|
|
Some(3)
|
|
);
|
|
assert_eq!(
|
|
board
|
|
.summary
|
|
.status_counts
|
|
.get("boundary-family")
|
|
.and_then(|value| value.as_u64()),
|
|
Some(3)
|
|
);
|
|
assert_eq!(
|
|
board
|
|
.summary
|
|
.status_counts
|
|
.get("unvalidated")
|
|
.and_then(|value| value.as_u64()),
|
|
Some(79)
|
|
);
|
|
assert!(!board.notes.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn post_roadmap_execution_board_maps_real_sample_records_immediately() {
|
|
let board = load_execution_board();
|
|
|
|
let g2 = board
|
|
.scenes
|
|
.iter()
|
|
.find(|item| item.scene_name == "台区线损大数据-月_周累计线损率统计分析")
|
|
.expect("expected G2 board entry");
|
|
assert_eq!(g2.current_group.as_deref(), Some("G2"));
|
|
assert_eq!(g2.current_status, "promoted-baseline");
|
|
assert_eq!(g2.real_sample_record_id.as_deref(), Some("rsv-g2-001"));
|
|
assert_eq!(g2.real_sample_layer_status, "executed-pass");
|
|
|
|
let g1e = board
|
|
.scenes
|
|
.iter()
|
|
.find(|item| item.scene_name == "高低压新增报装容量月度统计表")
|
|
.expect("expected G1-E board entry");
|
|
assert_eq!(g1e.current_group.as_deref(), Some("G1-E"));
|
|
assert_eq!(g1e.current_status, "promoted-baseline");
|
|
assert_eq!(g1e.real_sample_record_id.as_deref(), Some("rsv-g1e-001"));
|
|
assert_eq!(g1e.real_sample_layer_status, "executed-pass");
|
|
|
|
let g3 = board
|
|
.scenes
|
|
.iter()
|
|
.find(|item| item.scene_name == "95598工单明细表")
|
|
.expect("expected G3 board entry");
|
|
assert_eq!(g3.current_group.as_deref(), Some("G3"));
|
|
assert_eq!(g3.current_status, "promoted-baseline");
|
|
assert_eq!(g3.real_sample_record_id.as_deref(), Some("rsv-g3-001"));
|
|
assert_eq!(g3.real_sample_layer_status, "executed-pass");
|
|
|
|
let g7 = board
|
|
.scenes
|
|
.iter()
|
|
.find(|item| item.current_group.as_deref() == Some("G7"))
|
|
.expect("expected G7 board entry");
|
|
assert_eq!(g7.current_group.as_deref(), Some("G7"));
|
|
assert_eq!(g7.current_status, "boundary-family");
|
|
assert_eq!(g7.real_sample_record_id.as_deref(), Some("rsv-g7-001"));
|
|
assert_eq!(g7.real_sample_layer_status, "executed-pass");
|
|
|
|
let g6 = board
|
|
.scenes
|
|
.iter()
|
|
.find(|item| item.current_group.as_deref() == Some("G6"))
|
|
.expect("expected G6 board entry");
|
|
assert_eq!(g6.current_group.as_deref(), Some("G6"));
|
|
assert_eq!(g6.current_status, "boundary-family");
|
|
assert_eq!(g6.real_sample_record_id.as_deref(), Some("rsv-g6-001"));
|
|
assert_eq!(g6.real_sample_layer_status, "executed-pass");
|
|
}
|
|
|
|
#[test]
|
|
fn post_roadmap_real_sample_validation_assets_are_consistent() {
|
|
let plan = load_validation_plan();
|
|
let template = load_validation_template();
|
|
let records = load_validation_records();
|
|
let taxonomy = load_mismatch_taxonomy();
|
|
|
|
assert_eq!(plan.plan_date, "2026-04-18");
|
|
assert_eq!(
|
|
plan.scope,
|
|
"post-roadmap-first-round-real-sample-validation"
|
|
);
|
|
assert_eq!(plan.criteria.len(), 5);
|
|
assert_eq!(plan.selected_families.len(), 3);
|
|
assert!(plan.selected_families.iter().any(|item| item.group == "G2"));
|
|
assert!(plan
|
|
.selected_families
|
|
.iter()
|
|
.any(|item| item.group == "G1-E"));
|
|
assert!(plan.selected_families.iter().any(|item| item.group == "G3"));
|
|
assert!(!plan.notes.is_empty());
|
|
|
|
assert_eq!(template.template_date, "2026-04-18");
|
|
assert_eq!(template.scope, "real-sample-validation-record-template");
|
|
assert!(template
|
|
.required_fields
|
|
.iter()
|
|
.any(|item| item == "recordId"));
|
|
assert!(template
|
|
.allowed_validation_states
|
|
.iter()
|
|
.any(|item| item == "selected-not-yet-run"));
|
|
assert!(!template.notes.is_empty());
|
|
|
|
assert_eq!(records.record_date, "2026-04-19");
|
|
assert_eq!(
|
|
records.scope,
|
|
"post-roadmap-first-round-real-sample-records"
|
|
);
|
|
assert_eq!(records.records.len(), 5);
|
|
assert!(!records.notes.is_empty());
|
|
|
|
assert_eq!(taxonomy.taxonomy_date, "2026-04-18");
|
|
assert_eq!(taxonomy.scope, "post-roadmap-real-sample-mismatch-taxonomy");
|
|
assert!(taxonomy
|
|
.codes
|
|
.iter()
|
|
.any(|item| item.code == "archetype_mismatch"));
|
|
assert!(taxonomy
|
|
.codes
|
|
.iter()
|
|
.any(|item| item.code == "selected_not_run"));
|
|
|
|
let g2 = records
|
|
.records
|
|
.iter()
|
|
.find(|item| item.record_id == "rsv-g2-001")
|
|
.expect("expected G2 record");
|
|
assert_eq!(g2.group, "G2");
|
|
assert_eq!(g2.validation_state, "executed-pass");
|
|
assert_eq!(g2.compile_success, Some(true));
|
|
assert_eq!(g2.result, "passed");
|
|
assert_eq!(g2.readiness_correctness, Some(true));
|
|
assert_eq!(g2.data_correctness, Some(true));
|
|
assert_eq!(g2.output_correctness, Some(true));
|
|
assert_eq!(g2.fail_closed_correctness, Some(true));
|
|
assert!(g2.mismatch_codes.is_empty());
|
|
|
|
let g1e = records
|
|
.records
|
|
.iter()
|
|
.find(|item| item.record_id == "rsv-g1e-001")
|
|
.expect("expected G1-E record");
|
|
assert_eq!(g1e.group, "G1-E");
|
|
assert_eq!(g1e.validation_state, "executed-pass");
|
|
assert_eq!(g1e.compile_success, Some(true));
|
|
assert_eq!(g1e.result, "passed");
|
|
assert!(g1e.mismatch_codes.is_empty());
|
|
|
|
let g3 = records
|
|
.records
|
|
.iter()
|
|
.find(|item| item.record_id == "rsv-g3-001")
|
|
.expect("expected G3 record");
|
|
assert_eq!(g3.group, "G3");
|
|
assert_eq!(g3.validation_state, "executed-pass");
|
|
assert_eq!(g3.compile_success, Some(true));
|
|
assert_eq!(g3.result, "passed");
|
|
assert_eq!(g3.data_correctness, Some(true));
|
|
assert_eq!(g3.output_correctness, Some(true));
|
|
assert!(g3.mismatch_codes.is_empty());
|
|
|
|
let g7 = records
|
|
.records
|
|
.iter()
|
|
.find(|item| item.record_id == "rsv-g7-001")
|
|
.expect("expected G7 record");
|
|
assert_eq!(g7.group, "G7");
|
|
assert_eq!(g7.validation_state, "executed-pass");
|
|
assert_eq!(g7.compile_success, Some(true));
|
|
assert_eq!(g7.result, "passed");
|
|
assert_eq!(g7.data_correctness, Some(true));
|
|
assert_eq!(g7.output_correctness, Some(true));
|
|
assert!(g7.mismatch_codes.is_empty());
|
|
|
|
let g6 = records
|
|
.records
|
|
.iter()
|
|
.find(|item| item.record_id == "rsv-g6-001")
|
|
.expect("expected G6 record");
|
|
assert_eq!(g6.group, "G6");
|
|
assert_eq!(g6.validation_state, "executed-pass");
|
|
assert_eq!(g6.compile_success, Some(true));
|
|
assert_eq!(g6.result, "passed");
|
|
assert_eq!(g6.data_correctness, Some(true));
|
|
assert_eq!(g6.output_correctness, Some(true));
|
|
assert!(g6.mismatch_codes.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn post_roadmap_boundary_and_runtime_entry_rules_keep_scope_bounded() {
|
|
let rules = load_boundary_runtime_rules();
|
|
|
|
assert_eq!(rules.asset_date, "2026-04-19");
|
|
assert_eq!(rules.scope, "post-roadmap-boundary-and-runtime-entry-rules");
|
|
assert_eq!(rules.boundary_readiness.len(), 3);
|
|
assert!(rules.boundary_readiness.iter().all(|item| {
|
|
matches!(item.group.as_str(), "G6" | "G7" | "G8")
|
|
&& item.status == "boundary-family-established"
|
|
}));
|
|
assert!(rules
|
|
.boundary_readiness
|
|
.iter()
|
|
.any(|item| item.group == "G6" && item.readiness == "executed-pass"));
|
|
assert!(rules
|
|
.boundary_readiness
|
|
.iter()
|
|
.any(|item| item.group == "G8" && item.readiness == "hold-as-boundary"));
|
|
assert!(rules
|
|
.boundary_readiness
|
|
.iter()
|
|
.any(|item| item.group == "G7" && item.readiness == "executed-pass"));
|
|
assert_eq!(rules.deferred_family_entry_criteria.len(), 2);
|
|
assert!(rules
|
|
.deferred_family_entry_criteria
|
|
.iter()
|
|
.any(|item| item.group == "G4" && item.current_status == "deferred"));
|
|
assert!(rules
|
|
.deferred_family_entry_criteria
|
|
.iter()
|
|
.any(|item| item.group == "G5" && item.current_status == "degraded"));
|
|
assert_eq!(rules.runtime_gap_matrix.len(), 6);
|
|
assert!(rules
|
|
.runtime_gap_matrix
|
|
.iter()
|
|
.any(|item| item.gap == "login-recovery" && item.category == "runtime-platform-gap"));
|
|
assert!(rules
|
|
.runtime_gap_matrix
|
|
.iter()
|
|
.any(|item| item.gap == "host-runtime-integration"));
|
|
assert!(rules.runtime_gap_matrix.iter().any(|item| item.gap
|
|
== "g3-real-sample-output-contract-verification"
|
|
&& item.category == "mainline-contract-gap"
|
|
&& item.status == "closed-in-mainline"));
|
|
assert!(rules
|
|
.runtime_gap_matrix
|
|
.iter()
|
|
.any(|item| item.gap == "g2-real-sample-contract-correction"
|
|
&& item.category == "mainline-contract-gap"
|
|
&& item.status == "closed-in-mainline"));
|
|
assert!(!rules.prioritization.is_empty());
|
|
assert!(rules
|
|
.prioritization
|
|
.iter()
|
|
.any(|item| item.contains("Both G3 and G2")));
|
|
assert!(rules
|
|
.prioritization
|
|
.iter()
|
|
.any(|item| item.contains("G7 is now the first boundary family")));
|
|
assert!(rules
|
|
.prioritization
|
|
.iter()
|
|
.any(|item| item.contains("G6 is now the second boundary family")));
|
|
}
|
|
|
|
fn load_handover() -> HandoverAsset {
|
|
serde_json::from_str(
|
|
&fs::read_to_string("tests/fixtures/generated_scene/post_roadmap_handover_2026-04-18.json")
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_execution_board() -> SceneExecutionBoard {
|
|
serde_json::from_str(
|
|
&fs::read_to_string("tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json")
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_validation_plan() -> RealSampleValidationPlan {
|
|
serde_json::from_str(
|
|
&fs::read_to_string(
|
|
"tests/fixtures/generated_scene/real_sample_validation_plan_2026-04-18.json",
|
|
)
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_validation_template() -> RealSampleValidationTemplate {
|
|
serde_json::from_str(
|
|
&fs::read_to_string(
|
|
"tests/fixtures/generated_scene/real_sample_validation_record_template_2026-04-18.json",
|
|
)
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_validation_records() -> RealSampleValidationRecords {
|
|
serde_json::from_str(
|
|
&fs::read_to_string(
|
|
"tests/fixtures/generated_scene/real_sample_validation_records_2026-04-18.json",
|
|
)
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_mismatch_taxonomy() -> MismatchTaxonomy {
|
|
serde_json::from_str(
|
|
&fs::read_to_string(
|
|
"tests/fixtures/generated_scene/real_sample_mismatch_taxonomy_2026-04-18.json",
|
|
)
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
fn load_boundary_runtime_rules() -> BoundaryRuntimeEntryRules {
|
|
serde_json::from_str(
|
|
&fs::read_to_string(
|
|
"tests/fixtures/generated_scene/boundary_runtime_entry_rules_2026-04-18.json",
|
|
)
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|