Compose reviewed attachments and State bends with saved Scenario

This commit is contained in:
2026-09-23 00:48:36 -07:00
parent 0b61771d07
commit a9b9c81eab
55 changed files with 5500 additions and 67 deletions
@@ -0,0 +1,27 @@
//! Read and validate a saved acceptance fixture without rewriting its source.
//! cargo run --locked -p oa-core --example attachment_snapshot -- input.arcadia output.json
use oa_core::{persistence, validate_candidate};
use std::{fs::OpenOptions, io::Write, path::Path};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<_> = std::env::args_os().skip(1).collect();
if args.len() != 2 {
return Err("Expected input source/JSON and a new output JSON path".into());
}
let project = persistence::load(Path::new(&args[0]))?;
validate_candidate(&project)?;
let bytes = serde_json::to_vec_pretty(&project)?;
let mut output = OpenOptions::new()
.write(true)
.create_new(true)
.open(&args[1])?;
output.write_all(&bytes)?;
output.write_all(b"\n")?;
output.sync_all()?;
println!(
"Validated {} objects and {} views; saved a complete Project snapshot",
project.identities().len(),
project.diagrams.len()
);
Ok(())
}
@@ -0,0 +1,101 @@
//! Read-only saved-State geometry evidence for a predeclared native bend trial.
//!
//! Usage:
//! state_bend_routing_snapshot INPUT.arcadia NEW_OUTPUT.json
//!
//! Loads and validates the complete Project, then independently projects/routes
//! every saved State view through core APIs. The complete Project permits exact
//! semantic and presentation comparison; derived geometry permits declaring a
//! segment and insertion position before native actions. No desktop command,
//! planner, gesture, or pin insertion helper is called. Input is never written;
//! output uses create_new and fails rather than overwriting an existing file.
//!
//! Limits: this shares production core routing, so it is not an independent
//! mathematical test of that router, nor evidence of UI picking/gesture success.
//! It does not generate expected mutations or adapt an oracle to observed edits.
//! The acceptance recipe must declare the intended segment/index/point and exact
//! Project mutation before UI execution, and bind this executable/source/input
//! and output hashes externally. Warning strings are diagnostic Debug output,
//! not a stable interchange schema. Missing/hidden/internal transitions have no
//! routed edge; their semantic records remain in the complete Project snapshot.
use oa_core::{persistence, projection, routing, validate_candidate};
use serde_json::json;
use std::{fs::OpenOptions, io::Write, path::Path};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<_> = std::env::args_os().skip(1).collect();
if args.len() != 2 {
return Err("Expected input source/JSON and a new output JSON path".into());
}
let project = persistence::load(Path::new(&args[0]))?;
validate_candidate(&project)?;
let mut views = Vec::new();
for (diagram_id, diagram) in &project.diagrams {
let Some(machine) = diagram.projection.state_machine() else {
continue;
};
let projected = projection::project_diagram(&project, diagram);
let routed = routing::route_diagram(&project, diagram, &projected);
let edges: Vec<_> = routed
.edges
.iter()
.map(|(edge_id, edge)| {
json!({
"edge": edge_id,
"id": edge.id,
"points": edge.points,
"pins": edge.pins,
"pin_fractions": edge.pin_fractions,
"custom_suspended": edge.custom_suspended,
"warnings": edge.warnings.iter().map(|warning| format!("{warning:?}")).collect::<Vec<_>>(),
"label": {
"text": edge.label.text,
"fraction": edge.label.fraction,
"anchor": edge.label.anchor,
"center": edge.label.center,
"bounds": {
"position": edge.label.bounds.position,
"size": edge.label.bounds.size
}
}
})
})
.collect();
views.push(json!({
"diagram": diagram_id,
"machine": machine,
"projected": projected,
"routed_bounds": {
"position": routed.bounds.position,
"size": routed.bounds.size
},
"routed_edges": edges
}));
}
// Preserve the canonical typed Project serialization (including f32
// formatting). Serializing it through Value directly promotes f32 to f64.
let project_json: serde_json::Value = serde_json::from_slice(&serde_json::to_vec(&project)?)?;
let snapshot = json!({
"schema": "state-bend-routing-snapshot/v1",
"project": project_json,
"state_views": views
});
// Finish all reading, validation, routing and serialization before creating
// the new evidence file. A failed load cannot leave an apparent snapshot.
let mut bytes = serde_json::to_vec_pretty(&snapshot)?;
bytes.push(b'\n');
let mut output = OpenOptions::new()
.write(true)
.create_new(true)
.open(&args[1])?;
output.write_all(&bytes)?;
output.sync_all()?;
println!(
"Validated {} objects and {} saved views; snapshotted {} State views and the complete Project",
project.identities().len(),
project.diagrams.len(),
views.len()
);
Ok(())
}