Compare commits

..
143 changed files with 27949 additions and 1335 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 -42
View File
@@ -37,8 +37,9 @@ mod port_hit_tests;
#[path = "diagram/view_options_tests.rs"]
mod view_options_tests;
#[path = "diagram/label_cues.rs"]
mod label_cues;
#[path = "diagram/label_layout_experiment.rs"]
mod label_layout_experiment;
#[path = "diagram/port_labels.rs"]
mod port_labels;
pub use port_labels::PortLabels;
@@ -90,10 +91,15 @@ 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>,
label_cues: BTreeMap<Id, label_cues::Cue>,
}
struct CachedScene {
context: Context,
@@ -517,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
@@ -525,18 +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(),
label_cues: label_cues::derive(
preview.project(),
&preview.placement.view,
&preview.routed,
),
core_routed,
routed,
});
*state.work_cache.borrow_mut() = Some(scene.clone());
return scene;
@@ -562,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();
}
@@ -571,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()
@@ -588,10 +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,
label_cues: label_cues::derive(self.project, &view, &routed),
view,
core_routed,
routed,
});
*state.cache.borrow_mut() = Some(CachedScene {
@@ -604,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,
@@ -1359,35 +1420,32 @@ impl canvas::Program<Message> for DiagramCanvas<'_> {
}
if !routed.label.text.is_empty() {
let label = &routed.label;
if let Some(cue) = scene.label_cues.get(&edge.id) {
f.stroke(
&Path::line(point(cue.boundary), point(cue.anchor)),
Stroke {
line_dash: canvas::LineDash {
segments: label_cues::DASH,
offset: 0,
},
..Stroke::default()
.with_color(style::MUTED)
.with_width(label_cues::WIDTH)
},
);
}
f.fill_rectangle(
point(label.bounds.position),
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) {
@@ -1966,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)
@@ -1975,8 +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 label_cues = label_cues::derive(p, &view, &routed);
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.;
@@ -2053,10 +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(cue) = label_cues.get(&edge.id) {
svg.push_str(&label_cues::svg(edge.id, *cue));
}
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,15 +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,
label_cues: BTreeMap::new(),
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();
-403
View File
@@ -1,403 +0,0 @@
//! Experimental, presentation-only label association. Never used for picking.
use oa_core::{
Id, Position, Project,
projection::ProjectedView,
routing::{self, RoutedView, RoutingBounds},
};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq)]
pub(super) struct Cue {
pub boundary: Position,
pub anchor: Position,
}
const MIN_GAP: f32 = 12.;
const LANDING_CLEARANCE: f32 = 7.;
pub(super) const DASH: &[f32] = &[2., 3.];
pub(super) const WIDTH: f32 = 1.;
pub(super) fn derive(
project: &Project,
view: &ProjectedView,
routed: &RoutedView,
) -> BTreeMap<Id, Cue> {
let association_labels: Vec<_> = routed
.edges
.values()
.flat_map(|edge| {
project
.relations
.get(&edge.id)
.into_iter()
.flat_map(move |relation| {
routing::association_end_geometry(relation, edge)
.into_iter()
.map(|end| end.label.bounds)
})
})
.collect();
routed
.edges
.values()
.filter_map(|edge| {
if edge.label.text.is_empty() {
return None;
}
let bounds = edge.label.bounds;
let anchor = edge.label.anchor;
// Nearest rectangle boundary, not center displacement (which inflates
// apparent separation for long labels).
let boundary = Position {
x: anchor
.x
.clamp(bounds.position.x, bounds.position.x + bounds.size.width),
y: anchor
.y
.clamp(bounds.position.y, bounds.position.y + bounds.size.height),
};
if (anchor.x - boundary.x).hypot(anchor.y - boundary.y) <= MIN_GAP {
return None;
}
let cue = Cue { boundary, anchor };
for other in routed.edges.values().filter(|other| other.id != edge.id) {
if other.points.windows(2).any(|pair| {
point_distance(anchor, pair[0], pair[1]) <= LANDING_CLEARANCE
|| intersects(cue.boundary, cue.anchor, pair[0], pair[1])
}) {
return None;
}
if !other.label.text.is_empty() && crosses_box(cue, other.label.bounds) {
return None;
}
}
if view.nodes.iter().any(|node| {
crosses_box(
cue,
RoutingBounds {
position: node.position,
size: node.size,
},
)
}) || association_labels
.iter()
.any(|bounds| crosses_box(cue, *bounds))
{
return None;
}
Some((edge.id, cue))
})
.collect()
}
fn point_distance(p: Position, a: Position, b: Position) -> f32 {
let dx = b.x - a.x;
let dy = b.y - a.y;
let length = dx * dx + dy * dy;
let t = if length == 0. {
0.
} else {
(((p.x - a.x) * dx + (p.y - a.y) * dy) / length).clamp(0., 1.)
};
(p.x - a.x - t * dx).hypot(p.y - a.y - t * dy)
}
fn cross(a: Position, b: Position, c: Position) -> f32 {
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
}
fn intersects(a: Position, b: Position, c: Position, d: Position) -> bool {
// Closed segments: touching an unrelated path is also ambiguous.
if a.x.max(b.x) < c.x.min(d.x)
|| c.x.max(d.x) < a.x.min(b.x)
|| a.y.max(b.y) < c.y.min(d.y)
|| c.y.max(d.y) < a.y.min(b.y)
{
return false;
}
cross(a, b, c) * cross(a, b, d) <= 0. && cross(c, d, a) * cross(c, d, b) <= 0.
}
fn crosses_box(cue: Cue, bounds: RoutingBounds) -> bool {
let x = bounds.position.x;
let y = bounds.position.y;
let right = x + bounds.size.width;
let bottom = y + bounds.size.height;
let inside = |p: Position| p.x >= x && p.x <= right && p.y >= y && p.y <= bottom;
let corners = [
Position { x, y },
Position { x: right, y },
Position {
x: right,
y: bottom,
},
Position { x, y: bottom },
];
inside(cue.boundary)
|| inside(cue.anchor)
|| (0..4).any(|i| intersects(cue.boundary, cue.anchor, corners[i], corners[(i + 1) % 4]))
}
pub(super) fn svg(edge: Id, cue: Cue) -> String {
format!(
"<path data-label-cue=\"{edge}\" d=\"M {} {} L {} {}\" fill=\"none\" stroke=\"#4b5968\" stroke-width=\"1\" stroke-dasharray=\"2 3\" pointer-events=\"none\"/>",
cue.boundary.x, cue.boundary.y, cue.anchor.x, cue.anchor.y
)
}
#[cfg(test)]
mod tests {
use super::*;
use oa_core::{Diagram, Size};
use serde_json::json;
fn representative() -> (Project, Id, Id) {
let mut project = oa_core::persistence::decode(include_bytes!(
"../../../../examples/release1/model.json"
))
.unwrap();
let id: Id = "00000000-0038-4000-8000-000000000001".parse().unwrap();
let mut nodes = serde_json::Map::new();
for (i, (alias, x, y, width, height)) in [
("oa_assessment_procedure", 314, 40, 243, 101),
("sa_technician", 1180, 18, 265, 143),
("sa_assess", 54, 245, 265, 143),
("sa_control", 736, 245, 265, 143),
("sa_repair", 1083, 343, 266, 143),
("sa_reset", 227, 516, 266, 119),
("oa_triage", 1317, 581, 243, 103),
("sa_confirm", 227, 689, 266, 143),
]
.into_iter()
.enumerate()
{
let element = project
.elements
.values()
.find(|e| e.alias == alias)
.unwrap()
.id;
let node = format!("00000000-0038-4000-8000-{:012}", 101 + i);
nodes.insert(
node.clone(),
json!({"id":node,"alias":format!("issue38_{alias}"),"element":element,
"position":{"x":x,"y":y},"size":{"width":width,"height":height},"collapsed":false}),
);
}
let diagram: Diagram =
serde_json::from_value(json!({"id":id,"alias":"issue38_representative_mixed",
"name":"Representative eight-card view","description":"Not recovered user source",
"layer":"Sa","projection":"Traceability","nodes":nodes,"routes":[]}))
.unwrap();
project.diagrams.insert(id, diagram);
assert!(
!oa_core::validation::validate(&project)
.iter()
.any(|issue| issue.severity == oa_core::validation::Severity::Error)
);
(
project,
id,
"63009b5f-539e-5914-b630-ec6b7fefb4d5".parse().unwrap(),
)
}
#[test]
fn representative_cue_and_svg_preserve_complete_project_and_geometry() {
let (project, diagram, edge) = representative();
let before = project.clone();
let view = oa_core::projection::project_view(&project, diagram);
let routed = routing::route_diagram(&project, &project.diagrams[&diagram], &view);
let geometry = routed.clone();
assert_eq!(view.edges.len(), 12);
let cues = derive(&project, &view, &routed);
assert_eq!(
cues[&edge],
Cue {
boundary: Position { x: 1180., y: 274.5 },
anchor: Position { x: 1162., y: 274.5 }
}
);
assert_eq!(project, before);
assert_eq!(routed, geometry);
let output = super::super::export_svg(&project, diagram).unwrap();
let cue = output
.split('<')
.find(|part| part.contains(&format!("data-label-cue=\"{edge}\"")))
.unwrap();
assert!(cue.contains("stroke-dasharray=\"2 3\""));
assert!(!cue.contains("marker") && !cue.contains("data-edge="));
assert_eq!(project, before);
assert_eq!(
routing::route_diagram(&project, &project.diagrams[&diagram], &view),
geometry
);
}
#[test]
fn default_gap_and_anchor_inside_label_do_not_add_cues() {
let (project, diagram, edge) = representative();
let view = oa_core::projection::project_view(&project, diagram);
let mut routed = routing::route_diagram(&project, &project.diagrams[&diagram], &view);
// Geometry controls: center 18 above anchor with a 24-high label leaves
// only a six-unit boundary gap. Large text width must not trigger a cue.
let label = &mut routed.edges.get_mut(&edge).unwrap().label;
label.bounds = RoutingBounds {
position: Position {
x: label.anchor.x - 116.5,
y: label.anchor.y - 30.,
},
size: Size {
width: 233.,
height: 24.,
},
};
assert!(!derive(&project, &view, &routed).contains_key(&edge));
// Same clear horizontal corridor as the representative cue: only the
// boundary gap changes, so these controls isolate the strict threshold.
for (gap, admitted) in [(12., false), (12.25, true)] {
let label = &mut routed.edges.get_mut(&edge).unwrap().label;
label.bounds = RoutingBounds {
position: Position {
x: label.anchor.x + gap,
y: label.anchor.y - 12.,
},
size: Size {
width: 233.,
height: 24.,
},
};
assert_eq!(
derive(&project, &view, &routed).contains_key(&edge),
admitted
);
}
let mut authored = project.clone();
authored
.diagrams
.get_mut(&diagram)
.unwrap()
.routes
.push(oa_core::EdgeRoute {
edge,
source_attachment: None,
target_attachment: None,
waypoints: vec![],
label: Some(oa_core::EdgeLabel {
fraction: 0.5,
offset: Position { x: 0., y: 0. },
}),
});
let authored_before = authored.clone();
let authored_routed =
routing::route_diagram(&authored, &authored.diagrams[&diagram], &view);
assert!(!derive(&authored, &view, &authored_routed).contains_key(&edge));
assert_eq!(authored, authored_before);
}
#[test]
fn shared_or_near_landing_and_route_card_label_obstructions_suppress_cue() {
let (project, diagram, edge) = representative();
let view = oa_core::projection::project_view(&project, diagram);
let routed = routing::route_diagram(&project, &project.diagrams[&diagram], &view);
let other = *routed.edges.keys().find(|id| **id != edge).unwrap();
for x in [1162., 1168., 1171.] {
let mut changed = routed.clone();
changed.edges.get_mut(&other).unwrap().points =
vec![Position { x, y: 260. }, Position { x, y: 290. }];
// x1162 shares the landing, x1168 is too near, x1171 crosses the cue.
assert!(!derive(&project, &view, &changed).contains_key(&edge));
}
// These segments lie LEFT of the cue and cannot intersect it. They
// independently exercise landing clearance, including its boundary.
for (x, admitted) in [(1156., false), (1155., false), (1154., true)] {
let mut changed = routed.clone();
changed.edges.get_mut(&other).unwrap().points =
vec![Position { x, y: 260. }, Position { x, y: 290. }];
assert_eq!(
derive(&project, &view, &changed).contains_key(&edge),
admitted
);
}
let mut cards = view.clone();
cards.nodes[0].position = Position { x: 1169., y: 270. };
cards.nodes[0].size = Size {
width: 4.,
height: 10.,
};
assert!(!derive(&project, &cards, &routed).contains_key(&edge));
let mut labels = routed.clone();
let label = &mut labels.edges.get_mut(&other).unwrap().label;
label.text = "Obstruction".into();
label.bounds = RoutingBounds {
position: Position { x: 1169., y: 270. },
size: Size {
width: 4.,
height: 10.,
},
};
assert!(!derive(&project, &view, &labels).contains_key(&edge));
}
#[test]
fn selection_hover_and_camera_reuse_cached_scene_cues() {
let (project, diagram, edge) = representative();
let mut canvas = super::super::DiagramCanvas {
selection: None,
allocation: None,
project: &project,
view_index: None,
diagram,
selected: Id::nil(),
navigation_focus: None,
zoom: 1.,
pan: iced::Vector::ZERO,
context: crate::route_edit::Context {
document: project.id,
diagram,
revision: 0,
epoch: 0,
},
selected_bend: None,
selected_attachment: None,
editable: true,
placing: false,
connection: None,
};
let mut state = super::super::State::default();
let before = canvas.scene(&state);
assert!(before.label_cues.contains_key(&edge));
canvas.selected = edge;
canvas.zoom = 0.52;
canvas.pan = iced::Vector::new(25., 30.);
state.pointer = Some(iced::Point::new(60., 70.));
let after = canvas.scene(&state);
assert!(std::sync::Arc::ptr_eq(&before, &after));
assert_eq!(before.label_cues, after.label_cues);
let mut changed = project.clone();
changed
.diagrams
.get_mut(&diagram)
.unwrap()
.routes
.push(oa_core::EdgeRoute {
edge,
source_attachment: None,
target_attachment: None,
waypoints: vec![],
label: Some(oa_core::EdgeLabel {
fraction: 0.5,
offset: Position { x: 0., y: 0. },
}),
});
canvas.project = &changed;
canvas.context.revision += 1;
let rebuilt = canvas.scene(&state);
assert!(!std::sync::Arc::ptr_eq(&after, &rebuilt));
assert!(!rebuilt.label_cues.contains_key(&edge));
assert_eq!(
rebuilt.routed.edges[&edge].label.center,
rebuilt.routed.edges[&edge].label.anchor
);
}
}
@@ -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
+13 -7
View File
@@ -1,12 +1,18 @@
# Isolated nonproduction label cue trial — 2026-10-01 PDT
# Isolated measured-label experiment checkpoint — 2026-10-01 PDT
This branch adds renderer experiment B at `3e5e094b` to the accepted foundation
below. [Actual trial and preserved evidence](experiments/label-cue-20261001/README.md)
pass code/conservation gates but fail reliable first-reading association. Do not
promote its cue or treat this branch as an accepted integrated release. Published
preview binaries/tags remain unchanged. Live next work stays in Gitea issue38.
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.
## Accepted foundation checkpoint
# Verified Windows source checkpoint — 2026-10-01 PDT
This branch combines the released integrated foundation
`715036e132677dd2bc2fb37ed316d93dc9987aec` with compact diagram controls and
@@ -1 +0,0 @@
evidence/** -text whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
@@ -1,69 +0,0 @@
# Guarded label cue: not promoted
Candidate B is not accepted for production. Exact source `3e5e094bb17877674f4f3ea027a25fc0bdecdfe7`
passes formatting, all 87 selected diagram tests, strict desktop/all-target Clippy
and the matching Windows GUI build. The initial independent source review preceded
formatting and strengthened clearance/invalidation controls; production geometry
policy stayed unchanged. Its original hashes and scope are retained in
[source-review.md](source-review.md), rather than relabeled as a review of new bytes.
The [fresh native reader](evidence/native-cue/first-reading/review.md) sees only the
complete target scene before locking answers. Initial participants are correct,
but the conversation still has plausible foreign Allocation ownership and the
pale cue cannot be used confidently at Fit52% or one zoom step. Request/report
tracing remains uncertain. This fails the predeclared reliable-association/no-
explanation gate. Correct guesses alone do not establish an intuitive workflow.
The separately published [baseline fresh static review](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/45bfb63b4fb90683c7ed769565698f04f808a36a/harness/experiments/diagram-readability-20261001/first-exposure/review.md)
assigns the conversation to that
Allocation and its arrowhead, but different readers and static/live conditions
prevent a causal effect estimate or human-study claim.
The existing-path 18-world-unit dotted cue changes neither model nor routing.
Native candidate and released-baseline SVG exports both succeed. The
[complete byte comparison](evidence/native-cue/svg-comparison-final.json) finds
one nonsemantic cue path; removing exactly that path makes the entire SVG
byte-identical to baseline, including every original drawing mark, label and
metadata. Both complete 138,661-byte input models stay exact, both desktop
processes close normally with exit0 and empty streams, and executable/runtime
pins remain unchanged. This is conservation evidence, not repaired reading.
Experimental desktop SHA256: `38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04`.
Baseline desktop: `d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e`
from source `6e7c4ddaf0775198384a8c4882809ea8e14b2976`. Both use runtime
`f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4` and fixture
`9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8`.
The [byte-preserved packet](evidence/evidence-files.json) includes raw screenshots,
locked/continued reading, setup/export reports, input models and actual SVGs,
launch/exit receipts, empty streams, scripts, gate logs and source identities.
Historical scripts retain absolute paths; adapt to a fresh isolated trial. Do not
overwrite prior receipts. B's first launcher stopped before process creation
because Windows manifest keys used backslashes; the corrected launcher normalizes
keys while preserving the original manifest. Baseline chooser's first typing
attempt left its field empty; explicit pointer focus/native path retry succeeds.
These tool/harness limitations are not recorded as product defects.
The first SVG checker used a regex-byte membership predicate that did not itself
prove baseline cue absence. Full cue-removal byte equality already passed; the
final checker adds the direct literal absence assertion, retains the initial
checker/receipt, and passes again against unchanged actual exports.
Reproduce code gates from the source checkout with Rust configured:
```powershell
cargo fmt --all -- --check
cargo test --locked -p oa-desktop -- diagram:: --test-threads=1
cargo clippy --locked -p oa-desktop --all-targets -- -D warnings
cargo build --locked -p oa-desktop --bin arcadia-studio
```
Build is a development Windows gnullvm executable; no packaged release, Linux,
full-suite or full OA/SA acceptance is claimed. Dense rebuild/preview timing,
general collision geometry, accessibility/DPI and edited-label persistence were
not pursued after the first-reading falsifier. No weight/contrast tuning around
this scene is accepted. The next materially different experiment tests measured
wrapped labels and placement, with an explicit unresolved authored-format boundary.
The permanent Properties pane and narrow canvas remain separate workspace costs;
the native chevron expands tools rather than recovering Inspector space.
[Independent final evidence review](final-evidence-review.md) reconciles the complete packet and the failed-reading conclusion.
@@ -1,79 +0,0 @@
# Label association cue candidate B: source handoff
Implemented only in the isolated `codex/label-cue-experiment-01a0d717-20261001`
worktree from `6ea7518e`. No compilation, GUI operation, Gitea mutation, commit,
or production acceptance is claimed. Intent was recorded before source edits in
`label-cue-experiment-intent.md`.
## Changes
- New private `diagram/label_cues.rs` derives an edge-ID-to-cue map. For nonempty
ordinary labels, it clamps the anchor to the label rectangle to obtain the
nearest boundary point. Gap must be strictly greater than 12 world units.
Anchor inside/on the box and normal six-unit gaps produce no cue.
- A cue is omitted if its anchor is within 7 world units of any distinct edge's
segment, if its closed segment intersects any distinct route, any visible card
rectangle, or another ordinary/association-end label rectangle. Touching is
rejected. This includes container rectangles: conservative omission is intended.
- Two production Scene constructors cache cues with their already-routed scene,
using the preview Project where appropriate. Existing cache reuse handles
ordinary selection, hover, zoom and pan without recomputation. Route/placement
previews and revisions that build new scenes recompute the map.
- Canvas draws one-world-unit neutral dotted lines (2 on / 3 off) behind the owning
label's backing. SVG computes the same geometry once per export and uses matching
color, width and dash spacing, with `pointer-events="none"`. There is no marker,
arrowhead, endpoint dot, semantic hit region or stored metadata. Existing SVG
content is retained; the cue is the only intended export addition.
- One existing attachment-test Scene literal received an empty cue map; that test
exercises attachment handles, not label decoration. No unrelated refactor.
Four focused tests are prepared (not run by this agent):
1. Complete representative model admits without errors, retains twelve edges,
derives conversation boundary (1180,274.5) to anchor (1162,274.5), emits an
arrowless SVG cue, and preserves Project and complete routed geometry.
2. A long normal-offset label with only six units of boundary clearance is skipped;
exact 12-unit gap is skipped and 12.25 admitted; a genuinely authored label
centered on its anchor is skipped and stays exact.
3. Shared and six-unit-near landings, intersecting foreign route, card and label
controls suppress the cue. Additional nonintersecting segments six and exactly
seven units LEFT of the anchor are rejected; eight units left is admitted,
isolating the clearance guard from the crossing guard.
4. Actual Scene cache identity and cue map remain identical after selection,
pointer, zoom and pan changes. A changed Project with an authored label centered
on its anchor plus incremented context revision creates a new Scene and removes
the obsolete cue, independently checking invalidation as well as cache reuse.
Parent reproduction selector:
```powershell
cargo test --locked -p oa-desktop diagram::label_cues -- --test-threads=1
```
Parent should format, compile, run appropriate affected diagram/SVG gates and
independently review before native comparison. All changes remain uncommitted.
## Limits and explicit tradeoffs
The cue does not fix the foreign Allocation stroke already running through the
conversation label. It may be too weak at Fit; this is the central native falsifier.
No claim of improved unselected reading follows from source/geometry tests.
Closed rectangle and segment guards use projected geometry, not exact text glyph
or port-symbol contours. Authored label locations are never moved; a blocked cue
is simply omitted. The tests use the established representative scene, not the
user's exact source. There are no camera-dependent admission thresholds, so zoom
does not introduce cue admission flicker; physical dot size still scales normally.
Rebuild cost scans scene routes/cards/labels for each eligible label. No global
optimizer, new index, arbitrary cutoff, or per-hover scan was introduced. Dense
rebuild and route-preview latency remain parent performance gates. Individual
cue guards do not perform cue-to-cue avoidance; multiple eligible leaders can
intersect each other in other scenes. This is an explicit experimental limitation
to inspect before widening scope or making a general rendering claim.
The intended native comparison preserves the complete model, paths, labels and
camera: baseline versus B, plus the saved manual-label control. Fresh reading must
precede Inspector answers, and distinguish correct first association from mere
selectability. Revisit or reject B if wrong association persists, added marks are
mistaken for relationships, other reading worsens, or rendering/preview cost
regresses. Selection disambiguation and automatic-placement A remain separate.
@@ -1,36 +0,0 @@
from pathlib import Path
import hashlib, json, re, xml.etree.ElementTree as ET
root=Path(__file__).resolve().parents[1]
candidate=root/'.local/native-cue'; baseline=root/'.local/native-cue-baseline'
sha=lambda b:hashlib.sha256(b).hexdigest()
c=(candidate/'working/candidate.svg').read_bytes(); b=(baseline/'working/baseline.svg').read_bytes()
pattern=rb'<path data-label-cue="([^"]+)"[^>]+/>'
cues=list(re.finditer(pattern,c))
assert cues and pattern not in b
assert re.sub(pattern,b'',c)==b, 'Export changed beyond nonsemantic cue paths'
records=[]
for match in cues:
elem=ET.fromstring(match.group(0))
assert elem.attrib['fill']=='none' and elem.attrib['stroke']=='#4b5968'
assert elem.attrib['stroke-width']=='1' and elem.attrib['stroke-dasharray']=='2 3'
assert elem.attrib['pointer-events']=='none'
assert not any('marker' in key for key in elem.attrib) and 'data-edge' not in elem.attrib
records.append(dict(elem.attrib))
assert len({row['data-label-cue'] for row in records})==len(records)
target=next(row for row in records if row['data-label-cue']=='63009b5f-539e-5914-b630-ec6b7fefb4d5')
assert target['d']=='M 1180 274.5 L 1162 274.5'
for run in [candidate,baseline]:
finish=json.loads((run/'finished.json').read_text(encoding='utf-8'))
assert finish['exit_code']==0 and finish['stdout_bytes']==finish['stderr_bytes']==0
assert (run/'stdout.log').read_bytes()==(run/'stderr.log').read_bytes()==b''
fixture=(run/'working/eight-card.json').read_bytes()
assert sha(fixture)=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
assert (candidate/'working/eight-card.json').read_bytes()==(baseline/'working/eight-card.json').read_bytes()
receipt={'status':'PASS','candidate_svg_sha256':sha(c),'baseline_svg_sha256':sha(b),
'candidate_bytes':len(c),'baseline_bytes':len(b),'cue_count':len(records),'cues':records,
'entire_svg_byte_identical_after_removing_only_cue_paths':True,
'both_complete_model_files_unchanged':True,'both_normal_exit_zero_empty_streams':True,
'scope':'Native SVG export conservation; not reliable first reading or production acceptance.'}
with (candidate/'svg-comparison.json').open('x',encoding='utf-8') as f: f.write(json.dumps(receipt,indent=2)+'\n')
print(json.dumps(receipt,indent=2))
@@ -1,36 +0,0 @@
from pathlib import Path
import hashlib, json, re, xml.etree.ElementTree as ET
root=Path(__file__).resolve().parents[1]
candidate=root/'.local/native-cue'; baseline=root/'.local/native-cue-baseline'
sha=lambda b:hashlib.sha256(b).hexdigest()
c=(candidate/'working/candidate.svg').read_bytes(); b=(baseline/'working/baseline.svg').read_bytes()
pattern=rb'<path data-label-cue="([^"]+)"[^>]+/>'
cues=list(re.finditer(pattern,c))
assert cues and b'data-label-cue' not in b
assert re.sub(pattern,b'',c)==b, 'Export changed beyond nonsemantic cue paths'
records=[]
for match in cues:
elem=ET.fromstring(match.group(0))
assert elem.attrib['fill']=='none' and elem.attrib['stroke']=='#4b5968'
assert elem.attrib['stroke-width']=='1' and elem.attrib['stroke-dasharray']=='2 3'
assert elem.attrib['pointer-events']=='none'
assert not any('marker' in key for key in elem.attrib) and 'data-edge' not in elem.attrib
records.append(dict(elem.attrib))
assert len({row['data-label-cue'] for row in records})==len(records)
target=next(row for row in records if row['data-label-cue']=='63009b5f-539e-5914-b630-ec6b7fefb4d5')
assert target['d']=='M 1180 274.5 L 1162 274.5'
for run in [candidate,baseline]:
finish=json.loads((run/'finished.json').read_text(encoding='utf-8'))
assert finish['exit_code']==0 and finish['stdout_bytes']==finish['stderr_bytes']==0
assert (run/'stdout.log').read_bytes()==(run/'stderr.log').read_bytes()==b''
fixture=(run/'working/eight-card.json').read_bytes()
assert sha(fixture)=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
assert (candidate/'working/eight-card.json').read_bytes()==(baseline/'working/eight-card.json').read_bytes()
receipt={'status':'PASS','candidate_svg_sha256':sha(c),'baseline_svg_sha256':sha(b),
'candidate_bytes':len(c),'baseline_bytes':len(b),'cue_count':len(records),'cues':records,
'entire_svg_byte_identical_after_removing_only_cue_paths':True,
'both_complete_model_files_unchanged':True,'both_normal_exit_zero_empty_streams':True,
'scope':'Native SVG export conservation; not reliable first reading or production acceptance.'}
with (candidate/'svg-comparison-final.json').open('x',encoding='utf-8') as f: f.write(json.dumps(receipt,indent=2)+'\n')
print(json.dumps(receipt,indent=2))
@@ -1,41 +0,0 @@
from pathlib import Path
import hashlib, json, shutil, subprocess
root=Path(__file__).resolve().parents[1]
source='3e5e094bb17877674f4f3ea027a25fc0bdecdfe7'
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)
packet=root/'harness/experiments/label-cue-20261001/evidence'; packet.mkdir(exist_ok=False)
sha=lambda b:hashlib.sha256(b).hexdigest()
for name in ['native-cue','native-cue-baseline']:
origin=root/'.local'/name
for path in origin.rglob('*'):
relative=path.relative_to(origin)
if not path.is_file() or relative.parts[0]=='bin': continue
dest=packet/name/relative; dest.parent.mkdir(parents=True,exist_ok=True)
shutil.copyfile(path,dest)
for name in ['label-cue-format-check.log','label-cue-diagram-tests.log','label-cue-clippy.log','label-cue-build.log',
'prepare-native-cue.py','launch-native-cue.py','launch-native-cue-first-failed.py',
'launch-native-cue-baseline.py','native-cue-prep-plan.md','check-cue-svg.py','check-cue-svg-first.py']:
shutil.copyfile(root/'.local'/name,packet/name)
shutil.copyfile(Path(__file__),packet/'collect-cue-evidence.py')
files=['crates/oa-desktop/src/diagram.rs','crates/oa-desktop/src/diagram/label_cues.rs',
'crates/oa-desktop/src/diagram/attachment_tests.rs','Cargo.lock']
manifest={'source':source,'base':'6ea7518e7be5b5f17d5fbc5d667da8b388058af4','files':{}}
for name in files:
b=subprocess.check_output(['git','show',source+':'+name],cwd=root)
manifest['files'][name]={'bytes':len(b),'sha256':sha(b)}
(packet/'source-manifest.json').write_text(json.dumps(manifest,indent=2)+'\n',encoding='utf-8')
commands={'source':source,'parent_observed_commands':[
'cargo fmt --all -- --check',
'cargo test --locked -p oa-desktop -- diagram:: --test-threads=1',
'cargo clippy --locked -p oa-desktop --all-targets -- -D warnings',
'cargo build --locked -p oa-desktop --bin arcadia-studio'],
'environment':'Rust1.98.1 stable gnullvm; LLVM-MinGW20260826 UCRT; one job, incremental0, shared target-gnullvm',
'test_result':{'passed':87,'failed':0,'ignored':0,'filtered':1463},
'scope':'Targeted diagram gates; flags are parent-observed, stdout logs alone do not prove invocation flags.'}
(packet/'commands.json').write_text(json.dumps(commands,indent=2)+'\n',encoding='utf-8')
inventory={p.relative_to(packet).as_posix():{'bytes':p.stat().st_size,'sha256':sha(p.read_bytes())}
for p in packet.rglob('*') if p.is_file()}
(packet/'evidence-files.json').write_text(json.dumps(inventory,indent=2)+'\n',encoding='utf-8')
print(json.dumps({'status':'collected','source':source,'captured_files':len(inventory),'bytes':sum(i['bytes'] for i in inventory.values())},indent=2))
@@ -1,17 +0,0 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"parent_observed_commands": [
"cargo fmt --all -- --check",
"cargo test --locked -p oa-desktop -- diagram:: --test-threads=1",
"cargo clippy --locked -p oa-desktop --all-targets -- -D warnings",
"cargo build --locked -p oa-desktop --bin arcadia-studio"
],
"environment": "Rust1.98.1 stable gnullvm; LLVM-MinGW20260826 UCRT; one job, incremental0, shared target-gnullvm",
"test_result": {
"passed": 87,
"failed": 0,
"ignored": 0,
"filtered": 1463
},
"scope": "Targeted diagram gates; flags are parent-observed, stdout logs alone do not prove invocation flags."
}
@@ -1,174 +0,0 @@
{
"check-cue-svg-first.py": {
"bytes": 2313,
"sha256": "bd7ed4495e6ac8bd3706de205f7558fa950d6484ea89a9ce264eec2ddd0588b0"
},
"check-cue-svg.py": {
"bytes": 2329,
"sha256": "bb185c9c412efb71de73706bac9d43bd46b83b9448237017bc0fc9bc7ff6f50b"
},
"collect-cue-evidence.py": {
"bytes": 2877,
"sha256": "950968884950e4bc4b42136bc06d058d0031e87d23ad437f0cece917aa43fa1a"
},
"commands.json": {
"bytes": 681,
"sha256": "49e62cce293c7d1e71c162413fb2308707d251a812d32183227278d7a416a842"
},
"label-cue-build.log": {
"bytes": 324,
"sha256": "3f9858855087c2696cee0c65dc72634b125523ab622019b4e4f0aa4a2fd0d14e"
},
"label-cue-clippy.log": {
"bytes": 399,
"sha256": "96ced22d412dbf5987232665b7cc98fa3be397f0d0b6f237647e7f6ce6fec9de"
},
"label-cue-diagram-tests.log": {
"bytes": 9953,
"sha256": "dfa084b8f34044f39eacb7e5d86a824417b2ccc2c2e6e23671eb9d5b814558e3"
},
"label-cue-format-check.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"launch-native-cue-baseline.py": {
"bytes": 2459,
"sha256": "150b33303ce23083f9bd6fff21fee02e5855ddd91eb4e4528211bab145c36082"
},
"launch-native-cue-first-failed.py": {
"bytes": 2072,
"sha256": "34362f29c7ded497e6a0ef9f8ce46bb5a2c9129a2b7852834dee38fcf48f6c75"
},
"launch-native-cue.py": {
"bytes": 2104,
"sha256": "e2550781b8960a42ccf997e61ff67b7dc2c26b2a5f8a9e3895df7c80b4c8a47b"
},
"native-cue-prep-plan.md": {
"bytes": 2138,
"sha256": "44f1cd13e40c13b3a53777aef65b894e319cf5ea30f1ef4d82e97d4a7d986abe"
},
"prepare-native-cue.py": {
"bytes": 1695,
"sha256": "9fc589afbe61f9d82ea43af602fc9f686b597dbf1f0fd22a701109b65ab57da2"
},
"source-manifest.json": {
"bytes": 776,
"sha256": "3b5b70dfe0a05caf4908c516243e8fd06e2d6a091867390b647b819248d53d04"
},
"native-cue/baseline.json": {
"bytes": 672,
"sha256": "064ee28601d60d693c794d201786875460be617789351b3265e609961ee1fcfe"
},
"native-cue/finished.json": {
"bytes": 661,
"sha256": "73d483b9581dc1ed1ed0354c87487496c7b97e10da78f1cf699f8d51a31b88be"
},
"native-cue/started.json": {
"bytes": 508,
"sha256": "47dd7ef8dc44351d0bcea6325e9bd53b40e955f1dea43e6a0137a910b6db5161"
},
"native-cue/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-cue/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-cue/svg-comparison-final.json": {
"bytes": 837,
"sha256": "8cdc2c2196a56a26b376c5a513aac61e81edd75bc932587548c0b4222a57a351"
},
"native-cue/svg-comparison.json": {
"bytes": 837,
"sha256": "8cdc2c2196a56a26b376c5a513aac61e81edd75bc932587548c0b4222a57a351"
},
"native-cue-baseline/finished.json": {
"bytes": 721,
"sha256": "963bc0b874318519b8c7678e8026cb2798a92bdc77151510126b5f53048da6da"
},
"native-cue-baseline/started.json": {
"bytes": 518,
"sha256": "8465e67b75b252ff02c86e3a302bf888535b50aa2d587b852a1d2072b41bdf3f"
},
"native-cue-baseline/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-cue-baseline/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"native-cue/export/00-path.png": {
"bytes": 141297,
"sha256": "addc4d8c619716abc4278fe1852d2029f298649a945c082dfad718ea13ad4523"
},
"native-cue/export/01-export-success.png": {
"bytes": 146710,
"sha256": "228a3e0dcf24f66d57a31493530afd7012f95f491f4f6482db8091998d970773"
},
"native-cue/export/02-tools-expanded.png": {
"bytes": 151283,
"sha256": "df20a50b7431125080a3e769246ed1d0df54a61cbc09c1351860390b532dfaf6"
},
"native-cue/export/03-restored.png": {
"bytes": 146610,
"sha256": "61fe81874d300e0432f0b8d37d8e6091c71515d439285367b3683527f3936b1d"
},
"native-cue/export/review.md": {
"bytes": 1710,
"sha256": "a52991690668baf83dc05b9c00887c4bfb00db3f4bab29977dd9342696285842"
},
"native-cue/first-reading/01-first-fit.png": {
"bytes": 150900,
"sha256": "471db6b7ab5e38a059b9043d6aa34f3956f671af199d63863d719801e8f40f69"
},
"native-cue/first-reading/02-zoom-62.png": {
"bytes": 151070,
"sha256": "a11d2e130fe4bc1774981815ba3a7fa6a7f5128a0031658ded1c314bed7ad700"
},
"native-cue/first-reading/03-restored-fit.png": {
"bytes": 150949,
"sha256": "a870dee6c38c3c639148863fdca749b25a76783025abd0c7c4b29b6649e63999"
},
"native-cue/first-reading/review.md": {
"bytes": 6825,
"sha256": "781d4fa051c96b5425856927ef5242061b3c95c4aa358455cd10f655eeecbc05"
},
"native-cue/prep/preparation.md": {
"bytes": 1434,
"sha256": "7a51a7eec8b978db205a5aa9d236b678db296e0d081e263c36dfa1f7762ce8b9"
},
"native-cue/prep/target-ready.png": {
"bytes": 151170,
"sha256": "4165d59578b1817ce01edb742309a2c35ffe2db5508e53842b79dcec710b6f73"
},
"native-cue/working/candidate.svg": {
"bytes": 7391,
"sha256": "ada19523bb65734ee636003f5db0f49755159b0239449050c4284b9212be1060"
},
"native-cue/working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
},
"native-cue-baseline/export/00-path.png": {
"bytes": 141523,
"sha256": "6434ae7252d67aa72887b2aa75e8a4df315f40f4604c8db2f2df259316a4a86a"
},
"native-cue-baseline/export/01-export-success.png": {
"bytes": 146588,
"sha256": "8b9fac30f6b47e65cfe8060359d0ed9a7e3d38b42e4cf0ac68b1f61e520364eb"
},
"native-cue-baseline/export/review.md": {
"bytes": 1717,
"sha256": "ab890084bc2ccd9ac27b5ff79a756d9bfe08bd7e8ed988ca64128ab5ad017ca8"
},
"native-cue-baseline/working/baseline.svg": {
"bytes": 7209,
"sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d"
},
"native-cue-baseline/working/eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
}
@@ -1,5 +0,0 @@
Compiling iced_widget v0.14.2 (C:\ar-label-cue-01a0d717\crates\vendor\iced_widget)
Compiling oa-core v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-core)
Compiling iced v0.14.0
Compiling oa-desktop v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-desktop)
Finished `dev` profile [unoptimized] target(s) in 1m 08s
@@ -1,6 +0,0 @@
Compiling oa-core v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-core)
Checking iced_widget v0.14.2 (C:\ar-label-cue-01a0d717\crates\vendor\iced_widget)
Compiling oa-server v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-server)
Compiling oa-desktop v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-desktop)
Checking iced v0.14.0
Finished `dev` profile [unoptimized] target(s) in 1m 02s
@@ -1,34 +0,0 @@
from pathlib import Path
import datetime, hashlib, json, os, shutil, subprocess
root = Path(__file__).resolve().parents[1]
run = root/'.local/native-cue-baseline'; run.mkdir(exist_ok=False)
work = run/'working'; work.mkdir()
fixture = root/'.local/native-cue/working/eight-card.json'
sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest()
assert sha(fixture)=='9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
shutil.copyfile(fixture,work/'eight-card.json')
bundle = Path('C:/ar-compact-01a0d717/.local/package39/extracted/ArcadiaStudio-0.2.0-preview.compact-help.20261001-x86_64-pc-windows-gnullvm')
exe=bundle/'arcadia-studio.exe'; runtime=bundle/'libunwind.dll'
assert sha(exe)=='d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e'
assert sha(runtime)=='f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4'
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]
receipt={'source':'6e7c4ddaf0775198384a8c4882809ea8e14b2976','start':datetime.datetime.now(datetime.timezone.utc).isoformat(),
'binary_sha256':sha(exe),'runtime_sha256':sha(runtime),'fixture_sha256':sha(fixture),
'cwd':str(work),'path':env['PATH']}
with (run/'stdout.log').open('xb') as out,(run/'stderr.log').open('xb') as err:
child=subprocess.Popen([str(exe)],cwd=work,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,
'fixture_unchanged':sha(work/'eight-card.json')==receipt['fixture_sha256'],
'binary_unchanged':sha(exe)==receipt['binary_sha256'],'runtime_unchanged':sha(runtime)==receipt['runtime_sha256']})
(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 all(receipt[k] for k in ['fixture_unchanged','binary_unchanged','runtime_unchanged'])
@@ -1,34 +0,0 @@
from pathlib import Path
import datetime, hashlib, json, os, subprocess
root = Path(__file__).resolve().parents[1]
run = root / '.local/native-cue'
record = json.loads((run/'baseline.json').read_text(encoding='utf-8'))
files = {Path(name).as_posix(): entry for name, entry in record['files'].items()}
sha = lambda path: hashlib.sha256(path.read_bytes()).hexdigest()
for relative, entry in 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]
receipt = {'source': record['source'], 'start': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'binary_sha256': files['bin/arcadia-studio.exe']['sha256'],
'runtime_sha256': files['bin/libunwind.dll']['sha256'],
'fixture_sha256': 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 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']
Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

@@ -1,11 +0,0 @@
# Baseline native SVG export
Parent identity: source 6e7c4ddaf0775198384a8c4882809ea8e14b2976; executable SHA256 d55ecad4b0f75c0c9c26625e5441bef9c9360890b65bc13236c6ebfaf03d631e; runtime prefix f456; PID 10220. Native window returned ID 16778564, app executable in extracted ArcadiaStudio-0.2.0-preview.compact-help.20261001-x86_64-pc-windows-gnullvm package under C:/ar-compact-01a0d717/.local/package39/extracted/.
Opened C:/ar-label-cue-01a0d717/.local/native-cue-baseline/working/eight-card.json with native Open. Initial Ctrl+A/type on apparent filename focus left the field empty; no Open was committed. Explicit pointer focus and one literal backslash-path retry displayed the exact intended path, then pointer Open loaded it. This transient chooser input observation is not classified as an application defect.
Switched System, selected Issue 38 representative eight-card mixed view, observed OA → SA traceability, clicked Fit and Escape. Target at 52%, 1442×932, eight cards visible, zero selection. Clicked Export SVG; in app-native Export diagram modal focused path, Ctrl+A, typed C:/ar-label-cue-01a0d717/.local/native-cue-baseline/working/baseline.svg and clicked Export diagram. Footer reported Diagram exported as SVG. Screenshots 00-path.png and 01-export-success.png.
No model edit, Apply, Save, JSON export, diagram selection or drag. No model/SVG text or bytes inspected. Parent owns file/model/XML comparison and output existence/hash validation. Experimental B and fresh-reader reports unchanged; no comparative interpretation made here.
Alt+F4 closed normally without an observed prompt. Fresh enumeration no longer listed Arcadia. Parent owns process exit/log checks. GUI relinquished.
@@ -1,12 +0,0 @@
# Native label-cue scene preparation
Scope: scene preparation only, before a separate fresh reader's first native inspection. Parent owns build identification, launch, fixture byte checks, and process logs. No GUI input or launch until exact parent readiness. Source branch inspected: `codex/label-cue-experiment-01a0d717-20261001`; clean tracked working tree at planning time.
1. On parent readiness, enumerate native windows and identify only the parent-launched experimental executable. Observe before each UI action using the Computer Use skill.
2. Open `C:/ar-label-cue-01a0d717/.local/native-cue/working/eight-card.json` through the native chooser. Focus the filename field and use Ctrl+A, literal typing, and actual Open/Return commit; do not use accessibility set_value.
3. In Architecture, switch to System perspective and choose the saved `Issue 38 representative eight-card mixed view`, then the Traceability projection. Resolve controls from actual screenshots. Do not expose intermediate OA or simpler SA views to the fresh reader.
4. Set normal 1440×900 client size (approximately 1442×932 outer screenshot), use Fit, and Escape to zero selection. Leave the target fully visible with no menu, Help, dialog, or element inspector overlay obstructing it. Do not edit, Apply, Save, drag, or infer relationship answers.
5. Save only the final target screenshot plus preparation report under `.local/native-cue/prep`. Record exact observed window size, zoom, header, zero selection, and visible card count. Record setup facts without decoding or naming diagram relationships for the reader.
6. Stop all GUI input and relinquish to the parent/new reader. The fresh reader's first view must be this complete target scene. Parent should give them no earlier source/geometry/results or preparation intermediate screenshots. Parent verifies pristine bytes independently.
If the target cannot be reached or the expected scene does not appear, stop and report the actual setup mismatch without editing or supplying inferred answers. No compilation, Gitea action, production edit, fixture generation, or app launch by this preparer.
@@ -1,20 +0,0 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"experiment": "B guarded label cue; not production acceptance",
"profile": "dev/unoptimized",
"target": "x86_64-pc-windows-gnullvm",
"files": {
"bin\\arcadia-studio.exe": {
"bytes": 119575040,
"sha256": "38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04"
},
"bin\\libunwind.dll": {
"bytes": 190976,
"sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4"
},
"working\\eight-card.json": {
"bytes": 138661,
"sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

@@ -1,9 +0,0 @@
# Experimental B native SVG export
Parent identity: source 3e5e094b, executable SHA256 38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04, runtime prefix f456, PID 2600. Native returned window ID 8979690. This is post-reading verification; original first-reader findings are unchanged and this export is not evidence that reading was repaired.
Started saved Issue 38 representative eight-card mixed view, System, OA → SA traceability, Fit 52%, 1442×932, zero selection. Clicked Export SVG; app-native Export diagram modal opened. Focused its path field, Ctrl+A, typed exact C:/ar-label-cue-01a0d717/.local/native-cue/working/candidate.svg and clicked Export diagram. Footer reported Diagram exported as SVG. Screenshots 00-path.png and 01-export-success.png. No model edit/Apply/Save/JSON export/selection. Did not read SVG or model bytes; parent owns parity/content checks.
Separate optional workspace observation: clicked left-chevron at canvas right. It expanded a labeled tool palette into the canvas, with Collapse tools at its top; it did not collapse the properties sidebar or enlarge the drawing. Zoom remained 52%, some right-side card area became obscured, so no improved legibility was established. Clicked Collapse tools and Fit; restored all eight cards fully visible at 52%, zero selection, original ordinary project-properties side pane. Screenshots 02-tools-expanded.png and 03-restored.png. No content filtering or dragging.
Alt+F4 closed normally without an observed import/save prompt. Fresh native enumeration no longer listed Arcadia. Parent owns watcher exit/logs and fixture hashes. Ready for separately identified baseline launch; no baseline GUI has been touched.
@@ -1,15 +0,0 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"start": "2026-10-02T01:58:14.783807+00:00",
"binary_sha256": "38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 2600,
"exit_code": 0,
"finished": "2026-10-02T02:04:57.934656+00:00",
"stdout_bytes": 0,
"stderr_bytes": 0,
"all_pinned_files_unchanged": true
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

@@ -1,33 +0,0 @@
# Independent first-exposure native diagram reading
## Phase 1: locked first reading, before any viewing input
Evaluator: candidate_blind_reading, GPT-6 Astra agent. Date: 2026-10-01. This is one fresh agent trial, not a human study or native editing acceptance.
Window: returned window 8979690, prepared native arcadia-studio.exe. The first live screenshot shows Architecture, System, saved view `Issue 38 representative eight-card mixed view`, view content `OA → SA traceability`, 52%, 0 selected, and all eight cards. Capture size: 1442 × 932. Evidence: [raw first Fit capture](01-first-fit.png).
No UI input, zoom, selection, Inspector/Connections interaction, semantic lookup, model/source reading, oracle, previous report, or comparison was used before this record. The existing Properties panel is visible in the complete screenshot; its text was not used to infer relations. Only the working agreement and Computer Use operating documentation were read.
| Displayed relation | First endpoint/card interpretation | Orientation | Confidence | Visible stroke/marker evidence and alternatives |
| --- | --- | --- | --- | --- |
| Request field repair | Assess pressure alarm to Repair valve in the field | Directed, left card toward repair card | Low to moderate, about 0.45 | The assessment card has a rightward green outlined triangle at its right edge; the repair card has a rightward triangle at its upper left edge. A thin orthogonal route and this label occupy the middle area, but I cannot confidently follow the label's entire route through the crossings at Fit. A plausible alternative is that the labelled route begins at Assess an alarm procedure or at the Pressure coordination service; another is that the triangles belong to neighboring relations. The chosen pair is partly aided by the meaning of the name, not established solely by an unambiguous stroke trace. |
| Report repair result | Repair valve in the field to Confirm safe pressure | Directed, from repair leftward and down to confirmation | Moderate, about 0.60 | The label sits just above a horizontal line leaving the lower left of the repair card. A leftward outlined green triangle appears there, and a leftward triangle enters the right edge of Confirm safe pressure. The vertical path through the left-middle network is hard to disambiguate. Reset valve remotely is a plausible alternative target because a left-facing marker also enters that card; the line might instead attach to the Pressure coordination service. The name helps the repair-to-confirmation interpretation. |
| Technician service conversation | Field technician and Pressure coordination service | Tentatively unoriented, not confidently bidirectional | Moderate for endpoints, about 0.65; low to moderate for orientation, about 0.45 | Purple and blue outlined square markers appear at Field technician's left edge and Pressure coordination service's right edge, with an orthogonal route between their vicinity. I read squares as connection endpoints without directional arrowheads. The label lies lower and nearer a separate down-going route from technician toward Repair valve in the field; therefore technician-to-repair, directed downward, is a credible alternative. I cannot confidently associate this label to one of those nearby routes at this size. |
### Immediate first-view reading observations
The labels are very small at 52%. The cards and broad routing are visible, but several central horizontal segments cross or share near-parallel vertical paths. Following a named line requires sustained tracing. The triangle and square shapes look potentially semantic; I have no legend establishing their meaning. They could also be connection affordances or ports rather than the relation's orientation. I did not treat them as editing handles with certainty. No obvious branch junction cue can be read reliably in this first view. These observations are locked before additional viewing input; later discoveries must be separate.
## Phase 2: bounded viewing after first-answer checkpoint
The first-answer checkpoint was sent to the parent before any input. I then refreshed the live native window, clicked Zoom + once (52% to 62%), observed and preserved [the raw 62% capture](02-zoom-62.png), refreshed again, clicked Fit, and verified [the restored raw 52% capture](03-restored-fit.png). These were the only two UI input actions. No card, link, label, model, view, property, connection, filter, or selection was clicked. No pan, drag, edit, Apply, Save, or semantic lookup was performed.
At 62%, the card titles and labels were slightly larger but several rightmost cards and the conversation label were clipped, and Confirm safe pressure was partly clipped at the bottom. This traded overall route context for only a small readability improvement. I stopped after that one step instead of gathering a partially visible enlarged route as if it established the answer.
The subsequent view did not establish a confident replacement for any locked first answer. In particular, the Request field repair label lies above a long horizontal stroke with upward and downward routing in a crowded area. Following it can suggest other cards than my initial pair; I cannot resolve the crossing versus branch associations from this bounded reading. Report repair result remains my most plausible first reading, but shared-looking vertical routes also approach Reset valve remotely. Technician service conversation remains uncertain because its text sits near the down-going technician-to-repair arrow as well as the square-ended technician/service route.
The pale stroke-like marks adjacent to some label text were not independently clear enough for me to use as semantic leaders. They could be subtle connector fragments or label attachment cues; I cannot reliably distinguish them from low-contrast visual noise at these scales. The colored endpoint shapes are more conspicuous, but without a visible legend their port/arrow/handle role is uncertain. This is a drawing-only readability finding, not proof of incorrect model semantics or an assertion that any particular marker is nonsemantic.
## Handoff and limits
The same native app remains open. Final observed state: Architecture, System, `Issue 38 representative eight-card mixed view`, `OA → SA traceability`, Fit 52%, 0 selected, all eight cards visible, 1442 × 932. GUI control is relinquished to the parent. The initial answers above remain locked for oracle adjudication. No source, model JSON, answer key, old report, research, or baseline comparison was inspected. This bounded agent trial measures first-exposure reading uncertainty and the cost of tracing these particular routes; it does not establish human usability, correctness, editing acceptance, or generalization beyond this scene.
@@ -1,11 +0,0 @@
# Native scene prepared
Preparation only; no reading answers or relationship interpretation.
Parent-provided launch: PID 2600, source 3e5e094b, executable SHA256 38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04, runtime SHA256 prefix f456. Target native window returned ID 8979690; app process:C:\ar-label-cue-01a0d717\.local\native-cue\bin\arcadia-studio.exe.
Opened exact C:/ar-label-cue-01a0d717/.local/native-cue/working/eight-card.json through focused filename field, Ctrl+A, literal full-path typing and pointer Open. Switched System perspective, selected saved Issue 38 representative eight-card mixed view; observed View content OA → SA traceability. Clicked Fit, then Escape.
Final observed outer screenshot 1442×932 (normal requested 1440×900 client). Zoom 52%, 0 selected, all eight cards wholly visible. Saved-view header exactly Issue 38 representative eight-card mixed view. Ordinary project-properties sidebar remains; no element inspector, menu, Help or dialog overlays the canvas. No edit, Apply, Save or drag performed. Parent owns fixture equality checks and process logs.
Only final scene screenshot saved as target-ready.png. No intermediate screenshots or relationship answers saved for the fresh reader. GUI input relinquished immediately after final capture. Reader should begin with the live complete scene; do not provide them this preparation conversation or earlier simpler views.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

@@ -1,10 +0,0 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"start": "2026-10-02T01:58:14.783807+00:00",
"binary_sha256": "38abdb21278f85b6d4f946d25535c084aa49eddfac74e99f78caa85ace1faa04",
"runtime_sha256": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"fixture_sha256": "9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8",
"cwd": "C:\\ar-label-cue-01a0d717\\.local\\native-cue\\working",
"path": "C:\\Windows\\System32;C:\\Windows",
"pid": 2600
}
@@ -1,23 +0,0 @@
{
"status": "PASS",
"candidate_svg_sha256": "ada19523bb65734ee636003f5db0f49755159b0239449050c4284b9212be1060",
"baseline_svg_sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d",
"candidate_bytes": 7391,
"baseline_bytes": 7209,
"cue_count": 1,
"cues": [
{
"data-label-cue": "63009b5f-539e-5914-b630-ec6b7fefb4d5",
"d": "M 1180 274.5 L 1162 274.5",
"fill": "none",
"stroke": "#4b5968",
"stroke-width": "1",
"stroke-dasharray": "2 3",
"pointer-events": "none"
}
],
"entire_svg_byte_identical_after_removing_only_cue_paths": true,
"both_complete_model_files_unchanged": true,
"both_normal_exit_zero_empty_streams": true,
"scope": "Native SVG export conservation; not reliable first reading or production acceptance."
}
@@ -1,23 +0,0 @@
{
"status": "PASS",
"candidate_svg_sha256": "ada19523bb65734ee636003f5db0f49755159b0239449050c4284b9212be1060",
"baseline_svg_sha256": "645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d",
"candidate_bytes": 7391,
"baseline_bytes": 7209,
"cue_count": 1,
"cues": [
{
"data-label-cue": "63009b5f-539e-5914-b630-ec6b7fefb4d5",
"d": "M 1180 274.5 L 1162 274.5",
"fill": "none",
"stroke": "#4b5968",
"stroke-width": "1",
"stroke-dasharray": "2 3",
"pointer-events": "none"
}
],
"entire_svg_byte_identical_after_removing_only_cue_paths": true,
"both_complete_model_files_unchanged": true,
"both_normal_exit_zero_empty_streams": true,
"scope": "Native SVG export conservation; not reliable first reading or production acceptance."
}
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.2 KiB

@@ -1,25 +0,0 @@
from pathlib import Path
import hashlib, json, shutil, subprocess
root = Path(__file__).resolve().parents[1]
source = '3e5e094bb17877674f4f3ea027a25fc0bdecdfe7'
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)
run = root / '.local/native-cue'
run.mkdir(exist_ok=False)
bins = run / 'bin'; bins.mkdir()
work = run / 'working'; work.mkdir()
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-compact-01a0d717/.local/package39/bin/libunwind.dll')
fixture = Path('C:/ar-diagram-01a0d717/.local/native-reading/working/eight-card.json')
assert sha(runtime) == 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4'
assert sha(fixture) == '9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8'
for original, destination in [(target, bins/'arcadia-studio.exe'), (runtime, bins/'libunwind.dll'), (fixture, work/'eight-card.json')]:
shutil.copyfile(original, destination)
record = {'source': source, 'experiment': 'B guarded label cue; not production acceptance',
'profile': 'dev/unoptimized', 'target': 'x86_64-pc-windows-gnullvm',
'files': {str(p.relative_to(run)): {'bytes': p.stat().st_size, 'sha256': sha(p)}
for p in [bins/'arcadia-studio.exe', bins/'libunwind.dll', work/'eight-card.json']}}
(run/'baseline.json').write_text(json.dumps(record, indent=2)+'\n', encoding='utf-8')
print(json.dumps(record, indent=2))
@@ -1,22 +0,0 @@
{
"source": "3e5e094bb17877674f4f3ea027a25fc0bdecdfe7",
"base": "6ea7518e7be5b5f17d5fbc5d667da8b388058af4",
"files": {
"crates/oa-desktop/src/diagram.rs": {
"bytes": 125929,
"sha256": "590ba010ad890ec0da54289a87b51e6b334c29170e89ec35ce8bf1d464f6a8cc"
},
"crates/oa-desktop/src/diagram/label_cues.rs": {
"bytes": 14932,
"sha256": "a2f5c119a4fbc0bd8378515e10db454e6cc96d676b4234472f18315125d99313"
},
"crates/oa-desktop/src/diagram/attachment_tests.rs": {
"bytes": 14763,
"sha256": "1cbfa3d926e8c6d7dcbab2d393ce248dd7e190583886f75165c7d2f5c9e7e127"
},
"Cargo.lock": {
"bytes": 119855,
"sha256": "2aa80d113c5112b31c0767b874845d60f555e4e8ae7eb3ecd0b4b91954b55378"
}
}
}
@@ -1,29 +0,0 @@
# Independent B falsification and evidence checkpoint review
No material blocker remains for preserving this failed experiment. Candidate B remains NOT promoted. This review accepts the bounded evidence/claim reconciliation, not production rendering, editing/persistence, performance, release or generalized usability.
Reviewed source identity `3e5e094bb17877674f4f3ea027a25fc0bdecdfe7`, packet README/STATE, original scoped source review, actual first-reading and setup/export reports, both helpers and retained corrections, captured SVGs/input models/process receipts, gate logs, commands and source manifest. No compiler, GUI, Gitea, commit or source/document patch; this review file is the only new artifact.
## Independently reconciled integrity
All 43 evidence inventory entries match working-file sizes and SHA256. Only evidence-files.json itself is unlisted. At the final read, all 43 staged Git blobs also match the inventory exactly. The four source-manifest file entries match Git blobs at 3e5e094b. Relevant relative README/first-reading links resolve.
Actual copied and local SVG bytes agree. Candidate SVG is 7,391 bytes, SHA256 `ada19523bb65734ee636003f5db0f49755159b0239449050c4284b9212be1060`; baseline SVG is 7,209 bytes, SHA256 `645ee69cc97d11acc812539b62528d7fdceec32aa2516d4ade8508016164119d`. Independently parsed exactly one added path for edge `63009b5f-539e-5914-b630-ec6b7fefb4d5`, M1180 274.5 to L1162 274.5, no fill, #4b5968 stroke, width1, dash2/3, pointer-events none and no semantic edge/arrow marker. Baseline literally contains no data-label-cue attribute. Removing that exact candidate path makes the entire SVG byte-identical to baseline, not just selected geometry fields.
Both actual input models and copied packet models are 138,661 bytes with unchanged SHA256 `9db1015369f450d5810c96a01fddb8a009d57f6aafbda5182703f15ded23d9c8`. Actual candidate/baseline executable hashes match their receipts (`38abdb21...` / `d55ecad4...`); both DLLs match `f45604a1...`. Candidate PID2600 and baseline PID10220 each have normal exit0 receipts and genuinely empty stdout/stderr files. These are no-edit fixture/export conservation checks, not source Save, edited-label persistence or model migration acceptance.
## Claim reconciliation
The test log supports 87 passes, zero failures/ignores and 1,463 filtered out. Commands.json explicitly attributes formatting, strict desktop/all-target Clippy and GUI build flags to parent-observed invocations; logs record successful completion. No full-suite claim is made. The earlier source review's preformat/pre-strengthened-test hashes remain historical and are not misrepresented as exact final-source review.
The candidate first-reading report supports the stated rejection: the fresh agent gave correct initial participant guesses but retained technician-to-repair Allocation as a credible conversation-label alternative; it could not confidently use the pale marks at Fit or one zoom step. Request/report tracing remained uncertain. Setup was performed separately and the reader reports locked answers before interaction or semantic lookup. The packet does not turn this one-agent trial into human-study evidence or prove causal improvement relative to a different static reader.
Initially README's auxiliary baseline static-reading comparison lacked its source. Parent added a direct commit-specific link to `45bfb63b.../first-exposure/review.md`; that local authoritative report indeed assigns the conversation to the technician-to-repair Allocation/arrowhead and disclaims human/generalized acceptance. The traceability finding is resolved. This reviewer did not query Gitea or independently certify remote availability.
README and STATE clearly say B is not accepted and must not be treated as an integrated release. Stopping before dense-preview timing and edited-label persistence is reasonable after the predeclared first-reading falsifier; those tests are expressly unperformed, not assumed to pass. Passing compilation/conservation does not repair this failed association result. Future multiline/layout work remains a separate experiment with an unresolved authored-format boundary.
## Retained harness limitations
The original launcher used forward-slash dictionary keys against a Windows manifest containing backslashes. Its receipt construction precedes stdout creation/Popen, consistent with failure before process creation. Corrected code normalizes keys without altering the original manifest. The original SVG checker tested literal regex bytes for baseline membership, which was insufficient. Its whole-output equality check was already meaningful; the final checker adds literal data-label-cue absence. Both scripts and receipts remain preserved, and the independent direct comparison above confirms the corrected result.
Copied scripts retain their original filesystem assumptions and need adapted roots in a new checkout, as README states. No generic portability or hardened evaluator claim is appropriate. No source mutation, semantic contradiction, hidden cue promotion or unsupported persistence acceptance was found. Publication of this experiment checkpoint remains separate; no new tag, release or published asset is certified here.
@@ -1,37 +0,0 @@
# Isolated label association cue experiment
Base: 6ea7518e; branch codex/label-cue-experiment-01a0d717-20261001. This is
candidate B for issue 38, not production acceptance. The eight-card view is a
representative reconstruction, not recovered user source. Existing-candidate
automatic-placement feasibility is being investigated separately in Rust.
Before implementation, the intended policy is a private derived straight cue from
the nearest point on a nonempty label's rectangular boundary to its existing
route anchor. Require the anchor outside the box and a gap strictly greater than
12 world units. Reject a landing within 7 world units of any distinct edge's
segment, or a cue intersecting any other route, visible card, or other label
(including association-end labels). Exact thresholds are experimental geometry
controls, not measured perceptual limits. No arrows, junction dots, semantic hit
regions, project fields, route changes, label movement, or hiding/grouping.
Cache derived cues with the existing Scene and render a restrained dotted line
in both canvas and SVG. Camera and selection changes must not change admission or
rescan the scene. Scene rebuilds and actual route previews may recompute cues.
Conservative guards may omit potentially useful cues; omission is not a claim
that association is already clear. Container interception may suppress a cue.
Tests will cover the representative conversation's 18-unit boundary gap, normal
6-unit gap, an authored anchor inside its box, shared/near landing and route/card/
label obstruction. SVG must expose a cue without a semantic arrow/edge marker;
Project and routed geometry must remain unchanged. Parent owns formatting,
compilation, native reading, performance, and independent review.
Native evaluator: compare identical complete baseline and candidate scenes with
fresh reading (no Inspector), first association/selected stroke and confidence,
Fit and working zoom, Request/Report controls, and cue mistaken for a relationship.
Reject if the misplaced conversation still attaches perceptually to the foreign
Allocation, if other reading worsens, or if the cue needs prior explanation. The
existing foreign stroke through the label remains a known risk. Count added cues
and intersections; measure rebuild/preview cost against baseline. Preserve every
semantic identity, port, placement, authored field, path and label; Undo/Redo and
save/reopen remain separate native gates. No compiler or GUI run by this agent.
@@ -1,43 +0,0 @@
# Independent source review: isolated label cue candidate B
No blocker or high-severity source defect found in this frozen experimental diff. It is suitable for the parent's compilation and bounded native/performance experiment, not accepted as a fix or production behavior. No compiler, GUI, Gitea operation or production edit was performed. This report is the only new file.
## Reviewed identity
Base `6ea7518e`; uncommitted changes limited to `crates/oa-desktop/src/diagram.rs`, private `diagram/label_cues.rs`, and the added field in one `diagram/attachment_tests.rs` Scene literal. Read the predeclared experiment intent, source handoff, and the independent design critic from the diagram worktree.
Reviewed file SHA256:
- diagram.rs: `f9f7ff0ffa2f9cc41a2eb95651072a6200b67df1c28f427bd921b92724eaee3e`
- label_cues.rs: `82a819e2d7a1bd03a326a4e1c4bf318a6f6d4e87ebfcf22922253ab78a594055`
- attachment_tests.rs: `1cbfa3d926e8c6d7dcbab2d393ce248dd7e190583886f75165c7d2f5c9e7e127`
## Correctness assessment
The helper consumes immutable Project, ProjectedView and RoutedView inputs and returns only a private cue map. No core model field, semantic endpoint, route point, authored label, projected placement/port, selection policy, hitbox or command changes. Picking still uses original path/label geometry; cue strokes introduce no semantic target.
`label_cues.rs:16-46` implements the stated conservative geometry contract: clamp the route anchor to the label rectangle; omit gaps at or below 12 world units, including anchors inside/on the rectangle; reject closed intersection with every distinct edge's segments; reject landing distance at or below 7; and reject visible card/other ordinary label/association-end label intersections. Distinct edge IDs are retained, so a coincident foreign segment cannot be mistaken for a uniquely owned landing. Node/container suppression is intentional. The closed segment intersection and box tests are consistent for straight finite geometry, including collinear overlap and touching. No measured perceptual clearance is established by these constants.
Caching is attached to the existing Scene, not camera state. Both constructors derive from the geometry actually stored in that Scene. Allocation/work preview uses its own preview Project; ordinary route/node/port previews use the current semantic Project with their derived preview geometry, which is appropriate because these previews alter presentation. Existing context/revision, route, preview and port keys control rebuild; the work cache uses preview Arc identity. No new stale-cache path was found by inspection. Existing caller obligations to update context for model changes remain unchanged.
Canvas and SVG use the same derivation and boundary/anchor endpoints. Both paint the dotted cue after its owning path and before its label backing. The backing hides only the boundary's inward stroke half; the admitted open gap stays outside the box. Guards exclude later unrelated route/label/card centerline/rectangle intersections, addressing the ordinary interleaved rendering-order risk. Color matches MUTED (75,89,104); width and dash values match (1; 2/3). SVG has no arrow marker and uses pointer-events none. Cue endpoints are already within the routed path/label bounds, so no export bounds enlargement is required.
## Meaningful tests and specific coverage limits
The four tests are relevant: representative geometry/SVG and model preservation, boundary gap versus center-distance distinction, obstruction guards, and actual Scene Arc reuse across selection/pointer/camera changes. They do not establish compilation or behavior until run.
Nonblocking evaluator weakness at `label_cues.rs:160-165`: all three foreign vertical segments intersect the cue. In particular x=1168 tests both the six-unit clearance condition and crossing rejection. Removing the landing-clearance predicate would still pass that alleged near-landing control. A future focused control should place a short parallel segment six units from the anchor, outside the cue segment, with a corresponding safely distant positive control. Current production predicate itself is correct by inspection.
Further untested boundaries: exactly 12 versus greater-than-12 gap; exactly 7 versus greater-than-7 landing clearance; collinear/touching rectangles; association-end label obstruction; a safe positive control adjacent to each obstruction; scene invalidation for changed route/revision/work preview. The reuse test does not verify invalidation. These are coverage limitations, not reproduced stale state or geometric defects. The representative test does not assert the complete cue set/count, which the native experiment should record.
## Risks and release boundaries
The known central falsifier is unchanged: target cue length is 18 world units, approximately 9.3 pixels at representative Fit, while the foreign Allocation stroke still passes through the label. Four or so tiny dash elements may be missed or read as a relationship branch. Source correctness cannot show improved first association; require the fresh reading experiment before calling B a fix. This review does not endorse explaining the cue to the reader first.
Admission scans routes/cards/labels per eligible label: approximately O(eligible_labels * (total_route_segments + edges + nodes + association_labels)) per scene build, plus association-label geometry construction. The existing scene cache prevents ordinary hover/selection/camera rescans, but route drag previews can rebuild every changed gesture. Dense rebuild/preview latency remains an actual measurement gate. No demonstrated performance regression is claimed here.
Known limited geometry remains: no cue-to-cue avoidance; no port-symbol, arrowhead, glyph or stroke-width contour avoidance; own-route segments other than the anchor are not tested; no width-scaled guard. These may produce visual interference in other scenes, but no such failure was reproduced in this read-only scope. Do not generalize the straight-centerline/rectangle checks into an all-rendered-marks guarantee. Conservative omission is not proof that a label is already understandable.
The private module is proportionate for an isolated experiment. SVG duplicates width/dash/color literals that canvas receives via constants/style; values agree now, but sharing those values would reduce future drift if the candidate survives. No refactor is required before the bounded experiment.
Retain baseline and B with identical complete model, paths, labels and camera; measure first chosen association, controls, cue count/intersections and preview cost. Publication, native usability, save/reopen and broad accessibility acceptance remain outside this review.
@@ -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,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
@@ -1,12 +1,9 @@
Compiling oa-core v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-core)
Compiling oa-server v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-server)
Compiling iced_widget v0.14.2 (C:\ar-label-cue-01a0d717\crates\vendor\iced_widget)
Compiling oa-desktop v0.2.0 (C:\ar-label-cue-01a0d717\crates\oa-desktop)
Compiling iced v0.14.0
Finished `test` profile [unoptimized] target(s) in 2m 21s
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 87 tests
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
@@ -19,6 +16,22 @@ test app::scenario_diagram::tests::saved_picker_applies_valid_old_draft_and_uuid
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
@@ -46,10 +59,14 @@ test diagram::group_gesture::tests::unsnapped_fractional_pointer_delta_preserves
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_cues::tests::default_gap_and_anchor_inside_label_do_not_add_cues ... ok
test diagram::label_cues::tests::representative_cue_and_svg_preserve_complete_project_and_geometry ... ok
test diagram::label_cues::tests::selection_hover_and_camera_reuse_cached_scene_cues ... ok
test diagram::label_cues::tests::shared_or_near_landing_and_route_card_label_obstructions_suppress_cue ... 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
@@ -94,6 +111,30 @@ 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. 87 passed; 0 failed; 0 ignored; 0 measured; 1463 filtered out; finished in 1.78s
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

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