From f5467e50c5d510acbd0af178b9428d2ced940a87 Mon Sep 17 00:00:00 2001 From: "sorokin.oleg.edu" Date: Sun, 6 Sep 2026 04:43:41 +0300 Subject: [PATCH] Preserve authored source and reports through desktop migration --- crates/oa-desktop/src/app.rs | 105 ++++++++++++++++++++++++++- harness/STATE.md | 8 ++ harness/release-data-verification.md | 29 ++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/crates/oa-desktop/src/app.rs b/crates/oa-desktop/src/app.rs index 8d395af1..ee3d5a69 100644 --- a/crates/oa-desktop/src/app.rs +++ b/crates/oa-desktop/src/app.rs @@ -2612,8 +2612,14 @@ impl App { .discovered(&disk.bundle, disk.reachable.clone()); self.show_source_file(false); self.source_diagnostics = self.document.compiled().diagnostics.clone(); - self.status = - "Source project opened. Included files and comments are preserved.".into(); + self.migration = self.document.compiled().decoded.migration.clone(); + if self.migration.is_some() { + self.status = "Imported earlier source schema. Review Model checks; Save all explicitly writes the upgraded source while retaining comments and includes.".into(); + self.page = Page::Validation; + } else { + self.status = + "Source project opened. Included files and comments are preserved.".into(); + } } Err(error) => { self.canvas_document = Id::new_v4(); @@ -3243,7 +3249,9 @@ fn read_snapshot(path: PathBuf) -> Result { && let Some(source_files::DiskExpectation::Bytes(bytes)) = disk.expectations.get(&disk.bundle.entry) && let Ok(decoded) = persistence::decode_with_report_limited(bytes, LIMITS.model) - && decoded.migration.is_some() + // Source1/2 require the historical single-document adapters. + // Source3+ must retain its authored bundle and token migration. + && decoded.migration.as_ref().is_some_and(|report| report.from_schema <= 2) { return Ok(LoadedSnapshot::Legacy( path, @@ -3328,6 +3336,97 @@ mod source_project_tests { Ok(()) } + #[test] + fn source3_native_open_preserves_report_comments_nesting_and_save_reopen() { + let original = include_str!("../../oa-core/tests/fixtures/v3-data-contract.arcadia"); + for split in [false, true] { + let directory = Directory::new(); + let path = directory.0.join("project.arcadia"); + let mut authored = std::collections::BTreeMap::new(); + if split { + let start = original.find("{\n").unwrap() + 2; + let end = original.rfind('}').unwrap(); + authored.insert( + "project.arcadia", + format!( + "{} include \"dictionary.arcadia\";\n}}\n", + &original[..start] + ), + ); + authored.insert("dictionary.arcadia", original[start..end].to_owned()); + } else { + authored.insert("project.arcadia", original.to_owned()); + } + for (file, source) in &authored { + std::fs::write(directory.0.join(file), source).unwrap(); + } + let mut app = App::with_project(Project::empty()); + send( + &mut app, + Message::Loaded(Ok(Some(read_snapshot(path.clone()).unwrap()))), + ); + assert_eq!(app.migration.as_ref().unwrap().from_schema, 3); + assert_eq!(app.page, Page::Validation); + assert_eq!(app.path, Some(path.clone())); + assert_eq!(app.document.bundle().files.len(), authored.len()); + assert!( + app.dirty(), + "accepted source migration needs explicit saving" + ); + for (file, source) in &authored { + assert_eq!( + std::fs::read_to_string(directory.0.join(file)).unwrap(), + *source + ); + } + let text = app + .document + .bundle() + .files + .values() + .cloned() + .collect::(); + assert!(text.contains("// Reused record parameters retain their own identities.")); + assert!(text.contains("// Frozen authored schema3 compatibility input.")); + let packet = app + .project() + .elements + .values() + .find(|e| e.alias == "packet") + .unwrap() + .id; + let origin = app + .project() + .elements + .values() + .find(|e| e.alias == "origin") + .unwrap() + .id; + assert_eq!( + app.document.compiled().index.lexical_owners.get(&origin), + Some(&packet) + ); + let before = app.document.snapshot(); + save(&mut app, path.clone()).unwrap(); + assert!(!app.dirty()); + for (file, source) in &before.bundle.files { + assert_eq!( + std::fs::read_to_string(directory.0.join(file)).unwrap(), + *source + ); + } + let mut reopened = App::with_project(Project::empty()); + send( + &mut reopened, + Message::Loaded(Ok(Some(read_snapshot(path).unwrap()))), + ); + assert!(reopened.migration.is_none()); + assert_eq!(reopened.project(), app.project()); + assert_eq!(reopened.document.bundle(), app.document.bundle()); + assert!(!reopened.dirty()); + } + } + fn pending_journal(directory: &Directory, before: Option<&str>) -> (PathBuf, PathBuf) { let path = directory.0.join("project.arcadia"); let journal = directory.0.join(".arcadia-save-project.arcadia.journal"); diff --git a/harness/STATE.md b/harness/STATE.md index 0bd2b388..feae4ca5 100644 --- a/harness/STATE.md +++ b/harness/STATE.md @@ -149,3 +149,11 @@ Windows: cargo test --locked --workspace; cargo clippy --locked --workspace --all-targets -- -D warnings; cargo build --locked -p oa-desktop -p oa-server. WSL Ubuntu24.04 uses target/linux-cargo.toml and Mesa software Vulkan for native WSLg. No remote push or usage reset authorized. No broad recursive target deletion. + +Latest R6 checkpoint: native recursive scenario authoring passed two distinct +shared-leaf values, paired Create/Undo/Redo and save (55objects/5links). Runtime +found unreadable long-path picker names (fixed74989b6,262 desktop tests/Clippy/build) +and single-file source3 migration discarding comments on save (desktop shortcut +now corrected; actual disk include/single-file regression passes). Final build and +native retests remain. Old native exec37598 closed normally. See the updated R6 +verification note; earlier ab661f2 suite evidence remains valid only for that freeze. diff --git a/harness/release-data-verification.md b/harness/release-data-verification.md index 103dd2c9..32f75489 100644 --- a/harness/release-data-verification.md +++ b/harness/release-data-verification.md @@ -66,3 +66,32 @@ material findings before R6 acceptance. Independent semantic/correctness/spec reviews already drove fixes; final native observations may require further review. The broader release still needs semantic reconciliation, direct scenario/process editing, lifecycle/hosted/help work and fresh cross-disciplinary end-state review. + +## Native findings and follow-up fixes (2026-09-06) + +At1100x700, the53-object recursive fixture exposed32/33 nested fields in two pages. +Native Call+Reply creation stored distinct Origin/Latitude and Destination/Latitude +expressions despite their shared terminal UUID. One Undo removed the pair; Redo +restored it. Save All wrote55objects/5links; source confirms both paths and reply +correlation. Three expected checks concern the absent SA System and two unallocated +functions. The saved evidence is ui-r6-scenario-windows/model/project.arcadia. + +A third-hop popup exposed a material UI defect: repeated long path prefixes hid +all terminal field names. Fix74989b6 shows the terminal name first, sorts choices, +and retains the full address as wrapping detail text.262 desktop tests, strict +Clippy and release build passed; native retest is pending. Intermediate fixed hash +E592165A6FFFAEC64B67FF0A33FB4E78571527EE3C8F2CC457666DA6C277D5CB. + +Native source3 import showed8semantic defaults,2generated allocations,1unresolved +value address and left the original hash305F19D1B79F99F8D4CF627BA2E9CA6836BB7959CC0070227815937A699EAFEA unchanged. +Its old desktop Save All path requested a new file and preserved the original, but +canonical regeneration discarded comments/nesting in the upgraded copy. This is a +material desktop/source parity defect, not a core bundle migration defect. The fix +keeps the historical single-document adapter only for source1/2; source3+ follows +bundle migration and propagates its report into Model checks. A regression passes +for actual disk single-file and included-file open, no write until explicit save, +comments, lexical ownership, report, exact saved source and clean reopened state. +Full desktop/Clippy/build and native retest are in progress; do not accept R6 yet. + +The old Windows native window1835476 closed normally; exec37598 exited0 with no +runtime output beyond a newline. Re-inventory before opening the rebuilt binary.