//! Source-only preflight; parent compiles/runs this against its exact oa-core. //! Usage: preflight.exe PATH_TO_lifecycle-native.arcadia use oa_core::{operations, source_project, validation, *}; use std::collections::BTreeMap; fn id(n: u128) -> Id { Id::from_u128(0x21c0fe00000040008000000000000000 + n) } fn main() { let args: Vec<_> = std::env::args().collect(); assert_eq!(args.len(), 2, "Pass the prepared source file"); let source = std::fs::read_to_string(&args[1]).unwrap(); let p = language::parse(&source).expect("Prepared source must parse through actual core"); let issues = validation::validate(&p); let errors: Vec<_> = issues .iter() .filter(|issue| issue.severity == validation::Severity::Error) .collect(); assert!(errors.is_empty(), "Fixture admission failed: {errors:#?}"); validate_candidate(&p).expect("Ordinary command admission must accept the whole Project"); let bundle = source_project::SourceBundle { entry: "lifecycle-native.arcadia".into(), files: BTreeMap::from([("lifecycle-native.arcadia".into(), source.clone())]), }; let compiled = source_project::compile_bundle(&bundle, Default::default()) .expect("Use the actual source-project admission path"); assert_eq!( compiled.bundle, bundle, "Keep comments, Unicode and all explicit IDs byte-for-byte" ); assert_eq!(compiled.decoded.project, p); let canonical = language::format(&p); let reparsed = language::parse(&canonical).unwrap(); assert_eq!( reparsed, p, "Compare the entire Project, not selected elements" ); assert_eq!(language::format(&reparsed), canonical); assert_eq!(p.elements.len(), 61); assert_eq!(p.relations.len(), 5); for (owner, steps) in [ (1000, vec![1005, 1040, 1030, 1060, 1050, 1070]), (2000, vec![2005, 2040, 2030, 2060, 2050, 2070]), (3000, vec![3010, 3020, 3040, 3050, 3070]), (4000, vec![4040, 4080]), (5000, vec![5040, 5070, 5050]), (6000, vec![6080]), ] { assert_eq!( p.elements[&id(owner)].steps().unwrap(), &steps.into_iter().map(id).collect::>() ); } for base in [1000, 2000] { for (offset, call, expression) in [ (40, 40, "420.0"), (30, 30, "380.0"), (60, 30, "378.0"), (50, 40, "418.0"), ] { let occurrence = id(base + offset); let Some(SharedBody::Occurrence { body: OccurrenceBody::Exchange { values, .. }, .. }) = p.elements[&occurrence].shared() else { panic!("Expected an exchange occurrence") }; assert_eq!(values.len(), 1); assert_eq!(values[0].expression, expression); if base == 2000 { let operations::OperationResolution::Selected(proof) = operations::resolve(&p, occurrence).unwrap() else { panic!("SA pressure operation must remain actually bound") }; assert_eq!(proof.invocation, id(base + call)); assert_eq!(proof.allocation, id(220)); assert_eq!(proof.caller_port, id(202)); assert_eq!(proof.provider_port, id(203)); } else { assert_eq!( operations::resolve(&p, occurrence).unwrap(), operations::OperationResolution::Ordinary ); } } } let Some(SharedBody::Occurrence { body: OccurrenceBody::Exchange { sender, receiver, reply_to, .. }, .. }) = p.elements[&id(5050)].shared() else { panic!("Expected incomplete reply") }; assert_eq!( (*sender, *receiver, *reply_to), (None, Some(id(5001)), Some(id(5040))) ); for issue in &issues { println!( "{:?} {} {:?}: {}", issue.severity, issue.code, issue.element, issue.message ); } println!( "PASS: six scenarios,61 elements,5 relations,zero Errors,{} warnings; exact source bundle and whole-Project roundtrip; bound OA values and SA operation proofs preserved", issues.len() ); }