Add audited, versioned MCP save workflow (#1452)

- `--export ... --target-version`, and explicit target_format /
  target_version on automation and protocol saves; a conversion that
  would drop unsupported records is refused unless allow_lossy is set.
- `audit` read op: dangling layers/blocks, duplicate handles, non-finite
  bounds, serialization, lossy records and the source DXF handle graph.
- `save_verified`: writes the requested version from the same snapshot a
  normal save writes, reopens it, checks the version and the entity
  manifest, audits the ASCII DXF handle graph and returns a SHA-256.
- ZOOM EXTENTS includes SDF text glyphs.
- Live MCP acceptance script and an optional reference-console audit
  runner under docs/automation.

Squashed from the PR with review fixes: merged with the DWT save path,
the save snapshot, the tool lists added since, and vendor-neutral
harness names; the dated verification record is left out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Luis MartinezandClaude Opus 5.5 authored and Hakan Seven committed 2026-09-24 16:49:11 +03:00
1 parent 0f99b77004
commit dddf60d79e
16 files changed
+1102 -22

No files matched your search

+16 -1
View File
@@ -1446,6 +1446,21 @@ impl OpenCADStudio {
i: usize,
path: std::path::PathBuf,
set_current_path: bool,
) -> Result<(), crate::io::SaveFailure> {
let version = self.tabs[i].scene.document.version;
self.save_tab_synchronously_protected_as(i, path, version, set_current_path)
}
/// Synchronous protected save with an explicit output version. Automation
/// uses this path so format conversion never depends on an implicit source
/// version or silently upgrades to the newest DWG.
#[cfg(not(target_arch = "wasm32"))]
pub(in crate::app) fn save_tab_synchronously_protected_as(
&mut self,
i: usize,
path: std::path::PathBuf,
version: acadrust::DxfVersion,
set_current_path: bool,
) -> Result<(), crate::io::SaveFailure> {
let previous_autosave = self.autosave_target(i);
if self.tabs[i].recovery_save_as_required
@@ -1499,7 +1514,6 @@ impl OpenCADStudio {
Self::native_save_verification(&path, lease, expected_fingerprint)?;
self.prepare_native_save(i);
let version = self.tabs[i].scene.document.version;
let snapshot = self.tabs[i].scene.document_for_save();
crate::io::save_owned_as_version_atomic(
snapshot,
@@ -1512,6 +1526,7 @@ impl OpenCADStudio {
if set_current_path {
self.tabs[i].current_path = Some(path.clone());
self.tabs[i].scene.document.version = version;
}
self.refresh_native_edit_guard_after_save(i, &path, path_changed, destination_lease);
self.tabs[i].dirty = false;