Files
ARCADIA-Studio/harness/save-as-diagnostics-20261001.md
T

8.8 KiB

Protected source destination diagnostics (#46)

Contribution for issue 46. Code commit 0e83157e09d52e6152df91208e41693b62da2d46 and evidence checkpoint 046cdc1b463371c1868efcd800b3c333d7a50ac2 are published and ref-verified on codex/save-as-diagnostics-01a0d717-20261001. The tested source was based on ea23e229260d7d050b3c3b88e77c3a851e936abe. Merge checkpoint 8e59309cbc2fee08c4c3f9b6415c88b56c027a4a adds published compact Help evidence from 6ea7518e without changing any crate, Cargo, example, documentation or specification inputs relative to the tested code. The bounded contribution validation below is complete. Fresh scoped package validation supplies later extracted-runtime evidence and links confirmed scoped publication. Broader follow-up integration remains separate. Windows only; no Linux/WSL validation is claimed or requested. The earlier #39 release remains separate and retains its old wording.

Problem and bounded change

Source Save As preserves relative included-file paths. Existing disk expectations are reused only when both the physical root directory and entry filename match. Saving a multi-file project under a new entry name in the same directory therefore establishes a new destination and refuses already-existing included files. This is intentional protection, consistent with the visible Save As guidance and the source integration contract. It does not authorize overwriting the existing includes, even when their bytes match the loaded project.

Previously, this new-destination collision reused the core Conflict message describing files changed outside the editor. That diagnosis was misleading when no observed file had changed. A private closure in desktop write_snapshot_inner now formats conflicts from new_project and expect_new_file as existing protected destination files. It suggests a fresh directory for Save As, or Save All at the current entry when the document has an original destination. A new-include collision while saving an existing project instead asks the user to review that include's destination.

Conflicts reported by save_project retain the external-change diagnostic: these checks compare against established observations. Non-conflict errors retain their existing messages. The change affects only desktop error presentation; core and server APIs, schema, source formatting, disk expectations, no-overwrite guards, save transactions, and document/history behavior are unchanged.

Review and verification

Independent review found no production blocker, but identified a test-helper compile error: write_snapshot returns SaveFailure, while the helper promised String. The first frozen candidate failed with Rust E0308 at app/save_as_tests.rs:42. The only correction was returning error.message after dispatching the cloned failure and checking preserved editor state. The failed run was retained rather than replaced by the passing result.

The corrected targeted run completed 29 passed, 0 failed, 0 ignored; 1,520 tests were filtered out. Its log records the Windows GNU LLVM debug executable under the shared target-gnullvm directory. This is targeted test evidence, not a full-suite or packaged-application claim.

New boundary regressions exercise:

  • Same-root/new-entry refusal with all original source bytes unchanged and no new entry, preserving accepted snapshot, revision, raw draft, current path, dirty state, and available Undo/Redo history.
  • Fresh-root/pre-existing-include refusal before any bundle file is written, preserving the unrelated destination bytes and editor state.
  • A genuine external dependency edit retaining the external-change message and both changed dependency and entry bytes; successful existing Save All after restoring observed bytes; successful fresh-directory Save As with complete source-bundle and decoded-model equality after reopening through core APIs.

Existing source collision coverage remains in crates/oa-core/tests/source_files.rs::new_destinations_require_explicit_missing_expectations_and_reject_collisions. No expectation was relaxed to make the new tests pass.

Completed bounded acceptance and evidence

Strict all-target desktop Clippy and the GUI development build completed successfully. The parent-observed executed commands were:

cargo test --locked -p oa-desktop -- save_as_tests source_project_tests repair_save_state_tests --test-threads=1
cargo clippy --locked -p oa-desktop --all-targets -- -D warnings
cargo build --locked -p oa-desktop --bin arcadia-studio

The configured Windows GNU LLVM environment used the shared target-gnullvm directory, one build job and disabled incremental compilation. Command scope is parent-observed; the stdout logs alone do not record flags. This is not a new full-suite result.

An independent native reviewer exercised the exact frozen desktop build, with 16 screenshots and a predeclared single Activity-name change. Same-root/new-entry Save As refused the protected dependency with the accurate destination diagnostic; unsaved state and authored name remained visible. Its full pointer tooltip was readable at normal and minimum sizes, including both recovery choices. Existing Save All and fresh-directory Save As succeeded. A separately loaded clean project with a parent-injected valid external comment retained the genuine external-change diagnostic and refused to overwrite it; restoring exact baseline bytes allowed Save All recovery. The desktop closed normally with exit 0, empty stdout/stderr, and unchanged executable/runtime hashes.

Eight byte-oracle checkpoints compare every relative filename and byte of the 37-file fixture. Collision preserved baseline bytes and created no new entry; existing Save All and fresh Save As changed only the declared Activity name; external refusal retained the injected comment; restoration and recovery matched pristine bytes. Fresh Save As wrote 30 source files; the other seven companion files were prepared by the parent, not copied by the application.

A separately pinned reused server decoded the complete pristine and saved 30-file source requests. Full returned source bundles equal those requests; the complete parsed Project differs only in the declared Activity name. The final independent review reconciled phase receipts, final actual directories, requests/responses and persisted server envelopes. The parser server came from source 715036e132677dd2bc2fb37ed316d93dc9987aec, not a #46 rebuild. Its owned forced termination returned 1 after acknowledged import/read; no graceful-shutdown claim is made.

Exact artifact SHA256
Native desktop e9cce9355525ecdc59bfae12608b1e0272167acef5a86b25368ef547e08886ff
Runtime f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4
Reused parser server 6cebacc117e46fdab023c6402a5cebd6929fb55993ae8ff6b89cd1c6c1170237
First failed test log b19127590c07949232db015b09aa965d77c93a1d0a0d1d496fb05373f2686a82
Corrected targeted test log 9079652120e18a7176feb8e5f4ac289cbf0c27f979a0c042fef5d8b4e2e252d4

The byte-preserved evidence packet contains the first failure/diff/hashes, passing gate logs, launch/freeze/oracle scripts, original native captures and receipts, parser requests/responses, donor identity and final independent review. Its inventory and read-only verify.py allow another checkout to check hashes, phase receipt byte sets and complete source/model equality without the local binaries or live server store. Replaying native interaction is a separate check.

Contribution limits and subsequent delivery

The longer persistent collision footer truncates; its pointer tooltip is readable. Keyboard-only tooltip access remains untested. On a clean document, the header “All changes saved” describes absence of local edits; it does not override the explicit external-conflict footer. No exhaustive save-error, concurrency-race, new-platform or complete OA/SA acceptance is claimed. The original contribution review alone did not establish packaged delivery; the later fresh package validation and confirmed publication supply that separate evidence.

The independent final review found no material blocker within this bounded contribution. Source and its byte-preserved evidence are published, and scoped release 9 delivers the correction. Broader follow-up integration and live coordination remain in Gitea issue 46. Earlier #39 release 8 remains unchanged and does not contain this diagnostic fix.