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.