use std::fs; use serde::Deserialize; #[derive(Debug, Deserialize)] struct RoadmapExecutionStatus { #[serde(rename = "statusDate")] status_date: String, plan: String, #[serde(rename = "derivedFrom")] derived_from: DerivedFrom, #[serde(rename = "phaseStatus")] phase_status: Vec, #[serde(rename = "trackStatus")] track_status: Vec, #[serde(rename = "boundaryStatus")] boundary_status: Vec, #[serde(rename = "deferredStatus")] deferred_status: Vec, notes: Vec, } #[derive(Debug, Deserialize)] struct DerivedFrom { #[serde(rename = "familyPolicy")] family_policy: String, #[serde(rename = "familyResults")] family_results: String, #[serde(rename = "ledgerSnapshot")] ledger_snapshot: String, #[serde(rename = "ledgerStatusOverlay")] ledger_status_overlay: String, } #[derive(Debug, Deserialize)] struct PhaseStatus { phase: String, status: String, notes: Vec, } #[derive(Debug, Deserialize)] struct TrackStatus { track: String, group: String, status: String, #[serde(rename = "completedItems")] completed_items: Vec, #[serde(rename = "remainingItems")] remaining_items: Vec, } #[derive(Debug, Deserialize)] struct GroupStatus { group: String, status: String, } #[test] fn roadmap_execution_status_asset_is_actionable() { let status = load_status(); assert_eq!(status.status_date, "2026-04-18"); assert!(status.plan.ends_with(".md")); assert!(status.derived_from.family_policy.ends_with(".json")); assert!(status.derived_from.family_results.ends_with(".json")); assert!(status.derived_from.ledger_snapshot.ends_with(".json")); assert!(status.derived_from.ledger_status_overlay.ends_with(".json")); assert_eq!(status.phase_status.len(), 5); assert_eq!(status.track_status.len(), 5); assert_eq!(status.boundary_status.len(), 3); assert_eq!(status.deferred_status.len(), 2); assert!(!status.notes.is_empty()); } #[test] fn roadmap_execution_status_tracks_mainline_progress() { let status = load_status(); let phase4 = status .phase_status .iter() .find(|item| item.phase == "Phase 4") .expect("expected phase 4 status"); assert_eq!(phase4.status, "in_progress"); assert!(!phase4.notes.is_empty()); let track_a = status .track_status .iter() .find(|item| item.track == "Track A") .expect("expected track A"); assert_eq!(track_a.group, "G2"); assert_eq!(track_a.status, "batch-expansion-promoted"); assert!(track_a .completed_items .iter() .any(|item| item == "five-promoted-expansions")); assert!(track_a.remaining_items.is_empty()); let track_b = status .track_status .iter() .find(|item| item.track == "Track B") .expect("expected track B"); assert_eq!(track_b.group, "G1-E"); assert_eq!(track_b.status, "batch-expansion-promoted"); assert!(track_b .completed_items .iter() .any(|item| item == "two-promoted-expansions")); assert!(track_b.remaining_items.is_empty()); let track_c = status .track_status .iter() .find(|item| item.track == "Track C") .expect("expected track C"); assert_eq!(track_c.group, "G3"); assert_eq!(track_c.status, "batch-expansion-promoted"); assert!(track_c .completed_items .iter() .any(|item| item == "ten-promoted-expansions")); assert!(track_c.remaining_items.is_empty()); } #[test] fn roadmap_execution_status_keeps_boundary_and_deferred_scope_clear() { let status = load_status(); assert!(status.boundary_status.iter().all(|item| { matches!(item.group.as_str(), "G6" | "G7" | "G8") && item.status == "boundary-family-established" })); assert!(status .deferred_status .iter() .any(|item| item.group == "G4" && item.status == "deferred")); assert!(status .deferred_status .iter() .any(|item| item.group == "G5" && item.status == "degraded")); let track_e = status .track_status .iter() .find(|item| item.track == "Track E") .expect("expected track E"); assert_eq!(track_e.status, "status-overlay-established"); assert!(track_e .completed_items .iter() .any(|item| item == "current-ledger-status-overlay")); } fn load_status() -> RoadmapExecutionStatus { serde_json::from_str( &fs::read_to_string( "tests/fixtures/generated_scene/roadmap_execution_status_2026-04-18.json", ) .unwrap(), ) .unwrap() }