Compare commits

..
104 changed files with 37161 additions and 26 deletions
+7 -1
View File
@@ -5417,11 +5417,17 @@ impl App {
self.pan = iced::Vector::new(30., 30.);
return;
}
let geometry = oa_core::routing::route_diagram(
let mut geometry = oa_core::routing::route_diagram(
self.project(),
&self.project().diagrams[&self.active_diagram.unwrap()],
&view,
);
crate::diagram::apply_label_experiment(
self.project(),
&self.project().diagrams[&self.active_diagram.unwrap()],
&view,
&mut geometry,
);
let left = geometry.bounds.position.x;
let top = geometry.bounds.position.y;
let right = left + geometry.bounds.size.width;
+125 -15
View File
@@ -37,6 +37,9 @@ mod port_hit_tests;
#[path = "diagram/view_options_tests.rs"]
mod view_options_tests;
#[path = "diagram/label_layout_experiment.rs"]
mod label_layout_experiment;
#[path = "diagram/port_labels.rs"]
mod port_labels;
pub use port_labels::PortLabels;
@@ -88,8 +91,14 @@ pub struct State {
cache: RefCell<Option<CachedScene>>,
}
struct Scene {
label_layout: Option<label_layout_experiment::Layout>,
profile: label_layout_experiment::Profile,
font_version: Option<iced::advanced::graphics::text::Version>,
work: Option<Arc<crate::app::allocation_drag::Preview>>,
view: ProjectedView,
/// Core routing is the gesture baseline. Presentation-only wrapping must
/// never become a frozen label in a later core preview.
core_routed: Arc<RoutedView>,
routed: Arc<RoutedView>,
}
struct CachedScene {
@@ -514,6 +523,14 @@ impl DiagramCanvas<'_> {
}
}
fn scene(&self, state: &State) -> Arc<Scene> {
self.scene_with_profile(state, label_layout_experiment::profile())
}
fn scene_with_profile(
&self,
state: &State,
profile: label_layout_experiment::Profile,
) -> Arc<Scene> {
let font_version = label_layout_experiment::font_version(profile);
if let Some(preview) = self.work_preview()
&& state
.work
@@ -522,13 +539,32 @@ impl DiagramCanvas<'_> {
{
if let Some(scene) = state.work_cache.borrow().as_ref()
&& scene.work.as_ref().is_some_and(|p| Arc::ptr_eq(p, preview))
&& scene.profile == profile
&& scene.font_version == font_version
{
return scene.clone();
}
let core_routed = preview.routed.clone();
let mut routed = core_routed.clone();
let label_layout = if profile == label_layout_experiment::Profile::Baseline {
None
} else {
label_layout_experiment::apply(
preview.project(),
&preview.placement.diagram,
&preview.placement.view,
Arc::make_mut(&mut routed),
profile,
)
};
let scene = Arc::new(Scene {
label_layout,
profile,
font_version,
work: Some(preview.clone()),
view: preview.placement.view.clone(),
routed: preview.routed.clone(),
core_routed,
routed,
});
*state.work_cache.borrow_mut() = Some(scene.clone());
return scene;
@@ -554,6 +590,8 @@ impl DiagramCanvas<'_> {
&& cache.preview == preview
&& cache.route == route
&& cache.port == port
&& cache.scene.profile == profile
&& cache.scene.font_version == font_version
{
return cache.scene.clone();
}
@@ -563,7 +601,7 @@ impl DiagramCanvas<'_> {
self.project.diagrams[&self.diagram].clone()
};
let view = self.projected(&diagram);
let routed = Arc::new(
let core_routed = Arc::new(
if let Some(gesture) = state
.route_drag
.as_ref()
@@ -580,9 +618,25 @@ impl DiagramCanvas<'_> {
route_diagram(self.project, &diagram, &view)
},
);
let mut routed = core_routed.clone();
let label_layout = if profile == label_layout_experiment::Profile::Baseline {
None
} else {
label_layout_experiment::apply(
self.project,
&diagram,
&view,
Arc::make_mut(&mut routed),
profile,
)
};
let scene = Arc::new(Scene {
label_layout,
profile,
font_version,
work: None,
view,
core_routed,
routed,
});
*state.cache.borrow_mut() = Some(CachedScene {
@@ -595,7 +649,23 @@ impl DiagramCanvas<'_> {
scene
}
fn begin_route(&self, state: &mut State, world: Point, handle: Handle, route: EdgeRoute) {
let baseline = self.scene(state).routed.clone();
self.begin_route_with_profile(
state,
world,
handle,
route,
label_layout_experiment::profile(),
);
}
fn begin_route_with_profile(
&self,
state: &mut State,
world: Point,
handle: Handle,
route: EdgeRoute,
profile: label_layout_experiment::Profile,
) {
let baseline = self.scene_with_profile(state, profile).core_routed.clone();
state.route_drag = Some(Gesture {
context: self.context,
start: world,
@@ -1355,16 +1425,27 @@ impl canvas::Program<Message> for DiagramCanvas<'_> {
Size::new(label.bounds.size.width, label.bounds.size.height),
Color::WHITE,
);
f.fill_text(Text {
content: label.text.clone(),
position: point(label.center),
color: if active { style::TEAL } else { style::MUTED },
size: 13.into(),
align_x: iced::widget::text::Alignment::Center,
align_y: iced::alignment::Vertical::Center,
max_width: f32::INFINITY,
..Default::default()
});
if let Some(layout) = scene
.label_layout
.as_ref()
.filter(|_| edge.id == label_layout_experiment::edge_id())
{
for line in layout.canvas_lines(if active { style::TEAL } else { style::MUTED })
{
f.fill_text(line);
}
} else {
f.fill_text(Text {
content: label.text.clone(),
position: point(label.center),
color: if active { style::TEAL } else { style::MUTED },
size: 13.into(),
align_x: iced::widget::text::Alignment::Center,
align_y: iced::alignment::Vertical::Center,
max_width: f32::INFINITY,
..Default::default()
});
}
}
if let Some(relation) = project.relations.get(&edge.id) {
for end in routing::association_end_geometry(relation, routed) {
@@ -1943,7 +2024,30 @@ impl std::fmt::Display for ExportError {
}
impl std::error::Error for ExportError {}
/// Private opt-in trial adapter for consumers that already own routed geometry.
pub(crate) fn apply_label_experiment(
p: &Project,
diagram: &Diagram,
view: &ProjectedView,
routed: &mut RoutedView,
) {
let _ = label_layout_experiment::apply(
p,
diagram,
view,
routed,
label_layout_experiment::profile(),
);
}
pub fn export_svg(p: &Project, diagram: Id) -> Result<String, ExportError> {
export_svg_with_profile(p, diagram, label_layout_experiment::profile())
}
fn export_svg_with_profile(
p: &Project,
diagram: Id,
profile: label_layout_experiment::Profile,
) -> Result<String, ExportError> {
let d = p
.diagrams
.get(&diagram)
@@ -1952,7 +2056,8 @@ pub fn export_svg(p: &Project, diagram: Id) -> Result<String, ExportError> {
return Err(ExportError::UnsupportedScenario(diagram));
}
let view = project_view(p, diagram);
let routed = route_diagram(p, d, &view);
let mut routed = route_diagram(p, d, &view);
let label_layout = label_layout_experiment::apply(p, d, &view, &mut routed, profile);
let left = routed.bounds.position.x - 30.;
let top = routed.bounds.position.y - 30.;
let right = routed.bounds.position.x + routed.bounds.size.width + 30.;
@@ -2029,7 +2134,12 @@ pub fn export_svg(p: &Project, diagram: Id) -> Result<String, ExportError> {
.join(" ");
svg.push_str(&format!("<path data-edge=\"{}\" d=\"{path}\" fill=\"none\" stroke=\"#8999a9\" stroke-width=\"1.5\"{dashed}{arrow}><title>{}</title></path>",edge.id,escape(p.named(edge.id))));
let label = &route.label;
if !label.text.is_empty() {
if let Some(layout) = label_layout
.as_ref()
.filter(|_| edge.id == label_layout_experiment::edge_id())
{
svg.push_str(&layout.svg());
} else if !label.text.is_empty() {
svg.push_str(&format!("<rect x=\"{}\" y=\"{}\" width=\"{}\" height=\"{}\" fill=\"white\"/><text x=\"{}\" y=\"{}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-family=\"sans-serif\" font-size=\"13\" fill=\"#637487\">{}</text>",label.bounds.position.x,label.bounds.position.y,label.bounds.size.width,label.bounds.size.height,label.center.x,label.center.y,escape(&label.text)));
}
if let Some(relation) = p.relations.get(&edge.id) {
@@ -421,14 +421,19 @@ fn coincident_attachment_handles_honor_explicit_end_choice() {
EdgeEnd::Target,
)));
let c = canvas(&app, 1.);
let core_routed = Arc::new(route_diagram(
c.project,
&c.project.diagrams[&c.diagram],
&projection::project_view(c.project, c.diagram),
));
let mut scene = Scene {
label_layout: None,
profile: label_layout_experiment::Profile::Baseline,
font_version: None,
work: None,
view: projection::project_view(c.project, c.diagram),
routed: Arc::new(route_diagram(
c.project,
&c.project.diagrams[&c.diagram],
&projection::project_view(c.project, c.diagram),
)),
routed: core_routed.clone(),
core_routed,
};
let routed = Arc::make_mut(&mut scene.routed);
let edge = routed.edges.get_mut(&c.selected).unwrap();
@@ -0,0 +1,767 @@
//! Explicit, one-fixture visual experiment. No persisted formatting policy.
use super::*;
use iced::advanced::{graphics::text as graphics_text, text as shaped};
use shaped::Paragraph as _;
use std::sync::{Mutex, OnceLock};
const DIAGRAM: u128 = 0x00000000003840008000000000000001;
const EDGE: u128 = 0x63009b5f539e5914b630ec6b7fefb4d5;
pub(super) fn edge_id() -> Id {
Id::from_u128(EDGE)
}
const NAME: &str = "Technician service conversation";
const FONT_SIZE: f32 = 13.;
const ADVANCE: f32 = 16.;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(super) enum Profile {
#[default]
Baseline,
E,
F,
}
pub(super) fn profile() -> Profile {
static PROFILE: OnceLock<Profile> = OnceLock::new();
*PROFILE.get_or_init(
|| match std::env::var("ARCADIA_LABEL_EXPERIMENT").as_deref() {
Ok("E") => Profile::E,
Ok("F") => Profile::F,
_ => Profile::Baseline,
},
)
}
#[derive(Clone, Debug, PartialEq)]
struct MeasuredLine {
text: &'static str,
width: f32,
baseline: f32,
family: String,
}
#[derive(Clone, Debug, PartialEq)]
pub(super) struct Line {
pub text: &'static str,
pub position: Position,
pub baseline_y: f32,
pub width: f32,
pub family: String,
}
#[derive(Clone, Debug, PartialEq)]
pub(super) struct Layout {
pub canonical_text: String,
pub lines: Vec<Line>,
pub geometry: routing::EdgeLabelGeometry,
/// Authored moves retain their shape even outside the automatic guard.
pub clear: bool,
}
pub(super) fn font_version(profile: Profile) -> Option<graphics_text::Version> {
(profile != Profile::Baseline).then(|| {
graphics_text::font_system()
.read()
.expect("Read font system")
.version()
})
}
fn measured(profile: Profile) -> Option<Arc<Vec<MeasuredLine>>> {
type Entry = (Profile, graphics_text::Version, Arc<Vec<MeasuredLine>>);
static CACHE: OnceLock<Mutex<Vec<Entry>>> = OnceLock::new();
let version = font_version(profile)?;
let mut cache = CACHE.get_or_init(|| Mutex::new(Vec::new())).lock().ok()?;
if let Some((_, _, lines)) = cache
.iter()
.find(|(p, v, _)| *p == profile && *v == version)
{
return Some(lines.clone());
}
let strings: &[&'static str] = match profile {
Profile::Baseline => return None,
Profile::E => &["Technician service", "conversation"],
Profile::F => &["Technician", "service", "conversation"],
};
let mut lines = Vec::new();
for &content in strings {
let paragraph = graphics_text::Paragraph::with_text(shaped::Text {
content,
bounds: Size::INFINITE,
size: FONT_SIZE.into(),
line_height: shaped::LineHeight::Absolute(ADVANCE.into()),
font: iced::Font::default(),
align_x: shaped::Alignment::Left,
align_y: iced::alignment::Vertical::Top,
shaping: shaped::Shaping::Basic,
wrapping: shaped::Wrapping::None,
});
let mut runs = paragraph.buffer().layout_runs();
let run = runs.next()?;
if runs.next().is_some() || run.rtl || run.glyphs.is_empty() {
return None;
}
let width = paragraph.min_width();
if !width.is_finite() || width <= 0. || paragraph.min_height() > ADVANCE + 0.01 {
return None;
}
// This fixed English witness must resolve to one actual font face.
// Mixed fallback is not silently exported as a generic SVG font.
let font_id = run.glyphs.first()?.font_id;
if run.glyphs.iter().any(|glyph| glyph.font_id != font_id) {
return None;
}
let family = graphics_text::font_system()
.write()
.ok()?
.raw()
.db()
.face(font_id)?
.families
.first()?
.0
.clone();
lines.push(MeasuredLine {
text: content,
width,
baseline: run.line_y,
family,
});
}
let lines = Arc::new(lines);
cache.retain(|(_, v, _)| *v == version);
cache.push((profile, version, lines.clone()));
Some(lines)
}
/// Runs before any scene consumer; never edits the model or any routed points.
pub(super) fn apply(
project: &Project,
diagram: &Diagram,
view: &ProjectedView,
routed: &mut RoutedView,
profile: Profile,
) -> Option<Layout> {
if profile == Profile::Baseline || diagram.id.as_u128() != DIAGRAM {
return None;
}
let id = Id::from_u128(EDGE);
let edge = routed.edges.get(&id)?;
if edge.label.text != NAME
|| project.relations.get(&id)?.name != NAME
|| edge.custom_suspended
|| view
.nodes
.iter()
.any(|node| node.visual_parent.is_some() || node.collapsed)
{
return None;
}
let metrics = measured(profile)?;
let width = metrics.iter().map(|line| line.width).fold(0., f32::max) + 16.;
let height = 8. + ADVANCE * metrics.len() as f32;
let authored = diagram
.routes
.iter()
.find(|route| route.edge == id)
.and_then(|route| route.label.as_ref());
let fraction = authored.map_or(if profile == Profile::E { 0.5 } else { 0.55 }, |label| {
label.fraction
});
let anchor = routing::point_along_polyline(&edge.points, fraction)?;
let offset = authored.map_or(
Position {
x: if profile == Profile::E {
0.
} else {
18. + width / 2.
},
y: 0.,
},
|label| label.offset,
);
let center = Position {
x: anchor.x + offset.x,
y: anchor.y + offset.y,
};
let bounds = routing::RoutingBounds {
position: Position {
x: center.x - width / 2.,
y: center.y - height / 2.,
},
size: oa_core::Size { width, height },
};
let clear = guarded(project, view, routed, id, bounds, profile);
if authored.is_none() && !clear {
return None;
}
let geometry = routing::EdgeLabelGeometry {
text: edge.label.text.clone(),
fraction,
anchor,
center,
bounds,
};
let lines = metrics
.iter()
.enumerate()
.map(|(index, line)| {
let top = bounds.position.y + 4. + ADVANCE * index as f32;
Line {
text: line.text,
position: Position {
x: center.x - line.width / 2.,
y: top,
},
baseline_y: top + line.baseline,
width: line.width,
family: line.family.clone(),
}
})
.collect();
let layout = Layout {
canonical_text: edge.label.text.clone(),
lines,
geometry,
clear,
};
routed.edges.get_mut(&id)?.label = layout.geometry.clone();
// Retain conservative existing bounds; add authored placements outside them.
// The fixed automatic witnesses are inside the unchanged node extents.
let old = routed.bounds;
let left = old.position.x.min(bounds.position.x);
let top = old.position.y.min(bounds.position.y);
let right = (old.position.x + old.size.width).max(bounds.position.x + width);
let bottom = (old.position.y + old.size.height).max(bounds.position.y + height);
routed.bounds = routing::RoutingBounds {
position: Position { x: left, y: top },
size: oa_core::Size {
width: right - left,
height: bottom - top,
},
};
Some(layout)
}
fn rectangle(bounds: routing::RoutingBounds, padding: f32) -> Rectangle {
Rectangle {
x: bounds.position.x - padding,
y: bounds.position.y - padding,
width: bounds.size.width + 2. * padding,
height: bounds.size.height + 2. * padding,
}
}
fn overlap(a: Rectangle, b: Rectangle) -> bool {
a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y
}
fn crossing(bounds: Rectangle, span: &[Position]) -> bool {
let [a, b] = [span[0], span[1]];
if a.x == b.x {
a.x >= bounds.x
&& a.x <= bounds.x + bounds.width
&& a.y.min(b.y) <= bounds.y + bounds.height
&& a.y.max(b.y) >= bounds.y
} else if a.y == b.y {
a.y >= bounds.y
&& a.y <= bounds.y + bounds.height
&& a.x.min(b.x) <= bounds.x + bounds.width
&& a.x.max(b.x) >= bounds.x
} else {
// The bounded witness supports orthogonal geometry only.
true
}
}
fn guarded(
project: &Project,
view: &ProjectedView,
routed: &RoutedView,
id: Id,
bounds: routing::RoutingBounds,
profile: Profile,
) -> bool {
let label = rectangle(bounds, 0.);
if view.nodes.iter().any(|node| {
overlap(
label,
Rectangle {
x: node.position.x - 12.,
y: node.position.y - 12.,
width: node.size.width + 24.,
height: node.size.height + 24.,
},
)
}) {
return false;
}
let stroke_bounds = rectangle(bounds, 3.);
let mut own_crossings = Vec::new();
for edge in routed.edges.values() {
if edge.id != id
&& !edge.label.text.is_empty()
&& overlap(label, rectangle(edge.label.bounds, 4.))
{
return false;
}
if let Some(relation) = project.relations.get(&edge.id) {
for end in routing::association_end_geometry(relation, edge) {
if !end.label.text.is_empty() && overlap(label, rectangle(end.label.bounds, 4.)) {
return false;
}
}
}
for span in edge.points.windows(2) {
if crossing(stroke_bounds, span) {
if edge.id != id || profile == Profile::F {
return false;
}
own_crossings.push(span);
}
}
}
if profile == Profile::E {
let [span] = own_crossings.as_slice() else {
return false;
};
let [a, b] = [span[0], span[1]];
// One complete straight crossing, not a bend, lead, tip, or shared run.
(a.x == b.x
&& a.y.min(b.y) < stroke_bounds.y
&& a.y.max(b.y) > stroke_bounds.y + stroke_bounds.height)
|| (a.y == b.y
&& a.x.min(b.x) < stroke_bounds.x
&& a.x.max(b.x) > stroke_bounds.x + stroke_bounds.width)
} else {
true
}
}
impl Layout {
pub(super) fn canvas_lines(&self, color: Color) -> impl Iterator<Item = Text> + '_ {
self.lines.iter().map(move |line| Text {
content: line.text.into(),
position: point(line.position),
color,
size: FONT_SIZE.into(),
line_height: shaped::LineHeight::Absolute(ADVANCE.into()),
font: iced::Font::default(),
align_x: shaped::Alignment::Left,
align_y: iced::alignment::Vertical::Top,
shaping: shaped::Shaping::Basic,
max_width: f32::INFINITY,
})
}
pub(super) fn svg(&self) -> String {
let bounds = self.geometry.bounds;
let mut out = format!(
"<g data-label-experiment=\"wrapped\"><title>{}</title><rect x=\"{}\" y=\"{}\" width=\"{}\" height=\"{}\" fill=\"white\"/>",
escape(&self.canonical_text),
bounds.position.x,
bounds.position.y,
bounds.size.width,
bounds.size.height
);
for line in &self.lines {
out.push_str(&format!("<text x=\"{}\" y=\"{}\" font-family=\"{}\" font-size=\"13\" fill=\"#637487\">{}</text>",
line.position.x, line.baseline_y, escape(&line.family), escape(line.text)));
}
out.push_str("</g>");
out
}
}
#[cfg(test)]
mod tests {
use super::*;
fn fixture() -> (Project, Id) {
let p: Project = serde_json::from_slice(include_bytes!(
"../../../../harness/experiments/wrapped-label-20261001/fixture/eight-card.json"
))
.unwrap();
(p, Id::from_u128(DIAGRAM))
}
fn canvas(p: &Project, diagram: Id) -> DiagramCanvas<'_> {
DiagramCanvas {
selection: None,
allocation: None,
project: p,
view_index: None,
diagram,
selected: edge_id(),
navigation_focus: None,
zoom: 1.,
pan: Vector::ZERO,
context: Context {
document: p.id,
diagram,
revision: 0,
epoch: 0,
},
selected_bend: None,
selected_attachment: None,
editable: true,
placing: false,
connection: None,
}
}
#[test]
fn baseline_is_exact_and_wrapping_changes_only_target_derived_geometry() {
let (p, id) = fixture();
let before = serde_json::to_vec(&p).unwrap();
let diagram = &p.diagrams[&id];
let view = project_view(&p, id);
let baseline = route_diagram(&p, diagram, &view);
assert_eq!(baseline.edges.len(), 12);
let mut unchanged = baseline.clone();
assert!(apply(&p, diagram, &view, &mut unchanged, Profile::Baseline).is_none());
assert_eq!(unchanged, baseline);
for profile in [Profile::E, Profile::F] {
let mut routed = baseline.clone();
let layout =
apply(&p, diagram, &view, &mut routed, profile).expect("Measured witness must fit");
assert!(layout.clear);
assert_eq!(layout.canonical_text, NAME);
assert_eq!(
layout
.lines
.iter()
.map(|line| line.text)
.collect::<Vec<_>>()
.join(" "),
NAME
);
assert_eq!(routed.edges[&edge_id()].label.text, NAME);
for (id, old) in &baseline.edges {
assert_eq!(routed.edges[id].points, old.points);
if *id != edge_id() {
assert_eq!(&routed.edges[id], old);
}
}
let mut restored = routed.clone();
restored.edges.get_mut(&edge_id()).unwrap().label =
baseline.edges[&edge_id()].label.clone();
assert_eq!(
restored, baseline,
"No paths, ports, solver state, other labels or scene extents change"
);
assert_eq!(
layout.geometry.bounds.size.height,
8. + ADVANCE * layout.lines.len() as f32
);
let max_width = layout
.lines
.iter()
.map(|line| line.width)
.fold(0., f32::max);
assert_eq!(layout.geometry.bounds.size.width, max_width + 16.);
assert!(
layout
.lines
.iter()
.all(|line| !line.family.is_empty() && line.width > 0.)
);
if profile == Profile::F {
assert_eq!(layout.geometry.fraction, 0.55);
assert!(
(layout.geometry.bounds.position.x - layout.geometry.anchor.x - 18.).abs()
< 0.001
);
assert!(
layout.geometry.bounds.size.width < 114.5,
"Measured F loses own-is-closer margin"
);
} else {
assert_eq!(layout.geometry.fraction, 0.5);
assert_eq!(layout.geometry.center, layout.geometry.anchor);
}
println!(
"{profile:?}: bounds={:?}; lines={:?}",
layout.geometry.bounds, layout.lines
);
}
assert_eq!(serde_json::to_vec(&p).unwrap(), before);
}
#[test]
fn measured_backing_canvas_svg_picking_and_focus_share_geometry() {
let (p, id) = fixture();
let c = canvas(&p, id);
for profile in [Profile::E, Profile::F] {
let state = State::default();
let scene = c.scene_with_profile(&state, profile);
let layout = scene.label_layout.as_ref().unwrap();
let bounds = rectangle(layout.geometry.bounds, 0.);
let texts = layout.canvas_lines(Color::BLACK).collect::<Vec<_>>();
let svg = super::super::export_svg_with_profile(&p, id, profile).unwrap();
assert!(svg.contains(&layout.svg()));
assert_eq!(
crate::diagram_usage::edge_focus_bounds(&scene.routed.edges[&edge_id()]),
bounds
);
for (line, text) in layout.lines.iter().zip(texts) {
assert_eq!(text.content, line.text);
assert_eq!(text.position, point(line.position));
assert_eq!(text.size.0, FONT_SIZE);
assert_eq!(
text.line_height,
shaped::LineHeight::Absolute(ADVANCE.into())
);
assert!(line.position.x >= bounds.x + 7.99);
assert!(line.position.x + line.width <= bounds.x + bounds.width - 7.99);
assert_eq!(
c.hit_label(
&scene.routed,
Point::new(line.position.x + line.width / 2., line.position.y + 8.)
),
Some(edge_id())
);
assert!(svg.contains(&format!(
"x=\"{}\" y=\"{}\" font-family=\"{}\"",
line.position.x,
line.baseline_y,
escape(&line.family)
)));
}
assert_eq!(
c.hit_label(&scene.routed, Point::new(bounds.x + 1., bounds.y + 1.)),
Some(edge_id())
);
}
}
#[test]
fn automatic_guard_refuses_foreign_coincident_stroke_and_card() {
let (p, id) = fixture();
let diagram = &p.diagrams[&id];
let view = project_view(&p, id);
let baseline = route_diagram(&p, diagram, &view);
for profile in [Profile::E, Profile::F] {
let mut valid = baseline.clone();
let layout = apply(&p, diagram, &view, &mut valid, profile).unwrap();
let mut blocked = baseline.clone();
let foreign = blocked
.edges
.keys()
.copied()
.find(|id| *id != edge_id())
.unwrap();
let bounds = layout.geometry.bounds;
blocked.edges.get_mut(&foreign).unwrap().points = vec![
Position {
x: layout.geometry.center.x,
y: bounds.position.y - 40.,
},
Position {
x: layout.geometry.center.x,
y: bounds.position.y + bounds.size.height + 40.,
},
];
let snapshot = blocked.clone();
assert!(apply(&p, diagram, &view, &mut blocked, profile).is_none());
assert_eq!(blocked, snapshot);
let mut occluded_view = view.clone();
occluded_view.nodes[0].position = bounds.position;
let mut routed = baseline.clone();
assert!(apply(&p, diagram, &occluded_view, &mut routed, profile).is_none());
assert_eq!(routed, baseline);
}
}
#[test]
fn authored_fraction_offset_keep_shape_even_during_conflicting_move() {
let (mut p, id) = fixture();
let view = project_view(&p, id);
for profile in [Profile::E, Profile::F] {
let original = route_diagram(&p, &p.diagrams[&id], &view);
let mut automatic = original.clone();
let initial = apply(&p, &p.diagrams[&id], &view, &mut automatic, profile).unwrap();
let offset = Position {
x: initial.geometry.center.x - initial.geometry.anchor.x + 17.,
y: -9.,
};
p.diagrams.get_mut(&id).unwrap().routes = vec![EdgeRoute {
edge: edge_id(),
source_attachment: None,
target_attachment: None,
waypoints: vec![],
label: Some(EdgeLabel {
fraction: initial.geometry.fraction,
offset,
}),
}];
let c = canvas(&p, id);
let state = State::default();
let scene = c.scene_with_profile(&state, profile);
let moved = scene.label_layout.as_ref().unwrap();
assert_eq!(
moved.lines.iter().map(|line| line.text).collect::<Vec<_>>(),
initial
.lines
.iter()
.map(|line| line.text)
.collect::<Vec<_>>()
);
assert_eq!(moved.geometry.fraction, initial.geometry.fraction);
assert!((moved.geometry.center.x - moved.geometry.anchor.x - offset.x).abs() < 0.001);
assert!((moved.geometry.center.y - moved.geometry.anchor.y - offset.y).abs() < 0.001);
let mut preview = State {
context: Some(c.context),
..State::default()
};
preview.route_drag = Some(Gesture {
context: c.context,
start: point(moved.geometry.center),
handle: Handle::Label { original: offset },
route: p.diagrams[&id].routes[0].clone(),
changed: true,
baseline: scene.core_routed.clone(),
});
preview
.route_drag
.as_mut()
.unwrap()
.route
.label
.as_mut()
.unwrap()
.offset
.x += 100.;
let dragged = c.scene_with_profile(&preview, profile);
let layout = dragged.label_layout.as_ref().unwrap();
assert_eq!(layout.lines.len(), moved.lines.len());
assert!(
(layout.geometry.center.x - layout.geometry.anchor.x - offset.x - 100.).abs()
< 0.001
);
for (id, edge) in &scene.routed.edges {
assert_eq!(dragged.routed.edges[id].points, edge.points);
}
p.diagrams.get_mut(&id).unwrap().routes.clear();
}
}
#[test]
fn different_edge_preview_guard_rejection_restores_complete_core_geometry() {
// Exercise the actual gesture capture and core preview, with a pure
// explicit profile. Moving another label onto the wrapped target must
// reject wrapping, leaving the full original one-line target geometry.
// All twelve point arrays and every other frozen label remain exact.
let (p, id) = fixture();
let view = project_view(&p, id);
let core = route_diagram(&p, &p.diagrams[&id], &view);
let foreign = core
.edges
.values()
.find(|edge| edge.id != edge_id() && !edge.label.text.is_empty())
.unwrap();
let original_offset = Position {
x: foreign.label.center.x - foreign.label.anchor.x,
y: foreign.label.center.y - foreign.label.anchor.y,
};
let c = DiagramCanvas {
selected: foreign.id,
..canvas(&p, id)
};
for profile in [Profile::E, Profile::F] {
let mut state = State {
context: Some(c.context),
..State::default()
};
let initial = c.scene_with_profile(&state, profile);
let target = initial
.label_layout
.as_ref()
.expect("Initial witness must wrap");
c.begin_route_with_profile(
&mut state,
point(foreign.label.center),
Handle::Label {
original: original_offset,
},
EdgeRoute {
edge: foreign.id,
source_attachment: None,
target_attachment: None,
waypoints: vec![],
label: Some(EdgeLabel {
fraction: foreign.label.fraction,
offset: original_offset,
}),
},
profile,
);
state
.route_drag
.as_mut()
.unwrap()
.move_to(point(target.geometry.center), 1.);
let diagram = c.preview_diagram(&state);
let expected = routing::route_edge_preview(&p, &diagram, &view, &core, foreign.id);
let mut guard_probe = expected.clone();
assert!(
apply(&p, &diagram, &view, &mut guard_probe, profile).is_none(),
"Foreign label now overlaps target: wrapping must be refused"
);
assert_eq!(guard_probe, expected);
let actual = c.scene_with_profile(&state, profile);
assert!(actual.label_layout.is_none());
for (edge, before) in &core.edges {
assert_eq!(
actual.routed.edges[edge].points, before.points,
"Label drag must not reroute"
);
if *edge != foreign.id && *edge != edge_id() {
assert_eq!(
actual.routed.edges[edge].label, before.label,
"Other labels remain frozen"
);
}
}
assert_eq!(
actual.routed.edges[&edge_id()].label,
core.edges[&edge_id()].label,
"No Layout means original complete one-line target geometry, never stale wrapped hit bounds"
);
assert_eq!(
*actual.routed, expected,
"Fallback is the complete core preview result"
);
}
}
#[test]
fn scene_and_measurement_cache_reuse_and_geometry_invalidation() {
let (p, id) = fixture();
let c = canvas(&p, id);
let mut state = State::default();
let first = c.scene_with_profile(&state, Profile::F);
state.pointer = Some(Point::new(100., 200.));
let changed_camera = DiagramCanvas {
pan: Vector::new(40., 30.),
zoom: 0.5,
selected: p.id,
..c
};
assert!(Arc::ptr_eq(
&first,
&changed_camera.scene_with_profile(&state, Profile::F)
));
assert!(Arc::ptr_eq(
&measured(Profile::F).unwrap(),
&measured(Profile::F).unwrap()
));
let other_profile = c.scene_with_profile(&state, Profile::E);
assert!(!Arc::ptr_eq(&first, &other_profile));
let next_revision = DiagramCanvas {
context: Context {
revision: 1,
..c.context
},
..c
};
assert!(!Arc::ptr_eq(
&other_profile,
&next_revision.scene_with_profile(&state, Profile::E)
));
let plain = c.scene_with_profile(&state, Profile::Baseline);
assert!(plain.label_layout.is_none());
assert!(Arc::ptr_eq(&plain.core_routed, &plain.routed));
assert_eq!(
*plain.routed,
route_diagram(&p, &p.diagrams[&id], &plain.view)
);
}
}
+2 -1
View File
@@ -6,7 +6,8 @@ impl DiagramCanvas<'_> {
pub(crate) fn work_dirty_point(&self, bounds: Rectangle, screen: Point) -> bool {
let diagram = &self.project.diagrams[&self.diagram];
let view = self.projected(diagram);
let routed = routing::route_diagram(self.project, diagram, &view);
let mut routed = routing::route_diagram(self.project, diagram, &view);
super::apply_label_experiment(self.project, diagram, &view, &mut routed);
self.work_dirty_press(
&view,
&routed,
+12 -4
View File
@@ -327,7 +327,11 @@ pub(crate) fn saved_usages_for(p: &Project, subject: Id, only_diagram: Option<Id
"state machine view"
}
.into(),
bounds: routed_bounds(routing::route_diagram(p, diagram, &view).bounds),
bounds: {
let mut routed = routing::route_diagram(p, diagram, &view);
crate::diagram::apply_label_experiment(p, diagram, &view, &mut routed);
routed_bounds(routed.bounds)
},
});
}
for node in &view.nodes {
@@ -407,9 +411,13 @@ pub(crate) fn saved_usages_for(p: &Project, subject: Id, only_diagram: Option<Id
}
}
if view.edges.iter().any(|edge| edge.id == subject)
&& let Some(edge) = routing::route_diagram(p, diagram, &view)
.edges
.get(&subject)
&& let Some(edge) = {
let mut routed = routing::route_diagram(p, diagram, &view);
crate::diagram::apply_label_experiment(p, diagram, &view, &mut routed);
routed
}
.edges
.get(&subject)
{
usages.push(Usage {
subject,
+23
View File
@@ -1,5 +1,28 @@
# Architectural and product decisions
## Measured label wrapping remains experimental — 2026-10-01
Preserve the isolated E/F prototypes and their
[validation, locked readings and conservation oracles](experiments/wrapped-label-20261001/validation.md)
without promoting either placement rule. E centers two measured lines on the
own stroke; F offsets three lines beside it. Both reduce backing width using
actual Iced shaping and conserve canonical model data and route geometry. F's
first reader still misidentified two exchanges; both readers retained a plausible
wrong conversation ownership. The experiments therefore do not meet dependable
association at Fit, despite correct E endpoint guesses. Separate readers and a
single fixture do not establish causal superiority or general usability.
Keep raw routing distinct from derived presentation during gesture previews:
the adversarial different-edge test exposed stale wrapped bounds after guard
refusal, fixed by retaining the original core RoutedView. This is reusable
architecture evidence, not acceptance of private fixture-specific layout code.
Saved fraction/offset survive under F, but ordinary reopening derives one line;
external profiles cannot provide a production formatting contract. A general
format/layout proposal requires explicit persistence semantics, shared consumer
bounds, native representative workflows and glyph/performance evidence. Further
work should address view scale and ambiguous stroke ownership rather than tune
this same label scene until it looks successful.
## Private source composition decision — 2026-09-23
Adopt the opaque validated original-span rename batch as the next private
+14
View File
@@ -1,3 +1,17 @@
# Isolated measured-label experiment checkpoint — 2026-10-01 PDT
This branch adds the private E/F label experiment at
`d0896ced75fea73bcda6bd14f259a34503840704` to the compact Help foundation below.
[Validation and retained raw evidence](experiments/wrapped-label-20261001/validation.md)
cover actual measured Iced layout, 126 focused tests, native first readings,
selection/edit/Undo/Redo, exact exports and saved-F reopening. An independent
review verified complete Project conservation and unchanged paths/drawing bytes.
Neither candidate established reliable first-reading label ownership, and
ordinary reopening loses the externally selected wrapping. Both remain excluded
from production and releases. This branch is experimental evidence, not an
integrated product checkpoint or complete OA/SA acceptance. Live #38 ownership
and next actions remain in Gitea.
# Verified Windows source checkpoint — 2026-10-01 PDT
This branch combines the released integrated foundation
@@ -0,0 +1,4 @@
fixture/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
source-review-initial.md -text whitespace=-blank-at-eof,cr-at-eol
evidence/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
final-review.md -text whitespace=cr-at-eol
@@ -0,0 +1,29 @@
# E/F wrapped-label experiment evidence
Neither profile is promoted. Start with [validation and limitations](validation.md),
then the locked [E](evidence/native-E/first-reading.md) and
[F](evidence/native-F/first-reading.md) readings. Source gates and artifact
conservation passed; dependable first-reading ownership did not.
Run from the repository root with Python 3, without launching the application:
```powershell
python harness/experiments/wrapped-label-20261001/evidence/verify.py
python harness/experiments/wrapped-label-20261001/evidence/verify.py --index
python harness/experiments/wrapped-label-20261001/evidence/verify.py --source
```
Default verification uses only included packet bytes. `--index` additionally
requires this packet staged in Git; `--source` reads the pinned d089 source
objects from Git. The helper checks the inventory, pristine E/F SVG conservation,
full exported Project delta, reopened-F logical coordinates and process receipts.
It does not render SVG or replay native interactions. Original checkers and
launchers are preserved byte-for-byte under [evidence/scripts](evidence/scripts/);
some retain historical local paths, so use the wrapper for portable offline checks.
The [earlier independent review](evidence/reviews/wrapped-final-evidence-review.md)
predates fresh reopen tests. The [later saved-F review](evidence/reviews/wrapped-reopen-svg-review.md)
covers their model/export files; [parent observations](evidence/reviews/wrapped-native-observation.md)
describe the actual native events and limitations. Profile selection is external
and not persisted. The ordinary Baseline reopen showed one line; it is not a
claim of ordinary wrapping parity or a source-save round trip.
@@ -0,0 +1,70 @@
# Issue 38: bounded label-generator alternatives
Local-only feasibility study; root owns synthesis. Source baseline is the original saved full twelve-relation geometry in `.local/native-reading/manual/geometry-before.json`, not a simplified view. The existing-generator feasibility result is separately confirmed by the Rust probe at source `70cf` and published in packet `45bfb63b`; this note does not rerun or replace that evidence. Candidate B's fresh native evaluation is still independent and its outcome is not assumed here.
Only this report was written. No production/probe changes, compiler, native GUI, or Gitea actions. All alternative results below are read-only JavaScript double-precision rectangle/orthogonal-segment arithmetic over the saved JSON. They are feasible geometric witnesses, not fresh reading passes or production implementation recommendations.
## Fixed requirements and arithmetic
Keep all twelve paths, cards, semantic identities/endpoints/ports, other displayed labels, and authored fields exact. Change only the automatic conversation label's derived position and, for explicitly identified alternatives, its visual line wrapping. The semantic string remains `Technician service conversation` throughout. The conversation ID is `63009b5f-539e-5914-b630-ec6b7fefb4d5`.
Use full flat card rectangles inflated by 12, other nonempty label rectangles inflated by 4, and candidate label rectangle inflated by 3 for stroke intersection checks. Own/foreign clearances below are shortest distances from the **uninflated** label rectangle to the respective routes. Foreign routes retain semantic identity, including coincident portions. These conventions match the bounded probe's geometry assumptions; they do not establish a perceptual threshold.
The original label is 233 x 24, centered (1296.5,274.5). It intersects foreign allocation `sa_repair_allocation` at x1312.5, y179..325. Its own vertical route is x1162, y89.5..316.5. Other foreign verticals at x1065 and x1071 bound the space to its left. The foreign allocation also runs horizontally at y325, which matters for taller labels.
For multiline witnesses only, assume unchanged font size 13, line advance 16, and padding consistent with the existing 24-high one-line box: height = 8 + 16 * line_count; width = 16 + 7 * longest_line_character_count. These are explicit experimental dimensions. Production typography must use actual rendered line metrics and then recheck geometry; replacing exact semantic text with a shortened name is excluded.
## Actual witnesses
Every row below has **zero node, foreign-stroke, and other-label collisions** under the declared margins. All boxes stay inside the original whole-scene node extents, so their union cannot enlarge Fit bounds. Whole-scene Fit would remain geometrically unchanged under these fixed paths and cards.
| Alternative | Center; size | Own stroke intersections | Own / foreign clearance | Center displacement from baseline |
| --- | --- | ---: | ---: | ---: |
| D. Dynamic single-line corridor placement, permit own backing | (1191.75,274.5); 233 x 24 | 1 | 0 / 4.25 | 104.75 |
| E. Two lines centered on own route, permit own backing | (1162,274.5); 142 x 40 | 1 | 0 / 20 | 134.5 |
| F. Three lines beside own route, keep every stroke clear | (1230,254.2); 100 x 56 | 0 | 18 / 32.5 | about 69.53 |
D bounds: x1075.25..1308.25, y262.5..286.5. Own vertical x1162 passes through the box. The nearest foreign lines are x1071 and x1312.5, 4.25 units away on either side. A minimum-movement variant centered at (1193,274.5) moves 103.5 units but leaves only 3 units to the allocation. D's balanced witness maximizes horizontal clearance within this narrow corridor; its 4.25-unit clearance is only about **2.2 pixels at Fit**. Collision freedom therefore does not imply good association or legibility. A grid enumeration at 0.5-unit steps over x950..1470/y180..340 found the minimum-movement variant above, but this bounded grid is not a global optimum proof and is not a suggested production algorithm.
E wraps as `Technician service` / `conversation`; longest line is 18 characters, yielding width 142. Bounds are x1091..1233, y254.5..294.5. Own stroke is centered beneath the opaque backing; the closest foreign stroke is x1071, 20 units away. The box intentionally hides a 40-unit own-route interval, about 20.6 screen pixels at Fit. This may create clear line-label association through aligned entering/exiting segments, or may make the path look broken. Geometry cannot decide which. It moves farther than D but gains substantial foreign clearance and uses only two text lines.
F wraps as `Technician` / `service` / `conversation`; longest line is 12 characters, yielding width 100. Bounds are x1180..1280, y226.2..282.2. Its own anchor can use the **already-existing fraction .55**, which is approximately (1162,254.2); the existing right-offset formula for the narrower box gives +68. The label is 18 units right of its own vertical path, 32.5 units left of the allocation vertical, and 42.8 above the allocation horizontal. It adds no strokes and obscures no route. It does increase label height from 24 to 56 (about 12.4 to 28.9 screen pixels at Fit), at the same small font size. The geometric own-versus-foreign clearance margin is 14.5 units, about 7.5 pixels; it is an evaluator observation, not a validated scoring threshold.
F at the original .5 fraction is also collision-free: center (1230,274.5), same width/height, displacement 66.5. However, its bottom lies 22.5 units above the allocation horizontal, leaving only 4.5 units of own-versus-foreign distance advantage. Thus a first-zero-collision chooser can still pick a perceptually weaker candidate even after wrapping. The .55 witness improves that geometry without introducing a new fraction generator.
## Materially different definitions
**D: dynamic free-interval generation, unchanged text shape, changed own-stroke objective.** For a bounded set of existing route fractions, take candidate label y positions from the existing offsets. Subtract forbidden horizontal center intervals induced by padded nodes, other labels, and foreign strokes that meet the candidate's vertical extent. Generate at most the nearest feasible center to the old center plus an interval midpoint; do not raster-scan the canvas. Permit covering the owning stroke only where one unique straight own segment enters and exits opposite box sides and no foreign semantic owner occupies that segment. This is a new generator and a new collision objective, not a tie-break patch. Keep node/other-label/foreign collisions hard exclusions. Use limited candidates and charged comparisons before considering any reusable spatial index.
D demonstrates that a single line can avoid the wrong allocation under a changed objective, but its narrow foreign margins weaken it as the next visual experiment. Reject the tempting minimum-movement variant as a preferred witness: it optimizes movement by hugging the wrong stroke at the collision margin. Also reject unconstrained own-stroke occlusion at turns or shared runs.
**E: bounded wrapping plus on-route placement.** Derive one-, two-, and three-line layouts from legal word boundaries, preserve the complete string, and measure them at the same font size. Include placement centered on a unique straight own segment as an explicit alternative. Keep all foreign strokes/cards/other labels excluded while permitting the defined own-route backing interval. Limit line count and candidate count; if a long unbreakable token cannot fit, fail this fallback rather than shrink text indefinitely or change the name. E is the smallest actual witness with materially comfortable foreign clearance and only two lines, but its intentional route interruption needs direct comparison.
**F: bounded wrapping with the existing side-placement family and improved ownership comparison.** For each permitted line layout, recompute its real width/height, then apply existing fractions and side-offset construction. Maintain exclusion of **all** strokes, including own strokes. Among feasible candidates, compare own/foreign association with displacement and wrapping cost; report these dimensions separately before accepting any scalar weighting. Prefer one-line layouts only when they also meet the experiment's association gate, not merely because they are collision-free. F is the strongest current geometric comparison if B fails: it keeps all routes visibly continuous, moves less than D/E, and has a clear own/foreign separation margin. Its tradeoff is a taller and less quickly scanned name. It requires matching multiline layout, hit/backing bounds, and SVG output; simply inserting a newline in the existing string/size formula is incorrect.
No one of D/E/F is accepted for production. A useful next native comparison would be **E versus F versus baseline**, using these frozen witnesses, after B's current result. D need not consume a native run unless the narrower alternatives prove unreadable or typography invalidates their feasibility.
## Rejected or deferred alternatives
- **Same fixed candidates with another weight:** already falsified for collision-preserving A. The new widths/objectives above are explicit departures.
- **A long horizontal-own-segment preference alone:** own horizontal segments are 18, 143, 18 units. No segment accommodates the original 233-wide label. The 143-unit segment is crossed by foreign corridors at 1065/1071 and sits next to the system/repair cards. Merely moving the old label above that segment reproduces foreign/corner crowding. It can remain one candidate family, not a solution claim.
- **Move the original full-width box just outside the allocation and add a leader:** local rightward placements require the leader to cross that foreign vertical; guarded B would properly suppress it. Large exterior placements add displacement and potential Fit costs. A short guard cannot repair arbitrary distant placement.
- **Minimal movement as the first objective:** D's 3-unit foreign margin is the counterexample. Use movement to break ties only after meaningful ownership/clearance evidence.
- **Shorter semantic text, hidden relations, or smaller font:** these evade the intended full-scene reading task. Multiline display must preserve the entire name and font size.
- **Global packing/rerouting or a new general layout API:** not justified by three concrete label-only witnesses. Keep exploratory geometry separate until a reader establishes an improvement.
## Policy boundaries before any whole-scene implementation
These witnesses concern one automatic label in an unnested scene. A whole-scene policy must treat authored label offsets/fractions as authoritative and must not silently wrap or move authored labels as collateral changes. All other automatic-label settlement must be inventoried, not hidden behind identical serialized fields.
Include association-end text and every visible label as obstacles. Nested/folded views require their actual label/card/header visibility rules; the flat-node arithmetic must reject or separately handle them, not silently reuse traversable route obstacles for text. Shared/partially coincident paths retain all semantic owners; an apparently own-only segment with another owner is foreign for the guard. Segment indices are zero-based windows over original points, independent of collision deduplication.
Separate fixed-path label-order permutations from full UUID-remapped reroutes, because the latter changes the evidence under the label. Keep existing gesture baseline caching; do not recompute wrap/interval packing on unchanged pointer hover. Charge extra interval/candidate scoring work and bound it on geometry rebuilds. A target label drag must commit once, preserve authored shape/anchor semantics, and remain stable across Undo/Redo, reopen, and canvas/SVG rendering. A layout policy depending continuously on zoom can cause label jumps; use zoom for evaluation first, not an automatic per-frame generator.
## Explicit gates and stop rule
Before implementation, render the measured typography for E/F in an isolated experiment with frozen scene/viewport. Recheck the reported bounds and all collisions. Reject a witness if actual text exceeds the assumed box, any node/foreign/other-label collision appears, endpoints disappear from Fit, or any semantic/path/authored state changes.
Then use a reader without prior endpoint exposure: first unselected path and port-owner identification, no Inspector answer beforehand. Require the conversation's original wrong allocation association to disappear without new wrong turns on Request/Report or the port mappings; record font readability and multiline scan cost separately. For E, explicitly ask whether the path remains traceable across the label backing; for F, whether stacked words associate with the left conversation route rather than the lower/right allocation. Any need to explain the intended attachment first is a failure of this experiment, not a pass after coaching.
A positive isolated result permits considering a small production rule and its regression/latency tests; it does not close the broader full-view shared-corridor readability issue. If E/F both fail first reading, stop tuning weights around this fixture and record the failed hypotheses before choosing a different approach.
@@ -0,0 +1,108 @@
# E/F measured-label experiment implementation handoff
Local uncommitted implementation against `6ea7518e7be5b5f17d5fbc5d667da8b388058af4`.
No compiler, GUI, Gitea, commit or push run by this worker. Root owns all gates.
`rustfmt --edition 2024 --config skip_children=true` completed for the six
explicitly owned/authorized Rust files. This establishes formatting only.
## Changed implementation
- New private `crates/oa-desktop/src/diagram/label_layout_experiment.rs` contains
read-once external E/F/Baseline profile, one-target identity guards, measured
typography cache, shared Layout, fixed placements, collision guards, Canvas
line records, explicit SVG line export and five focused tests.
- `diagram.rs`: Scene stores the shared Layout, profile and font-system version;
both ordinary and work-preview scenes apply it before geometry consumers.
Existing cache additionally keys profile/font version. Drawing and SVG consume
the same ordered line positions. Derived target label bounds feed existing hit
and route-drag start code. The private adapter applies to already-routed data.
- Parent-authorized thin calls: `app.rs` Fit, `diagram_usage.rs` whole/edge bounds,
and `diagram/work_drag.rs` dirty-input shield. No second routing call introduced.
- `diagram/attachment_tests.rs`: existing manual Scene literal gains default fields.
- Parent supplied the pinned `harness/experiments/wrapped-label-20261001/fixture/eight-card.json`;
it is referenced with include_bytes, not rewritten by this worker.
No changes to core, schema, source formats, canonical label.text/Name, Project,
port/card/path state, or B's cue. The fixture and diagram are identified exactly;
other labels return untouched. Baseline returns the complete routed value unchanged.
Automatic guard failure leaves baseline rather than painting an invalid narrower
shape over an old hitbox. Nested/collapsed scenes are excluded from this witness.
## Measurement and scope
Pinned Iced 0.14 graphics Paragraph is accessible through
`iced::advanced::graphics::text::Paragraph`; the same implementation is used by
Canvas Text. Each fixed line is shaped at font 13 with absolute line height 16,
Basic ASCII shaping and no wrap. Width comes from Paragraph min_width; baseline
and resolved face family come from actual cosmic-text runs. A single face per
line is required; mixed fallback or unsupported metrics reject the trial.
Cached measurements are keyed by profile and Iced font-system version; ordinary
hover, selection and camera changes reuse the entire Scene. No character-count
width heuristic is used.
SVG writes explicit per-line x and shaped baseline y with the resolved family,
not browser wrapping or generic sans-serif. It does not embed the font: native
export rendering and font availability on another machine remain a validation
boundary, not proven glyph parity. Tests compare generated text/geometry records,
not raster output or browser appearance.
Automatic E permits exactly one straight own segment crossing both padded sides;
all foreign strokes, cards and labels (including association-end labels) are
excluded. Automatic F clears all strokes. Guards use measured boxes, card margin
12, other-label margin 4 and stroke margin 3. Fixed F's own-is-closer width margin
is explicitly asserted by its fixture test rather than accepted as a general
placement scoring rule.
Authored target labels keep the externally selected line shape and honor actual
fraction/offset. They deliberately retain that shape when a user moves into a
collision, reporting Layout.clear=false; silently unwrapping/resetting would
violate the trial boundary. Conservative whole-scene bounds retain prior bounds
and include moved authored boxes. No ordinary save/reopen formatting contract,
general typesetter, placement winner, or production policy is claimed.
## Parent gates
Suggested targeted test selector:
```powershell
cargo test --locked -p oa-desktop label_layout_experiment -- --test-threads=1 --nocapture
```
Five tests cover full unchanged baseline and all 12 point arrays/other labels,
actual measured dimensions and guard result, matching Canvas/SVG/picking/focus
geometry records, foreign-stroke/card rejection without mutation, authored
fraction/offset/shape retention during real route-preview construction, and
actual Scene/measurement cache reuse plus profile/revision invalidation.
The first test prints measured line/family/bounds records for parent capture.
Compilation, strict lint, fixture guard feasibility on this font installation,
native rendering, actual edit lifecycle, performance, independent fresh-reader
trial, and integration/publication remain pending. Preserve first failures and
revise at the responsible layer; no successful test/native outcome is asserted.
## Captured failure and responsible preview-baseline correction
Parent observed initial source `d8ccd6ed49adac799c02a3c52cb9e431214a4963`
fail compilation because the test EdgeRoute literal omitted its attachment fields.
The first compiler log remains `.local/wrapped-label-tests-first.log`.
At regression source `ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d`, parent observed
five tests passing and the added different-edge preview regression failing:
guard rejection cleared Layout, but target geometry retained wrapped E bounds
(119.174805 x 40) instead of core one-line bounds (233 x 24). Parent's measured
F was 89.18213 x 56; both used Segoe UI. These are parent-reported executed
results, not worker-executed gates. Failed transition log is retained at
`.local/wrapped-label-regression-first.log`.
Correction, now local and frozen for parent compilation: Scene retains a
`core_routed` Arc before the experiment modifies derived presentation. Both
ordinary and allocation-work-preview constructors store that raw Arc; Baseline
shares it with `routed` without copying. `begin_route_with_profile` captures
`core_routed`, so core preview freezes raw one-line labels and a refused wrapper
leaves a complete valid fallback. No guards, measured dimensions, route/path
scoring or failing-regression assertions were changed. The existing authored
preview test setup now uses the same raw baseline contract; existing cache test
also checks Baseline's Arc identity. The one manual Scene literal was updated.
No additional compiler/native execution by this worker. Explicit-file rustfmt
and git diff --check passed. Parent rerun of all six tests and broader gates is
pending at this correction checkpoint.
@@ -0,0 +1,59 @@
# Independent adversarial review: next #38 label experiment
Recommend a bounded measured F prototype, with E retained as the materially different comparison. Defer D. F has enough geometric advantage to justify a real Rust/Iced test, but neither F nor E is an accepted remedy. Candidate B's source correctness and passing gates do not reverse its unsuccessful fresh-reading result: correct participants with a plausible foreign-allocation alternative is not reliable label ownership.
Read the alternatives note, immutable full baseline geometry/Project, prior native/cue caveats, and current derived-label, picking, drag and SVG consumers. Independently recomputed rectangle/orthogonal-segment clearances and card/other-label exclusions from actual baseline data. No broad external research was needed to distinguish these local hypotheses. No code, compiler, GUI, Gitea or commit action; this report is the only new artifact.
## Comparison and recommendation
Independent arithmetic reproduces the witnesses: D own/foreign clearance 0/4.25, E 0/20, F 18/32.5. None overlaps padded visible cards or the other two nonempty labels. The full scene retains eight cards, twelve semantic routes and the independently recorded 37 distinct stroke geometries. These are backing-box distances, not measured glyph or perceptual clearances.
D keeps one-line scanning but requires a new free-interval generator and hides its own route while leaving only about 2.2 pixels to foreign routes at Fit. That is weak separation for considerable algorithmic change. It should not consume the next native trial unless measured typography invalidates both narrower alternatives.
E has only two lines and directly aligns its label with a uniquely owned straight segment. This can be an effective conventional line-label cue, but it intentionally obscures about 40 world units of the path and moves farther. A reader must reconnect the entering/exiting stroke across text; in this already congested scene that may recreate a branch ambiguity. E is a useful comparator precisely because it tests association by on-line interruption rather than proximity.
F preserves every visible route, has the least displacement, separates the foreign stroke from the label backing, and uses an existing route fraction/side-placement family. Unlike B it removes the foreign stroke through the text rather than adding a faint secondary cue. This is a meaningful improvement in the hypothesis, not merely another weight. The cost is three-line scanning at the same tiny Fit font. F may still look associated with the nearby allocation, or require zoom for words. The three-line box is only about 29 pixels high at Fit; each character remains about 6.7 pixels at nominal font size 13. Neither geometry nor extra height establishes legibility.
Prototype the frozen measured F .55 witness first, retaining E .5 for a separate fresh comparison. Do not immediately implement a general winner-selection algorithm. A fixed-witness experiment can falsify the visual premise before spending effort on candidate objectives, global ordering or persistence schema.
## Blocking conceptual issues before production/parity claims
1. **Authored layout transition is unspecified.** EdgeLabel currently persists fraction and offset only. The note requires automatic wrapping and also says authored labels must not silently wrap. Dragging automatic F makes it authored; a naive implementation then unwraps it, changes its box and may put the foreign stroke back through the label. Saving/reopening loses any transient remembered wrapping. Decide explicitly whether wrapping is derived independently of authored position, an opt-in display policy, or persisted authored presentation before claiming drag/Undo/Redo/reopen parity. Do not add a serialized field solely to rescue an unvalidated visual witness.
2. **Measured text and consumed geometry must be the same layout.** Inserting newlines into text while retaining old dimensions, or painting narrower text over the old label hitbox, invalidates the experiment. Actual font, font size, shaping, advance, line height, baseline, alignment and padding must determine one geometry object. The whole name stays canonical; derived line breaks are presentation. SVG must consume the same measured line positions/bounds rather than relying on browser auto-wrap or a different generic font. A screenshot-only drawing patch cannot establish edit/export/spec parity.
3. **A production placement objective remains undecided.** F .5 is already collision-free but weaker than .55. Existing first-zero exit will choose it. The next experiment must not claim an implemented general rule merely because a manually chosen .55 screenshot looks better. Keep the witness explicitly fixed, then use observed readability to decide a separate ordering/association criterion. Do not silently elevate minimum displacement or nearest-box margin into a validated human metric.
These issues do not block a clearly isolated visual experiment. They block general product or persisted-label acceptance.
## Feasible implementation boundary
Use an isolated experiment profile, explicitly selecting the target relation and frozen E/F line split/anchor policy. Derive a transient LabelLayout containing the original display text, ordered line strings and measured positions, anchor/fraction, union backing/hit bounds and font identity/metrics. Preserve Project, canonical Name, source text, all routed point arrays and authored fields. Apply that layout to the derived scene before any consumer uses it, not only in the final paint call.
Canvas painting, label hit testing, label drag start/offset calculation, focus/navigation bounds, overall scene bounds and SVG export must read that same derived layout. Existing semantic relation identity remains the hit result; no new relation or leader target is introduced. Both preview and committed scenes need the same transformation. A test-only/external experiment profile can preserve the target's chosen layout through the controlled editing trial, but then save/reopen evidence must explicitly say it requires that experiment profile and does not prove the ordinary product's persisted formatting contract. Alternatively postpone edit/reopen acceptance until the authored-layout decision is resolved.
Keep the old one-line layout as the default for all unrelated labels. For the first fixed-path experiment, freeze and inventory those other derived labels rather than allowing an unnoticed re-settlement. This is a deliberately scoped witness, not yet a whole-scene policy. If the witness passes, define the shared derived-layout interface and documentation at the appropriate layer before promoting it into production routing or export. Avoid a general typesetting/layout framework until there is positive evidence.
## Finite assumptions to falsify early
- Re-measure before native reading. With F's left side fixed 18 units from x1162, nearest foreign vertical x1312.5 gives clearance 132.5 minus measured width. F retains the claimed own-is-closer advantage only below width 114.5, and its 3-unit foreign exclusion only below width 129.5 (strict-border details must follow the scorer). The predicted width100 has useful but finite slack. Actual glyph extents and antialiasing are distinct from backing bounds.
- At F center y254.2, the foreign horizontal y325 yields clearance 70.8 minus half the measured height. Recheck all actual card/label/stroke constraints, not just that one line. For E, recheck the enlarged backing against the entire unique straight own segment, both margins and all foreign segments.
- E's permitted own crossing must be one uniquely owned straight interval entering and leaving opposite sides. Reject bends, endpoint/port-symbol coverage, shared or partially coincident foreign runs, unrelated strokes just beyond a rectangle boundary, and other label/node interception. Ownership lists must retain all IDs rather than deduplicating to one owner.
- F must keep all strokes clear after measurement, including its own; do not add an explanatory cue when the comparison is supposed to isolate wrapping/placement.
- Names with Unicode, long unbreakable tokens, punctuation or explicit whitespace need declared non-destructive line-breaking rules. A failure to fit must fail this experimental fallback rather than shrink font, truncate semantic Name or insert source newlines. This one English name does not validate general wrapping.
## Reading experiment and causal controls
Predeclare fixed F and E geometry after measurement. Hold complete model, paths, cards, viewport, zoom, font and other labels identical. Disable B cues in these comparisons. Record actual pixel and world bounds, rather than assuming unchanged Fit because the old arithmetic fit inside node extents.
First reading must precede Inspector/selection/highlighting or explanation of the intended owning path. A reader who has already identified this conversation in B or baseline is not fresh. Showing the same participant names in baseline before F also teaches the answer. Prefer fresh readers per arm; if constrained, use separately declared isomorphic, relabeled scenes with counterbalanced presentation and report that limitation. Do not present repeated same-scene exposure as independent accuracy.
Record the first path chosen and participant/port-owner answer, confidence, wrong alternatives, tracing time, pan/zoom and word-reading difficulty. Correct participants with persistent plausible allocation ownership remains failure. Ask an unleading trace task first; ask whether E looks broken or F appears attached to the allocation only afterward. Verify Request/Report and the two port mappings so improvement does not come at their expense. A correct click after highlighting proves selectability, not unselected association. Stop if coaching is needed, target words become hard to scan, another relationship becomes harder, or full-scene endpoint context is lost.
## Later integration gates
After a positive visual witness, compare full Project and every computed route/port/node/label record. Any other automatic label movement must be listed. Exercise target hitbox at each line and padding, drag start/preview/commit, Undo/Redo, cancellation, save/export/reopen under the declared layout policy, and canvas/SVG parity. Preserve authored offsets/fractions and unrelated authored labels exactly.
For a generalized rule, separately test fixed-path label-order permutations and consistent UUID-remapped reroutes. Do not conflate the latter with a label-only change. Charge every new measurement/candidate/foreign-segment comparison, retain a bounded budget and deterministic fallback, and measure actual scene rebuild and active preview costs on the representative scene plus the existing dense control. Cache font/layout for unchanged text/style; hover, selection and camera changes must not reshape or rescore. Do not add an index or optimizer before measurements justify it.
A successful first F reading would justify the next bounded implementation decision. It would not close shared-corridor ambiguity, broad accessibility, arbitrary names, nested/folded views, full OA/SA usability, or production release acceptance. If both measured E and F fail, record the hypotheses as rejected and change approach instead of tuning around this one scene.
@@ -0,0 +1,17 @@
{
"source": "6e7c4ddaf0775198384a8c4882809ea8e14b2976",
"start": "2026-10-02T02:05:58.837634+00:00",
"binary_sha256": "d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 10220,
"exit_code": 0,
"finished": "2026-10-02T02:09:43.777146+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"fixture_unchanged": true,
"binary_unchanged": true,
"runtime_unchanged": true
}
@@ -0,0 +1,10 @@
{
"source": "6e7c4ddaf0775198384a8c4882809ea8e14b2976",
"start": "2026-10-02T02:05:58.837634+00:00",
"binary_sha256": "d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 10220
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

@@ -0,0 +1,13 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"platform": "Windows x86_64-pc-windows-gnullvm; Rust 1.98.1; LLVM-MinGW 20260826 UCRT; jobs1 incremental0",
"environment": "C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/env.ps1",
"target_directory": "C:/Users/User/Documents/Git/ARCADIA-Studio/.local/target-gnullvm",
"final_gates": [
{"command":"cargo fmt --all -- --check","log":"wrapped-label-format-check.log","exit_code":0,"note":"fresh parent check after earlier summary named a nonexistent log; empty output with exit0"},
{"command":"cargo test --locked -p oa-desktop -- diagram:: diagram_usage:: fit_ --test-threads=1 --nocapture","log":"wrapped-label-diagram-tests.log","exit_code":0,"passed":126,"failed":0,"ignored":0,"filtered":1426},
{"command":"cargo clippy --locked -p oa-desktop --all-targets -- -D warnings","log":"wrapped-label-clippy.log","exit_code":0},
{"command":"cargo build --locked -p oa-desktop --bin arcadia-studio","log":"wrapped-label-build.log","exit_code":0}
],
"limits":"Focused desktop gates; no full workspace or desktop suite rerun, release packaging, Linux or performance acceptance"
}
@@ -0,0 +1,334 @@
{
"baseline/finished.json": {
"bytes": 721,
"sha256": "963bc0b874318519b8c7678e8026cb2798a92bdc77151510126b5f53048da6da"
},
"baseline/started.json": {
"bytes": 518,
"sha256": "8465e67b75b252ff02c86e3a302bf888535b50aa2d587b852a1d2072b41bdf3f"
},
"baseline/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"baseline/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"baseline/working/baseline.svg": {
"bytes": 7209,
"sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d"
},
"baseline/working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"commands.json": {
"bytes": 1172,
"sha256": "a6c2d18688bfa1eda0e6efc4a1c5897d2b705b40b50faec5ee5a1136cd8fce4a"
},
"gates/wrapped-label-build.log": {
"bytes": 309,
"sha256": "3e9d2faf1a2d098a2309f08677b66b4a5ab4dcbdf2af06a93d65cb1875d5ed4b"
},
"gates/wrapped-label-clippy.log": {
"bytes": 379,
"sha256": "cdcbd2156854eba0cac90a96b87de470d3c90e50ed9a7b6f5169819849269dae"
},
"gates/wrapped-label-diagram-tests.log": {
"bytes": 16179,
"sha256": "801d4e9223530db238aeba790fc37ac99f8e82404c41cff1f9983d89ce961921"
},
"gates/wrapped-label-format-check.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"gates/wrapped-label-regression-first.log": {
"bytes": 3269,
"sha256": "4759fdfa2a879ae8e645d27fb3a6ea89fef5181efa67bb1cc82a7d7131141bbc"
},
"gates/wrapped-label-tests-first.log": {
"bytes": 877,
"sha256": "224b7168de971dbc60a3ec1e8647cf8fe1c826ee68338ef6d2424f14035b8782"
},
"native-E/baseline.json": {
"bytes": 717,
"sha256": "8d252d9652eb00a07034e9f3ba8801cd6ec73475aa07ee8eb004ad1618e0de2c"
},
"native-E/captures/00-fit-pristine.jpg": {
"bytes": 151158,
"sha256": "48adaf65c6b655e66bcab47d3a7a4ac9080a0da4f7e98dc84e9ea9573f731acb"
},
"native-E/captures/01-svg-exported.jpg": {
"bytes": 146692,
"sha256": "769c4df771000ff444419104e99c10557a5846d81ccee71d014d348c20e456c2"
},
"native-E/captures/02-first-line-selected.jpg": {
"bytes": 149452,
"sha256": "42648a450d21b2654d02eab5df5e53cb43984b1917d5c75ced31a1dd3fdba84e"
},
"native-E/captures/03-second-line-selected.jpg": {
"bytes": 149304,
"sha256": "5584ac78406107367a9b72773ac5927c675068b73c9b7f1418b34923a294d38f"
},
"native-E/finished.json": {
"bytes": 687,
"sha256": "20ea462b837ac98d02fe41b56446d1fe8a4f2e6f7a640b26c37e45016e069537"
},
"native-E/first-reading.md": {
"bytes": 4778,
"sha256": "9de823d0d43e7753f2799e203a68332b7361c1c6c2f8f18baece5c60baa01c66"
},
"native-E/started.json": {
"bytes": 534,
"sha256": "9c8b4e4152d8ed361e39d5b8719560a1f8c27df5e9764987fdcebd2df8f7330a"
},
"native-E/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-E/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-E/svg-conservation.json": {
"bytes": 3162,
"sha256": "968ae031b1e25940c70332b3a3351df7dc08b11040b211537c477c0d7fe3e88b"
},
"native-E/working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"native-E/working/pristine-E.svg": {
"bytes": 7353,
"sha256": "d84f6c4b03a305f89849b013e809501f7d613203fd2c71bea80b645958a4b64c"
},
"native-F/baseline.json": {
"bytes": 717,
"sha256": "68a070420bfe0d118048dbbc6e7d865eead6dc21a26c99f96d6931888d5ce340"
},
"native-F/captures/00-fit-pristine.jpg": {
"bytes": 151241,
"sha256": "213647f0f826deb78267ff58197755e17bfcc6f5f9b86273f90093a45769870e"
},
"native-F/captures/01-first-line-selected.jpg": {
"bytes": 149733,
"sha256": "186d87402cd2aca0a305e55f050c916116135c2044b9e76aad7f7e66d7ad57e5"
},
"native-F/captures/02-middle-line-selected.jpg": {
"bytes": 149546,
"sha256": "e11fd35de721db851d53410e62bc5b2a022080459a0d844fb0f9d412db304c1d"
},
"native-F/captures/03-label-moved.jpg": {
"bytes": 150951,
"sha256": "4c3c39e2c4e04eebdbe725d8cc2dd4a68f26ebef1d2725351901dec0d1c0e04c"
},
"native-F/captures/04-undo.jpg": {
"bytes": 149702,
"sha256": "cffb756bad10e0378758da7e0fae9e9c1a49791199dcfa025532e63f776fe697"
},
"native-F/captures/05-redo.jpg": {
"bytes": 149546,
"sha256": "766083066a95d57cadd01e4b6ed70227eb57bf135c1f2f526cedd5c3f8b15041"
},
"native-F/captures/06-save-path.jpg": {
"bytes": 57727,
"sha256": "e4b7752864a0df2ac2fa769dab41c60ae60001b94d7d204e0f1182ff47892f03"
},
"native-F/captures/07-saved.jpg": {
"bytes": 152431,
"sha256": "b224e3d21849acceb1cc7bd6a2595a2d9394703c98437a44bd19a7c1967335b9"
},
"native-F/captures/08-after-export-undo-clean.jpg": {
"bytes": 148392,
"sha256": "417a5ddad9f231229edf6a1ba91231fab1475bccfc5469aea92da5ac880a2ff5"
},
"native-F/finished.json": {
"bytes": 687,
"sha256": "304b144a7c2f9696a1006e9fbd9dd64084887904e6c7e5293b9eca5602493b28"
},
"native-F/first-reading.md": {
"bytes": 4192,
"sha256": "2867ba22c3195e7b77cf696fffbdcc65ca6e8a74dc212f38407ef797216b5f8e"
},
"native-F/model-oracle.json": {
"bytes": 618,
"sha256": "007e0ca5765c80a6726d27a28ecc39e2a7e252d3c42aab17c544185e7d512928"
},
"native-F/started.json": {
"bytes": 534,
"sha256": "9521cf90ef719c16313329f21ae85d082ad1f804c2318a2a7db6be5e93d06aad"
},
"native-F/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-F/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-F/svg-conservation-v2.json": {
"bytes": 3261,
"sha256": "d8c738cb16c7cf756f7ecc23816c367ea7ccc01df74bde686d3eeb7c2bb7f4c6"
},
"native-F/svg-conservation.json": {
"bytes": 3261,
"sha256": "b3af75b6a6386fabef612898cd643b7bdb6b226985754e1380be99885e988fc2"
},
"native-F/working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"native-F/working/moved-F.json": {
"bytes": 138935,
"sha256": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"native-F/working/pristine-F.svg": {
"bytes": 7436,
"sha256": "5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0"
},
"reopen-Baseline/captures/00-reopened-single-line.jpg": {
"bytes": 151284,
"sha256": "b2e0aadb03aa219bab95298e21b944584a223f6c7d3cef65f67b6c4e8ea306de"
},
"reopen-Baseline/finished.json": {
"bytes": 774,
"sha256": "e63262dee74aa8b90977430f5c74b0922874907f2932559a2ce5e9f53fb30c6f"
},
"reopen-Baseline/started.json": {
"bytes": 621,
"sha256": "bdf75da27f5307f82808898ab414bddca2ce55359dc7e7adef7c9434455e3d9b"
},
"reopen-Baseline/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"reopen-Baseline/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"reopen-Baseline/working/moved-F.json": {
"bytes": 138935,
"sha256": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"reopen-F/captures/00-forward-slash-path-refused.jpg": {
"bytes": 98127,
"sha256": "abfe0ef0a83927637de5cbfe413b0c89709aed60729a5e704824ab9c0e3e78be"
},
"reopen-F/captures/01-reopened-authored-label.jpg": {
"bytes": 151196,
"sha256": "9acac41740199155c565651967271f6216d05989f3bb1caef652185dc0b8bd18"
},
"reopen-F/captures/02-reopened-svg-exported.jpg": {
"bytes": 146684,
"sha256": "cb120e7be70a1f730115c7b6a8054902eb32dda1937913f2d4f6afe512a9af9a"
},
"reopen-F/finished.json": {
"bytes": 759,
"sha256": "7c2b590582d29780243c12b8209d435492f3be44ac4923cbe7af0bee8c5f5488"
},
"reopen-F/started.json": {
"bytes": 606,
"sha256": "5f721c530aa78e077cce78ad3c633ae2dfe37f7c25358bdcc8794b01e76f3551"
},
"reopen-F/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"reopen-F/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"reopen-F/working/moved-F.json": {
"bytes": 138935,
"sha256": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"reopen-F/working/reopened-F.svg": {
"bytes": 7449,
"sha256": "5b1106b9f8cdb6030e29d657f8aac1920e1a554e868bab4fce3e250a42469cd5"
},
"reviews/native-wrapped-plan.md": {
"bytes": 3018,
"sha256": "d9ae551792921cf2e816699e0434794dc75f140b5b89fa805bc09c195100a3c7"
},
"reviews/wrapped-final-evidence-review.md": {
"bytes": 13422,
"sha256": "c23b9c97ec21dec3591431ba8fc6a583e6f5e167f45c4b8b59b2fc34ddd066d2"
},
"reviews/wrapped-label-change-summary.md": {
"bytes": 6489,
"sha256": "2670a438b3e4506e99538cef2dcd070b93c69438dfae9f2c338411cfde118627"
},
"reviews/wrapped-label-independent-repair-review.md": {
"bytes": 8518,
"sha256": "11f3b06cb551162124f95f375395172347f943937ab8dfbe654bbfe47b8c2e29"
},
"reviews/wrapped-label-independent-source-review.md": {
"bytes": 12676,
"sha256": "262673d399bab74502ce15ec11b6b6e8cc50daab6eb79d0d4914e06c9ee8a05d"
},
"reviews/wrapped-native-observation.md": {
"bytes": 5985,
"sha256": "11a295fd1f60dad6c57b674f810a16d2e91b40bf2f84592cadc51ae5f4c3d114"
},
"reviews/wrapped-reopen-independent-result.json": {
"bytes": 2866,
"sha256": "8804ba0f50500ae92c1dd2c175ca241aa23070db6a0221793d6a85d67cd27e0f"
},
"reviews/wrapped-reopen-independent-selfcheck.json": {
"bytes": 1422,
"sha256": "7e22a0379be1ecf095130ab179525525b850f50ee905e804b607db3bc92e023b"
},
"reviews/wrapped-reopen-svg-review.md": {
"bytes": 6784,
"sha256": "dcfeaa45e888adc798bcb1d5493e3e1142fc306b64f973e411ce19e66184784d"
},
"reviews/wrapped-svg-oracle-report.md": {
"bytes": 4470,
"sha256": "0f1c608b09e0b3f85a51e187383701d5e3b157847bb687f65652b9a49dbe5a0e"
},
"reviews/wrapped-svg-oracle-selfcheck-first-failed.json": {
"bytes": 244,
"sha256": "67e6ceb254e614184cb99ce86a77a3855e98b055715f2052ffb58287fe9319b0"
},
"reviews/wrapped-svg-oracle-selfcheck.json": {
"bytes": 1758,
"sha256": "88f6b86b4c00a3bd50b19681de821c47fdc52ce3963d311f8d03e35435d61dc0"
},
"scripts/check-wrapped-model.py": {
"bytes": 1991,
"sha256": "55765130c9aabe85e1b8b243aa12272a88de66f8d0d62d38d66150a7c18d009e"
},
"scripts/check-wrapped-svg-initial.py": {
"bytes": 8851,
"sha256": "e679b3dfb056d441c4627967b469118621f83e6941c7a6daa4213ce3a7ff4970"
},
"scripts/check-wrapped-svg.py": {
"bytes": 9102,
"sha256": "136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099"
},
"scripts/launch-native-wrapped.py": {
"bytes": 2272,
"sha256": "3daf15de7abdc820ae66190e8218f50402f08fd1e34adfd9de187ed835b18c78"
},
"scripts/launch-wrapped-reopen.py": {
"bytes": 2692,
"sha256": "fdba16739e87ef172be5c083668949141d0d8977a67e09ec39cad7ce5a8b8ff3"
},
"scripts/prepare-native-wrapped.py": {
"bytes": 1903,
"sha256": "5315b4d71db4eb7f2f9784afb68543cc32901e7fe76a4cad16e8de28aeb0d8c8"
},
"scripts/wrapped-reopen-independent-check.py": {
"bytes": 7852,
"sha256": "8d718db9a52e894e8160436eab2d57998f211b71f4485b3543c6badde36b7815"
},
"source-manifest.json": {
"bytes": 52831,
"sha256": "bc858025f5f0b7c10d02cc0b5a19b1659a6ced5cf6f09f5ea623025e71ad7c0a"
},
"verify.py": {
"bytes": 7021,
"sha256": "282f8d95355d764d09ceea5662be2aa381b17ed863b5fd442d37599817616c23"
}
}
@@ -0,0 +1,5 @@
Compiling iced_widget v0.14.2 (C:\ar-wrap-01a0d717\crates\vendor\iced_widget)
Compiling oa-core v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-core)
Compiling iced v0.14.0
Compiling oa-desktop v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-desktop)
Finished `dev` profile [unoptimized] target(s) in 1m 25s
@@ -0,0 +1,6 @@
Compiling oa-core v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-core)
Checking iced_widget v0.14.2 (C:\ar-wrap-01a0d717\crates\vendor\iced_widget)
Compiling oa-desktop v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-desktop)
Compiling oa-server v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-server)
Checking iced v0.14.0
Finished `dev` profile [unoptimized] target(s) in 1m 10s
@@ -0,0 +1,140 @@
Compiling oa-desktop v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-desktop)
Finished `test` profile [unoptimized] target(s) in 1m 40s
Running unittests src\main.rs (C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\deps\arcadia_studio-c5b42126ba36cd38.exe)
running 126 tests
test app::allocation_drag::tests::modal_roundtrip_equal_fit_undo_resize_and_focus_retire_press_before_replay ... ok
test app::scenario_diagram::adoption_tests::missing_and_deleted_picker_ids_cannot_apply_an_unrelated_valid_property_draft ... ok
test app::scenario_diagram::adoption_tests::source_cross_layer_owner_retarget_undo_redo_keeps_requested_saved_uuid ... ok
test app::scenario_diagram::adoption_tests::source_deleted_owner_and_saved_view_mount_unavailable_instead_of_another_behavior ... ok
test app::scenario_diagram::adoption_tests::source_same_layer_owner_retarget_undo_redo_keeps_requested_saved_uuid ... ok
test app::scenario_diagram::owner_navigation_tests::saved_scenario_direct_behavior_selection_enters_explicit_process_or_state_owner ... ok
test app::scenario_diagram::owner_navigation_tests::saved_scenario_guide_selection_returns_to_explicit_process_or_state_owner ... ok
test app::scenario_diagram::tests::arrangement_picker_rejects_previous_visit_and_switches_automatic_without_model_changes ... ok
test app::scenario_diagram::tests::leaving_and_reentering_saved_view_preserves_source_and_retires_passive_visit ... ok
test app::scenario_diagram::tests::saved_picker_applies_valid_old_draft_and_uuid_edit_follows_that_same_view ... ok
test app::scenario_diagram::tests::saved_reference_back_restores_exact_view_with_a_fresh_visit ... ok
test app::scenario_diagram::tests::saved_view_return_rejects_old_passive_events_without_an_intermediate_frame ... ok
test app::scenario_diagram::tests::saved_view_switches_are_distinct_passive_visits_and_preserve_actual_history ... ok
test app::state_diagram_tests::same_size_viewport_after_revision_or_tool_epoch_does_not_refit_the_camera ... ok
test app::state_diagram_tests::state_navigation_return_to_the_same_view_preserves_camera_tool_and_fit_mode ... ok
test app::state_multiselect_focus_tests::mounted_state_selection_and_missing_picker_never_resize_or_refit_the_canvas ... ok
test behavior::scenario::camera::tests::fit_remains_active_across_first_and_changed_viewport ... ok
test behavior::scenario::camera::tests::negative_origin_fit_contains_independently_known_extremes ... ok
test behavior::scenario::camera::tests::pan_leaves_fit_from_displayed_position_and_zero_motion_preserves_fit ... ok
test behavior::scenario::camera::tests::tiny_fit_zoom_in_out_preserves_pointer_world_anchor_without_floor_jump ... ok
test behavior::scenario::workspace::spacing_tests::saved_drag_return_to_origin_preserves_redo_selection_and_original_fit_camera ... ok
test behavior::scenario::workspace::spacing_tests::saved_header_preview_survives_frames_and_freezes_fit_while_actual_bounds_expand ... ok
test behavior::scenario::workspace::tests::scenario_workspace_fit_uses_measured_inner_viewport_and_rejects_nonfinite_inputs ... ok
test behavior::scenario::workspace::tests::scenario_workspace_same_size_owner_and_document_changes_remeasure_fit_viewport ... ok
test behavior::topology::contextual_routing::tests::contextual_route_shared_anchor_preserves_selected_direct_reconnect_at_fit_and_full_scale ... ok
test behavior::topology::direct_tests::direct_process_palette_preserves_fit_and_manual_camera ... ok
test behavior::topology::direct_tests::direct_process_readable_default_fit_expansion_and_bounded_choices ... ok
test behavior::topology::tests::process_fit_uses_measured_height_and_reports_minimum_without_changing_manual_zoom ... ok
test behavior::topology::view::layout_tests::production_process_canvas_focus_wheel_fit_and_stale_camera_are_presentation_only ... ok
test diagram::allocation_group_tests::allocation_handle_click_collapses_but_out_and_back_refuses_after_app_rebuilds ... ok
test diagram::allocation_group_tests::allocation_handles_keep_exact_edge_through_shift_and_pending_group_dispatch ... ok
test diagram::allocation_group_tests::armed_isolated_bend_is_owned_but_unarmed_controls_still_edit_routes ... ok
test diagram::allocation_group_tests::dirty_selected_pin_outer_ring_is_shielded_without_starting_pan ... ok
test diagram::allocation_group_tests::ordinary_performer_body_uses_one_token_and_retains_existing_movement_policy ... ok
test diagram::attachment_tests::attachment_camera_layout_focus_and_outside_release_cancel_after_motion ... ok
test diagram::attachment_tests::attachment_event_batches_commit_one_source_history_change_at_three_zooms ... ok
test diagram::attachment_tests::attachment_fast_release_uses_release_position_and_stays_in_one_view ... ok
test diagram::attachment_tests::attachment_reset_preserves_opposite_end_pins_label_and_semantics ... ok
test diagram::attachment_tests::attachment_stale_context_wrong_placement_and_unowned_route_fields_are_rejected ... ok
test diagram::attachment_tests::attachment_stationary_return_and_escape_leave_source_unchanged ... ok
test diagram::attachment_tests::attachment_wheel_and_middle_pan_cancel_before_same_batch_left_release ... ok
test diagram::attachment_tests::coincident_attachment_handles_honor_explicit_end_choice ... ok
test diagram::group_gesture::tests::any_frozen_viewport_change_is_detected ... ok
test diagram::group_gesture::tests::explicit_grid_and_default_constructor_keep_existing_quantization ... ok
test diagram::group_gesture::tests::finite_inputs_that_overflow_world_geometry_retire_without_an_operation ... ok
test diagram::group_gesture::tests::full_typed_selection_and_saved_surface_are_required ... ok
test diagram::group_gesture::tests::invalid_initial_geometry_cannot_start ... ok
test diagram::group_gesture::tests::invalid_pointer_permanently_retires_even_if_pointer_returns ... ok
test diagram::group_gesture::tests::offgrid_anchor_yields_one_shared_delta_and_release_matches_preview ... ok
test diagram::group_gesture::tests::release_only_displacement_that_snaps_to_zero_still_preserves_group ... ok
test diagram::group_gesture::tests::stationary_or_exact_threshold_release_is_click_without_snapping ... ok
test diagram::group_gesture::tests::threshold_latches_and_return_to_offgrid_origin_is_zero_move ... ok
test diagram::group_gesture::tests::unsnapped_fractional_pointer_delta_preserves_authored_offset ... ok
test diagram::group_gesture::tests::unsnapped_release_only_movement_and_invalid_pointer_retirement ... ok
test diagram::group_gesture::tests::unsnapped_threshold_and_return_to_origin_preserve_group_lifecycle ... ok
test diagram::group_gesture::tests::zoom_scales_world_delta_but_threshold_remains_in_screen_pixels ... ok
test diagram::label_layout_experiment::tests::authored_fraction_offset_keep_shape_even_during_conflicting_move ... ok
test diagram::label_layout_experiment::tests::automatic_guard_refuses_foreign_coincident_stroke_and_card ... ok
test diagram::label_layout_experiment::tests::baseline_is_exact_and_wrapping_changes_only_target_derived_geometry ... E: bounds=RoutingBounds { position: Position { x: 1102.4126, y: 254.5 }, size: Size { width: 119.174805, height: 40.0 } }; lines=[Line { text: "Technician service", position: Position { x: 1110.4126, y: 258.5 }, baseline_y: 271.8828, width: 103.174805, family: "Segoe UI" }, Line { text: "conversation", position: Position { x: 1125.4089, y: 274.5 }, baseline_y: 287.8828, width: 73.18213, family: "Segoe UI" }]
F: bounds=RoutingBounds { position: Position { x: 1180.0, y: 226.2 }, size: Size { width: 89.18213, height: 56.0 } }; lines=[Line { text: "Technician", position: Position { x: 1194.2905, y: 230.2 }, baseline_y: 243.58281, width: 60.601074, family: "Segoe UI" }, Line { text: "service", position: Position { x: 1205.0847, y: 246.2 }, baseline_y: 259.58282, width: 39.012695, family: "Segoe UI" }, Line { text: "conversation", position: Position { x: 1188.0, y: 262.2 }, baseline_y: 275.58282, width: 73.18213, family: "Segoe UI" }]
ok
test diagram::label_layout_experiment::tests::different_edge_preview_guard_rejection_restores_complete_core_geometry ... ok
test diagram::label_layout_experiment::tests::measured_backing_canvas_svg_picking_and_focus_share_geometry ... ok
test diagram::label_layout_experiment::tests::scene_and_measurement_cache_reuse_and_geometry_invalidation ... ok
test diagram::lifecycle_tests::menu_reset_and_draw_use_fresh_open_context ... ok
test diagram::lifecycle_tests::middle_and_arrow_panning_preserve_source_and_history ... ok
test diagram::lifecycle_tests::motion_after_release_must_not_move_clicked_port ... ok
test diagram::lifecycle_tests::motion_after_source_click_release_must_not_create_connection ... ok
test diagram::multiselect_tests::changed_selection_generation_rejects_press_even_after_membership_is_restored ... ok
test diagram::multiselect_tests::changed_viewport_or_context_retires_group_without_a_release_intent ... ok
test diagram::multiselect_tests::delete_is_captured_without_hiding_during_live_group_then_release_moves_once ... ok
test diagram::multiselect_tests::escape_cancels_live_group_without_clearing_or_publishing_a_model_intent ... ok
test diagram::multiselect_tests::group_canvas_preview_and_release_match_independent_expected_geometry ... ok
test diagram::multiselect_tests::initial_press_without_pointer_history_consumes_release_only_displacement ... ok
test diagram::multiselect_tests::middle_pan_excludes_group_start_and_delete_even_when_left_is_pressed ... ok
test diagram::multiselect_tests::mixed_set_keeps_click_lifecycle_and_refuses_only_actual_drag ... ok
test diagram::multiselect_tests::shift_press_uses_ordered_hit_not_native_batch_final_cursor ... ok
test diagram::multiselect_tests::stationary_group_click_does_not_use_motion_after_release_in_same_batch ... ok
test diagram::multiselect_tests::threshold_crossing_then_return_to_origin_emits_zero_move_not_singleton_click ... ok
test diagram::pointer_tests::coalesced_fe_ports_commit_once_through_app_and_source_history ... ok
test diagram::pointer_tests::coalesced_port_drag_commits_once_through_app_and_source_history ... ok
test diagram::pointer_tests::drag_from_already_selected_stationary_port_keeps_source_between_batches ... ok
test diagram::pointer_tests::menu_captured_motion_must_not_turn_following_click_into_old_port_drag ... ok
test diagram::pointer_tests::modal_and_stale_epoch_block_queued_connection_and_port_commits ... ok
test diagram::port_hit_tests::coincident_ports_keep_selection_then_use_stable_identity ... ok
test diagram::port_hit_tests::nearest_port_center_wins_on_all_borders_and_zoom_levels ... ok
test diagram::port_hit_tests::nested_owner_palette_selection_drag_and_context_menu_pick_the_same_port ... ok
test diagram::port_labels::tests::leaving_and_reentering_keeps_suppression_until_each_held_button_releases ... ok
test diagram::port_labels::tests::menu_epoch_clears_suppression_when_the_overlay_consumes_release ... ok
test diagram::port_labels::tests::outside_presses_do_not_suppress_and_cancel_or_focus_loss_clear_held_buttons ... ok
test diagram::port_labels::tests::passive_layer_leaves_port_drag_selection_and_commit_with_the_interactive_canvas ... ok
test diagram::tests::association_end_contracts_share_svg_geometry_and_select_without_moving_name_label ... ok
test diagram::tests::bend_gestures_use_screen_hit_radius_and_commit_one_undo_at_three_zooms ... ok
test diagram::tests::coincident_line_hit_retains_the_selected_connection ... ok
test diagram::tests::connection_gestures_pick_real_ports_and_commit_coalesced_drag_at_every_zoom ... ok
test diagram::tests::detached_label_selects_connection_and_occluding_card_owns_its_hit ... ok
test diagram::tests::dragging_a_child_previews_the_same_enclosure_and_ports_as_commit ... ok
test diagram::tests::fast_drags_commit_the_release_cursor_without_a_final_motion_event ... ok
test diagram::tests::implicit_port_click_selects_semantics_and_drag_preview_svg_share_anchors ... ok
test diagram::tests::route_cache_ignores_pan_zoom_and_cancelled_drag_cannot_commit ... ok
test diagram::tests::routed_svg_has_same_polyline_label_and_bounds_as_canvas_scene ... ok
test diagram::tests::svg_accepts_populated_and_empty_architecture_views ... ok
test diagram::tests::svg_distinguishes_inferred_work_allocation_from_direct_allocation ... ok
test diagram::tests::svg_preserves_visible_exchange_labels_and_capability_stereotypes ... ok
test diagram::tests::svg_rejects_missing_diagram_without_mutation ... ok
test diagram::tests::svg_rejects_saved_scenario_with_absent_or_authored_layout_without_mutation ... ok
test diagram::tests::typed_function_glyphs_and_unoriented_standard_connections_have_distinct_svg ... ok
test diagram::view_options_tests::communication_svg_uses_saved_visibility_labels_and_direction ... ok
test diagram_usage::coverage_tests::absent_endpoint_placements_and_hidden_performer_do_not_create_grouping_targets ... ok
test diagram_usage::coverage_tests::allocation_grouping_has_exact_relation_placements_and_readable_work_geometry ... ok
test diagram_usage::coverage_tests::allocation_grouping_walks_two_visible_summary_levels_without_inventing_allocations ... ok
test diagram_usage::coverage_tests::collapsed_leaf_and_edge_filter_still_leave_the_actual_nesting_visible ... ok
test diagram_usage::coverage_tests::folded_summary_or_performer_does_not_substitute_a_visible_ancestor_for_the_leaf ... ok
test diagram_usage::coverage_tests::other_projections_do_not_report_allocation_nesting_when_only_an_arrow_or_nothing_is_drawn ... ok
test diagram_usage::coverage_tests::repeated_saved_views_keep_allocation_placement_identity_and_geometry_independent ... ok
test diagram_usage::coverage_tests::role_derived_nesting_without_a_direct_allocation_does_not_invent_one ... ok
test diagram_usage::tests::folded_child_is_not_a_visible_node_and_placement_identity_stays_exact ... ok
test diagram_usage::tests::oversized_container_reveal_targets_its_labelled_header ... ok
test diagram_usage::tests::ports_are_found_at_the_visible_owner_and_unplaced_elements_do_not_match_names ... ok
test diagram_usage::tests::reveal_camera_centers_target_without_whole_view_shrink ... ok
test diagram_usage::tests::saved_membership_respects_filters_and_does_not_change_project ... ok
test diagram_usage::tests::state_machine_owner_finds_its_view_without_a_machine_placement ... ok
test diagram_usage::tests::whole_diagram_camera_fits_large_bounds_instead_of_individual_object_scale ... ok
test source_annotations::widget::tests::measured_footer_and_omitted_count_fit_actual_shaped_widths_and_ancestor_clip ... ok
test tests::fit_adapts_to_canvas_returning_after_help_but_preserves_manual_navigation ... ok
test tests::fit_uses_measured_canvas_bounds_and_preserves_them_on_open ... ok
test tests::routing_actions_are_atomic_guarded_and_fit_the_authored_detour ... ok
test views::text_workspace::summary_visibility_tests::all_reference_exceptions_fit_allocated_width_with_wide_alias_and_large_counts ... old alias-first summary width=840 alias="雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨": 0 missing/clipped flag-byte checks; first=None
old alias-first summary width=720 alias="雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨雨": 18 missing/clipped flag-byte checks; first=Some("flag Detached is clipped: glyph Rectangle { x: 724.93945, y: 0.0, width: 8.4140625, height: 15.599999 }, clip Rectangle { x: 0.0, y: 0.0, width: 720.0, height: 24.0 }")
old alias-first summary width=840 alias="WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW": 0 missing/clipped flag-byte checks; first=None
old alias-first summary width=720 alias="WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW": 15 missing/clipped flag-byte checks; first=Some("flag Detached is clipped: glyph Rectangle { x: 718.3828, y: 0.0, width: 6.1054688, height: 15.599999 }, clip Rectangle { x: 0.0, y: 0.0, width: 720.0, height: 24.0 }")
ok
test result: ok. 126 passed; 0 failed; 0 ignored; 0 measured; 1426 filtered out; finished in 5.44s
@@ -0,0 +1,28 @@
Compiling oa-desktop v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-desktop)
Finished `test` profile [unoptimized] target(s) in 1m 44s
Running unittests src\main.rs (C:\Users\User\Documents\Git\ARCADIA-Studio\.local\target-gnullvm\debug\deps\arcadia_studio-c5b42126ba36cd38.exe)
running 6 tests
test diagram::label_layout_experiment::tests::authored_fraction_offset_keep_shape_even_during_conflicting_move ... ok
test diagram::label_layout_experiment::tests::automatic_guard_refuses_foreign_coincident_stroke_and_card ... ok
test diagram::label_layout_experiment::tests::baseline_is_exact_and_wrapping_changes_only_target_derived_geometry ... E: bounds=RoutingBounds { position: Position { x: 1102.4126, y: 254.5 }, size: Size { width: 119.174805, height: 40.0 } }; lines=[Line { text: "Technician service", position: Position { x: 1110.4126, y: 258.5 }, baseline_y: 271.8828, width: 103.174805, family: "Segoe UI" }, Line { text: "conversation", position: Position { x: 1125.4089, y: 274.5 }, baseline_y: 287.8828, width: 73.18213, family: "Segoe UI" }]
F: bounds=RoutingBounds { position: Position { x: 1180.0, y: 226.2 }, size: Size { width: 89.18213, height: 56.0 } }; lines=[Line { text: "Technician", position: Position { x: 1194.2905, y: 230.2 }, baseline_y: 243.58281, width: 60.601074, family: "Segoe UI" }, Line { text: "service", position: Position { x: 1205.0847, y: 246.2 }, baseline_y: 259.58282, width: 39.012695, family: "Segoe UI" }, Line { text: "conversation", position: Position { x: 1188.0, y: 262.2 }, baseline_y: 275.58282, width: 73.18213, family: "Segoe UI" }]
ok
thread 'diagram::label_layout_experiment::tests::different_edge_preview_guard_rejection_restores_complete_core_geometry' (7440) panicked at crates\oa-desktop\src\diagram\label_layout_experiment.rs:714:13:
assertion `left == right` failed: No Layout means original complete one-line target geometry, never stale wrapped hit bounds
left: EdgeLabelGeometry { text: "Technician service conversation", fraction: 0.5, anchor: Position { x: 1162.0, y: 274.5 }, center: Position { x: 1162.0, y: 274.5 }, bounds: RoutingBounds { position: Position { x: 1102.4126, y: 254.5 }, size: Size { width: 119.174805, height: 40.0 } } }
right: EdgeLabelGeometry { text: "Technician service conversation", fraction: 0.5, anchor: Position { x: 1162.0, y: 274.5 }, center: Position { x: 1296.5, y: 274.5 }, bounds: RoutingBounds { position: Position { x: 1180.0, y: 262.5 }, size: Size { width: 233.0, height: 24.0 } } }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test diagram::label_layout_experiment::tests::different_edge_preview_guard_rejection_restores_complete_core_geometry ... FAILED
test diagram::label_layout_experiment::tests::measured_backing_canvas_svg_picking_and_focus_share_geometry ... ok
test diagram::label_layout_experiment::tests::scene_and_measurement_cache_reuse_and_geometry_invalidation ... ok
failures:
failures:
diagram::label_layout_experiment::tests::different_edge_preview_guard_rejection_restores_complete_core_geometry
test result: FAILED. 5 passed; 1 failed; 0 ignored; 0 measured; 1546 filtered out; finished in 0.21s
error: test failed, to rerun pass `-p oa-desktop --bin arcadia-studio`
@@ -0,0 +1,13 @@
Compiling oa-core v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-core)
Compiling oa-server v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-server)
Compiling iced_widget v0.14.2 (C:\ar-wrap-01a0d717\crates\vendor\iced_widget)
Compiling oa-desktop v0.2.0 (C:\ar-wrap-01a0d717\crates\oa-desktop)
Compiling iced v0.14.0
error[E0063]: missing fields `source_attachment` and `target_attachment` in initializer of `oa_core::EdgeRoute`
--> crates\oa-desktop\src\diagram\label_layout_experiment.rs:577:60
|
577 | p.diagrams.get_mut(&id).unwrap().routes = vec![EdgeRoute {
| ^^^^^^^^^ missing `source_attachment` and `target_attachment`
For more information about this error, try `rustc --explain E0063`.
error: could not compile `oa-desktop` (bin "arcadia-studio" test) due to 1 previous error
@@ -0,0 +1,21 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"experiment": "bounded measured multiline labels; not production acceptance",
"label_profile": "E",
"compiler_profile": "dev/unoptimized",
"target": "x86_64-pc-windows-gnullvm",
"files": {
"bin/arcadia-studio.exe": {
"bytes": 119551488,
"sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201"
},
"bin/libunwind.dll": {
"bytes": 190976,
"sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
},
"working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

@@ -0,0 +1,16 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"start": "2026-10-02T02:41:31.588364+00:00",
"label_profile": "E",
"binary_sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-E\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 6560,
"exit_code": 0,
"finished": "2026-10-02T02:47:04.978388+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"all_pinned_files_unchanged": true
}
@@ -0,0 +1,35 @@
# Locked first exposure: static screenshot reading
Source: `captures/00-fit-pristine.jpg`, viewed once at original detail as a complete screenshot. No crop, other image, model, repository, code, answer key, or agent interpretation was consulted before these answers. These are first impressions from visible strokes and ports, not verified model facts. Confidence values are qualitative estimates.
## First answers
| Label | First endpoint/direction interpretation | Confidence |
| --- | --- | --- |
| Request field repair | **Assess pressure alarm → Repair valve in the field** | Moderate (about 65%) |
| Report repair result | **Repair valve in the field → Confirm safe pressure** | Moderate (about 60%) |
| Technician service conversation | **Pressure coordination service — Field technician**, with **no clearly visible arrow direction** | Moderate for endpoints (about 65%); moderately high that direction is not visually established (about 80%) |
### Request field repair
I associate this text, just below the Pressure coordination service card, with the horizontal stroke around screenshot y=611, running from about x=430 to x=807. My reading traces its left end upward to the Assess pressure alarm card's right port (roughly 422,568), and its right end upward to the upper left port of Repair valve in the field (roughly 815,591). The upper repair port appears to point toward the repair card, giving the direction above.
The alternatives I cannot confidently exclude are that one of the vertical overlaps belongs to a different relationship, or that the nearby Pressure coordination service is the source. The latter is spatially plausible from the label position but is less consistent with my first attempt to follow the stroke. The outline-like long rectangular routes complicate distinguishing crossings from route turns.
### Report repair result
I associate this label with the horizontal stroke around y=646, extending left from the lower left port of Repair valve in the field (roughly 815,646) to a vertical route near x=521. My first reading follows that route downward toward Confirm safe pressure, whose right port (roughly 511,797) appears to have a leftward arrow. The repair card's lower port also appears oriented leftward, supporting travel away from repair toward confirmation.
I am less confident about the long vertical continuation than the label's association with the y=646 stroke. Reset valve remotely is a plausible mistaken destination because its connection is immediately beside the same vertical corridor; another alternative is that a shared-looking stroke routes back toward the alarm function. The screenshot does not make the separation of coincident or closely spaced vertical lines easy to establish.
### Technician service conversation
My first reading assigns the two-line label to the horizontal connector emerging from the Pressure coordination service card's right square port at roughly (773,568), passing beneath the label toward x=855, and then routing toward the Field technician card's left square port at roughly (865,451). I see square endpoint marks rather than a definite arrowhead at those two cards, so I read a connection with unspecified direction rather than confidently calling it one-way or two-way.
The label appears to own the short horizontal segment immediately below it, near y=568, and its associated orthogonal route toward the technician. It does **not** initially read as the label of the technician-to-repair stroke farther right, which drops from the technician card near x=934 and turns left into the top of the repair card. Nevertheless, the label sits close to multiple vertical strokes and that technician-to-repair relationship is a plausible alternate ownership reading. I cannot confidently distinguish every bend near the shared upper horizontal corridor.
## Legibility and scope
The main application controls are readable. At the displayed 52% diagram zoom, card names require concentrated reading and relationship labels are substantially smaller and faint. “Technician service conversation” is readable as two lines, but its wrapping and position do not by themselves establish stroke ownership. “Request field repair” and “Report repair result” are just legible in the full image, with close scrutiny. Small port shapes and overlapping vertical routes are a greater obstacle to dependable endpoint/direction reading than the large card arrangement.
These answers are deliberately retained as an unverified first exposure. This is evidence from one agent reading one static image; it does not establish human usability, generalized UX performance, a causal comparison, or model correctness. No native GUI interaction or answer-key verification was performed.
@@ -0,0 +1,11 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"start": "2026-10-02T02:41:31.588364+00:00",
"label_profile": "E",
"binary_sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-E\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 6560
}
@@ -0,0 +1,88 @@
{
"status": "PASS",
"profile": "E",
"script": {
"bytes": 9102,
"sha256": "136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099"
},
"metrics_source": "ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d Rust/Iced test stdout; wrapped-label-regression-first.log",
"inputs": {
"baseline_svg": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\baseline.svg",
"bytes": 7209,
"sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d"
},
"candidate_svg": {
"path": ".local\\native-wrapped-E\\working\\pristine-E.svg",
"bytes": 7353,
"sha256": "d84f6c4b03a305f89849b013e809501f7d613203fd2c71bea80b645958a4b64c"
},
"baseline_project": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"candidate_project": {
"path": ".local\\native-wrapped-E\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
},
"full_project_bytes_equal": true,
"edge_uuids": [
"09eaa992-4cdf-5ea3-b748-f10fd74b8cba",
"3cc9ab52-2b00-57fd-8709-aabc75e5d3e3",
"55ec4dbf-bd17-5b0c-b3a3-95b2194aa8b9",
"568c5c01-de21-52a2-83bd-afdddc158085",
"628cb4fc-fe63-5f6b-b364-6268f26b5740",
"63009b5f-539e-5914-b630-ec6b7fefb4d5",
"684eadc3-e670-5779-a60f-bbc9a5bfb062",
"725f2e1b-aa2c-5615-9b1f-28da178168fa",
"93474111-f23e-56c1-b61b-b7c2396b91bd",
"9b9356d7-2db2-5a94-a47e-ea892cf02afe",
"b76bf8de-2fa4-563f-a540-dd30f30e6c49",
"e53b7a40-e8a3-5b3f-826d-c2b5c164a84a"
],
"all_12_edge_records_exact": true,
"root_and_viewBox_exact": true,
"all_remaining_svg_bytes_exact": true,
"remaining_svg": {
"bytes": 6977,
"sha256": "5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed"
},
"removed_baseline_presentation": {
"bytes": 232,
"sha256": "f43b00c1fbce723b31fc308027a537234bedf2ee3f0aea1a163008947a6ac033"
},
"removed_candidate_presentation": {
"bytes": 376,
"sha256": "287d99087d8cb87ab24cc523dbbf367420155271ddfef861821bc95c19d9d311"
},
"expected_logical_metrics": {
"rect": [
1102.4126,
254.5,
119.174805,
40.0
],
"lines": [
[
"Technician service",
1110.4126,
258.5,
271.8828,
103.174805
],
[
"conversation",
1125.4089,
274.5,
287.8828,
73.18213
]
]
},
"numeric_absolute_tolerance": 0.0002,
"conservation_scope": "All edge/path/orientation/drawing, card, port and unrelated label bytes preserved; only target immediate label presentation removed for comparison.",
"limits": "Logical SVG conservation and declared typography coordinates only. No browser/font availability, glyph/raster parity, screenshot reading, native input-event history, save/reopen or usability claim."
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

@@ -0,0 +1,21 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"experiment": "bounded measured multiline labels; not production acceptance",
"label_profile": "F",
"compiler_profile": "dev/unoptimized",
"target": "x86_64-pc-windows-gnullvm",
"files": {
"bin/arcadia-studio.exe": {
"bytes": 119551488,
"sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201"
},
"bin/libunwind.dll": {
"bytes": 190976,
"sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
},
"working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

@@ -0,0 +1,16 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"start": "2026-10-02T02:32:41.313598+00:00",
"label_profile": "F",
"binary_sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-F\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 2056,
"exit_code": 0,
"finished": "2026-10-02T02:41:22.385080+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"all_pinned_files_unchanged": true
}
@@ -0,0 +1,21 @@
# Locked first-exposure reading
Image: `C:/ar-wrap-01a0d717/.local/native-wrapped-F/captures/00-fit-pristine.jpg`
Method: one `view_image` call showing the complete image. No repository, source/model, other artifact, answer key, other agent, or GUI interaction was consulted. These are static image impressions from one agent, not human/generalized usability acceptance. First answers below are locked before any repeat inspection.
## First answers
- **Request field repair:** I cannot reliably identify both endpoints. My tentative stroke-based reading is **Assess an alarm procedure → Confirm safe pressure**, with **very low confidence**. The label appears above the long horizontal stroke at about y=611, which turns at x=430 and runs through a large rectangular detour around the central system card; a possible continuation reaches the right edge of Confirm safe pressure, where a left-pointing triangle is visible. At the right of the labeled segment several close vertical strokes run toward Assess an alarm procedure and Repair valve in the field, and I cannot reliably assign the turns to one connection. **Plausible alternative:** a connection ending at Repair valve in the field, with a source among Assess pressure alarm, Pressure coordination service, or Assess an alarm procedure. The wording suggests a request to the repair function but is insufficient visual evidence to choose that interpretation.
- **Report repair result:** Tentatively **Repair valve in the field → Reset valve remotely**, **low confidence**. The text appears above the horizontal stroke at about y=646, connected at its right to the lower left-facing triangular port on Repair valve in the field. To the left it meets a vertical stroke near x=520 that passes beside Reset valve remotely and Confirm safe pressure. A short leftward arrow reaches Reset valve remotely near y=702. **Plausible alternative:** Repair valve in the field → Confirm safe pressure, or a connection involving Assess pressure alarm via the same closely shared vertical alignment. The lower repair port appears left-facing, but shared/overlapping stroke routes prevent reliable destination assignment.
- **Technician service conversation:** Tentatively **Field technician — Pressure coordination service**, with **no confidently discernible direction**, **low confidence**. The label occupies the gap below/left of Field technician and above Repair valve in the field. It appears most directly associated with the thin vertical stroke near x=856 that bends left into the Pressure coordination service square port at y=568 and up/right toward the Field technician square port at y=451. **Plausible alternative:** it labels the adjacent Field technician → Repair valve in the field connection, whose stroke descends from the bottom of Field technician, turns left, then ends in a clearly downward-pointing arrow at the repair card's top. That latter direction is visually easier to see, but ownership of the nearby conversation label is unclear.
## Legibility and association
The full image contains all eight central cards, but card text, connection labels, and tiny type headings are extremely small at the displayed 52% fit. Names can be read with concentration; the three-line conversation label is especially faint and small. Request/report text requires careful scrutiny against faint lines and dotted background. The label positions do not let me confidently distinguish nearby/overlapping connection routes. Port triangles and ordinary arrowheads also appear to have different meanings, which the image alone does not explain.
The conversation label looks placed between two plausible strokes rather than unambiguously attached to one. My first choice is the left vertical stroke to the system square port, while the more obvious arrowed path from technician to repair is a strong alternative.
Image hash not yet computed at the time these first answers were written. Computing the hash of this same image afterwards does not consult an answer key.
Post-lock image SHA-256: 213647F0F826DEB78267FF58197755E17BFCC6F5F9B86273F90093A45769870E. No repeat image inspection or answer-key verification performed.
@@ -0,0 +1,19 @@
{
"status": "PASS",
"original_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"saved_sha256": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57",
"saved_bytes": 138935,
"declared_edit": {
"edge": "63009b5f-539e-5914-b630-ec6b7fefb4d5",
"waypoints": [],
"label": {
"fraction": 0.55,
"offset": {
"x": 120.812744,
"y": 38.814423
}
}
},
"complete_project_equal_after_removing_only_declared_route": true,
"scope": "F30px right/20px down at displayed52%; no extra formatting field persisted"
}
@@ -0,0 +1,11 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"start": "2026-10-02T02:32:41.313598+00:00",
"label_profile": "F",
"binary_sha256": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-F\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 2056
}
@@ -0,0 +1,95 @@
{
"status": "PASS",
"profile": "F",
"script": {
"bytes": 9102,
"sha256": "136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099"
},
"metrics_source": "ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d Rust/Iced test stdout; wrapped-label-regression-first.log",
"inputs": {
"baseline_svg": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\baseline.svg",
"bytes": 7209,
"sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d"
},
"candidate_svg": {
"path": ".local\\native-wrapped-F\\working\\pristine-F.svg",
"bytes": 7436,
"sha256": "5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0"
},
"baseline_project": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"candidate_project": {
"path": ".local\\native-wrapped-F\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
},
"full_project_bytes_equal": true,
"edge_uuids": [
"09eaa992-4cdf-5ea3-b748-f10fd74b8cba",
"3cc9ab52-2b00-57fd-8709-aabc75e5d3e3",
"55ec4dbf-bd17-5b0c-b3a3-95b2194aa8b9",
"568c5c01-de21-52a2-83bd-afdddc158085",
"628cb4fc-fe63-5f6b-b364-6268f26b5740",
"63009b5f-539e-5914-b630-ec6b7fefb4d5",
"684eadc3-e670-5779-a60f-bbc9a5bfb062",
"725f2e1b-aa2c-5615-9b1f-28da178168fa",
"93474111-f23e-56c1-b61b-b7c2396b91bd",
"9b9356d7-2db2-5a94-a47e-ea892cf02afe",
"b76bf8de-2fa4-563f-a540-dd30f30e6c49",
"e53b7a40-e8a3-5b3f-826d-c2b5c164a84a"
],
"all_12_edge_records_exact": true,
"root_and_viewBox_exact": true,
"all_remaining_svg_bytes_exact": true,
"remaining_svg": {
"bytes": 6977,
"sha256": "5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed"
},
"removed_baseline_presentation": {
"bytes": 232,
"sha256": "f43b00c1fbce723b31fc308027a537234bedf2ee3f0aea1a163008947a6ac033"
},
"removed_candidate_presentation": {
"bytes": 459,
"sha256": "e76e3da1b5ed47c72525052be8bd768caea05d25e89c9c7dcebd53098f7bfbd3"
},
"expected_logical_metrics": {
"rect": [
1180.0,
226.2,
89.18213,
56.0
],
"lines": [
[
"Technician",
1194.2905,
230.2,
243.58281,
60.601074
],
[
"service",
1205.0847,
246.2,
259.58282,
39.012695
],
[
"conversation",
1188.0,
262.2,
275.58282,
73.18213
]
]
},
"numeric_absolute_tolerance": 0.0002,
"conservation_scope": "All edge/path/orientation/drawing, card, port and unrelated label bytes preserved; only target immediate label presentation removed for comparison.",
"limits": "Logical SVG conservation and declared typography coordinates only. No browser/font availability, glyph/raster parity, screenshot reading, native input-event history, save/reopen or usability claim."
}
@@ -0,0 +1,95 @@
{
"status": "PASS",
"profile": "F",
"script": {
"bytes": 8851,
"sha256": "e679b3dfb056d441c4627967b469118621f83e6941c7a6daa4213ce3a7ff4970"
},
"metrics_source": "ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d Rust/Iced test stdout; wrapped-label-regression-first.log",
"inputs": {
"baseline_svg": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\baseline.svg",
"bytes": 7209,
"sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d"
},
"candidate_svg": {
"path": ".local\\native-wrapped-F\\working\\pristine-F.svg",
"bytes": 7436,
"sha256": "5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0"
},
"baseline_project": {
"path": "C:\\ar-label-cue-01a0d717\\.local\\native-cue-baseline\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"candidate_project": {
"path": ".local\\native-wrapped-F\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
},
"full_project_bytes_equal": true,
"edge_uuids": [
"09eaa992-4cdf-5ea3-b748-f10fd74b8cba",
"3cc9ab52-2b00-57fd-8709-aabc75e5d3e3",
"55ec4dbf-bd17-5b0c-b3a3-95b2194aa8b9",
"568c5c01-de21-52a2-83bd-afdddc158085",
"628cb4fc-fe63-5f6b-b364-6268f26b5740",
"63009b5f-539e-5914-b630-ec6b7fefb4d5",
"684eadc3-e670-5779-a60f-bbc9a5bfb062",
"725f2e1b-aa2c-5615-9b1f-28da178168fa",
"93474111-f23e-56c1-b61b-b7c2396b91bd",
"9b9356d7-2db2-5a94-a47e-ea892cf02afe",
"b76bf8de-2fa4-563f-a540-dd30f30e6c49",
"e53b7a40-e8a3-5b3f-826d-c2b5c164a84a"
],
"all_12_edge_records_exact": true,
"root_and_viewBox_exact": true,
"all_remaining_svg_bytes_exact": true,
"remaining_svg": {
"bytes": 6977,
"sha256": "5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed"
},
"removed_baseline_presentation": {
"bytes": 232,
"sha256": "f43b00c1fbce723b31fc308027a537234bedf2ee3f0aea1a163008947a6ac033"
},
"removed_candidate_presentation": {
"bytes": 459,
"sha256": "e76e3da1b5ed47c72525052be8bd768caea05d25e89c9c7dcebd53098f7bfbd3"
},
"expected_logical_metrics": {
"rect": [
1180.0,
226.2,
89.18213,
56.0
],
"lines": [
[
"Technician",
1194.2905,
230.2,
243.58281,
60.601074
],
[
"service",
1205.0847,
246.2,
259.58282,
39.012695
],
[
"conversation",
1188.0,
262.2,
275.58282,
73.18213
]
]
},
"numeric_absolute_tolerance": 0.0002,
"conservation_scope": "All edge/path/orientation/drawing, card, port and unrelated label bytes preserved; only target immediate label presentation removed for comparison.",
"limits": "Logical SVG conservation and declared typography coordinates only. No browser/font availability, glyph/raster parity, screenshot reading, native input-event history, save/reopen or usability claim."
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

@@ -0,0 +1,19 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"profile": "Baseline",
"start": "2026-10-02T02:51:26.581374+00:00",
"files": {
"bin/arcadia-studio.exe": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"bin/libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"working/moved-F.json": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-Baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"external_profile": null,
"pid": 8056,
"exit_code": 0,
"finished": "2026-10-02T02:52:19.584132+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"all_pinned_files_unchanged": true
}
@@ -0,0 +1,14 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"profile": "Baseline",
"start": "2026-10-02T02:51:26.581374+00:00",
"files": {
"bin/arcadia-studio.exe": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"bin/libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"working/moved-F.json": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-Baseline\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"external_profile": null,
"pid": 8056
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@@ -0,0 +1,19 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"profile": "F",
"start": "2026-10-02T02:47:59.060657+00:00",
"files": {
"bin/arcadia-studio.exe": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"bin/libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"working/moved-F.json": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-F\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"external_profile": "F",
"pid": 7244,
"exit_code": 0,
"finished": "2026-10-02T02:51:21.578722+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"all_pinned_files_unchanged": true
}
@@ -0,0 +1,14 @@
{
"source": "d0896ced75fea73bcda6bd14f259a34503840704",
"profile": "F",
"start": "2026-10-02T02:47:59.060657+00:00",
"files": {
"bin/arcadia-studio.exe": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
"bin/libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"working/moved-F.json": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"cwd": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-F\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"external_profile": "F",
"pid": 7244
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.3 KiB

@@ -0,0 +1,47 @@
# Predeclared native E/F trial
Parent owns the native UI, source, compiler, exact launch receipts and byte/model
oracles. Existing readers know this case; any review by them is an experienced
reader check, not pristine first exposure. A newly isolated reader is desired;
tool thread limits currently prevent further independent native delegation.
Freeze the identified built GUI, runtime f456 and complete fixture 9db in new
F/E folders. Launch with restricted system PATH and exactly one explicit
ARCADIA_LABEL_EXPERIMENT profile. Verify hashes before and after each normal
close and preserve empty/nonempty streams. Do not overwrite prior captures.
For F then E, open the complete fixture through the native filename field;
System perspective; saved representative mixed eight-card view; Fit; zero
selection. Record actual window/canvas dimensions and zoom, full scene, target
box and visible line placement. No projections or relationships are removed.
Before selecting anything, record which route the conversation appears to own,
plausible alternatives, whether the own route remains traceable, and whether
text/backing touches a foreign route. This is a qualitative check, not a causal
effect estimate or a human study.
Export an untouched SVG through native UI. Compare all twelve semantic paths,
all unrelated labels/cards/ports/drawing records and viewBox to baseline. Only
the declared target label presentation may differ. Inspect actual rendered SVG
and native text extents rather than treating shared strings as glyph parity.
Click inside each target line/backing and verify actual selected relationship.
Move the label by a predeclared 30 pixels right / 20 pixels down; preserve the
line shape during and after movement. Undo returns to exact automatic layout;
Redo restores the authored layout; Undo/Redo do not change paths or endpoints.
Cancellation at a menu/idle boundary must preserve the current model. The native
drag API is atomic, so held-pointer cancellation cannot be claimed from it.
Save JSON to a fresh explicit path through focused filename typing. Compare the
complete parsed Project: only one target EdgeRoute label fraction/offset may
change. All paths and twelve semantic relationships remain exact. Close and
reopen that exact saved file under the same profile; shape and authored position
must survive. Ordinary profile absence intentionally derives a one-line label;
this is an unresolved production formatting contract, never formatting-parity
acceptance. If a visual or lifecycle falsifier appears, preserve it and stop
promotion rather than tune the same scene until it looks successful.
The different-edge guard-refusal transition has a targeted actual core-preview
regression; observe a representative native foreign-label move if practical.
Full Allocation drop/frozen-occluder coverage is excluded because this case is
Traceability. General fonts, nesting, algorithm performance, other machines,
DPI/accessibility, Linux and production integration remain unverified.
@@ -0,0 +1,88 @@
# Independent E/F final evidence review
Reviewed experiment source HEAD `d0896ced75fea73bcda6bd14f259a34503840704` in `C:/ar-wrap-01a0d717`, both locked first-reading reports, both completed native launch receipts, actual E/F pristine SVG exports, the F saved-model export and receipts, both checker scripts, oracle selfcheck records, and relevant source/test evidence. E's export became available during this review and is included below.
Read-only work: no GUI, Cargo, source modification, Gitea, or publication. Only this report was written. PowerShell reads independently checked the actual SVG remainder and complete parsed F Project conservation; I did not merely accept receipt status strings. I did not re-read screenshots as a fresh reader or claim visual acceptance.
## Ranked findings and recommendation
1. **Promotion blocker: neither arm establishes reliable unselected ownership.** F's locked first reader retains the ordinary technician-to-repair allocation as a strong alternative for the conversation, and gives incorrect tentative first endpoints for Request and Report. E's first participant/endpoint answers are correct, but its reader explicitly retains plausible allocation ownership and uncertainty over shared-looking route continuations. The predeclared gate required the original wrong-ownership alternative to disappear without coaching. E therefore does not pass that gate merely because its first endpoint guesses were correct. Preserve both arms as useful failed/insufficient visual hypotheses; do not production-promote either.
2. **Evidence scope: conservation and logical export checks pass, but cannot substitute for the failed reading gate.** Both actual SVGs preserve every byte outside the target's declared presentation. F's saved Project has exactly the declared target-label route addition. These results rule out diagram simplification or semantic loss as the explanation for those exact artifacts; they do not establish glyph parity, native event history, same-profile reopening, or broad usability.
3. **Reporting gap, not a newly found code bug: lifecycle coverage is narrower than the predeclared plan.** The reviewed F captures/receipt support final serialization after one drag, with observed Undo/Redo captures held separately. No same-profile reopen receipt, after-move SVG/core geometry oracle, complete per-line click inventory, held-pointer cancellation, or native different-edge fallback result was present in the reviewed packet. E has a pristine visual/export result, not a matching edit/persistence result. Record these as unverified/stopped after a visual falsifier, not as implicit passes. Because the experiment is not being promoted, there is no need to finish every general-product gate merely to archive a negative result.
4. **Oracle maintainability limitation:** the model helper is deliberately F-specific and weaker as a reusable failure-recording harness than the SVG checker. It relies on Python assertions and writes a receipt only after all checks pass; optimized `python -O` would disable its checks, and failures otherwise leave no structured failure receipt. Its script hash is not embedded in its own receipt. This does not invalidate the independently checked actual F result, but publish the checker hash and invocation with it and do not call it a generic E/F lifecycle oracle. The tautological `assert 0.515 <= 0.525` tests nothing; the actual following offset bounds do the useful admission.
No new source-correctness blocker was found beyond the already repaired raw/presentation preview issue. The repair review remains the source assessment for d089. The correct next outcome is a preserved experimental evidence packet and an open broader readability problem, not release acceptance or a retuned threshold presented as success.
## First-reading interpretation
Both reports explicitly describe one isolated agent reading one static complete screenshot, not a human user or a native interactive session. The F report locks first answers before repeat inspection and records a post-lock image hash. E similarly locks first exposure; its image/report hashes are recorded below. First-reader isolation is supplied by those reports; filesystem inspection cannot independently prove what context an agent had seen.
F tentatively reads Request as Assess an alarm procedure to Confirm safe pressure and Report as Repair to Reset, with low confidence. Its conversation first choice is the actual system/technician connection, but the ordinary allocation remains a strong alternative. E correctly names Request, Report, and conversation participants with moderate confidence, while describing unresolved branch/overlap ambiguity and plausible alternate conversation ownership. E's observation that no arrow direction is established for the conversation is **not** itself an error: that boundary exchange is unoriented. The failure is dependable route/label association, not a demand to infer direction where none exists.
Differences between E and F cannot establish a causal superiority estimate: there is one different reader per arm, no replicated/counterbalanced cohort, and tiny text is judged through a screenshot. F's Request/Report errors do not prove wrapping caused a regression, since their exported paths and label bytes are unchanged. They do show that this complete-view reading task remains difficult in that exposure. E may justify a recorded qualitative lead, but not a pass or a general preference.
## SVG oracle assessment and independent check
`check-wrapped-svg.py` is appropriately strict for its stated job. It pins both adjacent original input Projects; checks the root/viewBox, all twelve distinct edge records, canonical title, exact group structure and attributes; compares E/F coordinates to pre-existing Rust/Iced metrics rather than fitting the candidate export; and removes only the target's immediate label presentation before comparing **all remaining raw bytes**. The v2 nested-element/stray-text guard closes a meaningful exclusion-hole in the earlier version. Exclusive receipt creation preserves prior results. The corruption selfchecks cover foreign path, viewBox, target font/baseline/word, unrelated label, card, port, orientation and nested presentation; their first failed setup is separately retained.
Independent read-only checks in this review confirmed both E/F raw remainders are exactly equal to the native baseline remainder. Actual file hashes match the current-script receipts:
- Baseline: 7,209 bytes, `645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d`.
- E: 7,353 bytes, `d84f6c4b03a305f89849b013e809501f7d613203fd2c71bea80b645958a4b64c`.
- F: 7,436 bytes, `5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0`.
- Common remaining SVG: 6,977 bytes, receipt hash `5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed`.
The receipt's `full_project_bytes_equal` describes the **two retained input files**, not proof that no in-memory edit preceded an export. Native process/capture chronology supplies that additional claim. Likewise, hardcoded metric expectations come from earlier output of the implementation under test. That makes them an independent fixed **export-conservation** target; it does not make them an independent typography renderer or ground-truth glyph oracle.
SVG line x/baseline y, full text, font family and backing dimensions match those declared logical records. The file still contains text strings, not glyph outlines or explicit per-glyph positions. Canvas uses its cached shaping path at scaled size; SVG viewers shape strings themselves and may apply different kerning/fallback. No actual rendered-SVG/glyph comparison appears in this packet. The scripts correctly disclaim that; preserve the disclaimer in publication.
## F model oracle assessment and independent check
The checker pins the immutable original file, requires that the target route was absent originally and occurs once after the edit, allows only the known route fields, requires empty waypoints and no attachments, checks fraction .55 and the declared drag-compatible offset range, then removes only that new route and requires full parsed Project equality. This catches unrelated semantic, view, placement, authored-route and sentinel changes, rather than just comparing endpoint counts.
I independently parsed both actual JSON files as PowerShell hashtables, removed only the one target route from the saved Project, and compared their full normalized serialization: equality held. The saved route is:
```json
{"edge":"63009b5f-539e-5914-b630-ec6b7fefb4d5","waypoints":[],"label":{"fraction":0.55,"offset":{"x":120.812744,"y":38.814423}}}
```
Using the declared original F x offset 62.591065 and the declared native 30/20 pixel movement gives independently calculated zooms:
- x: 30 / (120.812744 - 62.591065) = 0.5152719831;
- y: 20 / 38.814423 = 0.5152723770.
Those agree to expected f32 rounding and both round to displayed 52%. Thus the actual artifact is more coherent than merely passing the helper's separate per-axis tolerance bands. The helper does not generically require one common zoom, but no inconsistent-axis case occurred here. Its approximate bounds also cannot establish exact pointer coordinates or one history transaction; those are native interaction evidence.
The saved model contains no new formatting field and only the target's authored fraction/offset changes. It therefore supports the explicit external-profile experiment contract. It does not prove ordinary product wrapping persistence. Core source separates path routing from label placement, and the targeted tests cover path preservation, but this receipt itself does not reroute the saved file or compare post-edit computed geometry.
## Source, execution and missing acceptance dimensions
Source hashes still match the repair-reviewed d089 files. The retained parent log reports 126 tests passed in its broader filtered run; strict Clippy and build logs finish successfully. Those are parent execution records, not reruns by this reviewer, and do not override the visual result. The historical six-test failure and its complete stale-E-geometry assertion remain useful evidence of a discovered/repaired defect.
Both completed native receipts identify the same executable hash `2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201`, source d089, f456 runtime, and immutable 9db fixture. The launcher sets the explicit E/F environment, strips competing ARCADIA/WGPU/toolchain overrides, records the process, and checks clean exit, empty streams and unchanged pinned files. That is appropriate experiment provenance. It is not a cryptographic attestation that the exported SVG came from that process or that the binary corresponds to source; the frozen build/copy/UI workflow supplies those links.
The repair preserves core baselines and complete fallback geometry. Remaining limitations are unchanged: visual label movement on automatic guard refusal, no general font/version/raster study, no ordinary persisted formatting policy, no general candidate-selection rule, no nested/folded or Allocation frozen-occluder acceptance, no cross-platform/DPI/accessibility acceptance, and no generalized performance claim. The full twelve-relation/eight-card reading gate remains open.
## Reviewed fingerprints
All SHA-256 values below were read from actual files during this review. Paths are relative to `C:/ar-wrap-01a0d717` unless stated otherwise.
| Artifact | SHA-256 |
| --- | --- |
| .local/check-wrapped-svg.py | 136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099 |
| .local/check-wrapped-model.py | 55765130c9aabe85e1b8b243aa12272a88de66f8d0d62d38d66150a7c18d009e |
| .local/native-wrapped-E/first-reading.md | 9de823d0d43e7753f2799e203a68332b7361c1c6c2f8f18baece5c60baa01c66 |
| .local/native-wrapped-F/first-reading.md | 2867ba22c3195e7b77cf696fffbdcc65ca6e8a74dc212f38407ef797216b5f8e |
| .local/native-wrapped-E/captures/00-fit-pristine.jpg | 48adaf65c6b655e66bcab47d3a7a4ac9080a0da4f7e98dc84e9ea9573f731acb |
| .local/native-wrapped-F/captures/00-fit-pristine.jpg | 213647f0f826deb78267ff58197755e17bfcc6f5f9b86273f90093a45769870e |
| .local/native-wrapped-E/svg-conservation.json | 968ae031b1e25940c70332b3a3351df7dc08b11040b211537c477c0d7fe3e88b |
| .local/native-wrapped-F/svg-conservation-v2.json | d8c738cb16c7cf756f7ecc23816c367ea7ccc01df74bde686d3eeb7c2bb7f4c6 |
| .local/native-wrapped-F/model-oracle.json | 007e0ca5765c80a6726d27a28ecc39e2a7e252d3c42aab17c544185e7d512928 |
| .local/native-wrapped-F/working/moved-F.json | 0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57 |
| .local/native-wrapped-E/finished.json | 20ea462b837ac98d02fe41b56446d1fe8a4f2e6f7a640b26c37e45016e069537 |
| .local/native-wrapped-F/finished.json | 304b144a7c2f9696a1006e9fbd9dd64084887904e6c7e5293b9eca5602493b28 |
| crates/oa-desktop/src/diagram.rs | ab84ccce8ed8388318829489dda8e741e0e6ddd5ceda45929e1a548fa0006e75 |
| crates/oa-desktop/src/diagram/label_layout_experiment.rs | 1d2d8dd01f40d851548183ac9a2c55b02752526008a3e31e384a63e033b09942 |
Publish this as evidence of a preserved, bounded experiment with a meaningful negative reading result and verified artifact conservation. Do not label it an accepted readability improvement, persisted wrapping feature, or successful release milestone for issue 38.
@@ -0,0 +1,108 @@
# E/F measured-label experiment implementation handoff
Local uncommitted implementation against `6ea7518e7be5b5f17d5fbc5d667da8b388058af4`.
No compiler, GUI, Gitea, commit or push run by this worker. Root owns all gates.
`rustfmt --edition 2024 --config skip_children=true` completed for the six
explicitly owned/authorized Rust files. This establishes formatting only.
## Changed implementation
- New private `crates/oa-desktop/src/diagram/label_layout_experiment.rs` contains
read-once external E/F/Baseline profile, one-target identity guards, measured
typography cache, shared Layout, fixed placements, collision guards, Canvas
line records, explicit SVG line export and five focused tests.
- `diagram.rs`: Scene stores the shared Layout, profile and font-system version;
both ordinary and work-preview scenes apply it before geometry consumers.
Existing cache additionally keys profile/font version. Drawing and SVG consume
the same ordered line positions. Derived target label bounds feed existing hit
and route-drag start code. The private adapter applies to already-routed data.
- Parent-authorized thin calls: `app.rs` Fit, `diagram_usage.rs` whole/edge bounds,
and `diagram/work_drag.rs` dirty-input shield. No second routing call introduced.
- `diagram/attachment_tests.rs`: existing manual Scene literal gains default fields.
- Parent supplied the pinned `harness/experiments/wrapped-label-20261001/fixture/eight-card.json`;
it is referenced with include_bytes, not rewritten by this worker.
No changes to core, schema, source formats, canonical label.text/Name, Project,
port/card/path state, or B's cue. The fixture and diagram are identified exactly;
other labels return untouched. Baseline returns the complete routed value unchanged.
Automatic guard failure leaves baseline rather than painting an invalid narrower
shape over an old hitbox. Nested/collapsed scenes are excluded from this witness.
## Measurement and scope
Pinned Iced 0.14 graphics Paragraph is accessible through
`iced::advanced::graphics::text::Paragraph`; the same implementation is used by
Canvas Text. Each fixed line is shaped at font 13 with absolute line height 16,
Basic ASCII shaping and no wrap. Width comes from Paragraph min_width; baseline
and resolved face family come from actual cosmic-text runs. A single face per
line is required; mixed fallback or unsupported metrics reject the trial.
Cached measurements are keyed by profile and Iced font-system version; ordinary
hover, selection and camera changes reuse the entire Scene. No character-count
width heuristic is used.
SVG writes explicit per-line x and shaped baseline y with the resolved family,
not browser wrapping or generic sans-serif. It does not embed the font: native
export rendering and font availability on another machine remain a validation
boundary, not proven glyph parity. Tests compare generated text/geometry records,
not raster output or browser appearance.
Automatic E permits exactly one straight own segment crossing both padded sides;
all foreign strokes, cards and labels (including association-end labels) are
excluded. Automatic F clears all strokes. Guards use measured boxes, card margin
12, other-label margin 4 and stroke margin 3. Fixed F's own-is-closer width margin
is explicitly asserted by its fixture test rather than accepted as a general
placement scoring rule.
Authored target labels keep the externally selected line shape and honor actual
fraction/offset. They deliberately retain that shape when a user moves into a
collision, reporting Layout.clear=false; silently unwrapping/resetting would
violate the trial boundary. Conservative whole-scene bounds retain prior bounds
and include moved authored boxes. No ordinary save/reopen formatting contract,
general typesetter, placement winner, or production policy is claimed.
## Parent gates
Suggested targeted test selector:
```powershell
cargo test --locked -p oa-desktop label_layout_experiment -- --test-threads=1 --nocapture
```
Five tests cover full unchanged baseline and all 12 point arrays/other labels,
actual measured dimensions and guard result, matching Canvas/SVG/picking/focus
geometry records, foreign-stroke/card rejection without mutation, authored
fraction/offset/shape retention during real route-preview construction, and
actual Scene/measurement cache reuse plus profile/revision invalidation.
The first test prints measured line/family/bounds records for parent capture.
Compilation, strict lint, fixture guard feasibility on this font installation,
native rendering, actual edit lifecycle, performance, independent fresh-reader
trial, and integration/publication remain pending. Preserve first failures and
revise at the responsible layer; no successful test/native outcome is asserted.
## Captured failure and responsible preview-baseline correction
Parent observed initial source `d8ccd6ed49adac799c02a3c52cb9e431214a4963`
fail compilation because the test EdgeRoute literal omitted its attachment fields.
The first compiler log remains `.local/wrapped-label-tests-first.log`.
At regression source `ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d`, parent observed
five tests passing and the added different-edge preview regression failing:
guard rejection cleared Layout, but target geometry retained wrapped E bounds
(119.174805 x 40) instead of core one-line bounds (233 x 24). Parent's measured
F was 89.18213 x 56; both used Segoe UI. These are parent-reported executed
results, not worker-executed gates. Failed transition log is retained at
`.local/wrapped-label-regression-first.log`.
Correction, now local and frozen for parent compilation: Scene retains a
`core_routed` Arc before the experiment modifies derived presentation. Both
ordinary and allocation-work-preview constructors store that raw Arc; Baseline
shares it with `routed` without copying. `begin_route_with_profile` captures
`core_routed`, so core preview freezes raw one-line labels and a refused wrapper
leaves a complete valid fallback. No guards, measured dimensions, route/path
scoring or failing-regression assertions were changed. The existing authored
preview test setup now uses the same raw baseline contract; existing cache test
also checks Baseline's Arc identity. The one manual Scene literal was updated.
No additional compiler/native execution by this worker. Explicit-file rustfmt
and git diff --check passed. Parent rerun of all six tests and broader gates is
pending at this correction checkpoint.
@@ -0,0 +1,63 @@
# Independent repair review: raw routing versus wrapped presentation
Reviewed HEAD `d0896ced75fea73bcda6bd14f259a34503840704` in `C:/ar-wrap-01a0d717`, with a clean tracked working tree at review start. Read-only source/history/log review; no Cargo, native UI, source edit, Gitea, or commit action. Only this report was written. The initial source review remains historical.
## Conclusion
The repair addresses the actual state-ownership defect at the desktop scene/gesture boundary. I found no new blocking source issue in this bounded fix. It is not merely an expectation change that makes the demonstrated case pass: raw geometry is preserved before presentation mutation in both scene constructors, and the production gesture entrypoint captures that raw geometry. This supports proceeding with the parent's targeted verification, without implying visual, persistence, glyph, latency, or release acceptance.
## Failure evidence and what changed
The preserved `.local/wrapped-label-regression-first.log` records the six-test run before repair: five passed, the new different-edge preview test failed. Its actual E label was 119.174805 x 40 centered on its own anchor, while the expected complete core label was 233 x 24 centered at (1296.5,274.5). The scene had no wrapping Layout. This reproduces the previously identified coupling failure using actual measured Segoe UI geometry, rather than the older approximate rectangle widths.
The regression's measured F was 89.18213 x 56. These are historical log observations from that parent-run build, not fresh native measurements or tests executed by this reviewer. The earlier E0063 fixture-constructor omission is separate from the reproduced runtime-state assertion; it does not explain away that assertion.
Commit d089 introduces `Scene.core_routed: Arc<RoutedView>` while retaining `Scene.routed` for presentation:
- Ordinary scene construction obtains the core result from `route_diagram` or `route_edge_preview`, stores it, then clones its Arc before applying the experiment to presentation geometry.
- Work-preview scene construction stores the externally supplied core preview Arc before applying the same adapter to a distinct presentation Arc.
- `begin_route_with_profile`, called by ordinary `begin_route`, captures `scene.core_routed`, not `scene.routed`.
- The hand-constructed authored-preview test now obeys the same raw-baseline invariant. The attachment-test Scene literal has the new field with shared Baseline geometry.
`Arc::make_mut` creates a separate value for the E/F presentation branch because the core Arc remains held. The raw baseline therefore cannot accidentally acquire the experiment's label geometry through that mutation.
## Why the repair covers the causal path
For any normal gesture, core preview now receives a baseline generated entirely by core routing. Its documented unchanged-edge retention copies complete ordinary labels. The E/F adapter then either supplies a Layout and matching transformed target geometry, or refuses and leaves the complete core label intact. A conflict caused by a foreign **label** and a conflict caused by a foreign **stroke** converge on the same refusal path; the repair does not special-case the test's foreign edge or geometry.
The regression selects another nonempty label, starts through the real `begin_route_with_profile` helper, moves the actual Gesture with `move_to`, obtains the preview diagram, and independently constructs the expected core preview from the raw baseline. It requires guard refusal, no Layout, all twelve point arrays unchanged, unrelated labels unchanged, exact target core-label equality, and complete routed-result equality. It failed before the repair and those assertions remain unchanged. Replacing the authored test's manually assembled baseline with `scene.core_routed` updates its setup to the corrected production invariant; it does not relax its shape/offset/path assertions.
This test is stronger for isolating the fault than a foreign-bend example because it makes every route-point array stay exact. It does not itself exercise every bend/attachment gesture; source inspection shows those gestures use the same repaired baseline entrypoint. Broader diagram gates remain the parent's independent check.
## Target-label drag and normal behavior
Target-label drag still starts from the **presented** label geometry used for hit testing. Existing code obtains its current fraction and center-minus-anchor offset and inserts those authored values before calling `begin_route`. Changing the captured routing baseline does not replace those authored values with the old one-line placement. Core preview uses the raw paths and explicit authored label; the adapter retains the selected E/F line shape using that fraction/offset, even when the authored move conflicts with a guard. The repair therefore avoids the original contaminating baseline without discarding target drag intent.
A target bend or attachment gesture also keeps core path/solver metadata as its baseline. Wrapping remains a derived overlay; no production router, semantic data, route points, authored fields, guard predicate, dimension, or candidate score was changed by this repair.
The automatic target can now visibly return to the ordinary one-line position when another edit makes its wrapped placement invalid. That is the existing declared fallback, now internally consistent; it is **not** a stability or readability success. A future product policy would need to assess that visible transition separately. The fixed-scene native reading trial should not silently claim this repair prevents label movement during unrelated edits.
## Cache and Baseline constraints
Cache keys and reuse conditions are unchanged. A cache hit returns one Scene containing both raw and presentation Arcs; pointer, selection, camera changes, and unchanged geometry do not recreate those values. Baseline skips the adapter and shares the same Arc between `core_routed` and `routed`; the added pointer-equality assertion directly checks that ordinary behavior avoids an unnecessary deep clone. Work-preview source likewise shares in Baseline.
E/F scene rebuilds deliberately hold raw and presentation copies. This adds bounded memory/copy cost to the opt-in experiment. Because `Arc::make_mut` is called before the adapter checks diagram eligibility, a rebuild under an E/F environment profile may clone an unrelated diagram's routed geometry even though apply immediately refuses it. This is not a correctness blocker for the fixed small trial, and this review does not propose speculative cache restructuring. It is a limit to measure before claiming general performance neutrality.
No repeated core routing call was introduced solely to repair the state mismatch. Baseline path geometry and existing core preview semantics are preserved.
## Remaining limits from the initial review
The repair does not change typography or SVG behavior. Canvas cached shaping at scaled size and SVG viewer shaping still require actual rendering comparison; shared line records do not establish glyph parity. Authored wrapping still depends on the explicit external profile, so ordinary save/reopen formatting remains outside the acceptance claim. The dormant Allocation `Frozen::capture` label-bound mismatch remains outside the fixed Traceability workflow and was not addressed or newly exercised by this repair.
This review neither ran nor asserts the outcome of the parent's current `diagram::`, `diagram_usage::`, or Fit gates. Source review supports the repair's mechanism; test logs and native evidence must be attached separately to the tested commit. No new visual or persistent formatting acceptance follows from the regression passing.
## Reviewed fingerprints
| File | SHA-256 |
| --- | --- |
| crates/oa-desktop/src/diagram.rs | ab84ccce8ed8388318829489dda8e741e0e6ddd5ceda45929e1a548fa0006e75 |
| crates/oa-desktop/src/diagram/label_layout_experiment.rs | 1d2d8dd01f40d851548183ac9a2c55b02752526008a3e31e384a63e033b09942 |
| crates/oa-desktop/src/diagram/attachment_tests.rs | 71e8525b04c6ed2563d11dcd5653c86ed492b212cb98e386d51c01547e2af377 |
| .local/wrapped-label-regression-first.log | 4759fdfa2a879ae8e645d27fb3a6ea89fef5181efa67bb1cc82a7d7131141bbc |
The initial module hash `29a44d5c...` and initial source review describe the pre-repair implementation. This report is scoped to d089 and the full hashes above; it does not overwrite or relabel the earlier failure as success.
@@ -0,0 +1,78 @@
# Independent source review: measured E/F wrapped-label experiment
Read-only review of `C:/ar-wrap-01a0d717`, initially uncommitted against `6ea7518e7be5b5f17d5fbc5d667da8b388058af4`; parent froze the same inspected source during review as `d8ccd6ed49adac799c02a3c52cb9e431214a4963`. This reviewer did not run Cargo, native UI, a renderer, or change source. Only this report was written. Parent owns reproduction, compilation, repair, visual evaluation, and publication.
Read the implementation handoff/intent, the alternatives and independent design critique, six touched Rust files, relevant core preview logic, and installed Iced/cosmic-text implementation. This is a narrow opt-in experiment review, not a general wrapping-policy or usability acceptance.
## Finding requiring a bounded fix or explicit edit-scope exclusion
**P2: a different edge's preview can retain wrapped bounds while losing its wrapping renderer.**
The coupling between the modified `RoutedEdge.label` and `Scene.label_layout` fails on a guard-refusal transition:
1. Build an automatic E/F scene. `apply` replaces the target's derived label bounds/center/fraction, and the scene holds its line layout.
2. Begin a route gesture on another edge. `diagram.rs:644` captures `self.scene(state).routed` as the gesture baseline, so the baseline includes the wrapped conversation geometry.
3. Move a foreign path through that label box. `routing.rs` preview logic copies unchanged edges/labels from the baseline and only regenerates the changed edge's label. Thus the conversation keeps its wrapped geometry.
4. `diagram.rs:605–624` passes that routed preview to `apply`. The new foreign stroke makes `guarded` false; because the target is still automatic, `label_layout_experiment.rs:192–195` returns None without modifying it.
5. The resulting scene has no Layout but still has the wrapped target geometry. `diagram.rs:1415` falls back to drawing the full one-line canonical string centered over a two-/three-line backing and hitbox. This violates the shared-layout invariant and can paint outside the hit region.
Concrete reproduction setup for the parent: load the pinned fixture with F; obtain the wrapped target box and center; select ordinary allocation `725f2e1b-aa2c-5615-9b1f-28da178168fa`; construct a normal route preview with a waypoint at that box's center (approximately the declared F witness around x1230/y254.2, but use measured geometry). Set Gesture.baseline to the pre-gesture scene.routed and changed=true. That point is in the free corridor and forces the foreign path to intersect the box when the pin is honored. Verify the route really intersects before asserting the mismatch. E supplies the same control. Preserve the first failure as evidence.
Responsible fix boundary: the desktop experiment's scene/preview adapter must keep wrapped geometry and its line layout together. Either retain the frozen target's existing layout during an unrelated route preview, with clear=false recording the conflict, or restore a **complete** matching one-line geometry/layout when falling back. Do not weaken the automatic guard globally, discard the other's preview, or reroute production paths to hide this state mismatch. Core routing's documented unchanged-edge preview retention is functioning as designed.
The existing five tests do not cover this path: the authored test drags the target label itself, which intentionally bypasses guard refusal; the guard tests start from an unwrapped core baseline. A focused different-edge preview regression is justified. Until resolved, the untouched fixed-scene visual trial may still proceed with its narrow limits, but edit-lifecycle parity cannot pass.
## Typography and export fidelity
The code genuinely measures the fixed lines using the installed Iced/cosmic-text stack, with font size 13, absolute line height 16, default Font, Basic shaping, and left/top alignment. Width is `Paragraph::min_width`, baseline is `run.line_y`, and a resolved font family is retained. Unsupported multiple runs, RTL, and mixed faces within a line reject measurement. The canonical semantic text remains unchanged; line breaks are presentation only. This is materially stronger than the earlier character-count arithmetic.
However, the handoff's statement that Canvas Text uses the same Paragraph implementation is incomplete for the normal rendering path. In both `iced_wgpu-0.14.0/src/geometry.rs:306` and `iced_tiny_skia-0.14.0/src/geometry.rs:173`, positive uniform scale/translation goes through **Text::Cached**, scaling font size and absolute line height first. `iced_graphics-0.14.0/src/text/cache.rs` creates and shapes its own cosmic-text buffer. `Paragraph::with_text` through `geometry/text.rs::draw_with` is the other transform path. The inputs align for this fixed ASCII/infinite-width case, but the actual Canvas is not drawing the measurement Paragraph or immutable measured glyph positions. Pixel/antialiasing and scaled-metric parity remain native checks.
SVG has the correct logical box, ordered strings, explicit line starts, measured baselines, and resolved family. It nevertheless delegates each entire string's glyph placement to the SVG viewer. Cosmic-text Basic shaping (`cosmic-text-0.15.0/src/shape.rs`, `shape_skip`) uses individual glyph advance widths without contextual kerning; the SVG has no explicit per-glyph positions or kerning/ligature policy. Family names also do not embed the resolved face. Consequently **shared line records are established by source, exact glyph parity is not**—even on the same machine, browser shaping can differ. This is not a demonstrated clipping defect; compare actual exported and native rendering before claiming fidelity. Avoid solving arbitrary fonts or SVG shaping globally for this witness.
`min_width` is a layout advance bound, not an exact glyph-ink contour. The eight-unit horizontal padding and declared line spacing may be adequate for these words, but tests checking measured widths inside backing are not an independent raster extent check.
## Cache and font-version assessment
The measurement cache keys profile and Iced FontSystem Version. Scene/work-preview caches additionally compare profile and font version, along with existing context/preview/route/port state. Ordinary pointer, selection, pan and zoom changes therefore reuse logical layout rather than remeasure/rescore. Baseline avoids initializing the font-system version path. No new per-hover route scan was found in the ordinary scene path.
Iced's Version increments when its `FontSystem::load_font` loads font bytes. Raw database mutation through `.raw()` is outside that contract. No dynamic runtime font-loading path was found in this application's normal setup, so there is no demonstrated stale-font bug for the fixed trial. A true font-load invalidation test is absent: the cache test covers profile/revision changes and measurement reuse, not an actual Version increment. This is a test-evidence limit, not grounds to rewrite the cache.
Version is sampled before measurement and separately before scene creation; concurrent font loading could produce a one-frame mixed-version snapshot, then be invalidated next time. Without evidence of concurrent loading in this trial, treat that as a broader-policy limitation. Failed measurement is not cached, so unsupported metrics may repeatedly attempt shaping on geometry rebuild; the accepted fixed English witness avoids that only after the parent verifies measurement succeeds.
## Authored shape and geometry consumers
The explicit experiment policy is coherent for target-label dragging: it inserts the measured fraction/offset at drag start; authored moves retain E/F shape even when the guard fails, with clear=false; the same externally selected profile derives that shape after rebuild. Undo returns to the fixed automatic witness. Ordinary reopening without the environment profile restores ordinary one-line rendering, so this is not persisted formatting support. Existing authored fields remain exact, but previously authored target labels are intentionally visually wrapped under the experiment profile, as declared.
Fit in app.rs, main/work-preview scene rendering, label picking, drag start, saved-view/edge focus bounds, dirty-input shielding, and SVG are wired through the transformed geometry. Other routes/labels are not resettled by the adapter. Core retains routing ownership; application paths that use route points only, such as AddBend, do not need a label transform.
One **dormant consumer limitation** remains outside the representative Traceability workflow: `app/allocation_drag.rs:929` still passes an untransformed core RoutedView to `Frozen::capture`, whose controls include label bounds (`:155`). The visible work-preview scene is transformed, so the frozen Allocation drop occluders would use the old label box if this experiment were extended into an Allocation projection with the same target IDs. This is not an active defect in the fixed Traceability trial. Do not claim all Allocation drag consumers have measured-label parity, or generalize the experiment without reconciling that admission path.
Conservative bounds retain the core's original extents and enlarge them for new authored placements; they do not shrink away obsolete one-line extents. For this fixed automatic fixture both shapes are inside the same node extents, so unchanged Fit is supported by geometry. For arbitrary authored moves the result is intentionally conservative, not a minimal fitted bounding box.
## Guard and baseline invariants
The private adapter returns immediately for Baseline and checks target diagram ID, relation ID/name and canonical displayed string. It rejects nested/collapsed views and custom-suspended target routes. Automatic guards include full padded cards, other labels, association-end labels, and every semantic edge's strokes without discarding coincident ownership. E requires exactly one full straight own crossing; F rejects all stroke intersections. Authored collision bypass is explicit. These are sensible fixed-witness boundaries, not a general layout engine.
Baseline routing/export branches remain structurally unchanged apart from no-op adapter calls and additional cache fields. Existing output equality tests are appropriate, but this review does not claim they passed. The first focused test checks restoration of target label geometry yields complete baseline RoutedView equality, which usefully covers paths, other labels, bounds, and solver metadata. Canonical Project serialization equality is also checked. No core/schema or semantic mutation was found.
The identity guards do not hash the entire fixture: a same-ID diagram edited into another flat scene can still enter apply and be accepted/rejected geometrically. That is needed for controlled edits, but do not describe it as verifying exact immutable fixture bytes at runtime. Freeze fixture identity externally for the reading trial.
## Reviewed hashes and limits
SHA-256, collected from the inspected source; all relative paths are from the experiment worktree:
| File | SHA-256 |
| --- | --- |
| crates/oa-desktop/src/diagram/label_layout_experiment.rs | 29a44d5c2bc4e4f470623f538dd2a40b83a054a4b2f6886a266c5f078bf18398 |
| crates/oa-desktop/src/diagram.rs | 4c2eadea14f414b84fad74a894a0bd0ba06b1d7797e1e216939512a591848b3b |
| crates/oa-desktop/src/app.rs | 80e05e7643e0d382d703cc8fa5c97f7a34ec2020b79a36d613b37b35d1b5430f |
| crates/oa-desktop/src/diagram_usage.rs | b03f4ecbd7a6a9f5632cb885574cd4b64b6927fbfeec75734133038464c93418 |
| crates/oa-desktop/src/diagram/work_drag.rs | 8576eb0f1e0ba3a529bf458c6792c46d3344d4fabd11a0146327013bdb9ba058 |
| crates/oa-desktop/src/diagram/attachment_tests.rs | 95363b2e88ff627dc9ef3da27a1faf6ffd3020496326a9cfba5109bf7d52bd47 |
| harness/experiments/wrapped-label-20261001/fixture/eight-card.json | 9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8 |
Installed dependency sources were read under `C:/Users/User/Documents/Git/ARCADIA-Studio/.local/toolchain/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/`, versions Iced graphics/wgpu/tiny-skia 0.14.0 and cosmic-text 0.15.0. No web or secondary-source inference was required.
This review supports a narrowly identified fixed-scene measurement/render experiment, with one actionable preview state mismatch. It establishes neither native readability, glyph-level export parity, actual latency, successful tests, nor production acceptance. Parent should preserve the original failure, repair at the desktop layout/preview boundary, then recheck affected lifecycle behavior before broadening claims.
@@ -0,0 +1,94 @@
# Parent native observations, 2026-10-01 local / 2026-10-02 UTC
This is the parent's contemporaneous tool-observation summary, not a raw input
event transcript or an independent usability study. Raw screenshots, input
models, actual exports, launch/exit receipts and locked reader reports are
separate evidence. Prototype source: d0896ced75fea73bcda6bd14f259a34503840704.
Windows; one account/machine; 1442 x 932 app captures; restricted system PATH;
GUI 2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201,
libunwind f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4.
## Pristine profiles F then E
Each fresh process opened its frozen complete 9db101... eight-card.json using
the native file chooser, switched to System, selected the saved Issue 38
representative eight-card mixed view, and used Fit. All eight cards and all
mixed-view relationships remained present; zero selected; displayed zoom 52%.
The preparer saw simpler OA/SA diagrams first. Separate fresh Astra readers
received only their profile's untouched full JPEG before any selection. Their
locked first answers are preserved; they were not given correctness feedback
before locking. These are different readers, not a controlled causal comparison.
F first reader misread both functional exchanges and retained a plausible wrong
conversation ownership. E first reader named the correct request/report endpoints
and correct boundary-exchange participants, correctly found no direction, but
retained plausible wrong ownership and moderate confidence. Neither establishes
dependable first-reading association. No production promotion.
Untouched SVGs were exported through the actual Iced Export SVG modal, to new
explicit paths. Both actual exports passed comparison to the native baseline:
all twelve edge records and all 6977 bytes outside only the target label's
immediate presentation match exactly. This is logical export conservation,
not glyph/raster/browser parity.
F pointer clicks on first (888,527), last (888,544), and middle (888,536) lines
each selected the same Boundary exchange, alias sa_contact, undirected. The
first and middle observations have dedicated captures; the last has tool
observation only. Its selected highlight followed the correct own path.
A single atomic native drag from (888,536) to (918,556), predeclared +30/+20px,
kept the three-line shape and dirtied the model. Ctrl+Z restored the clean
automatic layout; Ctrl+Y restored the dirty authored layout. Separate captures
preserve those states. The authored layout crosses a foreign stroke: collision
refusal applies to automatic placement, not to authored offset. This is not a
readability success. Save As selected Model JSON and exported moved-F.json to
a fresh explicitly typed filename. The footer reported JSON exported; source
files/save state retained. The model remained dirty. This does NOT establish
Save All, source-file cleanliness or a source round trip. Ctrl+Z returned clean
before normal Alt+F4. Exit 0, empty streams, all frozen input/binary pins unchanged.
E pointer clicks inside its first line (855,542) and second line (855,551) both
selected the same correct undirected Boundary exchange. Both are captured.
No E native drag, JSON save, Undo/Redo or reopened edit was exercised. Normal
Alt+F4 closed clean: exit 0, empty streams, unchanged pins.
## Fresh saved-F reopening
launch-wrapped-reopen.py created separate immutable F and Baseline run folders,
copied frozen binaries and exact saved model 0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57,
and launched fresh processes with profile F / absent profile respectively.
F PID7244: Open chooser initially refused a forward-slash full path as invalid.
This failed attempt is captured. Sky's indexed OK click reported element83
unavailable; re-observation then Return dismissed the owned error. A first
backslash typing attempt left the filename empty. Re-observation, explicit
filename click and literal Windows-path typing succeeded. No file was changed
by those failed chooser actions. System/saved mixed view/Fit showed the authored
three-line label at the moved position. Actual reopened-F.svg was exported via
Iced modal. Normal close: exit 0, empty streams, frozen pins unchanged.
Baseline PID8056: Home's visible recent-model Open loaded the SAME file from
the preceding F folder, not the unused identical copy in the Baseline folder.
Footer confirms that path. System/saved mixed view/Fit showed a single-line
label at the stored anchor/offset. Captured ordinary reopening proves the
external profile's formatting is not persisted. Post-close loaded-file SHA
still 0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57.
Exit 0, empty streams, own frozen pins unchanged. No ordinary-profile SVG export.
## Tool limitations / excluded gates
Sky data URLs are JPEG, not PNG. Initial parent screenshot assertion expected
PNG and failed before writing; corrected preservation uses raw JPEG. Native
chooser snapshots include a dummy16x16 image plus the real1108x633 screenshot;
actions used the real snapshot. UIA focused_element repeatedly says Search Box
while filename caret/selection is visibly active. Literal focused typing is
verified visually. F's first saved-view picker clicks did not open the popup;
Escape then a refreshed click at (907,161) succeeded. Cause not established.
None of these uncertain automation observations is a diagnosed product defect.
Native Sky drag is atomic: no held-pointer cancel claim. Native foreign-label
guard-refusal preview, all-line independent drag lifecycle, native E editing,
SVG raster/font bounds, performance, general fonts, nested/collapsed views,
accessibility/DPI, a second Windows machine and Linux remain unverified. A
targeted actual-core-preview regression covers the different-edge transition
in unit tests, not a native workflow. No renderer-only prototype belongs in a
release or establishes graphical/textual formatting parity.
@@ -0,0 +1,105 @@
{
"status": "PASS",
"script_sha256": "8d718db9a52e894e8160436eab2d57998f211b71f4485b3543c6badde36b7815",
"invocation": [
".local/wrapped-reopen-independent-check.py",
".local/wrapped-reopen-independent-result.json"
],
"scope": "Saved-F full Project and logical SVG; no native input events, raster/font portability, baseline-profile reopen or usability acceptance",
"inputs": {
"pristine_project": {
"path": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-F\\working\\eight-card.json",
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"saved_project": {
"path": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-F\\working\\moved-F.json",
"bytes": 138935,
"sha256": "0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57"
},
"pristine_svg": {
"path": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-F\\working\\pristine-F.svg",
"bytes": 7436,
"sha256": "5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0"
},
"reopened_svg": {
"path": "C:\\ar-wrap-01a0d717\\.local\\native-wrapped-reopen-F\\working\\reopened-F.svg",
"bytes": 7449,
"sha256": "5b1106b9f8cdb6030e29d657f8aac1920e1a554e868bab4fce3e250a42469cd5"
}
},
"complete_project_only_target_label_route": true,
"original_bytes_unchanged": true,
"all_12_edges_exact": true,
"all_svg_bytes_outside_target_label_exact": true,
"remaining_svg_sha256": "5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed",
"expected_pristine": {
"path_length": 406.0,
"anchor": [
1162.0,
254.1999969482422
],
"center": [
1224.591064453125,
254.1999969482422
],
"rect": [
1180.0,
226.1999969482422,
89.18212890625,
56.0
],
"lines": [
[
"Technician",
1194.29052734375,
243.5828094482422
],
[
"service",
1205.084716796875,
259.58282470703125
],
[
"conversation",
1188.0,
275.58282470703125
]
]
},
"expected_reopened": {
"path_length": 406.0,
"anchor": [
1162.0,
254.1999969482422
],
"center": [
1282.812744140625,
293.014404296875
],
"rect": [
1238.2216796875,
265.014404296875,
89.18212890625,
56.0
],
"lines": [
[
"Technician",
1252.51220703125,
282.397216796875
],
[
"service",
1263.306396484375,
298.397216796875
],
[
"conversation",
1246.2216796875,
314.397216796875
]
]
},
"numeric_absolute_tolerance": 0.0002
}
@@ -0,0 +1,34 @@
{
"status": "PASS",
"in_memory_mutations_only": true,
"mutations": {
"unrelated_path": {
"rejected": true,
"reason": "Path, marker, title, style or edge order changed"
},
"target_coordinate": {
"rejected": true,
"reason": "rect.x: 1238.2317 versus expected 1238.2216796875"
},
"target_word": {
"rejected": true,
"reason": "Text content/font/fill changed"
},
"target_extra_attribute": {
"rejected": true,
"reason": "Immediate target wrapped label group missing"
},
"saved_metadata": {
"rejected": true,
"reason": "Saved bytes changed"
}
},
"inputs": {
".local/wrapped-reopen-independent-check.py": "8d718db9a52e894e8160436eab2d57998f211b71f4485b3543c6badde36b7815",
"crates/oa-desktop/src/diagram/label_layout_experiment.rs": "1d2d8dd01f40d851548183ac9a2c55b02752526008a3e31e384a63e033b09942",
"crates/oa-core/src/routing.rs": "b377fe80cece3892d64f62ba5e1578d8974eeefc2a317620f343a86f2f257fbd",
".local/wrapped-label-diagram-tests.log": "801d4e9223530db238aeba790fc37ac99f8e82404c41cff1f9983d89ce961921",
".local/native-wrapped-reopen-F/bin/arcadia-studio.exe": "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201",
".local/native-wrapped-reopen-F/bin/libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
}
}
@@ -0,0 +1,39 @@
# Independent saved-F reopen SVG and model review
Result: **PASS within the bounded file/model/logical-SVG scope. No material blocker found.** This does not accept F for production or establish ordinary-profile reopen behavior. No GUI, compiler, Gitea, production source or other author's helper was used or modified.
The actual files checked were `.local/native-wrapped-F/working/eight-card.json` and `pristine-F.svg`, and `.local/native-wrapped-reopen-F/working/moved-F.json` and `reopened-F.svg`. The pristine JSON remains SHA256 `9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8` (138,661 bytes); the saved input is `0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57` (138,935 bytes). Actual SVG hashes are respectively `5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0` and `5b1106b9f8cdb6030e29d657f8aac1920e1a554e868bab4fce3e250a42469cd5`.
I parsed the entire original and saved Projects. The original representative diagram `00000000-0038-4000-8000-000000000001` has no authored routes; the saved diagram has exactly one route for relation `63009b5f-539e-5914-b630-ec6b7fefb4d5`, with empty waypoints and label fraction 0.55, offset (120.812744, 38.814423). There are no added attachment or formatting fields. Removing only this route restores exact structural equality of the complete parsed Project, including every other diagram, node placement, port, relation and source content represented by that Project. The relation's canonical Name is still `Technician service conversation`. This is parsed JSON equality; serialization of the restored value is not claimed byte-identical to the original file. The original file's bytes independently retain their pinned hash.
The SVGs have exactly the same 12 distinct edge records in the same order, including all path data, titles, markers/orientation and drawing attributes. Both root/viewBox attributes are exactly `24 -12 1566 874`. Removing only the one wrapped label group immediately following the target edge leaves **byte-identical complete remaining SVGs**, SHA256 `5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed`. This covers all cards, ports, unrelated labels, definitions/background and other serialized content, not just selected path samples.
## Independent coordinate expectation
I read `routing::point_along_polyline` in `crates/oa-core/src/routing.rs:231` and layout application in `crates/oa-desktop/src/diagram/label_layout_experiment.rs:137`. The original pinned target path is (1001,316.5), (1019,316.5), (1162,316.5), (1162,89.5), (1180,89.5): segment lengths 18, 143, 227 and 18, totaling 406 world units. Fraction 0.55 lies on the third segment. An independent Python reconstruction rounds every arithmetic operation to IEEE f32, yielding anchor (1162, 254.1999969482422).
Font advances are from the pre-existing Rust/Iced metric output in `.local/wrapped-label-diagram-tests.log:65`, not from the reopened SVG: Technician 60.601074, service 39.012695, conversation 73.18213; Segoe UI at 13 with 16-unit line advance. With horizontal padding 16 and vertical padding 8, both F layouts require width 89.18212890625 and height 56. The line baseline increment is 13.3828125, independently consistent with the earlier test metrics and source's shaped-baseline placement. The SVG does not independently measure fonts; this check verifies export of the previously measured local typography.
The initial F default offset is 18 + width/2 = 62.591064453125 on x, zero on y, yielding center (1224.591064453125, 254.1999969482422). The saved fraction/offset instead predicts center (1282.812744140625, 293.014404296875), backing rectangle (1238.2216796875, 265.014404296875, 89.18212890625, 56), and these baseline positions:
| Line | Predicted x | Predicted baseline y |
| --- | ---: | ---: |
| Technician | 1252.51220703125 | 282.397216796875 |
| service | 1263.306396484375 | 298.397216796875 |
| conversation | 1246.2216796875 | 314.397216796875 |
Every actual initial and reopened numeric attribute agrees with its independently calculated expectation within an absolute 0.0002 world-unit tolerance, declared before comparison for f32/decimal export rounding. The same three ordered lines, font/fill/font-size, title, exact serialized width and height persist. No extra attributes/elements or nested/stray text are allowed in the target group. Expected candidate coordinates were not learned from candidate output. This establishes that the exported saved-F presentation uses the saved authored offset, rather than retaining the initial automatic position.
## Reproduction and provenance
New independent checker: `.local/wrapped-reopen-independent-check.py`, SHA256 `8d718db9a52e894e8160436eab2d57998f211b71f4485b3543c6badde36b7815`. It reads fixed original/actual inputs, uses exclusive receipt creation, records hashes/arguments, emits FAIL and exit 1 on failed guards, and never alters the inputs. Actual invocation from this worktree:
```powershell
& 'C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe' .local/wrapped-reopen-independent-check.py .local/wrapped-reopen-independent-result.json
```
The result is PASS. Use a new receipt filename for replay. `.local/wrapped-reopen-independent-selfcheck.json` records five in-memory negative controls, all rejected: an unrelated path change, a target coordinate change of 0.01, a changed word, an extra target opacity attribute, and altered saved metadata. Actual files were not mutated. It also records examined source/test-log and binary hashes.
Fresh-process receipts identify source `d0896ced75fea73bcda6bd14f259a34503840704`, external profile F, PID 7244, system-only PATH, normal exit 0, empty streams, and unchanged pinned input/runtime/EXE. I independently rehashed the present EXE to `2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201` and DLL to `f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4`. Process/interaction history is receipt evidence; I did not observe the GUI or independently reproduce those events.
Limits: this review establishes full parsed-model conservation and actual saved-F logical export geometry. It does not independently validate click/drag history, hit-testing, pixel/glyph raster equality, SVG rendering on another font environment, universal layout guards, performance or readable ownership. Ordinary-profile reopen is outside these inputs and remains pending in this review. The profile is selected externally; preservation of authored fraction/offset is model persistence, while the three-line F presentation is derived under profile F. No claim is made that wrapping became persisted formatting or that baseline mode will wrap it.
@@ -0,0 +1,72 @@
# Read-only native wrapped-label SVG conservation oracle
F passed using the actual native exports. This worker read SVG/JSON bytes only:
no GUI, screenshot interpretation, Cargo, model/source change or publication.
Parent identifies F's executable source as `d0896ced75fea73bcda6bd14f259a34503840704`
and executable SHA256 `2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201`;
its native baseline/launch receipts record these identities. This checker does
not itself establish which process produced an export.
## Result and exact scope
- Baseline native export: `C:/ar-label-cue-01a0d717/.local/native-cue-baseline/working/baseline.svg`,
7,209 bytes, SHA256 `645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d`.
- F native export: `.local/native-wrapped-F/working/pristine-F.svg`, 7,436 bytes,
SHA256 `5213a764251c134a7ebbad482abb82d260c6c4216c73cd4e5e2295a9da3094a0`.
- Both adjacent `eight-card.json` full Project inputs are 138,661 identical bytes,
pinned SHA256 `9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8`.
- All twelve distinct edge records match exactly, including ordered UUIDs, path
strings, orientation/marker attributes, drawing attributes and semantic titles.
- Root attributes and `viewBox="24 -12 1566 874"` match exactly.
- Remove only the target edge's immediately following old rect+text and the new
wrapped group. The entire remaining **6,977 raw bytes are identical**, SHA256
`5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed`.
This conserves every card, port, unrelated label and drawing primitive without
a selective whitelist that could hide another change.
- Target edge `63009b5f-539e-5914-b630-ec6b7fefb4d5` and wrapped group retain
canonical `Technician service conversation`. F has exactly ordered lines
`Technician`, `service`, `conversation`, Segoe UI size 13, backing
`(1180, 226.2, 89.18213, 56)`, and baseline coordinates
`(1194.2905, 243.58281)`, `(1205.0847, 259.58282)`, `(1188, 275.58282)`.
Expected E/F metrics are hardcoded from the pre-existing Rust/Iced output in
`.local/wrapped-label-regression-first.log` at
`ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d`. They are not inferred from the SVG
under evaluation. Numeric absolute tolerance is 0.0002 logical units to cover
printed f32 decimal round trips. Dimensions additionally reconcile with measured
maximum glyph advance plus 16 and height 8 + 16 per line. The export does not
contain independently measurable glyph outlines; the checker verifies declared
logical coordinates and font identity, not actual rendered glyph bounds.
## Reuse and verification
Portable Python 3 standard-library helper: `.local/check-wrapped-svg.py`, SHA256
`136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099`.
It takes baseline SVG, candidate SVG, E/F profile and a **new** output path.
Each SVG's directory must retain its original `eight-card.json`.
```powershell
python .local/check-wrapped-svg.py BASELINE.svg CANDIDATE.svg F NEW-OUTPUT.json
python .local/check-wrapped-svg.py BASELINE.svg CANDIDATE.svg E NEW-OUTPUT.json
```
Actual current-script receipt: `.local/native-wrapped-F/svg-conservation-v2.json`.
The first successful receipt `svg-conservation.json` is retained; the v2 helper
additionally rejects unexpected nested elements or stray text inside the removed
presentation group. Outputs use exclusive creation and are never overwritten,
including failures. A failing check records its reason before exit 1.
Ten in-memory corruption checks passed, recorded in
`.local/wrapped-svg-oracle-selfcheck.json`: changed foreign path, root viewBox,
target font/baseline/word, unrelated label, card drawing, port drawing, orientation
and nested presentation were all rejected. Native files were not modified.
The first selfcheck setup mistakenly selected a card fill absent from this SVG;
that setup failure is retained in `.local/wrapped-svg-oracle-selfcheck-first-failed.json`.
It was corrected to mutate an actual rounded-card fill; it was not a native
export or oracle acceptance failure.
E native export has not been evaluated at this checkpoint. This helper is ready
for it with the independently declared E metrics. Parent owns independent review,
native lifecycle/persistence and publication. No browser rendering, font
availability, glyph/raster parity, screenshot reading, fresh-reader accuracy,
save/reopen parity or usability acceptance follows from these byte checks.
@@ -0,0 +1,5 @@
{
"status": "FAIL",
"scope": "Selfcheck harness setup, not native export",
"failure": "AssertionError: card_drawing; requested fill #edf3f7 is absent from this SVG. Earlier mutation cases had been rejected; no native files changed."
}
@@ -0,0 +1,57 @@
{
"status": "PASS",
"method": "In-memory candidate byte mutations only; native files not changed",
"script_sha256": "136f0c458316e9c6747f2fbd26a4326a07cc6fc78a8bd4fe408beac331e4d099",
"cases": [
{
"mutation": "foreign_path",
"rejected": true,
"reason": "Edge order, UUID, path, orientation/marker, drawing attributes or title changed"
},
{
"mutation": "root_viewbox",
"rejected": true,
"reason": "Root attributes/viewBox changed"
},
{
"mutation": "target_font",
"rejected": true,
"reason": "text.font-family changed"
},
{
"mutation": "target_baseline",
"rejected": true,
"reason": "text.y: expected 243.58281, got 245.58281"
},
{
"mutation": "target_canonical_line",
"rejected": true,
"reason": "Ordered complete display line changed"
},
{
"mutation": "other_label",
"rejected": true,
"reason": "Raw SVG bytes outside ONLY target's immediate label presentation changed"
},
{
"mutation": "card_drawing",
"rejected": true,
"reason": "Raw SVG bytes outside ONLY target's immediate label presentation changed"
},
{
"mutation": "port_drawing",
"rejected": true,
"reason": "Raw SVG bytes outside ONLY target's immediate label presentation changed"
},
{
"mutation": "orientation",
"rejected": true,
"reason": "Edge order, UUID, path, orientation/marker, drawing attributes or title changed"
},
{
"mutation": "nested_presentation",
"rejected": true,
"reason": "Wrapped presentation contains unexpected nested elements or stray text"
}
]
}
@@ -0,0 +1,36 @@
from pathlib import Path
import copy, hashlib, json, sys
assert len(sys.argv) == 4
original, saved, output = map(Path, sys.argv[1:])
assert not output.exists()
sha = lambda path: hashlib.sha256(path.read_bytes()).hexdigest()
assert sha(original) == '9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
before, after = [json.loads(p.read_bytes()) for p in [original, saved]]
diagram = '00000000-0038-4000-8000-000000000001'
edge = '63009b5f-539e-5914-b630-ec6b7fefb4d5'
old_routes = before['diagrams'][diagram]['routes']
routes = after['diagrams'][diagram]['routes']
assert not any(r['edge'] == edge for r in old_routes)
changed = [r for r in routes if r['edge'] == edge]
assert len(changed) == 1
route = changed[0]
assert route['waypoints'] == []
assert route.get('source_attachment') is None and route.get('target_attachment') is None
assert set(route) <= {'edge','waypoints','label','source_attachment','target_attachment'}
label = route['label']
assert label['fraction'] == 0.55
assert set(label) == {'fraction','offset'} and set(label['offset']) == {'x','y'}
# Declared native delta30/20px at rounded Fit52%, not a geometry-derived oracle.
assert 0.515 <= 0.525
assert 62.591065 + 30/0.525 - 1 <= label['offset']['x'] <= 62.591065 + 30/0.515 + 1
assert 20/0.525 - 1 <= label['offset']['y'] <= 20/0.515 + 1
restored = copy.deepcopy(after)
restored['diagrams'][diagram]['routes'] = [r for r in routes if r['edge'] != edge]
assert restored == before, 'Complete Project must differ only by declared target route label'
receipt = {'status':'PASS', 'original_sha256':sha(original), 'saved_sha256':sha(saved),
'saved_bytes':saved.stat().st_size, 'declared_edit':route,
'complete_project_equal_after_removing_only_declared_route':True,
'scope':'F30px right/20px down at displayed52%; no extra formatting field persisted'}
with output.open('x',encoding='utf-8') as f: json.dump(receipt,f,indent=2);f.write('\n')
print(json.dumps(receipt,indent=2))
@@ -0,0 +1,157 @@
"""Read-only native SVG conservation check. Python 3 stdlib; never overwrite a receipt.
Usage: check-wrapped-svg.py BASELINE.svg CANDIDATE.svg E|F NEW-OUTPUT.json
Both native export directories must retain their original eight-card.json input.
"""
from pathlib import Path
import argparse
import hashlib
import json
import math
import re
import sys
import xml.etree.ElementTree as ET
TARGET = "63009b5f-539e-5914-b630-ec6b7fefb4d5"
NAME = "Technician service conversation"
FIXTURE_SHA = "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
NS = "{http://www.w3.org/2000/svg}"
# Independent expected logical metrics printed by the pinned Rust/Iced tests at
# ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d. Never infer these from candidate SVG.
# Lines: canonical display text, left x, top y, shaped baseline y, glyph advance.
METRICS = {
"E": {"rect": [1102.4126, 254.5, 119.174805, 40.0], "lines": [
["Technician service", 1110.4126, 258.5, 271.8828, 103.174805],
["conversation", 1125.4089, 274.5, 287.8828, 73.18213],
]},
"F": {"rect": [1180.0, 226.2, 89.18213, 56.0], "lines": [
["Technician", 1194.2905, 230.2, 243.58281, 60.601074],
["service", 1205.0847, 246.2, 259.58282, 39.012695],
["conversation", 1188.0, 262.2, 275.58282, 73.18213],
]},
}
def require(condition, message):
if not condition:
raise ValueError(message)
def digest(data):
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
def close(actual, expected, label):
value = float(actual)
require(math.isfinite(value) and abs(value - expected) <= 0.0002,
f"{label}: expected {expected}, got {actual}")
def element_attrs(element, tag, fixed, numeric):
require(element.tag == NS + tag, f"Expected {tag}, got {element.tag}")
require(set(element.attrib) == set(fixed) | set(numeric), f"Unexpected attributes on {tag}")
for key, value in fixed.items():
require(element.get(key) == value, f"{tag}.{key} changed")
for key, value in numeric.items():
close(element.get(key), value, tag + "." + key)
def strip_immediate_label(raw, candidate):
edge = re.compile(rb'<path\b[^>]*\bdata-edge="' + TARGET.encode() + rb'"[^>]*>.*?</path>', re.DOTALL)
matches = list(edge.finditer(raw))
require(len(matches) == 1, "Target edge must occur exactly once")
start = matches[0].end()
pattern = (rb'<g data-label-experiment="wrapped">.*?</g>' if candidate
else rb'<rect\b[^>]*/><text\b[^>]*>[^<]*</text>')
label = re.compile(pattern, re.DOTALL).match(raw, start)
require(label is not None, "Target label must immediately follow its edge")
return raw[:start] + raw[label.end():], raw[start:label.end()]
def check(args, report):
baseline, candidate = Path(args.baseline), Path(args.candidate)
before, after = baseline.read_bytes(), candidate.read_bytes()
report["inputs"] = {"baseline_svg": {"path": str(baseline), **digest(before)},
"candidate_svg": {"path": str(candidate), **digest(after)}}
fixture_bytes = []
for key, svg in [("baseline_project", baseline), ("candidate_project", candidate)]:
path = svg.parent / "eight-card.json"
data = path.read_bytes()
report["inputs"][key] = {"path": str(path), **digest(data)}
require(digest(data)["sha256"] == FIXTURE_SHA, key + " differs from pinned full Project")
fixture_bytes.append(data)
require(fixture_bytes[0] == fixture_bytes[1], "Full input Projects differ")
roots = [ET.fromstring(data) for data in [before, after]]
for root in roots:
require(root.tag == NS + "svg", "Expected SVG root")
require(roots[0].attrib == roots[1].attrib, "Root attributes/viewBox changed")
require(roots[0].get("viewBox") == "24 -12 1566 874", "Pinned full scene viewBox changed")
edges = [[e for e in root.iter() if e.get("data-edge") is not None] for root in roots]
for found in edges:
require(len(found) == 12 and len({e.get("data-edge") for e in found}) == 12,
"Expected all 12 distinct edge UUIDs")
require([ET.tostring(e) for e in edges[0]] == [ET.tostring(e) for e in edges[1]],
"Edge order, UUID, path, orientation/marker, drawing attributes or title changed")
for root in roots:
children = list(root)
target_index = next(i for i, e in enumerate(children) if e.get("data-edge") == TARGET)
require(children[target_index].find(NS + "title").text == NAME, "Canonical edge title changed")
bchildren = list(roots[0])
bi = next(i for i, e in enumerate(bchildren) if e.get("data-edge") == TARGET)
element_attrs(bchildren[bi + 1], "rect", {"fill": "white"},
{"x": 1180., "y": 262.5, "width": 233., "height": 24.})
element_attrs(bchildren[bi + 2], "text", {"text-anchor": "middle", "dominant-baseline": "central",
"font-family": "sans-serif", "fill": "#637487"}, {"x": 1296.5, "y": 274.5, "font-size": 13.})
require(bchildren[bi + 2].text == NAME, "Baseline target is not canonical one-line label")
groups = [e for e in roots[1].iter() if e.get("data-label-experiment") is not None]
require(len(groups) == 1, "Exactly one experimental label group is allowed")
group = groups[0]
element_attrs(group, "g", {"data-label-experiment": "wrapped"}, {})
cchildren = list(roots[1])
ci = next(i for i, e in enumerate(cchildren) if e.get("data-edge") == TARGET)
require(cchildren[ci + 1] is group, "Wrapped group belongs immediately to target edge")
expected = METRICS[args.profile]
parts = list(group)
require(len(parts) == 2 + len(expected["lines"]), "Unexpected wrapped group contents")
element_attrs(parts[0], "title", {}, {})
require(parts[0].text == NAME and not list(parts[0]), "Canonical group title changed")
element_attrs(parts[1], "rect", {"fill": "white"}, dict(zip(["x", "y", "width", "height"], expected["rect"])))
for actual, (name, x, top, baseline_y, width) in zip(parts[2:], expected["lines"]):
element_attrs(actual, "text", {"font-family": "Segoe UI", "fill": "#637487"},
{"x": x, "y": baseline_y, "font-size": 13.})
require(actual.text == name and not list(actual), "Ordered complete display line changed")
require(" ".join(e.text for e in parts[2:]) == NAME, "Wrapping altered the complete canonical text")
close(expected["rect"][2], max(line[4] for line in expected["lines"]) + 16., "Expected advance plus padding")
close(expected["rect"][3], 8. + 16. * len(expected["lines"]), "Expected line height plus padding")
bremaining, bremoved = strip_immediate_label(before, False)
cremaining, cremoved = strip_immediate_label(after, True)
require(bremaining == cremaining,
"Raw SVG bytes outside ONLY target's immediate label presentation changed")
report.update({
"status": "PASS", "full_project_bytes_equal": True,
"edge_uuids": [e.get("data-edge") for e in edges[0]],
"all_12_edge_records_exact": True, "root_and_viewBox_exact": True,
"all_remaining_svg_bytes_exact": True, "remaining_svg": digest(bremaining),
"removed_baseline_presentation": digest(bremoved), "removed_candidate_presentation": digest(cremoved),
"expected_logical_metrics": expected, "numeric_absolute_tolerance": 0.0002,
"conservation_scope": "All edge/path/orientation/drawing, card, port and unrelated label bytes preserved; only target immediate label presentation removed for comparison.",
"limits": "Logical SVG conservation and declared typography coordinates only. No browser/font availability, glyph/raster parity, screenshot reading, native input-event history, save/reopen or usability claim.",
})
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("baseline")
parser.add_argument("candidate")
parser.add_argument("profile", choices=["E", "F"])
parser.add_argument("output")
args = parser.parse_args()
report = {"status": "FAIL", "profile": args.profile,
"script": digest(Path(__file__).read_bytes()),
"metrics_source": "ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d Rust/Iced test stdout; wrapped-label-regression-first.log"}
# Exclusive creation precedes reads; a failed prior run is never overwritten.
with Path(args.output).open("x", encoding="utf-8") as output:
try:
check(args, report)
except Exception as error:
report["failure"] = {"type": type(error).__name__, "message": str(error)}
json.dump(report, output, indent=2)
output.write("\n")
print(json.dumps(report, indent=2))
return 0 if report["status"] == "PASS" else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,160 @@
"""Read-only native SVG conservation check. Python 3 stdlib; never overwrite a receipt.
Usage: check-wrapped-svg.py BASELINE.svg CANDIDATE.svg E|F NEW-OUTPUT.json
Both native export directories must retain their original eight-card.json input.
"""
from pathlib import Path
import argparse
import hashlib
import json
import math
import re
import sys
import xml.etree.ElementTree as ET
TARGET = "63009b5f-539e-5914-b630-ec6b7fefb4d5"
NAME = "Technician service conversation"
FIXTURE_SHA = "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
NS = "{http://www.w3.org/2000/svg}"
# Independent expected logical metrics printed by the pinned Rust/Iced tests at
# ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d. Never infer these from candidate SVG.
# Lines: canonical display text, left x, top y, shaped baseline y, glyph advance.
METRICS = {
"E": {"rect": [1102.4126, 254.5, 119.174805, 40.0], "lines": [
["Technician service", 1110.4126, 258.5, 271.8828, 103.174805],
["conversation", 1125.4089, 274.5, 287.8828, 73.18213],
]},
"F": {"rect": [1180.0, 226.2, 89.18213, 56.0], "lines": [
["Technician", 1194.2905, 230.2, 243.58281, 60.601074],
["service", 1205.0847, 246.2, 259.58282, 39.012695],
["conversation", 1188.0, 262.2, 275.58282, 73.18213],
]},
}
def require(condition, message):
if not condition:
raise ValueError(message)
def digest(data):
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
def close(actual, expected, label):
value = float(actual)
require(math.isfinite(value) and abs(value - expected) <= 0.0002,
f"{label}: expected {expected}, got {actual}")
def element_attrs(element, tag, fixed, numeric):
require(element.tag == NS + tag, f"Expected {tag}, got {element.tag}")
require(set(element.attrib) == set(fixed) | set(numeric), f"Unexpected attributes on {tag}")
for key, value in fixed.items():
require(element.get(key) == value, f"{tag}.{key} changed")
for key, value in numeric.items():
close(element.get(key), value, tag + "." + key)
def strip_immediate_label(raw, candidate):
edge = re.compile(rb'<path\b[^>]*\bdata-edge="' + TARGET.encode() + rb'"[^>]*>.*?</path>', re.DOTALL)
matches = list(edge.finditer(raw))
require(len(matches) == 1, "Target edge must occur exactly once")
start = matches[0].end()
pattern = (rb'<g data-label-experiment="wrapped">.*?</g>' if candidate
else rb'<rect\b[^>]*/><text\b[^>]*>[^<]*</text>')
label = re.compile(pattern, re.DOTALL).match(raw, start)
require(label is not None, "Target label must immediately follow its edge")
return raw[:start] + raw[label.end():], raw[start:label.end()]
def check(args, report):
baseline, candidate = Path(args.baseline), Path(args.candidate)
before, after = baseline.read_bytes(), candidate.read_bytes()
report["inputs"] = {"baseline_svg": {"path": str(baseline), **digest(before)},
"candidate_svg": {"path": str(candidate), **digest(after)}}
fixture_bytes = []
for key, svg in [("baseline_project", baseline), ("candidate_project", candidate)]:
path = svg.parent / "eight-card.json"
data = path.read_bytes()
report["inputs"][key] = {"path": str(path), **digest(data)}
require(digest(data)["sha256"] == FIXTURE_SHA, key + " differs from pinned full Project")
fixture_bytes.append(data)
require(fixture_bytes[0] == fixture_bytes[1], "Full input Projects differ")
roots = [ET.fromstring(data) for data in [before, after]]
for root in roots:
require(root.tag == NS + "svg", "Expected SVG root")
require(roots[0].attrib == roots[1].attrib, "Root attributes/viewBox changed")
require(roots[0].get("viewBox") == "24 -12 1566 874", "Pinned full scene viewBox changed")
edges = [[e for e in root.iter() if e.get("data-edge") is not None] for root in roots]
for found in edges:
require(len(found) == 12 and len({e.get("data-edge") for e in found}) == 12,
"Expected all 12 distinct edge UUIDs")
require([ET.tostring(e) for e in edges[0]] == [ET.tostring(e) for e in edges[1]],
"Edge order, UUID, path, orientation/marker, drawing attributes or title changed")
for root in roots:
children = list(root)
target_index = next(i for i, e in enumerate(children) if e.get("data-edge") == TARGET)
require(children[target_index].find(NS + "title").text == NAME, "Canonical edge title changed")
bchildren = list(roots[0])
bi = next(i for i, e in enumerate(bchildren) if e.get("data-edge") == TARGET)
element_attrs(bchildren[bi + 1], "rect", {"fill": "white"},
{"x": 1180., "y": 262.5, "width": 233., "height": 24.})
element_attrs(bchildren[bi + 2], "text", {"text-anchor": "middle", "dominant-baseline": "central",
"font-family": "sans-serif", "fill": "#637487"}, {"x": 1296.5, "y": 274.5, "font-size": 13.})
require(bchildren[bi + 2].text == NAME, "Baseline target is not canonical one-line label")
groups = [e for e in roots[1].iter() if e.get("data-label-experiment") is not None]
require(len(groups) == 1, "Exactly one experimental label group is allowed")
group = groups[0]
element_attrs(group, "g", {"data-label-experiment": "wrapped"}, {})
cchildren = list(roots[1])
ci = next(i for i, e in enumerate(cchildren) if e.get("data-edge") == TARGET)
require(cchildren[ci + 1] is group, "Wrapped group belongs immediately to target edge")
expected = METRICS[args.profile]
parts = list(group)
require(len(parts) == 2 + len(expected["lines"]), "Unexpected wrapped group contents")
require(not group.text and all(not list(part) and not part.tail for part in parts),
"Wrapped presentation contains unexpected nested elements or stray text")
element_attrs(parts[0], "title", {}, {})
require(parts[0].text == NAME and not list(parts[0]), "Canonical group title changed")
element_attrs(parts[1], "rect", {"fill": "white"}, dict(zip(["x", "y", "width", "height"], expected["rect"])))
require(not parts[1].text, "Backing rectangle contains unexpected text")
for actual, (name, x, top, baseline_y, width) in zip(parts[2:], expected["lines"]):
element_attrs(actual, "text", {"font-family": "Segoe UI", "fill": "#637487"},
{"x": x, "y": baseline_y, "font-size": 13.})
require(actual.text == name and not list(actual), "Ordered complete display line changed")
require(" ".join(e.text for e in parts[2:]) == NAME, "Wrapping altered the complete canonical text")
close(expected["rect"][2], max(line[4] for line in expected["lines"]) + 16., "Expected advance plus padding")
close(expected["rect"][3], 8. + 16. * len(expected["lines"]), "Expected line height plus padding")
bremaining, bremoved = strip_immediate_label(before, False)
cremaining, cremoved = strip_immediate_label(after, True)
require(bremaining == cremaining,
"Raw SVG bytes outside ONLY target's immediate label presentation changed")
report.update({
"status": "PASS", "full_project_bytes_equal": True,
"edge_uuids": [e.get("data-edge") for e in edges[0]],
"all_12_edge_records_exact": True, "root_and_viewBox_exact": True,
"all_remaining_svg_bytes_exact": True, "remaining_svg": digest(bremaining),
"removed_baseline_presentation": digest(bremoved), "removed_candidate_presentation": digest(cremoved),
"expected_logical_metrics": expected, "numeric_absolute_tolerance": 0.0002,
"conservation_scope": "All edge/path/orientation/drawing, card, port and unrelated label bytes preserved; only target immediate label presentation removed for comparison.",
"limits": "Logical SVG conservation and declared typography coordinates only. No browser/font availability, glyph/raster parity, screenshot reading, native input-event history, save/reopen or usability claim.",
})
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("baseline")
parser.add_argument("candidate")
parser.add_argument("profile", choices=["E", "F"])
parser.add_argument("output")
args = parser.parse_args()
report = {"status": "FAIL", "profile": args.profile,
"script": digest(Path(__file__).read_bytes()),
"metrics_source": "ebb6a9980b11c4d4df2f7e413c6b135a337f6f6d Rust/Iced test stdout; wrapped-label-regression-first.log"}
# Exclusive creation precedes reads; a failed prior run is never overwritten.
with Path(args.output).open("x", encoding="utf-8") as output:
try:
check(args, report)
except Exception as error:
report["failure"] = {"type": type(error).__name__, "message": str(error)}
json.dump(report, output, indent=2)
output.write("\n")
print(json.dumps(report, indent=2))
return 0 if report["status"] == "PASS" else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,36 @@
from pathlib import Path
import datetime, hashlib, json, os, subprocess, sys
assert len(sys.argv) == 2 and sys.argv[1] in ['E', 'F']
root = Path(__file__).resolve().parents[1]
run = root/('.local/native-wrapped-'+sys.argv[1])
record = json.loads((run/'baseline.json').read_text(encoding='utf-8'))
assert record['label_profile'] == sys.argv[1]
sha = lambda path: hashlib.sha256(path.read_bytes()).hexdigest()
for relative, entry in record['files'].items():
assert sha(run/relative) == entry['sha256']
system = os.environ['SystemRoot']
env = os.environ.copy()
env['PATH'] = str(Path(system)/'System32')+';'+system
for key in list(env):
if key.startswith(('CARGO_', 'RUST', 'LLVM', 'WGPU', 'ARCADIA_')):
del env[key]
env['ARCADIA_LABEL_EXPERIMENT'] = sys.argv[1]
receipt = {'source': record['source'], 'start': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'label_profile': sys.argv[1], 'binary_sha256': record['files']['bin/arcadia-studio.exe']['sha256'],
'runtime_sha256': record['files']['bin/libunwind.dll']['sha256'],
'fixture_sha256': record['files']['working/eight-card.json']['sha256'],
'cwd': str(run/'working'), 'path': env['PATH']}
with (run/'stdout.log').open('xb') as out, (run/'stderr.log').open('xb') as err:
child = subprocess.Popen([str(run/'bin/arcadia-studio.exe')], cwd=run/'working', env=env,
stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
receipt['pid'] = child.pid
(run/'started.json').write_text(json.dumps(receipt, indent=2)+'\n', encoding='utf-8')
print(json.dumps(receipt, indent=2), flush=True)
code = child.wait()
receipt.update({'exit_code': code, 'finished': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'stdout_bytes': (run/'stdout.log').stat().st_size, 'stderr_bytes': (run/'stderr.log').stat().st_size,
'all_pinned_files_unchanged': all(sha(run/r)==v['sha256'] for r,v in record['files'].items())})
(run/'finished.json').write_text(json.dumps(receipt, indent=2)+'\n', encoding='utf-8')
print(json.dumps(receipt, indent=2), flush=True)
assert code == 0 and receipt['stdout_bytes'] == receipt['stderr_bytes'] == 0 and receipt['all_pinned_files_unchanged']
@@ -0,0 +1,50 @@
from pathlib import Path
import datetime, hashlib, json, os, shutil, subprocess, sys
assert len(sys.argv) == 2 and sys.argv[1] in ['F', 'Baseline']
profile = sys.argv[1]
root = Path(__file__).resolve().parents[1]
donor = root / '.local/native-wrapped-F'
run = root / ('.local/native-wrapped-reopen-' + profile)
assert not run.exists(), 'Never overwrite a previous native run'
run.mkdir()
(run / 'bin').mkdir()
(run / 'working').mkdir()
(run / 'captures').mkdir()
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
pins = {
'bin/arcadia-studio.exe': '2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201',
'bin/libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
'working/moved-F.json': '0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57',
}
for relative, expected in pins.items():
source = donor / relative
assert sha(source) == expected
shutil.copyfile(source, run / relative)
assert sha(run / relative) == expected
system = os.environ['SystemRoot']
env = os.environ.copy()
env['PATH'] = str(Path(system) / 'System32') + ';' + system
for key in list(env):
if key.startswith(('CARGO_', 'RUST', 'LLVM', 'WGPU', 'ARCADIA_')):
del env[key]
if profile == 'F':
env['ARCADIA_LABEL_EXPERIMENT'] = 'F'
receipt = {'source': 'd0896ced75fea73bcda6bd14f259a34503840704',
'profile': profile, 'start': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'files': pins, 'cwd': str(run / 'working'), 'path': env['PATH'],
'external_profile': env.get('ARCADIA_LABEL_EXPERIMENT')}
with (run / 'stdout.log').open('xb') as out, (run / 'stderr.log').open('xb') as err:
child = subprocess.Popen([str(run / 'bin/arcadia-studio.exe')], cwd=run / 'working', env=env,
stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
receipt['pid'] = child.pid
(run / 'started.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
print(json.dumps(receipt, indent=2), flush=True)
code = child.wait()
receipt.update({'exit_code': code, 'finished': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'stdout_bytes': (run / 'stdout.log').stat().st_size,
'stderr_bytes': (run / 'stderr.log').stat().st_size,
'all_pinned_files_unchanged': all(sha(run / p) == h for p, h in pins.items())})
(run / 'finished.json').write_text(json.dumps(receipt, indent=2) + '\n', encoding='utf-8')
print(json.dumps(receipt, indent=2), flush=True)
assert code == 0 and receipt['stdout_bytes'] == receipt['stderr_bytes'] == 0 and receipt['all_pinned_files_unchanged']
@@ -0,0 +1,26 @@
from pathlib import Path
import hashlib, json, shutil, subprocess
root = Path(__file__).resolve().parents[1]
source = 'd0896ced75fea73bcda6bd14f259a34503840704'
assert subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=root, text=True).strip() == source
subprocess.run(['git', 'diff', '--exit-code', source, '--', 'crates', 'Cargo.toml', 'Cargo.lock'], cwd=root, check=True)
sha = lambda path: hashlib.sha256(path.read_bytes()).hexdigest()
target = Path('C:/Users/User/Documents/Git/ARCADIA-Studio/.local/target-gnullvm/debug/arcadia-studio.exe')
runtime = Path('C:/ar-save-01a0d717/.local/native46/bin/libunwind.dll')
fixture = root/'harness/experiments/wrapped-label-20261001/fixture/eight-card.json'
assert sha(runtime) == 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4'
assert sha(fixture) == '9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
for profile in ['F', 'E']:
run = root/('.local/native-wrapped-'+profile)
run.mkdir(exist_ok=False)
(run/'bin').mkdir(); (run/'working').mkdir(); (run/'captures').mkdir()
for original, destination in [(target, run/'bin/arcadia-studio.exe'), (runtime, run/'bin/libunwind.dll'), (fixture, run/'working/eight-card.json')]:
shutil.copyfile(original, destination)
assert sha(original) == sha(destination)
record = {'source': source, 'experiment': 'bounded measured multiline labels; not production acceptance',
'label_profile': profile, 'compiler_profile': 'dev/unoptimized', 'target': 'x86_64-pc-windows-gnullvm',
'files': {p.relative_to(run).as_posix(): {'bytes': p.stat().st_size, 'sha256': sha(p)}
for p in [run/'bin/arcadia-studio.exe', run/'bin/libunwind.dll', run/'working/eight-card.json']}}
(run/'baseline.json').write_text(json.dumps(record, indent=2)+'\n', encoding='utf-8')
print(json.dumps(record, indent=2))
@@ -0,0 +1,107 @@
"""Independent read-only saved-F Project/SVG oracle; writes a new receipt only.
Run from any cwd: python wrapped-reopen-independent-check.py NEW-RECEIPT.json
"""
from pathlib import Path
import copy, hashlib, json, math, re, struct, sys
import xml.etree.ElementTree as ET
ROOT = Path(__file__).resolve().parents[1]
EDGE = '63009b5f-539e-5914-b630-ec6b7fefb4d5'
DIAGRAM = '00000000-0038-4000-8000-000000000001'
NAME = 'Technician service conversation'
NS = '{http://www.w3.org/2000/svg}'
TOL = 0.0002
P = ROOT/'.local/native-wrapped-F/working'
Q = ROOT/'.local/native-wrapped-reopen-F/working'
FILES = {'pristine_project':P/'eight-card.json','saved_project':Q/'moved-F.json','pristine_svg':P/'pristine-F.svg','reopened_svg':Q/'reopened-F.svg'}
def sha(b): return hashlib.sha256(b).hexdigest()
def require(c,m):
if not c: raise ValueError(m)
def f(x): return struct.unpack('<f',struct.pack('<f',x))[0]
def add(a,b): return f(f(a)+f(b))
def sub(a,b): return f(f(a)-f(b))
def mul(a,b): return f(f(a)*f(b))
def div(a,b): return f(f(a)/f(b))
def close(a,b,m):
require(math.isfinite(float(a)) and abs(float(a)-b)<=TOL, f'{m}: {a} versus expected {b}')
def group_and_rest(raw):
path = re.compile(rb'<path\b[^>]*\bdata-edge="'+EDGE.encode()+rb'"[^>]*>.*?</path>',re.S)
hits=list(path.finditer(raw));require(len(hits)==1,'Exactly one target path required')
at=hits[0].end()
match=re.compile(rb'<g data-label-experiment="wrapped">.*?</g>',re.S).match(raw,at)
require(match is not None,'Immediate target wrapped label group missing')
return ET.fromstring(match.group()),raw[:at]+raw[match.end():]
def expected(points,label):
lengths=[f(math.hypot(sub(b[0],a[0]),sub(b[1],a[1]))) for a,b in zip(points,points[1:])]
total=0.
for n in lengths: total=add(total,n)
remaining=mul(total,label['fraction'])
for a,b,n in zip(points,points[1:],lengths):
if n>0 and remaining<=n:
t=div(remaining,n);anchor=[add(a[i],mul(sub(b[i],a[i]),t)) for i in range(2)];break
remaining=sub(remaining,n)
else: raise ValueError('Anchor outside path')
# Independent prior Iced shaping evidence, not candidate-derived metrics.
widths=[60.601074,39.012695,73.18213]
width=add(max(widths),16.);height=56.
center=[add(anchor[0],label['offset']['x']),add(anchor[1],label['offset']['y'])]
rect=[sub(center[0],div(width,2)),sub(center[1],28.),width,height]
lines=[]
for i,(name,w) in enumerate(zip(['Technician','service','conversation'],widths)):
top=add(add(rect[1],4.),mul(16.,i))
lines.append([name,sub(center[0],div(w,2)),add(top,13.3828125)])
return {'path_length':total,'anchor':anchor,'center':center,'rect':rect,'lines':lines}
def label_check(group,e):
require(group.tag=='g' and group.attrib=={'data-label-experiment':'wrapped'},'Unexpected group')
parts=list(group);require(len(parts)==5,'Exactly title, rect and three lines required')
require(group.text is None and all(not list(x) and x.tail is None for x in parts),'Unexpected nested/stray content')
require(parts[0].tag=='title' and parts[0].attrib=={} and parts[0].text==NAME,'Title changed')
rect=parts[1];require(rect.tag=='rect' and set(rect.attrib)=={'x','y','width','height','fill'} and rect.get('fill')=='white' and rect.text is None,'Rect shape changed')
for k,v in zip(['x','y','width','height'],e['rect']):close(rect.get(k),v,'rect.'+k)
for actual,(name,x,y) in zip(parts[2:],e['lines']):
require(actual.tag=='text' and set(actual.attrib)=={'x','y','font-family','font-size','fill'},'Text shape changed')
require(actual.text==name and actual.get('font-family')=='Segoe UI' and actual.get('fill')=='#637487','Text content/font/fill changed')
close(actual.get('font-size'),13.,'font-size');close(actual.get('x'),x,name+'.x');close(actual.get('y'),y,name+'.baseline')
require(' '.join(x.text for x in parts[2:])==NAME,'Canonical name changed')
def check(data):
require(sha(data['pristine_project'])=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8','Pristine bytes changed')
require(sha(data['saved_project'])=='0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57','Saved bytes changed')
old,new=[json.loads(data[x]) for x in ['pristine_project','saved_project']]
require(old['diagrams'][DIAGRAM]['routes']==[],'Unexpected original routes')
routes=new['diagrams'][DIAGRAM]['routes'];require(len(routes)==1,'Unexpected added routes')
route=routes[0]
require(route=={'edge':EDGE,'waypoints':[],'label':{'fraction':0.55,'offset':{'x':120.812744,'y':38.814423}}},'Unexpected saved route fields/values')
restored=copy.deepcopy(new);restored['diagrams'][DIAGRAM]['routes']=[]
require(restored==old,'Complete Project contains another delta')
require(old['relations'][EDGE]['name']==new['relations'][EDGE]['name']==NAME,'Canonical model Name changed')
before,after=[ET.fromstring(data[x]) for x in ['pristine_svg','reopened_svg']]
require(before.tag==after.tag==NS+'svg','SVG namespace/root changed')
require(before.attrib==after.attrib=={'viewBox':'24 -12 1566 874'},'Root bounds changed')
edges=[[e for e in root.iter() if e.get('data-edge') is not None] for root in [before,after]]
require(len(edges[0])==len(edges[1])==12 and len({e.get('data-edge') for e in edges[0]})==12,'Distinct 12-edge inventory changed')
require([ET.tostring(e) for e in edges[0]]==[ET.tostring(e) for e in edges[1]],'Path, marker, title, style or edge order changed')
target=next(e for e in edges[0] if e.get('data-edge')==EDGE)
require(target.get('d')=='M 1001 316.5 L 1019 316.5 L 1162 316.5 L 1162 89.5 L 1180 89.5','Pinned original target route changed')
points=[(1001.,316.5),(1019.,316.5),(1162.,316.5),(1162.,89.5),(1180.,89.5)]
groups=[];rests=[]
for key,root in [('pristine_svg',before),('reopened_svg',after)]:
require(len([e for e in root.iter() if e.get('data-label-experiment') is not None])==1,'Extra experimental groups')
g,r=group_and_rest(data[key]);groups.append(g);rests.append(r)
require(rests[0]==rests[1],'Bytes outside ONLY target label presentation changed')
pristine=expected(points,{'fraction':.55,'offset':{'x':add(18.,div(add(73.18213,16.),2.)),'y':0.}})
reopened=expected(points,route['label'])
label_check(groups[0],pristine);label_check(groups[1],reopened)
require(groups[0][1].get('width')==groups[1][1].get('width') and groups[0][1].get('height')==groups[1][1].get('height'),'Dimensions differ textually')
return {'complete_project_only_target_label_route':True,'original_bytes_unchanged':True,'all_12_edges_exact':True,'all_svg_bytes_outside_target_label_exact':True,'remaining_svg_sha256':sha(rests[0]),'expected_pristine':pristine,'expected_reopened':reopened,'numeric_absolute_tolerance':TOL}
def main():
require(len(sys.argv)==2,'Specify a new receipt path')
report={'status':'FAIL','script_sha256':sha(Path(__file__).read_bytes()),'invocation':sys.argv,'scope':'Saved-F full Project and logical SVG; no native input events, raster/font portability, baseline-profile reopen or usability acceptance'}
with Path(sys.argv[1]).open('x',encoding='utf-8') as out:
try:
data={k:p.read_bytes() for k,p in FILES.items()}
report['inputs']={k:{'path':str(FILES[k]),'bytes':len(v),'sha256':sha(v)} for k,v in data.items()}
report.update(check(data))
report['status']='PASS'
except Exception as e: report['failure']=str(e)
json.dump(report,out,indent=2);out.write('\n')
print(json.dumps(report,indent=2));return 0 if report['status']=='PASS' else 1
if __name__=='__main__': sys.exit(main())
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,112 @@
"""Read-only evidence check. Python 3; --index also compares every Git staged byte.
Historical launch/preparation scripts are never executed. SVG logic is loaded
without importing or writing __pycache__; the full model delta is independently
reconciled below. Optional --source verifies the frozen source manifest via Git.
"""
from pathlib import Path
from types import SimpleNamespace
import copy
import hashlib
import json
import subprocess
import sys
evidence = Path(__file__).resolve().parent
repo = evidence.parents[3]
load = lambda path: json.loads(path.read_text(encoding="utf-8"))
digest = lambda data: {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
inventory = load(evidence / "evidence-files.json")
actual_files = {p.relative_to(evidence).as_posix() for p in evidence.rglob("*") if p.is_file()}
assert actual_files == set(inventory) | {"evidence-files.json"}, "Missing or extra evidence files"
for name, expected in inventory.items():
assert digest((evidence / name).read_bytes()) == expected, name
if "--index" in sys.argv:
for name in actual_files:
path = evidence / name
staged = subprocess.check_output(["git", "show", ":" + path.relative_to(repo).as_posix()], cwd=repo)
assert staged == path.read_bytes(), "Staged byte conversion: " + name
if "--source" in sys.argv:
manifest = load(evidence / "source-manifest.json")
for name, expected in manifest["files"].items():
data = subprocess.check_output(["git", "show", manifest["source"] + ":" + name], cwd=repo)
assert digest(data) == expected, "Frozen source mismatch: " + name
source = "d0896ced75fea73bcda6bd14f259a34503840704"
binary = "2b6d76d744d7422fc826f7f7ca0009b296a0efb751fe0b3bbc1516b8a624c201"
runtime = "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
fixture = "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
assert digest((evidence.parent / "fixture/eight-card.json").read_bytes())["sha256"] == fixture
namespace = {"__name__": "readonly_svg_oracle", "__file__": str(evidence / "scripts/check-wrapped-svg.py")}
exec(compile((evidence / "scripts/check-wrapped-svg.py").read_bytes(), namespace["__file__"], "exec"), namespace)
svg_results = {}
for profile in ["E", "F"]:
run = evidence / ("native-" + profile)
baseline, start, finish = [load(run / name) for name in ["baseline.json", "started.json", "finished.json"]]
assert baseline["source"] == start["source"] == finish["source"] == source
assert start["label_profile"] == finish["label_profile"] == profile
assert start["binary_sha256"] == finish["binary_sha256"] == binary
assert start["runtime_sha256"] == finish["runtime_sha256"] == runtime
assert start["fixture_sha256"] == finish["fixture_sha256"] == fixture
assert digest((run / "working/eight-card.json").read_bytes())["sha256"] == fixture
assert finish["exit_code"] == 0 and finish["all_pinned_files_unchanged"]
for stream in ["stdout", "stderr"]:
assert finish[stream + "_bytes"] == 0 and (run / (stream + ".log")).read_bytes() == b""
result = {}
namespace["check"](SimpleNamespace(
baseline=str(evidence / "baseline/working/baseline.svg"),
candidate=str(run / ("working/pristine-" + profile + ".svg")), profile=profile), result)
assert result["status"] == "PASS" and result["all_remaining_svg_bytes_exact"]
svg_results[profile] = result["remaining_svg"]
run = evidence / "native-F"
before = load(run / "working/eight-card.json")
after = load(run / "working/moved-F.json")
receipt = load(run / "model-oracle.json")
assert digest((run / "working/moved-F.json").read_bytes())["sha256"] == receipt["saved_sha256"]
diagram = "00000000-0038-4000-8000-000000000001"
edge = "63009b5f-539e-5914-b630-ec6b7fefb4d5"
routes = after["diagrams"][diagram]["routes"]
declared = [route for route in routes if route["edge"] == edge]
assert len(declared) == 1 and declared[0] == receipt["declared_edit"]
route = declared[0]
assert set(route) <= {"edge", "waypoints", "label", "source_attachment", "target_attachment"}
assert route["waypoints"] == [] and route.get("source_attachment") is None and route.get("target_attachment") is None
assert set(route["label"]) == {"fraction", "offset"} and route["label"]["fraction"] == 0.55
assert route["label"]["offset"] == {"x": 120.812744, "y": 38.814423}
restored = copy.deepcopy(after)
restored["diagrams"][diagram]["routes"] = [route for route in routes if route["edge"] != edge]
assert restored == before, "Full Project delta exceeds target label fraction/offset"
log = (evidence / "gates/wrapped-label-diagram-tests.log").read_text(encoding="utf-8")
assert "126 passed; 0 failed; 0 ignored; 0 measured; 1426 filtered out" in log
commands = load(evidence / "commands.json")
assert commands["source"] == source and all(gate["exit_code"] == 0 for gate in commands["final_gates"])
assert (evidence / "gates/wrapped-label-format-check.log").read_bytes() == b""
for profile in ["F", "Baseline"]:
run = evidence / ("reopen-" + profile)
start, finish = [load(run / name) for name in ["started.json", "finished.json"]]
assert start["source"] == finish["source"] == source
assert start["profile"] == finish["profile"] == profile
assert start["external_profile"] == finish["external_profile"] == ("F" if profile == "F" else None)
assert start["files"] == finish["files"]
assert finish["files"]["bin/arcadia-studio.exe"] == binary
assert finish["files"]["bin/libunwind.dll"] == runtime
assert (run / "working/moved-F.json").read_bytes() == (evidence / "native-F/working/moved-F.json").read_bytes()
assert finish["exit_code"] == 0 and finish["all_pinned_files_unchanged"]
for stream in ["stdout", "stderr"]:
assert finish[stream + "_bytes"] == 0 and (run / (stream + ".log")).read_bytes() == b""
reopen_script = evidence / "scripts/wrapped-reopen-independent-check.py"
reopen_namespace = {"__name__": "readonly_reopen_oracle", "__file__": str(reopen_script)}
exec(compile(reopen_script.read_bytes(), str(reopen_script), "exec"), reopen_namespace)
reopen_result = reopen_namespace["check"]({
"pristine_project": (evidence / "native-F/working/eight-card.json").read_bytes(),
"saved_project": (evidence / "reopen-F/working/moved-F.json").read_bytes(),
"pristine_svg": (evidence / "native-F/working/pristine-F.svg").read_bytes(),
"reopened_svg": (evidence / "reopen-F/working/reopened-F.svg").read_bytes(),
})
assert reopen_result["all_12_edges_exact"] and reopen_result["all_svg_bytes_outside_target_label_exact"]
print(json.dumps({"status": "PASS", "inventory_files": len(inventory), "svg_conservation": svg_results,
"full_project_delta_exact": True, "reopened_F_logical_geometry_exact": True,
"index_checked": "--index" in sys.argv,
"source_manifest_checked": "--source" in sys.argv,
"scope": "Preserved evidence and offline oracles; not a native/glyph/usability replay"}, indent=2))
@@ -0,0 +1,84 @@
# Independent final consolidated E/F packet review
Review checkpoint: source HEAD `d0896ced75fea73bcda6bd14f259a34503840704`; documentation and raw evidence staged afterward for archival. This is a new packet review after the earlier source, repair, and pre-reopen evidence reviews. It does not relabel those historical reviews as having examined later data.
Read-only scope: reviewed README, validation, staged STATE/DECISIONS changes, inventory/source manifest, portable verifier, copied launch/exit records, raw failures, locked readings, native observation notes, and the later independent saved-F checker/results. Ran only the portable offline verifier without optional flags and read/hash checks. No Rust/helper/document edits, staging, commit, GUI, Cargo, or Gitea action. Only this report was written.
## Recommendation
**Accept the packet for archival as a bounded, non-promoted experiment. No material evidence or final-claim blocker found.** Neither E nor F establishes dependable unselected label ownership. The source repair and conservation evidence are useful, but they do not turn the experiment into a production readability improvement. Keep the wider issue open.
The README, validation, STATE, and DECISIONS consistently express that boundary. E's correct lack-of-direction observation is correctly treated as appropriate for an unoriented boundary exchange; it is not falsely graded as an error. F's wrong exchange readings are preserved. Both readers' plausible wrong conversation ownership remains the relevant negative observation. Separate single-agent screenshot readers are not presented as a controlled human or causal comparison.
## Inventory and portability
I independently ran:
```text
C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe harness/experiments/wrapped-label-20261001/evidence/verify.py
```
It exited 0 with PASS: 83 inventoried files, exact pristine E/F SVG conservation, complete F Project delta, and reopened-F logical geometry. The inventory totals **3,476,900 bytes**, excluding the inventory file itself. The source manifest declares 300 source files at d089. The verifier requires the actual evidence-file set to equal the inventory plus itself, so omitted/extra local packet files are not silently ignored. Scoped `-text` attributes preserve raw bytes through Git.
The verifier does not execute historical preparation/launch scripts. It loads checker definitions without invoking their main functions and supplies packet-local inputs; no native process, renderer, or bytecode cache is launched/written. Historical absolute paths remain preserved as provenance. The README properly directs portable replay through the wrapper rather than promising those historical launchers work from a new checkout.
The initial staged-byte verification failure, supplied by the parent, was due to ignored log files being absent from the index. Parent reported force-adding only the scoped evidence directory and rerunning the unchanged verifier. That is a packaging repair, not grounds to change the inventory or relax byte equality. This review's independent default run checks filesystem packet bytes; the parent's final `--index --source` checkpoint is recorded separately below.
## New reopen evidence, timing, and claims
The earlier final evidence review said same-profile reopening was then absent. The consolidated README and validation explicitly state that it predates the fresh reopen runs and link the later saved-F review. That correctly preserves the historical checkpoint without leaving its limitation to be mistaken for a final verdict on newer artifacts.
The later independent checker requires the exact original and saved Project hashes, the exact single authored target route, and complete parsed Project equality after removing it. It pins the original target path before deriving the authored label anchor/box/line positions through f32 arithmetic and earlier Iced font metrics. It compares every edge/path record and all SVG bytes outside only the moved target label. The five corruption controls and result are present. It uses explicit `require` checks rather than Python assertions for its logical oracle. This is materially stronger evidence of saved-F export geometry than simply comparing a screenshot with a remembered position.
Copied saved inputs under both reopen profiles are exact `0ad4015d...` files, and reopened-F SVG is `5b1106b9...`; exact hashes are below. The independent default verifier reran the logical saved-F check successfully from the packet. This establishes model-delta and logical-export preservation, not glyph/raster parity.
The ordinary Baseline process actually opened the saved file from the preceding F folder through Recent Open, rather than its unused identical local copy. The parent observation and validation call this out. Its watcher alone checks its own pinned copy; the explicitly recorded actual-loaded-path observation and post-close hash are therefore necessary provenance. The packet includes the actual F-folder input and its independently matching hash. No Baseline SVG is claimed. The one-line Baseline rendering remains a parent-observed native result; the independent saved-F checker does not claim to establish it.
The parent observation distinguishes tool-observed events, captures, and the unretained raw event transcript. F's last-line click is specifically marked tool-observed only. E's two line selections have captures; E editing is not claimed. F JSON export remains dirty until Undo, so it is not described as Save All or an ordinary source-file save/clean round trip. Failed chooser attempts and automation ambiguity are retained rather than diagnosed as application bugs without evidence.
## Gate scope and retained failures
`commands.json` explicitly records the parent-observed filtered command:
```text
cargo test --locked -p oa-desktop -- diagram:: diagram_usage:: fit_ --test-threads=1 --nocapture
```
The raw result and validation say 126 passed, 0 failed, 0 ignored, 1,426 filtered out. They do not claim a full desktop/workspace suite. Clippy is identified as desktop all-targets with `-D warnings`; the build is the development GUI binary. The command manifest acknowledges that logs alone do not prove invocation scope. An empty formatting log is paired with a fresh parent-recorded successful command, and the earlier missing-log summary error is disclosed.
The E0063 fixture compile failure and the later five-pass/one-fail stale-wrapped-geometry regression are preserved. The source/repair reviews and repaired raw/presentation split are not rewritten to imply first-pass success. The SVG oracle's initial selfcheck setup error and revised successful controls are also retained.
No new Rust correctness issue was identified by this packet review; the prior repair review still covers d089. Native different-edge guard refusal, held-pointer cancellation, E edit lifecycle, glyph/raster parity, generalized metrics/placement/persistence/performance, nesting, accessibility/DPI, Linux and broader modeling acceptance remain excluded. Those exclusions fit archival after a negative reading result; they are not undisclosed unfinished acceptance gates for a promoted feature.
## Remaining nonblocking caution
The wrapper and original F model helper use Python assertions, so the documented normal Python invocation matters: `python -O` would disable some checks. The SVG and later saved-F logical check functions retain explicit exception guards, but that does not rescue disabled inventory/index/source assertions. The packet documents this limitation for the original model helper; do not describe the wrapper as hardened against optimized-Python misuse. No such invocation was used in the reviewed successful run.
Source-manifest checks bind recorded files to Git objects; process receipts bind expected hashes/profiles to parent launches. They are not binary reproducibility attestations or a native interaction replay. Current documentation avoids those overclaims.
## Fingerprints at this review checkpoint
| Artifact | SHA-256 |
| --- | --- |
| README.md | 79f621b58fe0b9a5b16d3aa9d5b1c89994b79f4f314d4d97ff9419e7603f7a1a |
| validation.md | ad608b10ea9634fde22823cd841a5e7bdee5aa5b67faf21a2975f3726e505e8f |
| evidence/evidence-files.json | 57f137d47d73f0b28ed248c974815d10454339c35d73eb86a550b34d3061fd39 |
| evidence/verify.py | 282f8d95355d764d09ceea5662be2aa381b17ed863b5fd442d37599817616c23 |
| evidence/reviews/wrapped-native-observation.md | 11a295fd1f60dad6c57b674f810a16d2e91b40bf2f84592cadc51ae5f4c3d114 |
| evidence/scripts/wrapped-reopen-independent-check.py | 8d718db9a52e894e8160436eab2d57998f211b71f4485b3543c6badde36b7815 |
| evidence/native-E/first-reading.md | 9de823d0d43e7753f2799e203a68332b7361c1c6c2f8f18baece5c60baa01c66 |
| evidence/native-F/first-reading.md | 2867ba22c3195e7b77cf696fffbdcc65ca6e8a74dc212f38407ef797216b5f8e |
| evidence/reopen-F/working/moved-F.json and reopen-Baseline copy | 0ad4015d06cf513cd8f9cfe3a155c07590ba09585002277d6eed7a78dd3b6a57 |
| evidence/reopen-F/working/reopened-F.svg | 5b1106b9f8cdb6030e29d657f8aac1920e1a554e868bab4fce3e250a42469cd5 |
| evidence/reviews/wrapped-reopen-independent-result.json | 8804ba0f50500ae92c1dd2c175ca241aa23070db6a0221793d6a85d67cd27e0f |
| evidence/reviews/wrapped-reopen-independent-selfcheck.json | 7e22a0379be1ecf095130ab179525525b850f50ee905e804b607db3bc92e023b |
The copied locked-reading hashes exactly match their pre-packet originals reviewed earlier. The packet inventory supplies remaining file hashes; the verifier confirms them. This report itself will be archived after that inventory checkpoint, so adding it to the inventoried directory requires inventory regeneration and another staged-byte check rather than pretending the 83-file result covered the new report.
## Final staged/source checkpoint received before completion
Parent confirmed the unchanged `verify.py --index --source` run completed at d089 with exit 0/PASS: inventory 83; E and F each retain the exact 6,977-byte remainder SHA256 `5603ada145dbb255eb4dfd583258427057a9312443685d47f278ef76756ef8ed`; complete F model delta and reopened-F logical geometry true; `index_checked: true`; `source_manifest_checked: true`. All 300 pinned source-blob checks succeeded. This optional-flags result is parent-run evidence, distinguished from my independent default run above.
The first index failure remains in chat history rather than as an inventoried file: ignored log files had not been staged. Parent force-added only the scoped packet evidence directory, reran the full checker unchanged, and obtained the result above. No Rust/source change was made for that repair.
Parent will archive this review as `final-review.md` at the experiment root, outside `evidence/`. That preserves the 83-file raw-evidence inventory and avoids a self-referential review/inventory cycle. This review's acceptance is for archival of that verified packet and explicitly non-promoted experiment; it does not claim the later review file was part of the earlier inventory result.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
{
"source_commit": "45bfb63b4fb90683c7ed769565698f04f808a36a",
"source_path": "harness/experiments/diagram-readability-20261001/native-reading/working/eight-card.json",
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"bytes": 138661,
"scope": "Complete representative reconstructed8card12relationshipProject; not recovereduser model."
}

Some files were not shown because too many files have changed in this diff Show More